PageSourceSearch

https://www.coursicle.com/all/js/credits.js?new3

js coursicle.com collected 2026-09-24 08:48:32 UTC 16,063 bytes, 421 lines download raw bytes

1$(document).ready(function(){
2
3    // load the credit view data on page load so that we're ready to display the view as soon 
4    // as they open the credit views 
5    
6    // removed for now since we 
7    // getCreditViewDataFromServer();
8})
9
10// if the PWA or web app becomes focused and they're currently looking at the number of credits they have
11// then we update the number. This is pretty important if they're actively referring their friends, 
12// we want them to see the number update without them having to dismiss the view and re-open it.
13ifvisible.on("focus", function () {
14    var creditsModalVisibleOnPWA = (window.isPWA && window.modalStack && window.modalStack.includes("modal#getPaidModal"));
15    var creditsModalVisibleOnWeb = (!window.isPWA && $("#getPaidModal").css('display') != 'none');
16    if(creditsModalVisibleOnPWA || creditsModalVisibleOnWeb){
17        var paymentAmountType = $("#getPaidModal").find(".payoutAmount").attr('class').replace("payoutAmount", "").trim();
18        // just in case we change the classes in there, don't want to send bad data to the server
19        if(["monetary", "premium"].includes(paymentAmountType)){
20            // getUsersCreditsFromServer(paymentAmountType);
21        }
22    }
23});
24
25
26
27async function getCreditViewDataFromServer(){
28    var data = {}
29    if(store.get('uuid')){
30		data['uuid'] = store.get('uuid');
31	}
32    $.ajax({
33        url: "/shared/credits/getCreditViewData.php",
34        type: 'GET',
35        dataType: 'json',
36        data: data,
37        success: function(response){
38            setCreditViewData(response);
39        }
40    })
41}
42
43//get referral URL
44function generateReferralLink(subtype){
45    var data = {type:"referral", subtype:subtype};
46    let params = {
47        "uuid" : store.get("uuid"),
48        "data" : JSON.stringify(data)
49    };
50    $.ajax({
51		url: "/shared/link/generate.php",
52		type: 'POST',
53		dataType: 'json',
54		data: params,
55		success: function(response){
56            if(response.error == true){
57                return
58            }
59            //we don't want to continue the animation if the link has loaded successfully.
60            checkLinkLoadingAnimation()
61            setUserLink(response.url, data);
62            //note that this function also updates the modal.
63            $('#webShareLink').text(getUserLink(data))
64		}
65	});
66}
67
68async function getUsersCreditsFromServer(type){
69    var params = {type:type,uuid:store.get('uuid')}
70    $.ajax({
71		url: "/shared/credits/getUsersCredits.php",
72		type: 'GET',
73		dataType: 'json',
74		data: params,
75		success: function(response){
76            
77            if(response.error == true){
78                //
79            }else{
80
81                setUsersCredits(type, response.credits)
82                setUsersReferrals(type, response.referrals)
83                //note that this function also updates the modal.
84                displayAndFormatUsersCredits(type, response.credits, response.referrals)
85            
86		}}
87	});
88}
89
90function checkLinkLoadingAnimation(){
91    if(window.linkLoadingAnimation){
92        clearInterval(window.linkLoadingAnimation)
93    }
94}
95
96//GETTERS AND SETTERS
97//getters to be used to display existing values while calls to server are in transit
98//setters to be used by network call callbacks when retrieving link, credits from server.
99
100function setCreditViewData(data){
101    store.set("creditViewData", data);
102}
103
104function getCreditViewData(){
105    return store.get("creditViewData")
106}
107
108function setUsersCredits(type,credits){
109    var data = store.get("usersCredits") != null ? store.get("usersCredits") : {} 
110    data[type] = credits
111    store.set("usersCredits",data)
112}
113
114function setUsersReferrals(type,referrals){
115    var data = store.get("usersReferrals") != null ? store.get("usersReferrals") : {} 
116    data[type] = referrals
117    store.set("usersReferrals",data)
118}
119
120function getUsersCredits(type){
121    if(store.get("usersCredits") != null && type in store.get("usersCredits")){
122        return store.get("usersCredits")[type]
123    }else{
124        return null;
125    }
126}
127function getUsersReferrals(type){
128    if(store.get("usersReferrals") != null && type in store.get("usersReferrals")){
129        return store.get("usersReferrals")[type]
130    }else{
131        return null;
132    }
133}
134
135// also used in purchase.js when purchasing premium
136function markAsPurchasedOrRedeemedOnServer(purchasedOrRedeemed){
137
138    var userData = store.get('userData')
139    var purchases = userData["premium"]
140
141    if (purchases == null) {
142        userData["premium"] = []
143    }
144
145    var premiumObj = {}
146    premiumObj[window.registrationSemester] = purchasedOrRedeemed
147    userData["premium"].push(premiumObj)
148
149
150    // make explicit change to server userData
151    setUserData(uuid=store.get("uuid"), deviceID=null, token=null, school=null, userDataJ
151sonString=JSON.stringify(userData))
152    store.set("userData", userData)
153
154    // make explicit log on apache
155    // note: currently deprecated as of new premium purchase because we no longer do free credits for now
156    // we'll be using an entirely different mechanism of credits if we re-implement it.
157    // endpoint has been deleted, just so you know
158    $.ajax({
159        url: '/shared/premium/log.php',
160        type: 'POST',
161        dataType: 'text',
162        data: {
163            uuid: store.get('uuid'),
164            client: (!window.isPWA ? 'web' : 'android'),
165            school: retrieveSchoolParameter() ,
166            type: purchasedOrRedeemed,
167        },
168        success(response) {
169            // noice
170        }
171    })
172}
173
174//Apply all of the required classes for css.
175function displayAndFormatUsersCredits(monetaryOrPremium, credits, referrals){
176
177    //strip all of the formatting from the cash out button and payout amount. The function below should reapply as necessary.
178    $(".payoutAmount").removeClass("greaterThanThreshhold")
179    $(".cashOutBtn").removeClass("tenOrMore")
180    $("#cashingOutSpinner").hide();
181
182    if(monetaryOrPremium == "monetary"){
183        var threshold = getCreditViewData().monetary.threshold
184    }else if(monetaryOrPremium == "premium"){
185        var threshold = getCreditViewData().premium.threshold
186    }
187
188    if(credits>=threshold){
189        $(".payoutAmount").addClass("greaterThanThreshhold")
190        $(".cashOutBtn").addClass("tenOrMore")
191    }
192
193    if(monetaryOrPremium == "monetary"){
194        $('.payoutAmount').text("$"+credits)
195    }else if(monetaryOrPremium == "premium"){
196        $('.payoutAmount').text(credits)
197    }
198
199     //add a class so we can determine the context when cashout button pressed.
200    $('.payoutAmount').removeClass("monetary").removeClass("premium").addClass(monetaryOrPremium)
201    $('.referralSubtext').text(`You've referred ${referrals} friend${referrals != 1 ? 's' : ''} so far`);
202    
203}
204
205
206
207
208
209//this is the function being called when clicking a banner
210async function formatAndRenderGetPaidModal(monetaryOrPremium){
211    //pre-load the font set necessary for the copied to clipboard icon
212    $.ajax({
213		url: "/all/libCSS/webfonts/fa-light-300.woff2",
214		type: 'GET',
215        cache:true,
216		success: function(){
217		}
218	});
219    //if we don't do this, successive opens of the modal will layer setInterval calls and make the animation irregular.
220    checkLinkLoadingAnimation()
221    //preset the credits and the share link from localstorage if possible.
222    if (getUsersCredits(monetaryOrPremium) !== null){
223        displayAndFormatUsersCredits(monetaryOrPremium, getUsersCredits(monetaryOrPremium), getUsersReferrals(monetaryOrPremium));
224    }else{
225        // only if this is the first ever load, we just need to format the 0 basically
226        var countText = (monetaryOrPremium == "monetary") ? "$0"  : "0";
227        $(".payoutAmount").text(countText);
228    }
229    //do the same thing with the referraL LINK
230    let storedLink = getUserLink({type:"referral", subtype:monetaryOrPremium})
231    if (storedLink !== null){
232        $('#webShareLink').text(storedLink)
233    }else{
234        //here we want to put in a moving ellipsis loading animation
235        //https://stackoverflow.com/questions/15382608/punctuation-loading-animation-javascript
236        var count = 0
237            $('#webShareLink').text("Generating")
238            window.linkLoadingAnimation = setInterval(function(){
239                //we don't want to continue to do this if the link has loaded.
240                count++;
241                var dots = new Array(count % 4+1).join('.');
242                $('#webShareLink').text("Generating" + dots)
243            },1000)
244        }   
245
246    //update the share link and credits from the server.
247    generateReferralLink(monetaryOrPremium)
248    getUsersCreditsFromServer(monetaryOrPremium)
249    
250    //format the modal according to what the server says is appropriate as of first page load
251    var info;
252    if(monetaryOrPremium == "monetary"){
253        info = getCreditViewData().monetary;   
254    }else if (monetaryOrPremium == "premium"){
255        info = getCreditViewData().premium;
256    }
257    $('.cashOutBtn').text(info.actionButton);
258    $('.getPaidShareBtn').text(info.leftShareBtn);
259    $('.addToStoryBtn').text(info.rightShareBtn);
260    $('.getPaidRowText1').text(info.steps[0]);
261    $('.getPaidRowText2').text(info.steps[1]);
262    $('.getPaidRowText3').text(info.steps[2]);
263    $('.cashOutExplanation').text(info.subtext);
264    
265    //Here we need to switch the href to open the instagram app rather than the web page. While we're here, let's also modify modal width for pwa.
266    //https://stackoverflow.com/questions/21295051/link-on-a-webpage-to-open-instagram-app
267    // note: clicking on the Instagram button will now also copy their referral link to their clipboard
268    if(window.isPWA){
269        $('.instagramLink').attr({"href":"intent://instagram.com/_n/mainfeed/#Intent;package=com.instagram.android;scheme=https;end","target":"_blank"})
270    }else{
271        $('.instagramLink').attr({"href":"https://www.instagram.com","target":"_blank"})
272    }
273    //now that all the formatting has been done, display the modal.
274    if(window.isPWA){
275        renderSlidableModal('#getPaidModal',true)
276    }else{
277        $('#getPaidModal').modal("show")
278    }
279}
280
281//CLICK LISTENERS
282$('.getPaidShareBtn').on("click",function(){
283
284    //a way to get the monetary or premium context at the time of button click.
285    let monetaryOrPremium = $("#getPaidModal .payoutAmount").hasClass("monetary")? "monetary" : "premium"
286    let shareUrl = "https://" + getUserLink({type:"referral", subtype:monetaryOrPremium})
287    //if we can use the native share dialogue
288    if (navigator.share) {
289        navigator.share({
290          title: 'Coursicle',
291          text: 'This app notifies you when classes open up ' + shareUrl,
292        })
293      }else if (navigator.userAgent && navigator.userAgent.indexOf("Mac") != -1) {
294        //if mac send an sms
295		window.open("sms:?&body=" + encodeURIComponent("This app notifies you when classes open up " + shareUrl))
296	}else{
297        //all other cases: send an email
298		window.open("mailto:?subject=Coursicle&body=" + encodeURIComponent("This app notifies you when classes open up "+ shareUrl))
299	}
300})
301
302$('.cashOutBtn').on('click',function(){
303
304    //only continue if the cashOutBtn is blue
305    if(!$('.cashOutBtn').hasClass('tenOrMore')){
306        alert($('.cashOutExplanation').text());
307        return;
308    }
309
310    //take note of the current text so we can change the btn back after the network call is made
311    let currentBtnText = $('#getPaidModal .cashOutBtn').text()
312    //don't allow additional network calls while the text says checking.
313    if ($('.cashOutBtn').hasClass("redeeming")){
314        return
315    }
316    
317    //a way to get the monetary or premium context at the time of button click.
318    let monetaryOrPremium = $("#getPaidModal .payoutAmount").hasClass("monetary")? "monetary" : "premium"
319
320    if(monetaryOrPremium == "monetary"){
321        var processingText = "Cashing out...";
322        var completedText = "Cashed out";
323    }else if(monetaryOrPremium == "premium"){
324        var processingText = "Redeeming...";
325        var completedText = "Redeemed";
326    }
327    
328    $('.cashOutBtn').text(processingText);
329    $("#cashingOutSpinner").show();
330    $('.cashOutBtn').addClass("redeeming");
331    $.ajax({
332        url: "/shared/credits/redeem.php",
333        type: 'POST',
334        dataType: 'json',
335        data: {'uuid':store.get('uuid'),type:monetaryOrPremium},
336        success: function(response){
337            
338            if(monetaryOrPremium == "premium"){
339                // mark it as redeemed in their user data and log it 
340                markAsPurchasedOrRedeemedOnServer("redeemed");
341            }
342
343            // make sure it takes at least 2 seconds for the cashout
344            let btnTextReset = setTimeout(function(){
345                $('.cashOutBtn').text(completedText)
346                $('.cashOutBtn').addClass("redeemed");
347                if(response.error == false){
348                    displayAndFormatUsersCredits(monetaryOrPremium, getUsersCredits(monetaryOrPremium)-response.redeemed, getUsersReferrals(monetaryOrPremium));
349                }
350                setTimeout(function(){
351                    $('.cashOutBtn').text(currentBtnText)
352                    $('.cashOutBtn').removeClass("redeeming redeemed");
353                    // need to call it again here so that the next time they open it we have the updated data and it doesn't flash
354                    getUsersCreditsFromServer(monetaryOrPremium);
355                    if(monetaryOrPremium == "monetary"){
356                        $('#getPaidModal').modal("hide")
357                        showBaseModal('#universalContactModal')
358                        $("#universalContactModalTopNote").hide();
359                        $('#universalContactModalTextArea').val("Cashing out $" + response.redeemed + ". Code: " + btoa(response.redeemed) + " \n\nVenmo: [username]\nOR\nCash App: [username]")
360                    }
361                },1000)
362            },2000);
363        }
364    })
365})
366
367$(document).on("click",".instagramLink",function(){
368    var instructions = [
369        "Create a new story",
370        "Tap the sticker icon at the top",
371        "Tap \"Link\"",
372        "Paste your link",
373        "Tap \"Done\""
374    ];
375
376    // if it's desktop, you specify it has to be on the phone
377    // and you don't have to wait as long to show the alert
378    var delay = 2000;
379    if(!window.isPWA){
380        delay = 600;
381        instructions[0] = "Create a new story on your phone";
382    }
383
384    var numberedInstructions = "";
385    for (var i = 0; i < instructions.length; i++) {
386        numberedInstructions += (i + 1) + ". " + instructions[i] + "\n";
387    }
388
389    // note: it seems like on the PWA, displaying this alert causes 
390    // the URL bar to appear sometimes. Really weird. Not going to do this
391    // on the PWA for now and will just wait until we can create the story
392    // natively once we have the PWA and wrapper bicommunication channel established.
393    // update: it seems like we have this issue elsewhere though, anytime we use alert()
394    // so we should write our own alert and then use that everywhere in the app instead
395    // if(window.isPWA){return}
396
397    setTimeout(function(){
398        alert("To add your link to your story:\n"+numberedInstructions);
399    }, delay);
400});
401
402//copy user referral link to clipboard.
403$(document).on("click",".shareLinkBox, .instagramLink",function(){
404    //prevent pressing the button multiple times and timeouts backing up
405    if($(".shareLinkBox").hasClass("alreadyCopied")){
406        return
407    }
408    $(".shareLinkBox").addClass('alreadyCopied')
409    //copy to clipboard
410    let existingLink = $('#webShareLink').text()
411    navigator.clipboard.writeText("https://" + $('#webShareLink').text())
412
413    $(".shareLinkText").text("Link copied to clipboard")
414    $(".copyBtnContainer").empty().html('<i class="fa-light fa-clipboard-check"></i>')
415    //after 2.5 seconds, reset the link container.
416    currentTimeout = setTimeout(function(){
417        $('.shareLinkText').text(existingLink)
418        $(".copyBtnContainer").empty().html('<i class="fa fa-clone"></i>')
419        $(".shareLinkBox").removeClass('alreadyCopied')
420    },2500)
421})

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.