From 0f5c3e32d07fe84d9e461816157a4dfd2a264549 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 17 Mar 2023 09:50:29 +0000 Subject: [PATCH 01/10] feat: allow multiple images --- static/js/market.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/market.js b/static/js/market.js index bd71d31..632cf84 100644 --- a/static/js/market.js +++ b/static/js/market.js @@ -226,7 +226,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, From 93df7bb2c01dc16510caf5e719de5e803d0b1a25 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 17 Mar 2023 10:13:35 +0000 Subject: [PATCH 02/10] fix blocking loading button on checkout --- static/components/customer-stall/customer-stall.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/static/components/customer-stall/customer-stall.js b/static/components/customer-stall/customer-stall.js index 741bb31..7fb51c6 100644 --- a/static/components/customer-stall/customer-stall.js +++ b/static/components/customer-stall/customer-stall.js @@ -38,6 +38,7 @@ async function customerStall(path) { data: { payment_request: null }, + dismissMsg: null, show: false }, downloadOrderDialog: { @@ -181,6 +182,7 @@ async function customerStall(path) { this.checkoutDialog.show = true }, resetCheckout() { + this.loading = false this.checkoutDialog = { show: false, data: { @@ -190,6 +192,7 @@ async function customerStall(path) { }, closeQrCodeDialog() { this.qrCodeDialog.show = false + this.qrCodeDialog.dismissMsg = null }, async placeOrder() { this.loading = true @@ -319,7 +322,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 +334,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 From 14cea467a8f51733604fd9a928073503c08a6cfa Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 17 Mar 2023 10:25:46 +0000 Subject: [PATCH 03/10] fix: q-notify behaviour --- .../components/customer-stall/customer-stall.html | 7 +------ .../components/customer-stall/customer-stall.js | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/static/components/customer-stall/customer-stall.html b/static/components/customer-stall/customer-stall.html index ea37b72..53995ba 100644 --- a/static/components/customer-stall/customer-stall.html +++ b/static/components/customer-stall/customer-stall.html @@ -235,12 +235,7 @@ @click="copyText(qrCodeDialog.data.payment_request)" >Copy invoice - Close diff --git a/static/components/customer-stall/customer-stall.js b/static/components/customer-stall/customer-stall.js index 7fb51c6..0b0bddb 100644 --- a/static/components/customer-stall/customer-stall.js +++ b/static/components/customer-stall/customer-stall.js @@ -190,9 +190,20 @@ async function customerStall(path) { } } }, + openQrCodeDialog() { + this.qrCodeDialog = { + data: { + payment_request: null + }, + dismissMsg: null, + show: false + } + }, closeQrCodeDialog() { this.qrCodeDialog.show = false - this.qrCodeDialog.dismissMsg = null + setTimeout(() => { + this.qrCodeDialog.dismissMsg() + }, 1000) }, async placeOrder() { this.loading = true @@ -281,7 +292,7 @@ async function customerStall(path) { } this.loading = false this.resetCart() - this.qrCodeDialog.show = true + this.openQrCodeDialog() this.listenMessages() }, async listenMessages() { From 68e503df638dc4107fbb1c348f29d73e3b23dea7 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 17 Mar 2023 11:11:23 +0000 Subject: [PATCH 04/10] feat: make carts pesistent across stores --- .../customer-stall/customer-stall.js | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/static/components/customer-stall/customer-stall.js b/static/components/customer-stall/customer-stall.js index 0b0bddb..f5e7239 100644 --- a/static/components/customer-stall/customer-stall.js +++ b/static/components/customer-stall/customer-stall.js @@ -86,7 +86,6 @@ 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 @@ -115,7 +114,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-- @@ -126,7 +124,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 = { @@ -134,6 +135,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) @@ -372,6 +374,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 From cf5d43299802d4b12273e7342c9e6e5ef2f30b14 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 17 Mar 2023 11:13:46 +0000 Subject: [PATCH 05/10] don't show 'Visit Stall' when on stall page --- static/components/product-card/product-card.html | 1 + 1 file changed, 1 insertion(+) 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 Date: Fri, 17 Mar 2023 11:22:56 +0000 Subject: [PATCH 06/10] fix: don't allow adding more units than stock to cart --- static/components/customer-stall/customer-stall.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/static/components/customer-stall/customer-stall.js b/static/components/customer-stall/customer-stall.js index f5e7239..7a2ec20 100644 --- a/static/components/customer-stall/customer-stall.js +++ b/static/components/customer-stall/customer-stall.js @@ -89,6 +89,14 @@ async function customerStall(path) { 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 From ec56a93de5a189921b33df6249e135c10fb3e6f7 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 17 Mar 2023 12:45:54 +0000 Subject: [PATCH 07/10] fix: typo --- static/components/customer-stall/customer-stall.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/components/customer-stall/customer-stall.js b/static/components/customer-stall/customer-stall.js index 7a2ec20..1c4a476 100644 --- a/static/components/customer-stall/customer-stall.js +++ b/static/components/customer-stall/customer-stall.js @@ -206,7 +206,7 @@ async function customerStall(path) { payment_request: null }, dismissMsg: null, - show: false + show: true } }, closeQrCodeDialog() { From b4da149007c404779a8d69f45ef53549172246e3 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 17 Mar 2023 15:00:02 +0000 Subject: [PATCH 08/10] have a subscription on... --- static/js/market.js | 90 ++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 47 deletions(-) diff --git a/static/js/market.js b/static/js/market.js index 632cf84..54131f2 100644 --- a/static/js/market.js +++ b/static/js/market.js @@ -11,11 +11,16 @@ const market = async () => { ] 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}) } }) @@ -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() } } }) From aefe43f8a83e0ddd26fdfad16d9da60a13dc432d Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 17 Mar 2023 15:00:33 +0000 Subject: [PATCH 09/10] fix: notify misplacement --- static/components/customer-stall/customer-stall.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/static/components/customer-stall/customer-stall.js b/static/components/customer-stall/customer-stall.js index 1c4a476..9c7e150 100644 --- a/static/components/customer-stall/customer-stall.js +++ b/static/components/customer-stall/customer-stall.js @@ -205,7 +205,9 @@ async function customerStall(path) { data: { payment_request: null }, - dismissMsg: null, + dismissMsg: this.$q.notify({ + message: 'Waiting for invoice from merchant...' + }), show: true } }, @@ -271,9 +273,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) From 47adf676e2172aa7aa5e572dece9646080ec71a5 Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 17 Mar 2023 15:38:54 +0000 Subject: [PATCH 10/10] feat: one pool to rule them all (WIP) --- static/components/chat-dialog/chat-dialog.js | 12 ++++++++---- static/components/customer-stall/customer-stall.html | 1 + static/components/customer-stall/customer-stall.js | 3 ++- templates/nostrmarket/market.html | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) 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 53995ba..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" />