aboutsummaryrefslogtreecommitdiffstats
path: root/static/js/calculator.coffee
diff options
context:
space:
mode:
Diffstat (limited to 'static/js/calculator.coffee')
-rw-r--r--static/js/calculator.coffee268
1 files changed, 268 insertions, 0 deletions
diff --git a/static/js/calculator.coffee b/static/js/calculator.coffee
new file mode 100644
index 00000000..75192596
--- /dev/null
+++ b/static/js/calculator.coffee
@@ -0,0 +1,268 @@
+EXCHANGE_FAIL = "Problem fetching exchange rate"
+SOCKET_FAIL = "Problem connecting to payment server, notifications may not appear"
+ADDRESS_FAIL = "Invalid address"
+API_URL = "wss://socket.blockcypher.com/v1/btc/main"
+TEST_URL = "wss://socket.blockcypher.com/v1/btc/test3"
+
+g = exports ? this
+g.errors = []
+g.amount_requested = 0
+g.amount = 0.toFixed(2)
+g.tip = 1
+g.transactions = []
+
+$(->
+ $.ajax(
+ url: $('#user').val() + '.json',
+ dataType: 'json',
+ success: (data) ->
+ g.user = data
+ setup()
+ )
+
+ $('button').click((e) ->
+ e.preventDefault()
+ )
+
+ $('.numpad .btn').off('click').click((e) ->
+ e.preventDefault()
+
+ m = $(this).html()
+ n = parseFloat($('.amount').html())
+
+ if m is 'C'
+ g.amount = 0.toFixed(2)
+ updateTotal()
+ return
+
+ return if n > 10000000
+
+ if m is '00'
+ n = 100 * n
+ else
+ n = 10 * n + parseFloat(m) / 100
+
+ g.amount = n.toFixed(2)
+
+ updateTotal()
+ )
+
+ $('.numpad .btn:last').off('click').click((e) ->
+ e.preventDefault()
+
+ g.amount = (Math.floor(100 * (parseFloat($('.amount').html()) / 10)) / 100).toFixed(2)
+ updateTotal()
+ )
+
+ $('.tippad .btn').off('click').click((e) ->
+ e.preventDefault()
+
+ text = $(this).html()
+ if text is 'No Tip'
+ value = 0
+ else
+ value = text.slice(1, -1)
+
+ $(this).addClass('active')
+ $(this).siblings().removeClass('active')
+ g.tip = 1 + (parseFloat(value)/100)
+ updateTotal()
+ )
+
+ $('#received').click(-> window.location = "/#{g.user.username}/report")
+ $('#slide').click(->
+ $('#controls').slideToggle()
+ $(this).find('i').toggleClass('fa-sort-up').toggleClass('fa-sort-down')
+ )
+)
+
+setup = ->
+ g.user.address or= ''
+ g.user.commission or= 0
+ g.user.currency or= 'CAD'
+ g.user.symbol or= 'quadrigacx'
+ g.user.unit or= 'BTC'
+
+ if g.user.title
+ $('#title').html("<a href='/#{g.user.username}/edit'>#{g.user.title}</a>").show()
+
+ if g.user.logo
+ ext = g.user.logo.substr(g.user.logo.length - 3)
+ src = "/img/logos/#{g.user.username}.#{ext}"
+ $('#logo').attr('src', src).show()
+
+ getAddress()
+ if g.user.address[0] is 'm'
+ API_URL = TEST_URL
+
+ $('.symbol').html(g.user.currency)
+ $('.currency').html(g.user.currency)
+ $('.unit').html(g.user.unit)
+
+ $('#received').hide()
+
+ fetchExchangeRate()
+ listen()
+
+fetchExchangeRate = ->
+ $.ajax(
+ url: "ticker?currency=#{g.user.currency}&symbol=#{g.user.symbol}&type=bid",
+ success: (exchange) ->
+ if exchange?
+ clear(EXCHANGE_FAIL)
+ else
+ fail(EXCHANGE_FAIL)
+ return
+
+ g.exchange = (exchange - exchange * g.user.commission * 0.01).toFixed(2)
+ $('#exchange').html(g.exchange)
+ updateTotal()
+
+ unless g.setupComplete
+ g.setupComplete = true
+
+ error: -> fail(EXCHANGE_FAIL)
+ )
+ setTimeout(fetchExchangeRate, 900000)
+
+updateTotal = ->
+ precision = 9 - multiplier().toString().length
+ subtotal = parseFloat(g.amount * g.tip).toFixed(2)
+ total = (subtotal * multiplier() / g.exchange).toFixed(precision)
+ g.amount_requested = (subtotal / g.exchange).toFixed(8)
+
+ unless $.isNumeric(total)
+ total = ''
+
+ $('#received').hide()
+ $('#payment').fadeIn('slow')
+
+ $('.tip').html((subtotal - g.amount).toFixed(2))
+ $('.subtotal').html(subtotal.toString())
+ $('.amount').html(g.amount)
+ $('.exchange').html(g.exchange)
+ $('.symbol').html(g.user.symbol)
+
+ if g.user.commission < 0
+ $('.commission').html("+#{Math.abs(g.user.commission)}%")
+
+
+ $('#total').html(total.toString())
+
+ size = 300
+ $('#qr').css('height', size)
+
+ time = 0
+ if g.timeout
+ time = 10
+
+ clearTimeout(g.timeout)
+ g.timeout = setTimeout(->
+ $('#qr').html('')
+ new QRCode('qr',
+ text: "bitcoin:#{g.user.address}?amount=#{g.amount_requested.toString()}"
+ width: size
+ height: size
+ )
+ , time)
+
+listen = ->
+ g.attempts++
+ if g.blockchain and g.blockchain.readyState is 1
+ setTimeout(listen, 12000)
+ else
+ fail(SOCKET_FAIL) if g.attempts > 3
+ g.blockchain = new WebSocket(API_URL)
+
+ g.blockchain.onopen = ->
+ if g.blockchain.readyState is 1
+ g.attempts = 0
+ clear(SOCKET_FAIL)
+ g.blockchain.send('{"event":"unconfirmed-tx", "address":"' + g.user.address + '"}')
+ else
+ setTimeout(g.blockchain.onopen, 12000 * g.attempts)
+
+ g.blockchain.onerror = ->
+ fail(SOCKET_FAIL)
+ g.blockchain.close()
+ delete g.blockchain
+ listen()
+
+ g.blockchain.onclose = ->
+ delete g.blockchain
+ listen()
+
+ g.blockchain.onmessage = (e) ->
+ tx = JSON.parse(e.data)
+ amount = 0
+
+ return if tx.hash == g.last_seen
+ g.last_seen = tx.hash
+
+ for output in tx.outputs
+ if (output.addresses[0] == g.user.address)
+ amount += output.value / 100000000
+
+ logTransaction(tx.hash, amount)
+
+logTransaction = (txid, amount) ->
+ if $('#received').is(":hidden") and amount >= g.amount_requested
+ $('#payment').hide()
+ $('#received').fadeIn('slow')
+ $('#success')[0].play()
+ g.user.index++
+
+ if g.transactions.indexOf(txid) is -1
+ g.transactions.push(txid)
+ $.post("/#{g.user.username}/transactions",
+ txid: txid,
+ address: g.user.address,
+ date: moment().format("YYYY-MM-DD HH:mm:ss"),
+ received: amount,
+ exchange: g.exchange
+ tip: g.tip
+ )
+
+ getAddress()
+
+getAddress = ->
+ try
+ bitcoin.address.fromBase58Check(g.user.pubkey)
+ g.user.address = g.user.pubkey
+ catch
+ master = bitcoin.HDNode.fromBase58(g.user.pubkey)
+ child = master.derive(0).derive(g.user.index)
+ g.user.address = child.getAddress().toString()
+ g.blockchain.close() if g.blockchain
+ listen()
+
+ $('#address').html("<a href='https://blockchain.info/address/#{g.user.address}'>#{g.user.address}</a>")
+
+fail = (msg) ->
+ g.errors.push(msg)
+ g.errors = g.errors.uniq()
+ $('#error').show().html(g.errors.toString())
+
+clear = (msg) ->
+ i = g.errors.indexOf(msg)
+ g.errors.splice(i, 1) if i >= 0
+ if (g.errors.length > 0)
+ $('#error').show().html(g.errors.toString())
+ else
+ $('#error').hide()
+ $('#calculator').fadeIn('slow')
+
+Array::uniq = ->
+ output = {}
+ output[@[key]] = @[key] for key in [0...@length]
+ value for key, value of output
+
+multiplier = ->
+ switch g.user.unit
+ when 'BTC' then 1
+ when 'mBTC' then 1000
+ when 'µBTC' then 1000000
+ when 'bits' then 1000000
+ when 'satoshis' then 100000000
+
+