200 lines
6.3 KiB
JavaScript
200 lines
6.3 KiB
JavaScript
'use strict'
|
|
const formatUSD = (v) => v.toLocaleString(undefined, {
|
|
style: 'currency', currency: 'USD' })
|
|
const cancel = () =>
|
|
window.location = '/shop/cart/'
|
|
// Parse querystring (https://stackoverflow.com/a/901144/)
|
|
const qs = new Proxy(new URLSearchParams(window.location.search), {
|
|
get: (searchParams, prop) => searchParams.get(prop),
|
|
})
|
|
let socket
|
|
|
|
class moneroCheckoutItem { constructor(data) {
|
|
let self = this
|
|
self.name = data.name
|
|
self.price = data.price
|
|
self.qty = data.qty
|
|
self.subtotal = data.subtotal
|
|
} }
|
|
|
|
class moneroCheckoutTransaction { constructor(data) {
|
|
let self = this
|
|
self.amount = data.amount/1000000000000
|
|
self.confirmations = ko.observable(0)
|
|
self.double_spend_seen = ko.observable(false)
|
|
self.fee = data.fee/1000000000000
|
|
self.height = data.height
|
|
self.datetime = new Date(data.timestamp)
|
|
self.date = self.datetime.toLocaleDateString()
|
|
self.time = self.datetime.toLocaleTimeString()
|
|
self.tx_hash = data.tx_hash
|
|
self.unlock_time = ko.observable(0)
|
|
self.locked = ko.observable(true)
|
|
} }
|
|
|
|
class moneroCheckout { constructor(data) {
|
|
let self = this
|
|
self.items = ko.observableArray([])
|
|
self.shipname = ko.observable('')
|
|
self.contactname = ko.observable('')
|
|
self.phone = ko.observable('')
|
|
self.email = ko.observable('')
|
|
self.addr1 = ko.observable('')
|
|
self.addr2 = ko.observable('')
|
|
self.city = ko.observable('')
|
|
self.zip = ko.observable('')
|
|
self.state = ko.observable('')
|
|
self.tax = ko.observable('')
|
|
self.shipping = ko.observable('')
|
|
self.subtotal = ko.observable('')
|
|
self.total = ko.observable('')
|
|
self.totalxmr = ko.observable('')
|
|
self.totalxmr_pretty = ko.pureComputed(() =>
|
|
`${self.totalxmr()} XMR`
|
|
)
|
|
self.orderid = ko.observable('')
|
|
self.xmr_address = ko.observable('')
|
|
self.submitted = ko.observable(0)
|
|
self.submitted_pretty = ko.pureComputed( () =>
|
|
`${self.submitted()} XMR`
|
|
)
|
|
self.unsubmitted = ko.pureComputed( () =>
|
|
self.totalxmr() - self.submitted()
|
|
)
|
|
self.unlocked = ko.observable(0)
|
|
self.unlocked_pretty = ko.pureComputed( () =>
|
|
`${self.unlocked()} XMR`
|
|
)
|
|
self.isSubmitted = ko.pureComputed( () =>
|
|
( self.submitted() >= self.totalxmr() )
|
|
)
|
|
self.isPaid = ko.pureComputed( () =>
|
|
( self.unlocked() >= self.totalxmr() )
|
|
)
|
|
self.transactions = ko.observableArray([])
|
|
self.xmr_uri = ko.pureComputed(() =>
|
|
`monero:${self.xmr_address()}?tx_amount=${self.unsubmitted()}&tx_description=sales@slvit.us_${self.orderid()}`
|
|
)
|
|
let xmr_qr = new QRCode(
|
|
document.getElementById('xmr_qr'),
|
|
self.xmr_uri()
|
|
)
|
|
self.xmr_uri.subscribe(() => {
|
|
xmr_qr.clear()
|
|
xmr_qr.makeCode(self.xmr_uri())
|
|
})
|
|
self.checkingStatus = ko.observable('')
|
|
|
|
// Get order info from querystring
|
|
self.orderid(qs.order)
|
|
//self.xmr_address(qs.xmr_address)
|
|
|
|
// Load order from API
|
|
;(async () => {
|
|
let res; try {
|
|
res = await fetch(`${API_DOMAIN}/order/${qs.order}`, {
|
|
headers: {'Accept':'application/json'},
|
|
})
|
|
if (!res.ok) throw res.statusText
|
|
} catch (err) {
|
|
console.error(`Failed to fetch order from API!\n${err}`)
|
|
}; let order; try {
|
|
order = await res.json()
|
|
} catch (err) {
|
|
console.error(`Failed to parse JSON:\n${err}`)
|
|
}
|
|
|
|
self.xmr_address(order.xmr_address)
|
|
self.subtotal(formatUSD(order.subtotal))
|
|
self.shipping(formatUSD(order.shipping.amount))
|
|
self.tax(formatUSD(order.tax))
|
|
self.total(formatUSD(order.total))
|
|
self.orderid(order.id)
|
|
self.totalxmr(order.totalxmr)
|
|
order.items.forEach((item) =>
|
|
self.items.push({
|
|
name: item.name,
|
|
price: formatUSD(parseFloat(item.price)),
|
|
qty: item.qty,
|
|
subtotal: formatUSD(item.subtotal),
|
|
})
|
|
)
|
|
self.shipname(order.shipping.address.name)
|
|
self.addr1(order.shipping.address.addr1)
|
|
self.addr2(order.shipping.address.addr2)
|
|
self.city(order.shipping.address.city)
|
|
self.zip(order.shipping.address.zip)
|
|
self.state(order.shipping.address.state)
|
|
self.contactname(order.contact.name)
|
|
self.phone(order.contact.phone)
|
|
self.email(order.contact.email)
|
|
|
|
// Poll for transactions
|
|
let poll_in = MONERO_CHECKOUT_POLL_SECS
|
|
let isChecking = false
|
|
const getTransactions = async () => {
|
|
isChecking = true
|
|
let res; try {
|
|
res = await fetch(`${API_DOMAIN}/xmr-receive/${order.xmr_address}`)
|
|
} catch (err) {
|
|
return console.error(`Failed to get update about xmr address ${order.xmr_address}\n${err}`)
|
|
} if (!res.ok)
|
|
return console.error(`Got a bad response when requesting update on this xmr address: ${res.status}\n${res}`)
|
|
let resData; try {
|
|
resData = await res.json()
|
|
} catch (err) {
|
|
return console.error(`Failed to parse response JSON: ${err}`)
|
|
} finally {
|
|
isChecking = false
|
|
poll_in = MONERO_CHECKOUT_POLL_SECS
|
|
}
|
|
resData.transactions.forEach( (tx) => {
|
|
const existingTransactions = self.transactions()
|
|
.filter((i) => (i.tx_hash===tx.tx_hash))
|
|
if (existingTransactions.length) {
|
|
existingTransactions[0].confirmations(tx.confirmations)
|
|
existingTransactions[0].double_spend_seen(tx.double_spend_seen)
|
|
existingTransactions[0].unlock_time(tx.unlock_time)
|
|
existingTransactions[0].locked(tx.locked)
|
|
} else {
|
|
self.transactions.push(new moneroCheckoutTransaction(tx))
|
|
self.transactions.sort( (a,b) =>
|
|
(a.height===b.height)?0
|
|
:(a.height<b.height)?-1:1
|
|
)
|
|
}
|
|
})
|
|
self.submitted(resData.amount.covered.total/1000000000000)
|
|
self.unlocked(resData.amount.covered.unlocked/1000000000000)
|
|
}; getTransactions(); setInterval(() => {
|
|
if (poll_in<=0) {
|
|
self.checkingStatus('Checking for transactions...')
|
|
if (!isChecking) getTransactions()
|
|
} else {
|
|
self.checkingStatus(`Checking for transactions in ${
|
|
poll_in--}...`)
|
|
}
|
|
}, 1000)
|
|
|
|
// Websockets
|
|
// socket = io(API_DOMAIN,{query:{orderid:data.id}})
|
|
// socket.on('mp-cb', (body) => {
|
|
// console.log(body)
|
|
// body.transactions.forEach( (tx) => {
|
|
// const existingTransactions = self.transactions()
|
|
// .filter((i) => (i.tx_hash===tx.tx_hash))
|
|
// if (existingTransactions.length>0) {
|
|
// existingTransactions[0].confirmations(tx.confirmations)
|
|
// existingTransactions[0].double_spend_seen(tx.double_spend_seen)
|
|
// existingTransactions[0].unlock_time(tx.unlock_time)
|
|
// existingTransactions[0].locked(tx.locked)
|
|
// } else self.transactions.push(tx)
|
|
// })
|
|
// self.submitted(body.amount.covered.total)
|
|
// self.unlocked(body.amount.covered.unlocked)
|
|
// })
|
|
|
|
} )()
|
|
|
|
} }; ko.applyBindings(new moneroCheckout())
|