tipjar.js (4536B)
1 async function make_request(method, rune, params) { 2 const LNSocket = await lnsocket_init() 3 const ln = LNSocket() 4 5 ln.genkey() 6 await ln.connect_and_init("03f3c108ccd536b8526841f0a5c58212bb9e6584a1eb493080e7c1cc34f82dad71", "wss://cln.jb55.com:443") 7 8 const {result} = await ln.rpc({ rune, method, params }) 9 10 ln.disconnect() 11 return result 12 } 13 14 function fetch_tipjar_summary() { 15 const rune = "5sgpXcVRMy19h2Ai9LiklJ7jI_J3qNnnG36wvyViqR49OTQmbWV0aG9kPW9mZmVyLXN1bW1hcnkmcG5hbWVkZXNjcmlwdGlvbj1AZGFtdXMtYW5kcm9pZCZwbmFtZWxpbWl0PTU=" 16 return make_request("offer-summary", rune, { 17 offerid: "2043536dfec68d559102f73510927622812a230cfdda079e96fccbfe35a96d11", 18 description: "@damus-android", 19 limit: 5 20 }) 21 } 22 23 function make_invoice(description) { 24 const rune = "LZwGZJO7wZgmoScFQb5reZ0Ii8qPKCeUfTb-UcbDxWw9MTImbWV0aG9kPWludm9pY2U=" 25 description = (description && `${description} @damus-android`) || "@damus-android donation" 26 return make_request("invoice", rune, { 27 amount_msat: "any", 28 label: `damus-android-${new Date().getTime()}`, 29 description: description 30 }) 31 } 32 33 function make_qrcode(dat) { 34 const link = dat.toUpperCase() 35 document.querySelector("#qrcode").innerHTML = "" 36 const qr = new QRCode("qrcode", { 37 text: link, 38 width: 256, 39 height: 256, 40 colorDark : "#000000", 41 colorLight : "#ffffff", 42 correctLevel : QRCode.CorrectLevel.L 43 }) 44 } 45 46 async function click_make_invoice(el) { 47 const offerdata = document.querySelector("#offerdata") 48 const tipjar_img = document.querySelector("#tipjar-offer-qr") 49 50 const note = prompt("Leave a note!", "") 51 52 const invoice = await make_invoice(note) 53 54 make_qrcode("LIGHTNING:" + invoice.bolt11) 55 document.querySelector("#bolt12").href = "lightning:" + invoice.bolt11 56 57 el.style.display = "none"; 58 } 59 60 async function copy_tip() { 61 const offer = document.querySelector("#offerdata").value.trim(); 62 try { 63 await navigator.clipboard.writeText(offer) 64 alert("Invoice copied to clipboard!") 65 } catch(err) { 66 console.log("clipboard copy error", err) 67 document.querySelector("#offerdata").style.display = "block" 68 } 69 } 70 71 async function go() { 72 const summary = await fetch_tipjar_summary() 73 74 const el = document.querySelector("#tipjar-summary") 75 const bolt12 = document.querySelector("#bolt12") 76 77 make_qrcode(bolt12.href) 78 el.innerHTML = render_tips(summary) 79 } 80 81 function render_tips(res) { 82 const total_sats = res.total_msatoshi / 1000 83 const goal = 3000000 84 const perc = `${((total_sats / goal) * 100).toPrecision(2)}%` 85 const total_fmt = `${format_amount(total_sats)} / ${format_amount(goal)} sats goal (${perc})` 86 return ` 87 <p>Total: <b>${total_fmt}</b></p> 88 <div class="progres" style="height:20px; background-color: #f1f1f1"> 89 <div class="progress-bar" style="background-color: #f44336; height: 100%;width: ${perc}"></div> 90 </div> 91 <h5>Recent Donors</h5> 92 ${render_table(res.paid_invoices)} 93 <h5>Top Donors</h5> 94 ${render_table(res.top_donors)} 95 ` 96 } 97 98 function render_table(invoices) 99 { 100 return ` 101 <table style="width: 100%"> 102 <thead> 103 <tr> 104 <th>Note</th> 105 <th>Amount</th> 106 <th></th> 107 </tr> 108 </thead> 109 <tbody> 110 ${invoices.map(render_tip).join("\n")} 111 </tbody> 112 </table> 113 ` 114 } 115 116 function format_amount(amt) 117 { 118 return amt.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); 119 } 120 121 function render_tip(tip) 122 { 123 let note = tip.payer_note ? tip.payer_note : (tip.description || "Anonymous") 124 note = note.replace("@damus-android", "") 125 const amount = format_amount(tip.amount_msat / 1000) 126 const now = Math.floor(new Date().getTime() / 1000) 127 const date = time_delta(now * 1000, tip.paid_at * 1000) 128 129 return ` 130 <tr> 131 <td>${note}</td> 132 <td>${amount} sats</td> 133 <td class="reldate">${date}</td> 134 </tr> 135 ` 136 } 137 138 function time_delta(current, previous) { 139 var msPerMinute = 60 * 1000; 140 var msPerHour = msPerMinute * 60; 141 var msPerDay = msPerHour * 24; 142 var msPerMonth = msPerDay * 30; 143 var msPerYear = msPerDay * 365; 144 145 var elapsed = current - previous; 146 147 if (elapsed < msPerMinute) { 148 return Math.round(elapsed/1000) + ' seconds ago'; 149 } 150 151 else if (elapsed < msPerHour) { 152 return Math.round(elapsed/msPerMinute) + ' minutes ago'; 153 } 154 155 else if (elapsed < msPerDay ) { 156 return Math.round(elapsed/msPerHour ) + ' hours ago'; 157 } 158 159 else if (elapsed < msPerMonth) { 160 return Math.round(elapsed/msPerDay) + ' days ago'; 161 } 162 163 else if (elapsed < msPerYear) { 164 return Math.round(elapsed/msPerMonth) + ' months ago'; 165 } 166 167 else { 168 return Math.round(elapsed/msPerYear ) + ' years ago'; 169 } 170 } 171 172 go()