@@ -64,12 +71,12 @@
filled
dense
readonly
- hint="This your key pair! Don't lose it!"
- v-if="checkoutDialog.data.privkey"
- v-model="checkoutDialog.data.privkey"
+ type="password"
+ v-if="customerPrivkey"
+ v-model="customerPrivkey"
>
-
+
- Total: {{ stall.currency != 'sat' ? getAmountFormated(finalCost) :
- finalCost + 'sats' }}
- ({{ getValueInSats(finalCost) }} sats)
+ > -->
+
+
+
+
+
+
+
+
+ Copy invoice
+ Close
+
+
+
diff --git a/static/components/customer-stall/customer-stall.js b/static/components/customer-stall/customer-stall.js
index b72ba7d..4bd74c3 100644
--- a/static/components/customer-stall/customer-stall.js
+++ b/static/components/customer-stall/customer-stall.js
@@ -6,15 +6,16 @@ async function customerStall(path) {
template,
props: [
+ 'account',
'stall',
'products',
- 'exchange-rates',
'product-detail',
'change-page',
'relays'
],
data: function () {
return {
+ loading: false,
cart: {
total: 0,
size: 0,
@@ -23,8 +24,9 @@ async function customerStall(path) {
cartMenu: [],
hasNip07: false,
customerPubkey: null,
- customerPrivKey: null,
- nostrMessages: new Map(),
+ customerPrivkey: null,
+ customerUseExtension: null,
+ activeOrder: null,
checkoutDialog: {
show: false,
data: {
@@ -58,12 +60,6 @@ async function customerStall(path) {
changePageS(page, opts) {
this.$emit('change-page', page, opts)
},
- getValueInSats(amount, unit = 'USD') {
- if (!this.exchangeRates) return 0
- return Math.ceil(
- (amount / this.exchangeRates[`BTC${unit}`][unit]) * 1e8
- )
- },
getAmountFormated(amount, unit = 'USD') {
return LNbits.utils.formatCurrency(amount, unit)
},
@@ -125,26 +121,12 @@ async function customerStall(path) {
}
}
},
- async getPubkey() {
- try {
- this.customerPubkey = await window.nostr.getPublicKey()
- this.checkoutDialog.data.pubkey = this.customerPubkey
- this.checkoutDialog.data.privkey = null
- } catch (err) {
- console.error(
- `Failed to get a public key from a Nostr extension: ${err}`
- )
- }
- },
- generateKeyPair() {
- let sk = NostrTools.generatePrivateKey()
- let pk = NostrTools.getPublicKey(sk)
- this.customerPubkey = pk
- this.customerPrivKey = sk
- this.checkoutDialog.data.pubkey = this.customerPubkey
- this.checkoutDialog.data.privkey = this.customerPrivKey
+ closeQrCodeDialog() {
+ this.qrCodeDialog.dismissMsg()
+ this.qrCodeDialog.show = false
},
async placeOrder() {
+ this.loading = true
LNbits.utils
.confirmDialog(
`Send the order to the merchant? You should receive a message with the payment details.`
@@ -170,6 +152,7 @@ async function customerStall(path) {
':'
)
)
+ this.activeOrder = orderObj.id
let event = {
...(await NostrTools.getBlankEvent()),
kind: 4,
@@ -177,13 +160,13 @@ async function customerStall(path) {
tags: [['p', this.stall.pubkey]],
pubkey: this.customerPubkey
}
- if (this.customerPrivKey) {
+ if (this.customerPrivkey) {
event.content = await NostrTools.nip04.encrypt(
- this.customerPrivKey,
+ this.customerPrivkey,
this.stall.pubkey,
JSON.stringify(orderObj)
)
- } else {
+ } else if (this.customerUseExtension && this.hasNip07) {
event.content = await window.nostr.nip04.encrypt(
this.stall.pubkey,
JSON.stringify(orderObj)
@@ -196,15 +179,15 @@ async function customerStall(path) {
}
}
event.id = NostrTools.getEventHash(event)
- if (this.customerPrivKey) {
+ if (this.customerPrivkey) {
event.sig = await NostrTools.signEvent(
event,
- this.customerPrivKey
+ this.customerPrivkey
)
- } else if (this.hasNip07) {
+ } else if (this.customerUseExtension && this.hasNip07) {
event = await window.nostr.signEvent(event)
}
- console.log(event, orderObj)
+
await this.sendOrder(event)
})
},
@@ -223,25 +206,32 @@ async function customerStall(path) {
let pub = relay.publish(order)
pub.on('ok', () => {
console.log(`${relay.url} has accepted our event`)
+ relay.close()
})
pub.on('failed', reason => {
console.log(`failed to publish to ${relay.url}: ${reason}`)
+ relay.close()
})
} catch (err) {
console.error(`Error: ${err}`)
}
}
+ this.loading = false
this.resetCheckout()
+ this.resetCart()
+ this.qrCodeDialog.show = true
+ this.qrCodeDialog.dismissMsg = this.$q.notify({
+ timeout: 0,
+ message: 'Waiting for invoice from merchant...'
+ })
this.listenMessages()
},
async listenMessages() {
+ console.log('LISTEN')
try {
const pool = new NostrTools.SimplePool()
const filters = [
- {
- kinds: [4],
- authors: [this.customerPubkey]
- },
+ // /
{
kinds: [4],
'#p': [this.customerPubkey]
@@ -254,38 +244,74 @@ async function customerStall(path) {
let sender = mine
? event.tags.find(([k, v]) => k === 'p' && v && v !== '')[1]
: event.pubkey
- if (
- (mine && sender != this.stall.pubkey) ||
- (!mine && sender != this.customerPubkey)
- ) {
- console.log(`Not relevant message!`)
- return
- }
+
try {
- let plaintext = this.customerPrivKey
- ? await NostrTools.nip04.decrypt(
- this.customerPrivKey,
- sender,
- event.content
- )
- : await window.nostr.nip04.decrypt(sender, event.content)
- // console.log(`${mine ? 'Me' : 'Customer'}: ${plaintext}`)
- this.nostrMessages.set(event.id, {
- msg: plaintext,
- timestamp: event.created_at,
- sender: `${mine ? 'Me' : 'Merchant'}`
- })
+ let plaintext
+ if (this.customerPrivkey) {
+ plaintext = await NostrTools.nip04.decrypt(
+ this.customerPrivkey,
+ sender,
+ event.content
+ )
+ } else if (this.customerUseExtension && this.hasNip07) {
+ plaintext = await window.nostr.nip04.decrypt(
+ sender,
+ event.content
+ )
+ }
+ console.log(`${mine ? 'Me' : 'Merchant'}: ${plaintext}`)
+
+ // this.nostrMessages.set(event.id, {
+ // msg: plaintext,
+ // timestamp: event.created_at,
+ // sender: `${mine ? 'Me' : 'Merchant'}`
+ // })
+ this.messageFilter(plaintext, cb => Promise.resolve(pool.close))
} catch {
console.error('Unable to decrypt message!')
- return
}
})
} catch (err) {
console.error(`Error: ${err}`)
}
+ },
+ messageFilter(text, cb = () => {}) {
+ if (!isJson(text)) return
+ let json = JSON.parse(text)
+ if (json.id != this.activeOrder) return
+ if (json?.payment_options) {
+ // this.qrCodeDialog.show = true
+ this.qrCodeDialog.data.payment_request = json.payment_options.find(
+ o => o.type == 'ln'
+ ).link
+ this.qrCodeDialog.dismissMsg = this.$q.notify({
+ timeout: 0,
+ message: 'Waiting for payment...'
+ })
+ } else if (json?.paid) {
+ this.qrCodeDialog.dismissMsg = this.$q.notify({
+ type: 'positive',
+ message: 'Sats received, thanks!',
+ icon: 'thumb_up'
+ })
+ this.closeQrCodeDialog()
+ this.activeOrder = null
+ Promise.resolve(cb())
+ } else {
+ return
+ }
}
+ // async mockInit() {
+ // this.customerPubkey = await window.nostr.getPublicKey()
+ // this.activeOrder =
+ // 'e4a16aa0198022dc682b2b52ed15767438282c0e712f510332fc047eaf795313'
+ // await this.listenMessages()
+ // }
},
created() {
+ this.customerPubkey = this.account.pubkey
+ this.customerPrivkey = this.account.privkey
+ this.customerUseExtension = this.account.useExtension
setTimeout(() => {
if (window.nostr) {
this.hasNip07 = true
diff --git a/static/components/product-card/product-card.html b/static/components/product-card/product-card.html
index 5a92ba3..95f86e2 100644
--- a/static/components/product-card/product-card.html
+++ b/static/components/product-card/product-card.html
@@ -43,9 +43,6 @@
{{ product.formatedPrice }}
- ({{ product.priceInSats }} sats)
{{ product.quantity }} left
{{ product.formatedPrice }}
- ({{ product.priceInSats }} sats)
{
key: null
}
},
- drawer: true,
+ drawer: false,
pubkeys: new Set(),
relays: new Set(),
events: [],
@@ -49,7 +49,6 @@ const market = async () => {
products: [],
profiles: new Map(),
searchText: null,
- exchangeRates: null,
inputPubkey: null,
inputRelay: null,
activePage: 'market',
@@ -136,10 +135,8 @@ const market = async () => {
}
// Get notes from Nostr
- //await this.initNostr()
+ await this.initNostr()
- // Get fiat rates (i think there's an LNbits endpoint for this)
- //await this.getRates()
this.$q.loading.hide()
},
methods: {
@@ -233,23 +230,12 @@ const market = async () => {
obj.images = [obj.image]
if (obj.currency != 'sat') {
obj.formatedPrice = this.getAmountFormated(obj.price, obj.currency)
- obj.priceInSats = this.getValueInSats(obj.price, obj.currency)
}
return obj
})
pool.close(relays)
return
},
- async getRates() {
- let noFiat = this.stalls.map(s => s.currency).every(c => c == 'sat')
- if (noFiat) return
- try {
- let rates = await axios.get('https://api.opennode.co/v1/rates')
- this.exchangeRates = rates.data.data
- } catch (error) {
- LNbits.utils.notifyApiError(error)
- }
- },
navigateTo(page, opts = {stall: null, product: null, pubkey: null}) {
let {stall, product, pubkey} = opts
let url = new URL(window.location)
@@ -283,13 +269,6 @@ const market = async () => {
window.history.pushState({}, '', url)
this.activePage = page
},
-
- getValueInSats(amount, unit = 'USD') {
- if (!this.exchangeRates) return 0
- return Math.ceil(
- (amount / this.exchangeRates[`BTC${unit}`][unit]) * 1e8
- )
- },
getAmountFormated(amount, unit = 'USD') {
return LNbits.utils.formatCurrency(amount, unit)
},
diff --git a/static/js/utils.js b/static/js/utils.js
index e684ab8..c11cdef 100644
--- a/static/js/utils.js
+++ b/static/js/utils.js
@@ -26,3 +26,15 @@ async function hash(string) {
.join('')
return hashHex
}
+
+function isJson(str) {
+ if (typeof str !== 'string') {
+ return false
+ }
+ try {
+ JSON.parse(str)
+ return true
+ } catch (error) {
+ return false
+ }
+}
diff --git a/templates/nostrmarket/market.html b/templates/nostrmarket/market.html
index 77c0cac..20a4332 100644
--- a/templates/nostrmarket/market.html
+++ b/templates/nostrmarket/market.html
@@ -169,15 +169,14 @@
v-if="!isLoading && activeStall"
:stall="stalls.find(stall => stall.id == activeStall)"
:products="filterProducts"
- :exchange-rates="exchangeRates"
:product-detail="activeProduct"
:relays="relays"
+ :account="account"
@change-page="navigateTo"
>