feat: add merchant profile panel to Merchant tab
Display merchant profile information with: - Banner image or grey placeholder - Profile avatar with shadow - Display name (or name fallback) - About description - NIP-05 verified identity indicator - Lightning address (LUD16) Extends MerchantProfile model with new fields: display_name, banner, nip05, lud16 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
053dcd1785
commit
c3dea9f01d
6 changed files with 89 additions and 163 deletions
|
|
@ -33,8 +33,12 @@ class Nostrable:
|
|||
|
||||
class MerchantProfile(BaseModel):
|
||||
name: str | None = None
|
||||
display_name: str | None = None
|
||||
about: str | None = None
|
||||
picture: str | None = None
|
||||
banner: str | None = None
|
||||
nip05: str | None = None
|
||||
lud16: str | None = None
|
||||
|
||||
|
||||
class MerchantConfig(MerchantProfile):
|
||||
|
|
|
|||
|
|
@ -2,21 +2,10 @@ window.app.component('key-pair', {
|
|||
name: 'key-pair',
|
||||
template: '#key-pair',
|
||||
delimiters: ['${', '}'],
|
||||
props: ['public-key', 'private-key'],
|
||||
data: function () {
|
||||
return {
|
||||
showPrivateKey: false
|
||||
}
|
||||
},
|
||||
props: ['public-key', 'private-key', 'merchant-config'],
|
||||
methods: {
|
||||
copyText: function (text, message, position) {
|
||||
var notify = this.$q.notify
|
||||
Quasar.copyToClipboard(text).then(function () {
|
||||
notify({
|
||||
message: message || 'Copied to clipboard!',
|
||||
position: position || 'bottom'
|
||||
})
|
||||
})
|
||||
handleImageError: function (event) {
|
||||
event.target.style.display = 'none'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ window.app.component('merchant-tab', {
|
|||
'merchant-active',
|
||||
'public-key',
|
||||
'private-key',
|
||||
'is-admin'
|
||||
'is-admin',
|
||||
'merchant-config'
|
||||
],
|
||||
computed: {
|
||||
marketClientUrl: function () {
|
||||
|
|
|
|||
|
|
@ -1,93 +1,82 @@
|
|||
<div>
|
||||
<q-separator></q-separator>
|
||||
|
||||
<!-- Header with toggle -->
|
||||
<div class="row items-center justify-between q-mt-md q-px-md">
|
||||
<div class="text-subtitle2">Keys</div>
|
||||
<q-toggle
|
||||
v-model="showPrivateKey"
|
||||
color="primary"
|
||||
label="Show Private Key"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- QR Codes Container -->
|
||||
<div class="row q-col-gutter-md q-pa-md">
|
||||
<!-- Public Key QR -->
|
||||
<div class="col-12" :class="showPrivateKey ? 'col-sm-6' : ''">
|
||||
<q-card flat bordered>
|
||||
<q-card-section class="text-center">
|
||||
<div class="text-subtitle2 q-mb-sm">Public Key</div>
|
||||
<q-card v-if="publicKey" flat bordered>
|
||||
<!-- Banner Section -->
|
||||
<div
|
||||
class="cursor-pointer q-mx-auto"
|
||||
style="max-width: 200px"
|
||||
@click="copyText(publicKey)"
|
||||
>
|
||||
<q-responsive :ratio="1">
|
||||
<lnbits-qrcode
|
||||
:value="publicKey"
|
||||
:options="{width: 200}"
|
||||
:show-buttons="false"
|
||||
class="rounded-borders"
|
||||
></lnbits-qrcode>
|
||||
</q-responsive>
|
||||
v-if="merchantConfig && merchantConfig.banner"
|
||||
class="banner-container"
|
||||
:style="{
|
||||
height: '120px',
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
borderRadius: '4px 4px 0 0',
|
||||
backgroundImage: 'url(' + merchantConfig.banner + ')'
|
||||
}"
|
||||
></div>
|
||||
<div
|
||||
v-else
|
||||
class="banner-placeholder bg-grey-9"
|
||||
style="height: 120px; border-radius: 4px 4px 0 0"
|
||||
></div>
|
||||
|
||||
<!-- Profile Section -->
|
||||
<q-card-section class="q-pt-none" style="margin-top: -50px">
|
||||
<div class="row">
|
||||
<!-- Profile Image -->
|
||||
<div class="col-auto">
|
||||
<q-avatar size="100px" class="shadow-2">
|
||||
<img
|
||||
v-if="merchantConfig && merchantConfig.picture"
|
||||
:src="merchantConfig.picture"
|
||||
@error="handleImageError"
|
||||
/>
|
||||
<q-icon
|
||||
v-else
|
||||
name="person"
|
||||
size="60px"
|
||||
color="grey-5"
|
||||
style="background: var(--q-dark); border-radius: 50%"
|
||||
/>
|
||||
</q-avatar>
|
||||
</div>
|
||||
<div class="q-mt-md text-caption text-mono" style="padding: 0 16px">
|
||||
<span v-text="publicKey.substring(0, 8)"></span>...<span
|
||||
v-text="publicKey.substring(publicKey.length - 8)"
|
||||
|
||||
<!-- Name, About and NIP-05 -->
|
||||
<div class="col q-pl-md" style="padding-top: 50px">
|
||||
<div class="row items-center">
|
||||
<div class="col">
|
||||
<div
|
||||
class="text-h6"
|
||||
v-if="merchantConfig && (merchantConfig.display_name || merchantConfig.name)"
|
||||
>
|
||||
<span
|
||||
v-text="merchantConfig.display_name || merchantConfig.name"
|
||||
></span>
|
||||
</div>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="content_copy"
|
||||
label="Click to copy"
|
||||
@click="copyText(publicKey)"
|
||||
class="q-mt-xs"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
<div class="text-caption text-grey" v-else>(No name set)</div>
|
||||
</div>
|
||||
|
||||
<!-- Private Key QR (conditional) -->
|
||||
<div v-if="showPrivateKey" class="col-12 col-sm-6">
|
||||
<q-card flat bordered>
|
||||
<q-card-section class="text-center">
|
||||
<div class="text-subtitle2 q-mb-sm text-warning">
|
||||
<q-icon name="warning"></q-icon>
|
||||
Private Key (Keep Secret!)
|
||||
</div>
|
||||
<div
|
||||
class="cursor-pointer q-mx-auto"
|
||||
style="max-width: 200px"
|
||||
@click="copyText(privateKey)"
|
||||
class="text-body2 text-grey q-mt-xs"
|
||||
v-if="merchantConfig && merchantConfig.about"
|
||||
style="max-width: 400px"
|
||||
>
|
||||
<q-responsive :ratio="1">
|
||||
<lnbits-qrcode
|
||||
:value="privateKey"
|
||||
:options="{width: 200}"
|
||||
:show-buttons="false"
|
||||
class="rounded-borders"
|
||||
></lnbits-qrcode>
|
||||
</q-responsive>
|
||||
<span v-text="merchantConfig.about"></span>
|
||||
</div>
|
||||
<div class="row q-mt-xs q-gutter-sm">
|
||||
<div
|
||||
class="text-caption text-grey-5"
|
||||
v-if="merchantConfig && merchantConfig.nip05"
|
||||
>
|
||||
<q-icon name="verified" color="primary" size="14px"></q-icon>
|
||||
<span v-text="merchantConfig.nip05" class="q-ml-xs"></span>
|
||||
</div>
|
||||
<div
|
||||
class="text-caption text-grey-5"
|
||||
v-if="merchantConfig && merchantConfig.lud16"
|
||||
>
|
||||
<q-icon name="bolt" color="warning" size="14px"></q-icon>
|
||||
<span v-text="merchantConfig.lud16" class="q-ml-xs"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="q-mt-md text-caption text-mono" style="padding: 0 16px">
|
||||
<span v-text="privateKey.substring(0, 8)"></span>...<span
|
||||
v-text="privateKey.substring(privateKey.length - 8)"
|
||||
></span>
|
||||
</div>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="content_copy"
|
||||
label="Click to copy"
|
||||
@click="copyText(privateKey)"
|
||||
class="q-mt-xs"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-card>
|
||||
|
|
|
|||
|
|
@ -1,70 +1,12 @@
|
|||
<div>
|
||||
<div class="row q-col-gutter-md">
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="row items-center q-col-gutter-sm q-mb-md">
|
||||
<div class="col-12 col-sm-auto">
|
||||
<merchant-details
|
||||
:merchant-id="merchantId"
|
||||
:inkey="inkey"
|
||||
:adminkey="adminkey"
|
||||
:show-keys="showKeys"
|
||||
@toggle-show-keys="toggleShowKeys"
|
||||
@merchant-deleted="handleMerchantDeleted"
|
||||
></merchant-details>
|
||||
</div>
|
||||
<div class="col-12 col-sm-auto q-mx-sm">
|
||||
<div class="row items-center no-wrap">
|
||||
<q-toggle
|
||||
:model-value="merchantActive"
|
||||
@update:model-value="toggleMerchantState()"
|
||||
size="md"
|
||||
checked-icon="check"
|
||||
color="primary"
|
||||
unchecked-icon="clear"
|
||||
/>
|
||||
<span
|
||||
class="q-ml-sm"
|
||||
v-text="merchantActive ? 'Accepting Orders': 'Orders Paused'"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isAdmin" class="col-12 col-sm-auto q-ml-sm-auto">
|
||||
<q-btn
|
||||
label="Restart Nostr Connection"
|
||||
color="grey"
|
||||
outline
|
||||
size="sm"
|
||||
@click="restartNostrConnection"
|
||||
>
|
||||
<q-tooltip>
|
||||
Restart the connection to the nostrclient extension
|
||||
</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showKeys" class="q-mt-md">
|
||||
<div class="row q-mb-md">
|
||||
<div class="col">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="grey"
|
||||
outline
|
||||
@click="hideKeys"
|
||||
class="float-left"
|
||||
>Hide Keys</q-btn
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<key-pair
|
||||
:public-key="publicKey"
|
||||
:private-key="privateKey"
|
||||
:merchant-config="merchantConfig"
|
||||
></key-pair>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-card flat bordered>
|
||||
<q-card-section>
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@
|
|||
:public-key="merchant.public_key"
|
||||
:private-key="merchant.private_key"
|
||||
:is-admin="g.user.admin"
|
||||
:merchant-config="merchant.config"
|
||||
@toggle-show-keys="toggleShowKeys"
|
||||
@hide-keys="showKeys = false"
|
||||
@merchant-deleted="handleMerchantDeleted"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue