diff --git a/static/components/customer-stall/customer-stall.html b/static/components/customer-stall/customer-stall.html
index 9bc302c..aedec55 100644
--- a/static/components/customer-stall/customer-stall.html
+++ b/static/components/customer-stall/customer-stall.html
@@ -10,13 +10,20 @@
-
+
@@ -28,7 +35,102 @@
v-for="(item, idx) in products"
:key="idx"
>
-
+
+
+
+
+
+
+
+
+
+
+
+
+ Generate key pair
+
+
+ Get from Extension
+
+
+
+
+ Select the shipping zone:
+
+
+
+
+ Total: {{ stall.currency != 'sat' ? getAmountFormated(finalCost) :
+ finalCost + 'sats' }}
+ ({{ getValueInSats(finalCost) }} sats)
+
+
+ Checkout
+ Cancel
+
+
+
+
+
diff --git a/static/components/customer-stall/customer-stall.js b/static/components/customer-stall/customer-stall.js
index 1d9b395..858ed9d 100644
--- a/static/components/customer-stall/customer-stall.js
+++ b/static/components/customer-stall/customer-stall.js
@@ -10,23 +10,184 @@ async function customerStall(path) {
'products',
'exchange-rates',
'product-detail',
- 'change-page'
+ 'change-page',
+ 'relays'
],
data: function () {
- return {}
+ return {
+ cart: {
+ total: 0,
+ size: 0,
+ products: new Map()
+ },
+ cartMenu: [],
+ hasNip07: false,
+ checkoutDialog: {
+ show: false,
+ data: {
+ pubkey: null
+ }
+ },
+ qrCodeDialog: {
+ data: {
+ payment_request: null
+ },
+ show: false
+ }
+ }
},
computed: {
product() {
if (this.productDetail) {
return this.products.find(p => p.id == this.productDetail)
}
+ },
+ finalCost() {
+ if (!this.checkoutDialog.data.shippingzone) return this.cart.total
+
+ let zoneCost = this.stall.shipping.find(
+ z => z.id == this.checkoutDialog.data.shippingzone
+ )
+ return +this.cart.total + zoneCost.cost
}
},
methods: {
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)
+ },
+ 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
+ prod.set(item.id, {
+ ...prod.get(item.id),
+ quantity: qty + 1
+ })
+ } else {
+ prod.set(item.id, {
+ name: item.name,
+ quantity: 1,
+ price: item.price,
+ image: item?.images[0] || null
+ })
+ }
+ this.$q.notify({
+ type: 'positive',
+ message: `${item.name} added to cart`,
+ icon: 'thumb_up'
+ })
+ this.cart.products = prod
+ this.updateCart(+item.price)
+ },
+ removeFromCart(item) {
+ this.cart.products.delete(item.id)
+ this.updateCart(+item.price, true)
+ },
+ updateCart(price, del = false) {
+ console.log(this.cart, this.cartMenu)
+ if (del) {
+ this.cart.total -= price
+ this.cart.size--
+ } else {
+ this.cart.total += price
+ this.cart.size++
+ }
+ this.cartMenu = Array.from(this.cart.products, item => {
+ return {id: item[0], ...item[1]}
+ })
+ console.log(this.cart, this.cartMenu)
+ },
+ resetCart() {
+ this.cart = {
+ total: 0,
+ size: 0,
+ products: new Map()
+ }
+ },
+ async getPubkey() {
+ try {
+ this.checkoutDialog.data.pubkey = await window.nostr.getPublicKey()
+ 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.checkoutDialog.data.pubkey = pk
+ this.checkoutDialog.data.privkey = sk
+ },
+ placeOrder() {
+ LNbits.utils
+ .confirmDialog(
+ `Send the order to the merchant? You should receive a message with the payment details.`
+ )
+ .onOk(async () => {
+ let orderData = this.checkoutDialog.data
+ let content = {
+ name: orderData?.username,
+ description: null,
+ address: orderData.address,
+ message: null,
+ contact: {
+ nostr: orderData.pubkey,
+ phone: null,
+ email: orderData?.email
+ },
+ items: Array.from(this.cart.products, p => {
+ return {product_id: p[0], quantity: p[1].quantity}
+ })
+ }
+ let event = {
+ kind: 4,
+ created_at: Math.floor(Date.now() / 1000),
+ tags: [],
+ content: await window.nostr.nip04.encrypt(
+ orderData.pubkey,
+ content
+ ),
+ pubkey: orderData.pubkey
+ }
+ event.id = NostrTools.getEventHash(event)
+ if (orderData.privkey) {
+ event.sig = NostrTools.signEvent(event, orderData.privkey)
+ } else if (this.hasNip07) {
+ await window.nostr.signEvent(event)
+ }
+ await this.sendOrder(event)
+ })
+ },
+ async sendOrder(order) {
+ const pool = new NostrTools.SimplePool()
+ let relays = Array.from(this.relays)
+ let pubs = await pool.publish(relays, order)
+ pubs.on('ok', relay => {
+ console.log(`${relay.url} has accepted our event`)
+ })
+ pubs.on('failed', reason => {
+ console.log(`failed to publish to ${reason}`)
+ })
}
},
- created() {}
+ created() {
+ setTimeout(() => {
+ if (window.nostr) {
+ this.hasNip07 = true
+ }
+ }, 1000)
+ }
})
}
diff --git a/static/components/product-card/product-card.html b/static/components/product-card/product-card.html
index 93d4d96..5a92ba3 100644
--- a/static/components/product-card/product-card.html
+++ b/static/components/product-card/product-card.html
@@ -9,6 +9,22 @@
>
+ Add to cart
diff --git a/static/components/product-card/product-card.js b/static/components/product-card/product-card.js
index 9e8490b..5e049df 100644
--- a/static/components/product-card/product-card.js
+++ b/static/components/product-card/product-card.js
@@ -4,7 +4,7 @@ async function productCard(path) {
name: 'product-card',
template,
- props: ['product', 'change-page'],
+ props: ['product', 'change-page', 'add-to-cart', 'is-stall'],
data: function () {
return {}
},
diff --git a/static/components/product-detail/product-detail.html b/static/components/product-detail/product-detail.html
index 92fa1c0..be31eda 100644
--- a/static/components/product-detail/product-detail.html
+++ b/static/components/product-detail/product-detail.html
@@ -17,6 +17,11 @@
style="/*background-size: contain; background-repeat: no-repeat*/"
>
+
@@ -47,7 +52,7 @@
{{ product.amount > 0 ? 'In stock.' : 'Out of stock.' }}{{ product.quantity > 0 ? 'In stock.' : 'Out of stock.' }}
@@ -56,12 +61,13 @@
color="primary"
icon="shopping_cart"
label="Add to cart"
+ @click="$emit('add-to-cart', product)"
/>
diff --git a/static/components/product-detail/product-detail.js b/static/components/product-detail/product-detail.js
index 7b60f6b..d55b653 100644
--- a/static/components/product-detail/product-detail.js
+++ b/static/components/product-detail/product-detail.js
@@ -4,23 +4,14 @@ async function productDetail(path) {
name: 'product-detail',
template,
- props: ['product'],
+ props: ['product', 'add-to-cart'],
data: function () {
return {
slide: 1
}
},
- computed: {
- win_width() {
- return this.$q.screen.width - 59
- },
- win_height() {
- return this.$q.screen.height - 0
- }
- },
+ computed: {},
methods: {},
- created() {
- console.log('ping')
- }
+ created() {}
})
}
diff --git a/static/components/shopping-cart/shopping-cart.html b/static/components/shopping-cart/shopping-cart.html
index 8650cc6..2864cf3 100644
--- a/static/components/shopping-cart/shopping-cart.html
+++ b/static/components/shopping-cart/shopping-cart.html
@@ -1 +1,51 @@
-
+
+
+ {{ cart.size }}
+
+
+
+
+
+ {{p.quantity}} x
+
+
+
+
+
+
+
+
+ {{ p.name }}
+
+
+
+
+ {{p.currency != 'sat' ? p.formatedPrice : p.price + 'sats'}}
+
+
+
+
+
+
+
+
+
diff --git a/static/components/shopping-cart/shopping-cart.js b/static/components/shopping-cart/shopping-cart.js
index e0ad053..8f6902d 100644
--- a/static/components/shopping-cart/shopping-cart.js
+++ b/static/components/shopping-cart/shopping-cart.js
@@ -5,7 +5,7 @@ async function shoppingCart(path) {
name: 'shopping-cart',
template,
- props: [],
+ props: ['cart', 'cart-menu', 'remove-from-cart', 'reset-cart'],
data: function () {
return {}
},
diff --git a/static/js/market.js b/static/js/market.js
index 6a0d723..95bf5a6 100644
--- a/static/js/market.js
+++ b/static/js/market.js
@@ -1,20 +1,13 @@
const market = async () => {
Vue.component(VueQrcode.name, VueQrcode)
- const nostr = window.NostrTools
+ const NostrTools = window.NostrTools
const defaultRelays = [
'wss://relay.damus.io',
'wss://relay.snort.social',
- 'wss://nos.lol',
'wss://nostr.wine',
- 'wss://relay.nostr.bg',
'wss://nostr-pub.wellorder.net',
- 'wss://nostr-pub.semisol.dev',
- 'wss://eden.nostr.land',
- 'wss://nostr.mom',
- 'wss://nostr.fmt.wiz.biz',
- 'wss://nostr.zebedee.cloud',
- 'wss://nostr.rocks'
+ 'wss://nostr.zebedee.cloud'
]
const eventToObj = event => {
event.content = JSON.parse(event.content)
@@ -128,7 +121,7 @@ const market = async () => {
},
methods: {
naddr() {
- let naddr = nostr.nip19.naddrEncode({
+ let naddr = NostrTools.nip19.naddrEncode({
identifier: '1234',
pubkey:
'c1415f950a1e3431de2bc5ee35144639e2f514cf158279abff9ed77d50118796',
@@ -139,7 +132,7 @@ const market = async () => {
},
async initNostr() {
this.$q.loading.show()
- const pool = new nostr.SimplePool()
+ const pool = new NostrTools.SimplePool()
let relays = Array.from(this.relays)
let products = new Map()
let stalls = new Map()
@@ -243,7 +236,7 @@ const market = async () => {
let regExp = /^#([0-9a-f]{3}){1,2}$/i
if (pubkey.startsWith('n')) {
try {
- let {type, data} = nostr.nip19.decode(pubkey)
+ let {type, data} = NostrTools.nip19.decode(pubkey)
if (type === 'npub') pubkey = data
else if (type === 'nprofile') {
pubkey = data.pubkey
diff --git a/templates/nostrmarket/market.html b/templates/nostrmarket/market.html
index c885e10..5f01c41 100644
--- a/templates/nostrmarket/market.html
+++ b/templates/nostrmarket/market.html
@@ -145,6 +145,7 @@
:products="filterProducts"
:exchange-rates="exchangeRates"
:product-detail="activeProduct"
+ :relays="relays"
@change-page="navigateTo"
>
-{% endblock %} {% block scripts %}
-
-
-{% endblock %}