general fixes, prop passing and shopping cart (doesn't send dm)
This commit is contained in:
parent
f71b9f56d9
commit
52f8dead0e
11 changed files with 355 additions and 96 deletions
|
|
@ -10,13 +10,20 @@
|
|||
<q-breadcrumbs-el :label="stall.name" icon="widgets"></q-breadcrumbs-el>
|
||||
</q-breadcrumbs>
|
||||
<q-toolbar-title></q-toolbar-title>
|
||||
<shopping-cart></shopping-cart>
|
||||
<shopping-cart
|
||||
:cart="cart"
|
||||
:cart-menu="cartMenu"
|
||||
@remove-from-cart="removeFromCart"
|
||||
@reset-cart="resetCart"
|
||||
@open-checkout="checkoutDialog.show = true"
|
||||
></shopping-cart>
|
||||
</q-toolbar>
|
||||
<div class="row">
|
||||
<product-detail
|
||||
class="col-12"
|
||||
v-if="productDetail && product"
|
||||
:product="product"
|
||||
@add-to-cart="addToCart"
|
||||
></product-detail>
|
||||
<div class="col-12 q-my-lg">
|
||||
<q-separator></q-separator>
|
||||
|
|
@ -28,7 +35,102 @@
|
|||
v-for="(item, idx) in products"
|
||||
:key="idx"
|
||||
>
|
||||
<product-card :product="item" @change-page="changePageS"></product-card>
|
||||
<product-card
|
||||
:product="item"
|
||||
@change-page="changePageS"
|
||||
@add-to-cart="addToCart"
|
||||
:is-stall="true"
|
||||
></product-card>
|
||||
</div>
|
||||
</div>
|
||||
<!-- BEGIN CHECKOUT DIALOG -->
|
||||
<q-dialog v-model="checkoutDialog.show" position="top">
|
||||
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
||||
<q-form @submit="placeOrder" class="q-gutter-md">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="checkoutDialog.data.username"
|
||||
label="Name *optional"
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="checkoutDialog.data.pubkey"
|
||||
label="Public key"
|
||||
>
|
||||
</q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
readonly
|
||||
hint="This your key pair! Don't lose it!"
|
||||
v-if="checkoutDialog.data.privkey"
|
||||
v-model="checkoutDialog.data.privkey"
|
||||
>
|
||||
</q-input>
|
||||
<div class="row">
|
||||
<div class="col-5">
|
||||
<q-btn unelevated @click="generateKeyPair" color="primary"
|
||||
>Generate key pair</q-btn
|
||||
>
|
||||
</div>
|
||||
<div class="col-5" v-if="hasNip07">
|
||||
<q-btn unelevated @click="getPubkey" color="primary"
|
||||
>Get from Extension</q-btn
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="checkoutDialog.data.address"
|
||||
label="Address"
|
||||
></q-input>
|
||||
<q-input
|
||||
v-model="checkoutDialog.data.email"
|
||||
filled
|
||||
dense
|
||||
type="email"
|
||||
label="Email *optional"
|
||||
hint="Merchant may not use email"
|
||||
></q-input>
|
||||
<p>Select the shipping zone:</p>
|
||||
<div class="row q-mt-lg">
|
||||
<q-option-group
|
||||
:options="stall.shipping.map(s => ({label: s.countries.toString(), value: s.id}))"
|
||||
type="radio"
|
||||
emit-value
|
||||
v-model="checkoutDialog.data.shippingzone"
|
||||
/>
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
Total: {{ stall.currency != 'sat' ? getAmountFormated(finalCost) :
|
||||
finalCost + 'sats' }}
|
||||
<span v-if="stall.currency != 'sat'" class="q-ml-sm text-grey-6"
|
||||
>({{ getValueInSats(finalCost) }} sats)</span
|
||||
>
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="primary"
|
||||
:disable="checkoutDialog.data.address == null
|
||||
|| checkoutDialog.data.shippingzone == null"
|
||||
type="submit"
|
||||
>Checkout</q-btn
|
||||
>
|
||||
<q-btn
|
||||
v-close-popup
|
||||
flat
|
||||
@click="checkoutDialog = {show: false, data: {pubkey: null}}"
|
||||
color="grey"
|
||||
class="q-ml-auto"
|
||||
>Cancel</q-btn
|
||||
>
|
||||
</div>
|
||||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
<!-- END CHECKOUT DIALOG -->
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue