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):
|
class MerchantProfile(BaseModel):
|
||||||
name: str | None = None
|
name: str | None = None
|
||||||
|
display_name: str | None = None
|
||||||
about: str | None = None
|
about: str | None = None
|
||||||
picture: str | None = None
|
picture: str | None = None
|
||||||
|
banner: str | None = None
|
||||||
|
nip05: str | None = None
|
||||||
|
lud16: str | None = None
|
||||||
|
|
||||||
|
|
||||||
class MerchantConfig(MerchantProfile):
|
class MerchantConfig(MerchantProfile):
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,10 @@ window.app.component('key-pair', {
|
||||||
name: 'key-pair',
|
name: 'key-pair',
|
||||||
template: '#key-pair',
|
template: '#key-pair',
|
||||||
delimiters: ['${', '}'],
|
delimiters: ['${', '}'],
|
||||||
props: ['public-key', 'private-key'],
|
props: ['public-key', 'private-key', 'merchant-config'],
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
showPrivateKey: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
copyText: function (text, message, position) {
|
handleImageError: function (event) {
|
||||||
var notify = this.$q.notify
|
event.target.style.display = 'none'
|
||||||
Quasar.copyToClipboard(text).then(function () {
|
|
||||||
notify({
|
|
||||||
message: message || 'Copied to clipboard!',
|
|
||||||
position: position || 'bottom'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ window.app.component('merchant-tab', {
|
||||||
'merchant-active',
|
'merchant-active',
|
||||||
'public-key',
|
'public-key',
|
||||||
'private-key',
|
'private-key',
|
||||||
'is-admin'
|
'is-admin',
|
||||||
|
'merchant-config'
|
||||||
],
|
],
|
||||||
computed: {
|
computed: {
|
||||||
marketClientUrl: function () {
|
marketClientUrl: function () {
|
||||||
|
|
|
||||||
|
|
@ -1,93 +1,82 @@
|
||||||
<div>
|
<q-card v-if="publicKey" flat bordered>
|
||||||
<q-separator></q-separator>
|
<!-- Banner Section -->
|
||||||
|
|
||||||
<!-- 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>
|
|
||||||
<div
|
<div
|
||||||
class="cursor-pointer q-mx-auto"
|
v-if="merchantConfig && merchantConfig.banner"
|
||||||
style="max-width: 200px"
|
class="banner-container"
|
||||||
@click="copyText(publicKey)"
|
:style="{
|
||||||
>
|
height: '120px',
|
||||||
<q-responsive :ratio="1">
|
backgroundSize: 'cover',
|
||||||
<lnbits-qrcode
|
backgroundPosition: 'center',
|
||||||
:value="publicKey"
|
borderRadius: '4px 4px 0 0',
|
||||||
:options="{width: 200}"
|
backgroundImage: 'url(' + merchantConfig.banner + ')'
|
||||||
:show-buttons="false"
|
}"
|
||||||
class="rounded-borders"
|
></div>
|
||||||
></lnbits-qrcode>
|
<div
|
||||||
</q-responsive>
|
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>
|
||||||
<div class="q-mt-md text-caption text-mono" style="padding: 0 16px">
|
|
||||||
<span v-text="publicKey.substring(0, 8)"></span>...<span
|
<!-- Name, About and NIP-05 -->
|
||||||
v-text="publicKey.substring(publicKey.length - 8)"
|
<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>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
<q-btn
|
<div class="text-caption text-grey" v-else>(No name set)</div>
|
||||||
flat
|
|
||||||
dense
|
|
||||||
size="sm"
|
|
||||||
icon="content_copy"
|
|
||||||
label="Click to copy"
|
|
||||||
@click="copyText(publicKey)"
|
|
||||||
class="q-mt-xs"
|
|
||||||
/>
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</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>
|
||||||
<div
|
<div
|
||||||
class="cursor-pointer q-mx-auto"
|
class="text-body2 text-grey q-mt-xs"
|
||||||
style="max-width: 200px"
|
v-if="merchantConfig && merchantConfig.about"
|
||||||
@click="copyText(privateKey)"
|
style="max-width: 400px"
|
||||||
>
|
>
|
||||||
<q-responsive :ratio="1">
|
<span v-text="merchantConfig.about"></span>
|
||||||
<lnbits-qrcode
|
</div>
|
||||||
:value="privateKey"
|
<div class="row q-mt-xs q-gutter-sm">
|
||||||
:options="{width: 200}"
|
<div
|
||||||
:show-buttons="false"
|
class="text-caption text-grey-5"
|
||||||
class="rounded-borders"
|
v-if="merchantConfig && merchantConfig.nip05"
|
||||||
></lnbits-qrcode>
|
>
|
||||||
</q-responsive>
|
<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>
|
||||||
<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>
|
</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-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
|
||||||
|
|
@ -1,70 +1,12 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="row q-col-gutter-md">
|
<div class="row q-col-gutter-md">
|
||||||
<div class="col-12 col-md-8">
|
<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
|
<key-pair
|
||||||
:public-key="publicKey"
|
:public-key="publicKey"
|
||||||
:private-key="privateKey"
|
:private-key="privateKey"
|
||||||
|
:merchant-config="merchantConfig"
|
||||||
></key-pair>
|
></key-pair>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-md-4">
|
<div class="col-12 col-md-4">
|
||||||
<q-card flat bordered>
|
<q-card flat bordered>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@
|
||||||
:public-key="merchant.public_key"
|
:public-key="merchant.public_key"
|
||||||
:private-key="merchant.private_key"
|
:private-key="merchant.private_key"
|
||||||
:is-admin="g.user.admin"
|
:is-admin="g.user.admin"
|
||||||
|
:merchant-config="merchant.config"
|
||||||
@toggle-show-keys="toggleShowKeys"
|
@toggle-show-keys="toggleShowKeys"
|
||||||
@hide-keys="showKeys = false"
|
@hide-keys="showKeys = false"
|
||||||
@merchant-deleted="handleMerchantDeleted"
|
@merchant-deleted="handleMerchantDeleted"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue