This commit is contained in:
callebtc
2022-11-06 03:38:33 +01:00
committed by dni ⚡
parent 00c50fbfa6
commit 577b6889ad

View File

@@ -1,11 +1,13 @@
{% extends "public.html" %} {% block toolbar_title %} {% raw %} {{name}} Cashu {% endraw %} {% endblock %} {% extends "public.html" %} {% block toolbar_title %} {% raw %} {{name}} Cashu
{% block footer %}{% endblock %} {% endraw %} {% endblock %} {% block footer %}{% endblock %} {% block
{% block page_container %} page_container %}
<q-page-container> <q-page-container>
<q-page> <q-page>
<div class="row q-col-gutter-md justify-center q-pt-lg"> <div class="row q-col-gutter-md justify-center q-pt-lg">
<div class="col-12 col-sm-8 col-md-9 col-lg-7 text-center q-gutter-y-md"> <q-scroll-area style="height: 640px; max-width: 1024px">
<q-scroll-area style="height: 640px; max-width: 1024px;"> <div
class="col-12 col-sm-8 col-md-9 col-lg-7 text-center q-gutter-y-md"
>
<q-card class="q-mb-sm"> <q-card class="q-mb-sm">
<q-card-section> <q-card-section>
<div class="gt-sm"> <div class="gt-sm">
@@ -55,11 +57,9 @@
</div> </div>
</div> </div>
</div> </div>
</q-card-section> </q-card-section>
</q-card> </q-card>
<q-card> <q-card>
<q-card-section> <q-card-section>
<div class="row items-center no-wrap q-mb-sm"> <div class="row items-center no-wrap q-mb-sm">
@@ -89,8 +89,6 @@
</div> </div>
</div> </div>
<!-- /////////////////////////////////////////// <!-- ///////////////////////////////////////////
////////////////// TABLES ///////////////// ////////////////// TABLES /////////////////
/////////////////////////////////////////// --> /////////////////////////////////////////// -->
@@ -100,7 +98,6 @@
<q-tab name="history" label="History"></q-tab> <q-tab name="history" label="History"></q-tab>
</q-tabs> </q-tabs>
<q-tab-panels v-model="tab"> <q-tab-panels v-model="tab">
<!-- ////////////////// TOKEN LIST ///////////////// --> <!-- ////////////////// TOKEN LIST ///////////////// -->
<q-tab-panel name="tokens"> <q-tab-panel name="tokens">
@@ -172,10 +169,19 @@
</q-badge> </q-badge>
</div> </div>
<div v-if="props.row.status === 'paid'"> <div v-if="props.row.status === 'paid'">
<q-icon v-if="props.row.amount>0" name= "call_received" color="green"><q-tooltip>Received</q-tooltip></q-icon> <q-icon
<q-icon v-if="props.row.amount<0" name= "call_made" color="red"><q-tooltip>Paid</q-tooltip></q-icon> v-if="props.row.amount>0"
name="call_received"
color="green"
><q-tooltip>Received</q-tooltip></q-icon
>
<q-icon
v-if="props.row.amount<0"
name="call_made"
color="red"
><q-tooltip>Paid</q-tooltip></q-icon
>
<!-- <q-icon name="props.row.amount < 0 ? 'call_made' : 'call_received'" color="green"></q-icon> --> <!-- <q-icon name="props.row.amount < 0 ? 'call_made' : 'call_received'" color="green"></q-icon> -->
</div> </div>
</q-td> </q-td>
<q-td <q-td
@@ -238,10 +244,19 @@
</q-badge> </q-badge>
</div> </div>
<div v-if="props.row.status === 'paid'"> <div v-if="props.row.status === 'paid'">
<q-icon v-if="props.row.amount>0" name= "call_received" color="green"><q-tooltip>Received</q-tooltip></q-icon> <q-icon
<q-icon v-if="props.row.amount<0" name= "call_made" color="red"><q-tooltip>Paid</q-tooltip></q-icon> v-if="props.row.amount>0"
name="call_received"
color="green"
><q-tooltip>Received</q-tooltip></q-icon
>
<q-icon
v-if="props.row.amount<0"
name="call_made"
color="red"
><q-tooltip>Paid</q-tooltip></q-icon
>
<!-- <q-icon name="props.row.amount < 0 ? 'call_made' : 'call_received'" color="green"></q-icon> --> <!-- <q-icon name="props.row.amount < 0 ? 'call_made' : 'call_received'" color="green"></q-icon> -->
</div> </div>
</q-td> </q-td>
<q-td <q-td
@@ -263,8 +278,6 @@
{% endraw %} {% endraw %}
</q-table> </q-table>
</q-tab-panel> </q-tab-panel>
</q-tab-panels> </q-tab-panels>
</q-card-section> </q-card-section>
</q-card> </q-card>
@@ -276,7 +289,10 @@
rectangle rectangle
color="warning" color="warning"
outline outline
@click="showDisclaimerDialog"> Warning</q-btn> @click="showDisclaimerDialog"
>
Warning</q-btn
>
<q-btn <q-btn
class="q-mx-sm" class="q-mx-sm"
size="10px" size="10px"
@@ -285,10 +301,11 @@
icon="file_download" icon="file_download"
color="warning" color="warning"
tooltip="asd" tooltip="asd"
@click="getLocalstorageToFile">Backup<q-tooltip>Download wallet backup</q-tooltip></q-btn> @click="getLocalstorageToFile"
>Backup<q-tooltip>Download wallet backup</q-tooltip></q-btn
>
</div> </div>
</div> </div>
</q-scroll-area> </q-scroll-area>
<q-tabs <q-tabs
@@ -304,12 +321,12 @@
@click="showInvoicesDialog" @click="showInvoicesDialog"
> >
</q-tab> </q-tab>
</q-tab>
<q-tab <q-tab
icon="arrow_upwards" icon="arrow_upwards"
class="q-pa-none" class="q-pa-none"
label="Pay Invoice" label="Pay Invoice"
@click="showParseDialog"> @click="showParseDialog"
>
</q-tab> </q-tab>
<!-- <q-tab icon="photo_camera" label="Scan" @click="showCamera"> </q-tab> --> <!-- <q-tab icon="photo_camera" label="Scan" @click="showCamera"> </q-tab> -->
</q-tabs> </q-tabs>
@@ -336,7 +353,13 @@
</p> </p>
{% endraw %} {% endraw %}
<div v-if="canPay" class="row q-mt-lg"> <div v-if="canPay" class="row q-mt-lg">
<q-btn unelevated color="primary" :disabled="payInvoiceData.blocking" @click="melt">Pay</q-btn> <q-btn
unelevated
color="primary"
:disabled="payInvoiceData.blocking"
@click="melt"
>Pay</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto" <q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn >Cancel</q-btn
> >
@@ -485,7 +508,13 @@
type="submit" type="submit"
>Enter</q-btn >Enter</q-btn
> >
<q-btn unelevated icon="photo_camera" class="q-mx-0" @click="showCamera"> </q-btn> <q-btn
unelevated
icon="photo_camera"
class="q-mx-0"
@click="showCamera"
>
</q-btn>
<q-btn v-close-popup flat color="grey" class="q-ml-auto" <q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Cancel</q-btn >Cancel</q-btn
> >
@@ -529,27 +558,33 @@
<h6 class="q-my-md text-primary">Warning</h6> <h6 class="q-my-md text-primary">Warning</h6>
<p> <p>
<strong>Bookmark this page and backup your tokens!</strong> <strong>Bookmark this page and backup your tokens!</strong>
Ecash is a bearer asset, meaning losing access to this wallet will mean you will Ecash is a bearer asset, meaning losing access to this wallet will
lose the funds. This wallet stores ecash tokens in its database. If you lose the link or delete your mean you will lose the funds. This wallet stores ecash tokens in its
your data without backing up, you will lose your tokens. Press the Backup button to download database. If you lose the link or delete your your data without
a copy of your tokens. backing up, you will lose your tokens. Press the Backup button to
download a copy of your tokens.
</p> </p>
<p> <p>
<strong>Add to home screen.</strong> <strong>Add to home screen.</strong>
You can add Cashu to your home screen as a progressive web app (PWA). You can add Cashu to your home screen as a progressive web app
On Android Chrome, click the hamburger menu at the upper right. (PWA). On Android Chrome, click the hamburger menu at the upper
On iOS Safari, click the share button. Now press the Add to Home screen button. right. On iOS Safari, click the share button. Now press the Add to
Home screen button.
</p> </p>
<p> <p>
<strong>This service is in BETA!</strong> We hold no responsibility for people losing <strong>This service is in BETA!</strong> We hold no responsibility
access to funds. Use at your own risk! for people losing access to funds. Use at your own risk!
</p> </p>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<q-btn outline color="grey" @click="copyText(disclaimerDialog.location.href)">Copy wallet URL</q-btn> <q-btn
outline
color="grey"
@click="copyText(disclaimerDialog.location.href)"
>Copy wallet URL</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto" <q-btn v-close-popup flat color="grey" class="q-ml-auto"
>I understand</q-btn >I understand</q-btn
> >
</div> </div>
</q-card> </q-card>
</q-dialog> </q-dialog>
@@ -602,7 +637,11 @@
color="primary" color="primary"
>Copy invoice</q-btn >Copy invoice</q-btn
> >
<q-btn v-else color="primary" @click="requestMintButton" :disable="!invoiceData.amount > 0" <q-btn
v-else
color="primary"
@click="requestMintButton"
:disable="!invoiceData.amount > 0"
>Create Invoice</q-btn >Create Invoice</q-btn
> >
<q-btn v-close-popup flat color="grey" class="q-ml-auto" <q-btn v-close-popup flat color="grey" class="q-ml-auto"
@@ -653,7 +692,7 @@
> >
</qrcode> </qrcode>
</q-responsive> </q-responsive>
</a> <!-- </a> -->
</div> </div>
<q-input <q-input
outlined outlined
@@ -712,9 +751,7 @@
</div> </div>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<q-btn @click="redeem" color="primary" <q-btn @click="redeem" color="primary">Receive Tokens</q-btn>
>Receive Tokens</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto" <q-btn v-close-popup flat color="grey" class="q-ml-auto"
>Close</q-btn >Close</q-btn
> >
@@ -1033,12 +1070,12 @@
getTokenList: function () { getTokenList: function () {
console.log(this.proofs) console.log(this.proofs)
const amounts = this.proofs.map(t => t.amount) const amounts = this.proofs.map(t => t.amount)
const counts = {}; const counts = {}
for (const num of amounts) { for (const num of amounts) {
counts[num] = counts[num] ? counts[num] + 1 : 1; counts[num] = counts[num] ? counts[num] + 1 : 1
} }
console.log("counts", counts) console.log('counts', counts)
return Object.keys(counts).map(k => ({ return Object.keys(counts).map(k => ({
value: parseInt(k), value: parseInt(k),
count: parseInt(counts[k]), count: parseInt(counts[k]),
@@ -1397,7 +1434,6 @@
return proofs.reduce((s, t) => (s += t.amount), 0) return proofs.reduce((s, t) => (s += t.amount), 0)
}, },
//////////// API /////////// //////////// API ///////////
invoiceCheckWorker: async function () { invoiceCheckWorker: async function () {
@@ -1408,7 +1444,7 @@
// exit loop after 2m // exit loop after 2m
if (nInterval > 40) { if (nInterval > 40) {
console.log("### stopping invoice check worker") console.log('### stopping invoice check worker')
clearInterval(this.invoiceCheckListener) clearInterval(this.invoiceCheckListener)
} }
console.log('### setInterval', nInterval) console.log('### setInterval', nInterval)
@@ -1418,7 +1454,7 @@
await this.recheckInvoice(this.invoiceData.hash, false) await this.recheckInvoice(this.invoiceData.hash, false)
// only without error (invoice paid) will we reach here // only without error (invoice paid) will we reach here
console.log("### stopping invoice check worker") console.log('### stopping invoice check worker')
clearInterval(this.invoiceCheckListener) clearInterval(this.invoiceCheckListener)
this.invoiceData.bolt11 = '' this.invoiceData.bolt11 = ''
this.showInvoiceDetails = false this.showInvoiceDetails = false
@@ -1436,7 +1472,7 @@
requestMintButton: async function () { requestMintButton: async function () {
await this.requestMint() await this.requestMint()
console.log("#### request mint", this.invoiceData) console.log('#### request mint', this.invoiceData)
await this.invoiceCheckWorker() await this.invoiceCheckWorker()
}, },
@@ -1674,7 +1710,9 @@
) )
this.sendData.tokens = scndProofs this.sendData.tokens = scndProofs
console.log('### this.sendData.tokens', this.sendData.tokens) console.log('### this.sendData.tokens', this.sendData.tokens)
this.sendData.tokensBase64 = btoa(JSON.stringify(this.sendData.tokens)) this.sendData.tokensBase64 = btoa(
JSON.stringify(this.sendData.tokens)
)
this.historyTokens.push({ this.historyTokens.push({
status: 'pending', status: 'pending',
@@ -1688,7 +1726,6 @@
console.error(error) console.error(error)
throw error throw error
} }
}, },
checkFees: async function (payment_request) { checkFees: async function (payment_request) {
const payload = { const payload = {
@@ -1759,7 +1796,7 @@
amount: -amount, amount: -amount,
bolt11: this.payInvoiceData.data.request, bolt11: this.payInvoiceData.data.request,
hash: this.payInvoiceData.data.hash, hash: this.payInvoiceData.data.hash,
memo: this.payInvoiceData.data.memo, memo: this.payInvoiceData.data.memo
}) })
this.invoicesCashu.push({ this.invoicesCashu.push({
amount: -amount, amount: -amount,
@@ -1775,7 +1812,6 @@
this.payInvoiceData.invoice = false this.payInvoiceData.invoice = false
this.payInvoiceData.show = false this.payInvoiceData.show = false
this.payInvoiceData.blocking = false this.payInvoiceData.blocking = false
} catch (error) { } catch (error) {
this.payInvoiceData.blocking = false this.payInvoiceData.blocking = false
console.error(error) console.error(error)
@@ -1812,7 +1848,6 @@
this.storehistoryTokens() this.storehistoryTokens()
}, },
checkTokenSpendableWorker: async function () { checkTokenSpendableWorker: async function () {
let nInterval = 0 let nInterval = 0
this.tokensCheckSpendableListener = setInterval(async () => { this.tokensCheckSpendableListener = setInterval(async () => {
@@ -1821,21 +1856,23 @@
// exit loop after 2m // exit loop after 2m
if (nInterval > 24) { if (nInterval > 24) {
console.log("### stopping token check worker") console.log('### stopping token check worker')
clearInterval(this.tokensCheckSpendableListener) clearInterval(this.tokensCheckSpendableListener)
} }
console.log('### setInterval', nInterval) console.log('### setInterval', nInterval)
console.log(this.sendData) console.log(this.sendData)
// this will throw an error if the invoice is pending // this will throw an error if the invoice is pending
paid = await this.checkTokenSpendable(this.sendData.tokensBase64, false) paid = await this.checkTokenSpendable(
this.sendData.tokensBase64,
false
)
if (paid) { if (paid) {
console.log("### stopping token check worker") console.log('### stopping token check worker')
clearInterval(this.tokensCheckSpendableListener) clearInterval(this.tokensCheckSpendableListener)
this.sendData.tokens = '' this.sendData.tokens = ''
this.showSendTokens = false this.showSendTokens = false
} }
} catch (error) { } catch (error) {
console.log('not paid yet') console.log('not paid yet')
} }
@@ -1846,7 +1883,7 @@
const tokenJson = atob(token) const tokenJson = atob(token)
const proofs = JSON.parse(tokenJson) const proofs = JSON.parse(tokenJson)
const payload = { const payload = {
proofs: proofs.flat(), proofs: proofs.flat()
} }
console.log('#### payload', JSON.stringify(payload)) console.log('#### payload', JSON.stringify(payload))
try { try {
@@ -1865,7 +1902,7 @@
} }
} }
if (paid) { if (paid) {
console.log("### token paid") console.log('### token paid')
if (window.navigator.vibrate) navigator.vibrate(200) if (window.navigator.vibrate) navigator.vibrate(200)
this.$q.notify({ this.$q.notify({
timeout: 5000, timeout: 5000,
@@ -1873,7 +1910,7 @@
message: 'Token paid' message: 'Token paid'
}) })
} else { } else {
console.log("### token not paid yet") console.log('### token not paid yet')
if (verbose) { if (verbose) {
this.$q.notify({ this.$q.notify({
timeout: 5000, timeout: 5000,
@@ -1897,10 +1934,12 @@
`/cashu/api/v1/${this.mintId}/keys` `/cashu/api/v1/${this.mintId}/keys`
) )
this.keys = data this.keys = data
localStorage.setItem(this.mintKey(this.mintId, 'keys'), JSON.stringify(data)) localStorage.setItem(
this.mintKey(this.mintId, 'keys'),
JSON.stringify(data)
)
}, },
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1973,29 +2012,28 @@
getLocalstorageToFile: async function () { getLocalstorageToFile: async function () {
// https://stackoverflow.com/questions/24263682/save-restore-local-storage-to-a-local-file // https://stackoverflow.com/questions/24263682/save-restore-local-storage-to-a-local-file
const fileName = `cashu_backup_${currentDateStr()}.json` const fileName = `cashu_backup_${currentDateStr()}.json`
var a = {}; var a = {}
for (var i = 0; i < localStorage.length; i++) { for (var i = 0; i < localStorage.length; i++) {
var k = localStorage.key(i); var k = localStorage.key(i)
var v = localStorage.getItem(k); var v = localStorage.getItem(k)
a[k] = v; a[k] = v
} }
var textToSave = JSON.stringify(a) var textToSave = JSON.stringify(a)
var textToSaveAsBlob = new Blob([textToSave], { var textToSaveAsBlob = new Blob([textToSave], {
type: "text/plain" type: 'text/plain'
}); })
var textToSaveAsURL = window.URL.createObjectURL(textToSaveAsBlob); var textToSaveAsURL = window.URL.createObjectURL(textToSaveAsBlob)
var downloadLink = document.createElement("a"); var downloadLink = document.createElement('a')
downloadLink.download = fileName; downloadLink.download = fileName
downloadLink.innerHTML = "Download File"; downloadLink.innerHTML = 'Download File'
downloadLink.href = textToSaveAsURL; downloadLink.href = textToSaveAsURL
downloadLink.onclick = function () { downloadLink.onclick = function () {
document.body.removeChild(event.target); document.body.removeChild(event.target)
}; }
downloadLink.style.display = "none"; downloadLink.style.display = 'none'
document.body.appendChild(downloadLink); document.body.appendChild(downloadLink)
downloadLink.click(); downloadLink.click()
}, },
storeinvoicesCashu: function () { storeinvoicesCashu: function () {
@@ -2020,9 +2058,8 @@
mintKey: function (mintId, key) { mintKey: function (mintId, key) {
// returns a key for the local storage // returns a key for the local storage
// depending on the current mint // depending on the current mint
return "cashu." + mintId + "." + key return 'cashu.' + mintId + '.' + key
}, }
}, },
watch: { watch: {
payments: function () { payments: function () {
@@ -2049,7 +2086,10 @@
// get name // get name
if (params.get('mint_name')) { if (params.get('mint_name')) {
this.mintName = params.get('mint_name') this.mintName = params.get('mint_name')
this.$q.localStorage.set(this.mintKey(this.mintId, 'mintName'), this.mintName) this.$q.localStorage.set(
this.mintKey(this.mintId, 'mintName'),
this.mintName
)
} else if (this.$q.localStorage.getItem('cashu.name')) { } else if (this.$q.localStorage.getItem('cashu.name')) {
this.mintName = this.$q.localStorage.getItem('cashu.name') this.mintName = this.$q.localStorage.getItem('cashu.name')
} }
@@ -2059,13 +2099,23 @@
!params.get('tsh') && !params.get('tsh') &&
!this.$q.localStorage.getItem(this.mintKey(this.mintId, 'tickershort')) !this.$q.localStorage.getItem(this.mintKey(this.mintId, 'tickershort'))
) { ) {
this.$q.localStorage.set(this.mintKey(this.mintId, 'tickershort'), 'sats') this.$q.localStorage.set(
this.mintKey(this.mintId, 'tickershort'),
'sats'
)
this.tickershort = 'sats' this.tickershort = 'sats'
} else if (params.get('tsh')) { } else if (params.get('tsh')) {
this.$q.localStorage.set(this.mintKey(this.mintId, 'tickershort'), params.get('tsh')) this.$q.localStorage.set(
this.mintKey(this.mintId, 'tickershort'),
params.get('tsh')
)
this.tickershort = params.get('tsh') this.tickershort = params.get('tsh')
} else if (this.$q.localStorage.getItem(this.mintKey(this.mintId, 'tickershort'))) { } else if (
this.tickershort = this.$q.localStorage.getItem(this.mintKey(this.mintId, 'tickershort')) this.$q.localStorage.getItem(this.mintKey(this.mintId, 'tickershort'))
) {
this.tickershort = this.$q.localStorage.getItem(
this.mintKey(this.mintId, 'tickershort')
)
} }
const keysJson = localStorage.getItem(this.mintKey(this.mintId, 'keys')) const keysJson = localStorage.getItem(this.mintKey(this.mintId, 'keys'))
@@ -2083,7 +2133,9 @@
localStorage.getItem(this.mintKey(this.mintId, 'historyTokens')) || '[]' localStorage.getItem(this.mintKey(this.mintId, 'historyTokens')) || '[]'
) )
this.proofs = JSON.parse(localStorage.getItem(this.mintKey(this.mintId, 'proofs')) || '[]') this.proofs = JSON.parse(
localStorage.getItem(this.mintKey(this.mintId, 'proofs')) || '[]'
)
console.log('### invoicesCashu', this.invoicesCashu) console.log('### invoicesCashu', this.invoicesCashu)
console.table('### tokens', this.proofs) console.table('### tokens', this.proofs)
console.log('#### this.mintId', this.mintId) console.log('#### this.mintId', this.mintId)