Boltcard view page (#12)
This commit is contained in:
parent
f153c26517
commit
a823cf3e5d
4 changed files with 186 additions and 1 deletions
146
templates/boltcards/display.html
Normal file
146
templates/boltcards/display.html
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
{% extends "public.html" %} {% block toolbar_title %} Boltcard: ${
|
||||
card.card_name }{% endblock %} {% block page %}
|
||||
<div class="row q-col-gutter-md justify-center">
|
||||
<div class="col-12 col-md-6 col-lg-5 q-gutter-y-md">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<div class="text-h6">Card Info</div>
|
||||
<div class="text-subtitle2">This card is ${enabled}</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-separator dark inset></q-separator>
|
||||
|
||||
<q-card-section>
|
||||
<q-list>
|
||||
<q-item v-for="item in cardInfo">
|
||||
<q-item-section>
|
||||
<q-item-label lines="1">${item.label}</q-item-label>
|
||||
<q-item-label caption>${card[item.value]}</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section
|
||||
side
|
||||
v-if="!['tx_limit', 'daily_limit'].includes(item.value)"
|
||||
>
|
||||
<q-tooltip>Click to copy</q-tooltip>
|
||||
<q-btn
|
||||
flat
|
||||
round
|
||||
icon="content_copy"
|
||||
@click="copyText(item.value)"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-5 q-gutter-y-md">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<div class="text-h6">Transactions</div>
|
||||
<div class="text-subtitle2">Latest transactions</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-separator dark inset></q-separator>
|
||||
|
||||
<q-card-section>
|
||||
<q-list>
|
||||
<q-item v-for="hit in hits">
|
||||
<q-item-section avatar>
|
||||
<q-icon
|
||||
:name="hit.spent > 0 ? 'done_all' : 'done'"
|
||||
:color="hit.spent > 0 ? 'green' : 'grey'"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label
|
||||
>ID: ${hit.id} ${refunds.some(r => r.hit_id == hit.id) ?
|
||||
'(Refunded)' : null}</q-item-label
|
||||
>
|
||||
<q-item-label caption lines="1">IP: ${hit.ip}</q-item-label>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section side top>
|
||||
<q-item-label caption>${hit.date}</q-item-label>
|
||||
<q-item-label caption>${hit.amount} sats</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}{% block scripts %}
|
||||
<script>
|
||||
const mapHits = obj => {
|
||||
obj.date = Quasar.utils.date.formatDate(
|
||||
new Date(obj.time * 1000),
|
||||
'YYYY-MM-DD HH:mm'
|
||||
)
|
||||
|
||||
return obj
|
||||
}
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
new Vue({
|
||||
el: '#vue',
|
||||
delimiters: ['${', '}'],
|
||||
mixins: [windowMixin],
|
||||
data: function () {
|
||||
return {
|
||||
card: null,
|
||||
hits: null,
|
||||
cardInfo: [
|
||||
{
|
||||
label: 'Card UID',
|
||||
value: 'uid'
|
||||
},
|
||||
{
|
||||
label: 'Auth Key',
|
||||
value: 'k0'
|
||||
},
|
||||
{
|
||||
label: 'Meta Key',
|
||||
value: 'k1'
|
||||
},
|
||||
{
|
||||
label: 'File Key',
|
||||
value: 'k2'
|
||||
},
|
||||
{
|
||||
label: 'Transaction Limit',
|
||||
value: 'tx_limit'
|
||||
},
|
||||
{
|
||||
label: 'Daily Limit',
|
||||
value: 'daily_limit'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.card = JSON.parse('{{ card | tojson}}')
|
||||
let hits = JSON.parse('{{ hits | tojson}}')
|
||||
let refunds = JSON.parse('{{ refunds | tojson}}')
|
||||
this.refunds = refunds || []
|
||||
this.hits = hits.map(mapHits)
|
||||
},
|
||||
computed: {
|
||||
enabled() {
|
||||
return this.card.enable ? 'Enabled' : 'Disabled'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
copyText(text, message, position) {
|
||||
Quasar.utils.copyToClipboard(text).then(() => {
|
||||
this.$q.notify({
|
||||
message: message || 'Copied to clipboard!',
|
||||
position: position || 'bottom'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -42,6 +42,7 @@
|
|||
{% raw %}
|
||||
<template v-slot:header="props">
|
||||
<q-tr :props="props">
|
||||
<q-th auto-width></q-th>
|
||||
<q-th auto-width></q-th>
|
||||
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
||||
{{ col.label }}
|
||||
|
|
@ -64,6 +65,19 @@
|
|||
<q-tooltip>Card key credentials</q-tooltip>
|
||||
</q-btn>
|
||||
</q-td>
|
||||
<q-td auto-width>
|
||||
<q-btn
|
||||
unelevated
|
||||
dense
|
||||
icon="query_stats"
|
||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||
type="a"
|
||||
:href="'/boltcards/' + props.row.external_id"
|
||||
target="_blank"
|
||||
>
|
||||
<q-tooltip>Card Stats</q-tooltip>
|
||||
</q-btn>
|
||||
</q-td>
|
||||
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||
{{ col.value }}
|
||||
</q-td>
|
||||
|
|
|
|||
25
views.py
25
views.py
|
|
@ -1,11 +1,15 @@
|
|||
from http import HTTPStatus
|
||||
|
||||
from fastapi import Depends, Request
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from starlette.exceptions import HTTPException
|
||||
from starlette.responses import HTMLResponse
|
||||
|
||||
from lnbits.core.models import User
|
||||
from lnbits.decorators import check_user_exists
|
||||
|
||||
from . import boltcards_ext, boltcards_renderer
|
||||
from .crud import get_card_by_external_id, get_hits, get_refunds
|
||||
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
|
|
@ -15,3 +19,24 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
|
|||
return boltcards_renderer().TemplateResponse(
|
||||
"boltcards/index.html", {"request": request, "user": user.dict()}
|
||||
)
|
||||
|
||||
|
||||
@boltcards_ext.get("/{card_id}", response_class=HTMLResponse)
|
||||
async def display(request: Request, card_id: str):
|
||||
card = await get_card_by_external_id(card_id)
|
||||
if not card:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Card does not exist."
|
||||
)
|
||||
hits = [hit.dict() for hit in await get_hits([card.id])]
|
||||
refunds = [
|
||||
refund.hit_id for refund in await get_refunds([hit["id"] for hit in hits])
|
||||
]
|
||||
card = card.dict()
|
||||
# Remove wallet id from card dict
|
||||
del card["wallet"]
|
||||
|
||||
return boltcards_renderer().TemplateResponse(
|
||||
"boltcards/display.html",
|
||||
{"request": request, "card": card, "hits": hits, "refunds": refunds},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ from .models import Card, CreateCardData
|
|||
|
||||
@boltcards_ext.get("/api/v1/cards")
|
||||
async def api_cards(
|
||||
g: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)
|
||||
g: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = False
|
||||
):
|
||||
wallet_ids = [g.wallet.id]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue