fixup: ui

This commit is contained in:
Arc 2025-12-24 05:32:27 +00:00
parent 053dcd1785
commit a2931d675a
4 changed files with 210 additions and 251 deletions

View file

@ -74,6 +74,9 @@ window.app.component('stall-list', {
}
},
methods: {
emitStallCount: function () {
this.$emit('stalls-updated', this.stalls.length)
},
sendStallFormData: async function () {
const stallData = {
name: this.stallDialog.data.name,
@ -101,6 +104,7 @@ window.app.component('stall-list', {
)
this.stallDialog.show = false
this.stalls.unshift(data)
this.emitStallCount()
this.$q.notify({
type: 'positive',
message: 'Stall created!'
@ -120,6 +124,7 @@ window.app.component('stall-list', {
)
this.stallDialog.show = false
this.stalls.unshift(data)
this.emitStallCount()
this.$q.notify({
type: 'positive',
message: 'Stall restored!'
@ -151,6 +156,7 @@ window.app.component('stall-list', {
if (index !== -1) {
this.stalls.splice(index, 1, data)
}
this.emitStallCount()
this.$q.notify({
type: 'positive',
message: 'Stall updated!'
@ -168,6 +174,7 @@ window.app.component('stall-list', {
)
this.stalls = this.stalls.filter(s => s.id !== stall.id)
this.pendingStalls = this.pendingStalls.filter(s => s.id !== stall.id)
this.emitStallCount()
this.$q.notify({
type: 'positive',
message: 'Stall deleted'
@ -291,6 +298,7 @@ window.app.component('stall-list', {
},
created: async function () {
this.stalls = await this.getStalls()
this.emitStallCount()
this.currencies = this.getCurrencies()
this.zoneOptions = await this.getZones()
}

View file

@ -12,6 +12,7 @@ window.app = Vue.createApp({
activeChatCustomer: '',
orderPubkey: null,
showKeys: false,
stallCount: 0,
importKeyDialog: {
show: false,
data: {
@ -114,6 +115,7 @@ window.app = Vue.createApp({
this.shippingZones = []
this.activeChatCustomer = ''
this.showKeys = false
this.stallCount = 0
},
createMerchant: async function (privateKey) {
try {
@ -378,7 +380,6 @@ window.app = Vue.createApp({
},
goToOrders: function (stallId) {
this.selectedStallFilter = stallId
this.activeTab = 'orders'
}
},
created: async function () {

View file

@ -28,19 +28,6 @@
></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">
@ -65,40 +52,5 @@
</div>
</div>
</div>
<div class="col-12 col-md-4">
<q-card flat bordered>
<q-card-section>
<h6 class="text-subtitle1 q-my-none">Nostr Market Extension</h6>
</q-card-section>
<q-card-section class="q-pa-none">
<q-separator></q-separator>
<q-list>
<q-expansion-item group="api" dense icon="info" label="About">
<q-card>
<q-card-section>
A decentralized marketplace powered by Nostr and Lightning
Network. Create stalls, add products, and start selling with
Bitcoin.
</q-card-section>
</q-card>
</q-expansion-item>
<q-expansion-item
group="api"
dense
icon="link"
label="Market Client"
>
<q-card>
<q-card-section>
<a :href="marketClientUrl" target="_blank"
>Open Market Client</a
>
</q-card-section>
</q-card>
</q-expansion-item>
</q-list>
</q-card-section>
</q-card>
</div>
</div>
</div>

View file

@ -1,7 +1,7 @@
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
%} {% block page %}
<div class="row q-col-gutter-md">
<div class="col-12">
<div class="col-12 col-md-7 q-gutter-y-md">
<div v-if="merchant && merchant.id">
<q-card>
<div class="row items-center no-wrap">
@ -36,25 +36,215 @@
icon="inventory_2"
style="min-width: 120px"
></q-tab>
<q-tab
name="messages"
label="Messages"
icon="chat"
style="min-width: 120px"
></q-tab>
<q-tab
name="orders"
label="Orders"
icon="receipt"
style="min-width: 120px"
></q-tab>
</q-tabs>
<div class="col-auto q-mr-md">
</div>
<q-separator></q-separator>
<q-tab-panels v-model="activeTab" animated>
<!-- Merchant Tab -->
<q-tab-panel name="merchant">
<merchant-tab
:merchant-id="merchant.id"
:inkey="g.user.wallets[0].inkey"
:adminkey="g.user.wallets[0].adminkey"
:show-keys="showKeys"
:merchant-active="merchant.config.active"
:public-key="merchant.public_key"
:private-key="merchant.private_key"
:is-admin="g.user.admin"
@toggle-show-keys="toggleShowKeys"
@hide-keys="showKeys = false"
@merchant-deleted="handleMerchantDeleted"
@toggle-merchant-state="toggleMerchantState"
@restart-nostr-connection="restartNostrConnection"
></merchant-tab>
</q-tab-panel>
<!-- Shipping Tab -->
<q-tab-panel name="shipping">
<shipping-zones-list
:inkey="g.user.wallets[0].inkey"
:adminkey="g.user.wallets[0].adminkey"
></shipping-zones-list>
</q-tab-panel>
<!-- Stalls Tab -->
<q-tab-panel name="stalls">
<stall-list
:adminkey="g.user.wallets[0].adminkey"
:inkey="g.user.wallets[0].inkey"
:wallet-options="g.user.walletOptions"
@customer-selected-for-order="customerSelectedForOrder"
@go-to-products="goToProducts"
@go-to-orders="goToOrders"
@stalls-updated="stallCount = $event"
></stall-list>
</q-tab-panel>
<!-- Products Tab -->
<q-tab-panel name="products">
<product-list
:adminkey="g.user.wallets[0].adminkey"
:inkey="g.user.wallets[0].inkey"
:stall-filter="selectedStallFilter"
@clear-filter="selectedStallFilter = null"
></product-list>
</q-tab-panel>
<!-- Messages Tab -->
</q-tab-panels>
</q-card>
<q-card class="q-mt-md">
<q-card-section>
<div class="text-h6">Orders</div>
</q-card-section>
<q-separator></q-separator>
<q-card-section class="q-pt-none">
<order-list
ref="orderListRef"
:adminkey="g.user.wallets[0].adminkey"
:inkey="g.user.wallets[0].inkey"
:customer-pubkey-filter="orderPubkey"
@customer-selected="customerSelectedForOrder"
></order-list>
</q-card-section>
</q-card>
</div>
<q-card v-else>
<q-card-section>
<span class="text-h4">Welcome to Nostr Market!</span><br />
In Nostr Market, merchant and customer communicate via NOSTR relays, so
loss of money, product information, and reputation become far less
likely if attacked.
</q-card-section>
<q-card-section>
<span class="text-h4">Terms</span><br />
<ul>
<li>
<span class="text-bold">merchant</span> - seller of products with
NOSTR key-pair
</li>
<li>
<span class="text-bold">customer</span> - buyer of products with
NOSTR key-pair
</li>
<li>
<span class="text-bold">product</span> - item for sale by the
merchant
</li>
<li>
<span class="text-bold">stall</span> - list of products controlled
by merchant (a merchant can have multiple stalls)
</li>
<li>
<span class="text-bold">marketplace</span> - clientside software for
searching stalls and purchasing products
</li>
</ul>
</q-card-section>
<q-card-section>
<div class="row">
<div class="col-12">
<q-btn
@click="showImportKeysDialog"
label="Import Key"
color="primary"
class="float-left"
>
<q-tooltip> Use an existing private key (hex or npub) </q-tooltip>
</q-btn>
<q-btn
label="Generate New Key"
color="green"
@click="generateKeys"
class="float-right"
>
<q-tooltip> A new key pair will be generated for you </q-tooltip>
</q-btn>
</div>
</div>
</q-card-section>
</q-card>
</div>
<div class="col-12 col-md-5 q-gutter-y-md">
<div v-if="g.user.admin" class="col-12 q-mb-lg">
<q-card>
<q-card-section class="q-pa-md">
<div class="row items-center no-wrap q-col-gutter-sm">
<div class="col">
<q-btn-dropdown
:color="nostrStatusColor"
:label="nostrStatusLabel"
icon="sync"
split
@click="restartNostrConnection"
>
<q-list>
<q-item clickable v-close-popup @click="restartNostrConnection">
<q-item-section avatar>
<q-icon name="refresh" color="primary"></q-icon>
</q-item-section>
<q-item-section>
<q-item-label>Restart Connection</q-item-label>
<q-item-label caption>
Reconnect to the nostrclient extension
</q-item-label>
</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="checkNostrStatus(true)">
<q-item-section avatar>
<q-icon name="wifi_find" color="primary"></q-icon>
</q-item-section>
<q-item-section>
<q-item-label>Check Status</q-item-label>
<q-item-label caption>
Check connection to nostrclient
</q-item-label>
</q-item-section>
</q-item>
<q-separator></q-separator>
<q-item>
<q-item-section>
<q-item-label caption>
<strong>Status:</strong>
<q-badge
:color="nostrStatus.connected ? 'green' : 'red'"
class="q-ml-xs"
v-text="nostrStatus.connected ? 'Connected' : 'Disconnected'"
></q-badge>
</q-item-label>
<q-item-label
v-if="nostrStatus.relays_total > 0"
caption
class="q-mt-xs"
>
<strong>Relays:</strong>&nbsp;
<span v-text="nostrStatus.relays_connected"></span>
of
<span v-text="nostrStatus.relays_total"></span>
connected
</q-item-label>
<q-item-label
v-if="nostrStatus.error"
caption
class="text-negative q-mt-xs"
v-text="nostrStatus.error"
></q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div>
<div class="col-auto">
<div class="inline-block">
<q-btn-dropdown
color="primary"
label="Publish"
icon="publish"
unelevated
:disable="stallCount === 0"
>
<q-list>
<q-item clickable v-close-popup @click="publishNip15">
@ -135,216 +325,23 @@
</q-item>
</q-list>
</q-btn-dropdown>
<q-tooltip v-if="stallCount === 0">
First create a stall and add products.
</q-tooltip>
</div>
</div>
<q-separator></q-separator>
<q-tab-panels v-model="activeTab" animated>
<!-- Merchant Tab -->
<q-tab-panel name="merchant">
<merchant-tab
:merchant-id="merchant.id"
:inkey="g.user.wallets[0].inkey"
:adminkey="g.user.wallets[0].adminkey"
:show-keys="showKeys"
:merchant-active="merchant.config.active"
:public-key="merchant.public_key"
:private-key="merchant.private_key"
:is-admin="g.user.admin"
@toggle-show-keys="toggleShowKeys"
@hide-keys="showKeys = false"
@merchant-deleted="handleMerchantDeleted"
@toggle-merchant-state="toggleMerchantState"
@restart-nostr-connection="restartNostrConnection"
></merchant-tab>
</q-tab-panel>
<!-- Shipping Tab -->
<q-tab-panel name="shipping">
<shipping-zones-list
:inkey="g.user.wallets[0].inkey"
:adminkey="g.user.wallets[0].adminkey"
></shipping-zones-list>
</q-tab-panel>
<!-- Stalls Tab -->
<q-tab-panel name="stalls">
<stall-list
:adminkey="g.user.wallets[0].adminkey"
:inkey="g.user.wallets[0].inkey"
:wallet-options="g.user.walletOptions"
@customer-selected-for-order="customerSelectedForOrder"
@go-to-products="goToProducts"
@go-to-orders="goToOrders"
></stall-list>
</q-tab-panel>
<!-- Products Tab -->
<q-tab-panel name="products">
<product-list
:adminkey="g.user.wallets[0].adminkey"
:inkey="g.user.wallets[0].inkey"
:stall-filter="selectedStallFilter"
@clear-filter="selectedStallFilter = null"
></product-list>
</q-tab-panel>
<!-- Messages Tab -->
<q-tab-panel name="messages">
<direct-messages
ref="directMessagesRef"
:inkey="g.user.wallets[0].inkey"
:adminkey="g.user.wallets[0].adminkey"
:active-chat-customer="activeChatCustomer"
:merchant-id="merchant.id"
@customer-selected="filterOrdersForCustomer"
@order-selected="showOrderDetails"
>
</direct-messages>
</q-tab-panel>
<!-- Orders Tab -->
<q-tab-panel name="orders">
<order-list
ref="orderListRef"
:adminkey="g.user.wallets[0].adminkey"
:inkey="g.user.wallets[0].inkey"
:customer-pubkey-filter="orderPubkey"
@customer-selected="customerSelectedForOrder"
></order-list>
</q-tab-panel>
</q-tab-panels>
</q-card>
</div>
<q-card v-else>
<q-card-section>
<span class="text-h4">Welcome to Nostr Market!</span><br />
In Nostr Market, merchant and customer communicate via NOSTR relays, so
loss of money, product information, and reputation become far less
likely if attacked.
</q-card-section>
<q-card-section>
<span class="text-h4">Terms</span><br />
<ul>
<li>
<span class="text-bold">merchant</span> - seller of products with
NOSTR key-pair
</li>
<li>
<span class="text-bold">customer</span> - buyer of products with
NOSTR key-pair
</li>
<li>
<span class="text-bold">product</span> - item for sale by the
merchant
</li>
<li>
<span class="text-bold">stall</span> - list of products controlled
by merchant (a merchant can have multiple stalls)
</li>
<li>
<span class="text-bold">marketplace</span> - clientside software for
searching stalls and purchasing products
</li>
</ul>
</q-card-section>
<q-card-section>
<div class="row">
<div class="col-12">
<q-btn
@click="showImportKeysDialog"
label="Import Key"
color="primary"
class="float-left"
>
<q-tooltip> Use an existing private key (hex or npub) </q-tooltip>
</q-btn>
<q-btn
label="Generate New Key"
color="green"
@click="generateKeys"
class="float-right"
>
<q-tooltip> A new key pair will be generated for you </q-tooltip>
</q-btn>
</div>
</div>
</q-card-section>
</q-card>
</div>
<div class="col-12 col-md-5 q-gutter-y-md">
<div v-if="g.user.admin" class="col-12 q-mb-lg">
<q-card>
<q-card-section class="q-pa-md">
<q-btn-dropdown
:color="nostrStatusColor"
:label="nostrStatusLabel"
icon="sync"
split
@click="restartNostrConnection"
>
<q-list>
<q-item clickable v-close-popup @click="restartNostrConnection">
<q-item-section avatar>
<q-icon name="refresh" color="primary"></q-icon>
</q-item-section>
<q-item-section>
<q-item-label>Restart Connection</q-item-label>
<q-item-label caption>
Reconnect to the nostrclient extension
</q-item-label>
</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="checkNostrStatus(true)">
<q-item-section avatar>
<q-icon name="wifi_find" color="primary"></q-icon>
</q-item-section>
<q-item-section>
<q-item-label>Check Status</q-item-label>
<q-item-label caption>
Check connection to nostrclient
</q-item-label>
</q-item-section>
</q-item>
<q-separator></q-separator>
<q-item>
<q-item-section>
<q-item-label caption>
<strong>Status:</strong>
<q-badge
:color="nostrStatus.connected ? 'green' : 'red'"
class="q-ml-xs"
v-text="nostrStatus.connected ? 'Connected' : 'Disconnected'"
></q-badge>
</q-item-label>
<q-item-label
v-if="nostrStatus.relays_total > 0"
caption
class="q-mt-xs"
>
<strong>Relays:</strong>&nbsp;
<span v-text="nostrStatus.relays_connected"></span>
of
<span v-text="nostrStatus.relays_total"></span>
connected
</q-item-label>
<q-item-label
v-if="nostrStatus.error"
caption
class="text-negative q-mt-xs"
v-text="nostrStatus.error"
></q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</q-card-section>
</q-card>
</div>
<div class="col-12">
<q-card>
<q-expansion-item
icon="info"
label="Details"
header-class="text-grey"
expand-separator
>
<q-img
src="/nostrmarket/static/market/images/nostr-cover.png"
:ratio="3"
@ -362,6 +359,7 @@
<q-card-section class="q-pa-none">
<q-list> {% include "nostrmarket/_api_docs.html" %} </q-list>
</q-card-section>
</q-expansion-item>
</q-card>
</div>
<div v-if="merchant && merchant.id" class="col-12">