diff --git a/static/components/chat-dialog/chat-dialog.js b/static/components/chat-dialog/chat-dialog.js index 0e0d36f..abca869 100644 --- a/static/components/chat-dialog/chat-dialog.js +++ b/static/components/chat-dialog/chat-dialog.js @@ -5,13 +5,12 @@ async function chatDialog(path) { name: 'chat-dialog', template, - props: ['account', 'merchant', 'relays'], + props: ['account', 'merchant', 'relays', 'pool'], data: function () { return { dialog: false, isChat: true, loading: false, - pool: null, nostrMessages: [], newMessage: '', ordersTable: { @@ -82,11 +81,10 @@ async function chatDialog(path) { }, async closeDialog() { this.dialog = false - await this.pool.close(Array.from(this.relays)) + await this.sub.unsub() }, async startPool() { this.loading = true - this.pool = new NostrTools.SimplePool() let messagesMap = new Map() let sub = this.pool.sub(Array.from(this.relays), [ { @@ -98,6 +96,7 @@ async function chatDialog(path) { '#p': [this.account.pubkey] } ]) + sub.on('eose', () => { this.loading = false this.nostrMessages = Array.from(messagesMap.values()) @@ -133,6 +132,7 @@ async function chatDialog(path) { console.error('Unable to decrypt message!') } }) + this.sub = sub }, async sendMessage() { if (this.newMessage && this.newMessage.length < 1) return @@ -146,6 +146,10 @@ async function chatDialog(path) { } event.id = NostrTools.getEventHash(event) event.sig = this.signEvent(event) + // This doesn't work yet + // this.pool.publish(Array.from(this.relays), event) + // this.newMessage = '' + // We need this hack for (const url of Array.from(this.relays)) { try { let relay = NostrTools.relayInit(url) diff --git a/static/components/customer-stall/customer-stall.html b/static/components/customer-stall/customer-stall.html index ea37b72..1575c55 100644 --- a/static/components/customer-stall/customer-stall.html +++ b/static/components/customer-stall/customer-stall.html @@ -18,6 +18,7 @@ :account="account ? account : dropIn" :merchant="stall.pubkey" :relays="relays" + :pool="pool" /> Copy invoice - Close diff --git a/static/components/customer-stall/customer-stall.js b/static/components/customer-stall/customer-stall.js index 741bb31..9d67750 100644 --- a/static/components/customer-stall/customer-stall.js +++ b/static/components/customer-stall/customer-stall.js @@ -11,7 +11,8 @@ async function customerStall(path) { 'products', 'product-detail', 'change-page', - 'relays' + 'relays', + 'pool' ], data: function () { return { @@ -38,6 +39,7 @@ async function customerStall(path) { data: { payment_request: null }, + dismissMsg: null, show: false }, downloadOrderDialog: { @@ -85,10 +87,17 @@ async function customerStall(path) { return LNbits.utils.formatCurrency(amount, unit) }, addToCart(item) { - console.log('add to cart', item) let prod = this.cart.products if (prod.has(item.id)) { let qty = prod.get(item.id).quantity + if (qty == item.quantity) { + this.$q.notify({ + type: 'warning', + message: `${item.name} only has ${item.quantity} units!`, + icon: 'production_quantity_limits' + }) + return + } prod.set(item.id, { ...prod.get(item.id), quantity: qty + 1 @@ -114,7 +123,6 @@ async function customerStall(path) { this.updateCart(+item.price, true) }, updateCart(price, del = false) { - console.log(this.cart, this.cartMenu) if (del) { this.cart.total -= price this.cart.size-- @@ -125,7 +133,10 @@ async function customerStall(path) { this.cartMenu = Array.from(this.cart.products, item => { return {id: item[0], ...item[1]} }) - console.log(this.cart, this.cartMenu) + this.$q.localStorage.set(`diagonAlley.carts.${this.stall.id}`, { + ...this.cart, + products: Object.fromEntries(this.cart.products) + }) }, resetCart() { this.cart = { @@ -133,6 +144,7 @@ async function customerStall(path) { size: 0, products: new Map() } + this.$q.localStorage.remove(`diagonAlley.carts.${this.stall.id}`) }, async downloadOrder() { let created_at = Math.floor(Date.now() / 1000) @@ -181,6 +193,7 @@ async function customerStall(path) { this.checkoutDialog.show = true }, resetCheckout() { + this.loading = false this.checkoutDialog = { show: false, data: { @@ -188,8 +201,22 @@ async function customerStall(path) { } } }, + openQrCodeDialog() { + this.qrCodeDialog = { + data: { + payment_request: null + }, + dismissMsg: this.$q.notify({ + message: 'Waiting for invoice from merchant...' + }), + show: true + } + }, closeQrCodeDialog() { this.qrCodeDialog.show = false + setTimeout(() => { + this.qrCodeDialog.dismissMsg() + }, 1000) }, async placeOrder() { this.loading = true @@ -247,9 +274,6 @@ async function customerStall(path) { await this.sendOrder(event) }, async sendOrder(order) { - this.$q.notify({ - message: 'Waiting for invoice from merchant...' - }) for (const url of Array.from(this.relays)) { try { let relay = NostrTools.relayInit(url) @@ -278,7 +302,7 @@ async function customerStall(path) { } this.loading = false this.resetCart() - this.qrCodeDialog.show = true + this.openQrCodeDialog() this.listenMessages() }, async listenMessages() { @@ -319,7 +343,7 @@ async function customerStall(path) { this.messageFilter(plaintext, cb => Promise.resolve(pool.close)) } catch { - console.error('Unable to decrypt message!') + console.debug('Unable to decrypt message! Probably not for us!') } }) } catch (err) { @@ -331,9 +355,8 @@ async function customerStall(path) { let json = JSON.parse(text) if (json.id != this.activeOrder) return if (json.payment_options) { - let payment_request = json.payment_options.find( - o => o.type == 'ln' - ).link + let payment_request = json.payment_options.find(o => o.type == 'ln') + .link if (!payment_request) return this.loading = false this.qrCodeDialog.data.payment_request = payment_request @@ -359,6 +382,18 @@ async function customerStall(path) { this.customerPubkey = this.account?.pubkey this.customerPrivkey = this.account?.privkey this.customerUseExtension = this.account?.useExtension + let storedCart = this.$q.localStorage.getItem( + `diagonAlley.carts.${this.stall.id}` + ) + if (storedCart) { + this.cart.total = storedCart.total + this.cart.size = storedCart.size + this.cart.products = new Map(Object.entries(storedCart.products)) + + this.cartMenu = Array.from(this.cart.products, item => { + return {id: item[0], ...item[1]} + }) + } 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 95f86e2..55eefb5 100644 --- a/static/components/product-card/product-card.html +++ b/static/components/product-card/product-card.html @@ -77,6 +77,7 @@ View details { ] const eventToObj = event => { event.content = JSON.parse(event.content) || null + return { ...event, ...Object.values(event.tags).reduce((acc, tag) => { let [key, value] = tag - return {...acc, [key]: [...(acc[key] || []), value]} + if (key == 't') { + return {...acc, [key]: [...(acc[key] || []), value]} + } else { + return {...acc, [key]: value} + } }, {}) } } @@ -55,7 +60,8 @@ const market = async () => { inputRelay: null, activePage: 'market', activeStall: null, - activeProduct: null + activeProduct: null, + pool: null } }, computed: { @@ -209,13 +215,18 @@ const market = async () => { this.products.forEach(p => products.set(p.id, p)) events.map(eventToObj).map(e => { - if (e.kind == 30018) { + if (e.kind == 0) { + this.profiles.set(e.pubkey, e.content) + if (e.pubkey == this.account?.pubkey) { + this.accountMetadata = this.profiles.get(this.account.pubkey) + } + return + } else if (e.kind == 30018) { //it's a product `d` is the prod. id - products.set(e.d, {...e.content, id: e.d[0], categories: e.t}) + products.set(e.d, {...e.content, id: e.d, categories: e.t}) } else if (e.kind == 30017) { // it's a stall `d` is the stall id - stalls.set(e.d, {...e.content, id: e.d[0], pubkey: e.pubkey}) - return + stalls.set(e.d, {...e.content, id: e.d, pubkey: e.pubkey}) } }) @@ -226,7 +237,7 @@ const market = async () => { let stall = this.stalls.find(s => s.id == obj.stall_id) if (!stall) return obj.stallName = stall.name - obj.images = [obj.image] + obj.images = obj.images || [obj.image] if (obj.currency != 'sat') { obj.formatedPrice = this.getAmountFormated( obj.price, @@ -241,10 +252,9 @@ const market = async () => { this.$q.loading.show() const pool = new NostrTools.SimplePool() let relays = Array.from(this.relays) - let products = new Map() - let stalls = new Map() + // Get metadata and market data from the pubkeys - let sub = await pool + await pool .list(relays, [ { kinds: [0, 30017, 30018], // for production kind is 30017 @@ -252,46 +262,31 @@ const market = async () => { } ]) .then(async events => { - this.events = events || [] - this.events.map(eventToObj).map(e => { - if (e.kind == 0) { - this.profiles.set(e.pubkey, e.content) - if (e.pubkey == this.account?.pubkey) { - this.accountMetadata = this.profiles.get(this.account.pubkey) - } - return - } else if (e.kind == 30018) { - //it's a product `d` is the prod. id - products.set(e.d, {...e.content, id: e.d[0], categories: e.t}) - } else if (e.kind == 30017) { - // it's a stall `d` is the stall id - stalls.set(e.d, {...e.content, id: e.d[0], pubkey: e.pubkey}) - return - } - }) + if (!events || events.length == 0) return + await this.updateData(events) }) - await Promise.resolve(sub) - this.stalls = await Array.from(stalls.values()) - this.products = Array.from(products.values()) - .map(obj => { - let stall = this.stalls.find(s => s.id == obj.stall_id) - if (!stall) return - obj.stallName = stall.name - obj.images = [obj.image] - if (obj.currency != 'sat') { - obj.formatedPrice = this.getAmountFormated( - obj.price, - obj.currency - ) - } - return obj - }) - .filter(f => f) this.$q.loading.hide() - pool.close(relays) + this.pool = pool + this.poolSubscribe() return }, + async poolSubscribe() { + this.poolSub = this.pool.sub(Array.from(this.relays), [ + { + kinds: [0, 30017, 30018], + authors: Array.from(this.pubkeys), + since: Date.now() / 1000 + } + ]) + this.poolSub.on( + 'event', + event => { + this.updateData([event]) + }, + {id: 'masterSub'} //pass ID to cancel previous sub + ) + }, navigateTo(page, opts = {stall: null, product: null, pubkey: null}) { let {stall, product, pubkey} = opts let url = new URL(window.location) @@ -356,7 +351,7 @@ const market = async () => { `diagonAlley.merchants`, Array.from(this.pubkeys) ) - await this.initNostr() + this.initNostr() }, removePubkey(pubkey) { // Needs a hack for Vue reactivity @@ -368,7 +363,7 @@ const market = async () => { `diagonAlley.merchants`, Array.from(this.pubkeys) ) - Promise.resolve(this.initNostr()) + this.initNostr() }, async addRelay() { let relay = String(this.inputRelay).trim() @@ -379,7 +374,7 @@ const market = async () => { this.relays.add(relay) this.$q.localStorage.set(`diagonAlley.relays`, Array.from(this.relays)) this.inputRelay = null - await this.initNostr() + this.initNostr() }, removeRelay(relay) { // Needs a hack for Vue reactivity @@ -387,6 +382,7 @@ const market = async () => { relays.delete(relay) this.relays = new Set(Array.from(relays)) this.$q.localStorage.set(`diagonAlley.relays`, Array.from(this.relays)) + this.initNostr() } } }) diff --git a/templates/nostrmarket/market.html b/templates/nostrmarket/market.html index 4784483..248fa3b 100644 --- a/templates/nostrmarket/market.html +++ b/templates/nostrmarket/market.html @@ -189,6 +189,7 @@ :product-detail="activeProduct" :relays="relays" :account="account" + :pool="pool" @change-page="navigateTo" >