diff --git a/.env.example b/.env.example index ea5e8d1..0119d7e 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,6 @@ +# App Configuration +VITE_APP_NAME=MyApp + # Nostr Configuration VITE_NOSTR_RELAYS=["wss://relay.damus.io","wss://relay.snort.social"] VITE_ADMIN_PUBKEYS=["your-admin-pubkey-here"] @@ -5,6 +8,8 @@ VITE_ADMIN_PUBKEYS=["your-admin-pubkey-here"] # API Configuration VITE_LNBITS_BASE_URL=http://localhost:5000 VITE_API_KEY=your-api-key-here +VITE_LNBITS_DEBUG=false +VITE_WEBSOCKET_ENABLED=true # Lightning Address Domain (optional) # Override the domain used for Lightning Addresses @@ -17,13 +22,17 @@ VITE_VAPID_PUBLIC_KEY=your-vapid-public-key VITE_PUSH_NOTIFICATIONS_ENABLED=true # Support -VITE_SUPPORT_NPUB=your-support-npub +# OBSOLETE: Not used in codebase - config.support.npub is never consumed +# VITE_SUPPORT_NPUB=your-support-npub # Image Upload Configuration (pict-rs) VITE_PICTRS_BASE_URL=https://img.mydomain.com # Market Configuration VITE_MARKET_NADDR=naddr1qqjxgdp4vv6rydej943n2dny956rwwf4943xzwfc95ekyd3evenrsvrrvc6r2qf8waehxw309akxucnfw3ejuct5d96xcctw9e5k7tmwdaehgunjv4kxz7f0v96xjmczyqrfrfkxv3m8t4elpe28x065z30zszaaqa4u0744qcmadsz3y50cjqcyqqq82scmcafla -VITE_MARKET_RELAYS=["wss://relay.damus.io","wss://relay.snort.social","wss://nostr-pub.wellorder.net"] -VITE_LIGHTNING_ENABLED=true -VITE_MARKET_DEFAULT_CURRENCY=sat +# OBSOLETE: Not used in codebase - market uses VITE_NOSTR_RELAYS instead +# VITE_MARKET_RELAYS=["wss://relay.damus.io","wss://relay.snort.social","wss://nostr-pub.wellorder.net"] +# OBSOLETE: Not used in codebase - config.market.lightningEnabled is never consumed +# VITE_LIGHTNING_ENABLED=true +# OBSOLETE: Not used in codebase - config.market.defaultCurrency is never consumed +# VITE_MARKET_DEFAULT_CURRENCY=sat diff --git a/package-lock.json b/package-lock.json index aa24fb0..3486759 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "qr-scanner": "^1.4.2", "qrcode": "^1.5.4", "radix-vue": "^1.9.13", - "reka-ui": "^2.5.0", + "reka-ui": "^2.7.0", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "unique-names-generator": "^4.7.1", @@ -5850,14 +5850,6 @@ "node": ">= 0.4" } }, - "node_modules/async-validator": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", - "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -9763,13 +9755,13 @@ } }, "node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "dev": true, "license": "MIT", "dependencies": { - "jwa": "^2.0.0", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, @@ -12180,9 +12172,9 @@ } }, "node_modules/reka-ui": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.5.0.tgz", - "integrity": "sha512-81aMAmJeVCy2k0E6x7n1kypDY6aM1ldLis5+zcdV1/JtoAlSDck5OBsyLRJU9CfgbrQp1ImnRnBSmC4fZ2fkZQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.7.0.tgz", + "integrity": "sha512-m+XmxQN2xtFzBP3OAdIafKq7C8OETo2fqfxcIIxYmNN2Ch3r5oAf6yEYCIJg5tL/yJU2mHqF70dCCekUkrAnXA==", "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.6.13", @@ -13979,9 +13971,9 @@ } }, "node_modules/vite": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", - "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 304528e..00b5554 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "qr-scanner": "^1.4.2", "qrcode": "^1.5.4", "radix-vue": "^1.9.13", - "reka-ui": "^2.5.0", + "reka-ui": "^2.7.0", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "unique-names-generator": "^4.7.1", diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png index ba8df07..1f8c550 100644 Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ diff --git a/public/favicon.ico b/public/favicon.ico index 84495b0..9fef45b 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/icon-192.png b/public/icon-192.png index 17abda4..e77168a 100644 Binary files a/public/icon-192.png and b/public/icon-192.png differ diff --git a/public/icon-512.png b/public/icon-512.png index 3819dee..550b306 100644 Binary files a/public/icon-512.png and b/public/icon-512.png differ diff --git a/public/icon-maskable-192.png b/public/icon-maskable-192.png index b280cd5..0f2053d 100644 Binary files a/public/icon-maskable-192.png and b/public/icon-maskable-192.png differ diff --git a/public/icon-maskable-512.png b/public/icon-maskable-512.png index bdd4754..0926f7a 100644 Binary files a/public/icon-maskable-512.png and b/public/icon-maskable-512.png differ diff --git a/src/App.vue b/src/App.vue index 59e840b..559d0bf 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,35 +1,36 @@ + + diff --git a/src/components/layout/AppSidebar.vue b/src/components/layout/AppSidebar.vue new file mode 100644 index 0000000..7b5accf --- /dev/null +++ b/src/components/layout/AppSidebar.vue @@ -0,0 +1,149 @@ + + + diff --git a/src/components/layout/AppTopBar.vue b/src/components/layout/AppTopBar.vue new file mode 100644 index 0000000..eb1fe00 --- /dev/null +++ b/src/components/layout/AppTopBar.vue @@ -0,0 +1,242 @@ + + + diff --git a/src/components/layout/MobileDrawer.vue b/src/components/layout/MobileDrawer.vue new file mode 100644 index 0000000..98b0740 --- /dev/null +++ b/src/components/layout/MobileDrawer.vue @@ -0,0 +1,172 @@ + + + diff --git a/src/components/layout/Navbar.vue b/src/components/layout/Navbar.old.vue similarity index 97% rename from src/components/layout/Navbar.vue rename to src/components/layout/Navbar.old.vue index 07fbba1..6eb160f 100644 --- a/src/components/layout/Navbar.vue +++ b/src/components/layout/Navbar.old.vue @@ -1,3 +1,13 @@ + + + diff --git a/src/components/ui/sheet/SheetClose.vue b/src/components/ui/sheet/SheetClose.vue new file mode 100644 index 0000000..0295976 --- /dev/null +++ b/src/components/ui/sheet/SheetClose.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/components/ui/sheet/SheetContent.vue b/src/components/ui/sheet/SheetContent.vue new file mode 100644 index 0000000..50f3de6 --- /dev/null +++ b/src/components/ui/sheet/SheetContent.vue @@ -0,0 +1,53 @@ + + + diff --git a/src/components/ui/sheet/SheetDescription.vue b/src/components/ui/sheet/SheetDescription.vue new file mode 100644 index 0000000..455c2f4 --- /dev/null +++ b/src/components/ui/sheet/SheetDescription.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/components/ui/sheet/SheetFooter.vue b/src/components/ui/sheet/SheetFooter.vue new file mode 100644 index 0000000..5f481e5 --- /dev/null +++ b/src/components/ui/sheet/SheetFooter.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/components/ui/sheet/SheetHeader.vue b/src/components/ui/sheet/SheetHeader.vue new file mode 100644 index 0000000..f97d24a --- /dev/null +++ b/src/components/ui/sheet/SheetHeader.vue @@ -0,0 +1,16 @@ + + + diff --git a/src/components/ui/sheet/SheetTitle.vue b/src/components/ui/sheet/SheetTitle.vue new file mode 100644 index 0000000..5870787 --- /dev/null +++ b/src/components/ui/sheet/SheetTitle.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/components/ui/sheet/SheetTrigger.vue b/src/components/ui/sheet/SheetTrigger.vue new file mode 100644 index 0000000..a4fc3ee --- /dev/null +++ b/src/components/ui/sheet/SheetTrigger.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/components/ui/sheet/index.ts b/src/components/ui/sheet/index.ts new file mode 100644 index 0000000..a370633 --- /dev/null +++ b/src/components/ui/sheet/index.ts @@ -0,0 +1,32 @@ +import type { VariantProps } from "class-variance-authority" +import { cva } from "class-variance-authority" + +export { default as Sheet } from "./Sheet.vue" +export { default as SheetClose } from "./SheetClose.vue" +export { default as SheetContent } from "./SheetContent.vue" +export { default as SheetDescription } from "./SheetDescription.vue" +export { default as SheetFooter } from "./SheetFooter.vue" +export { default as SheetHeader } from "./SheetHeader.vue" +export { default as SheetTitle } from "./SheetTitle.vue" +export { default as SheetTrigger } from "./SheetTrigger.vue" + +export const sheetVariants = cva( + "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500", + { + variants: { + side: { + top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", + bottom: + "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", + left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", + right: + "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", + }, + }, + defaultVariants: { + side: "right", + }, + }, +) + +export type SheetVariants = VariantProps diff --git a/src/composables/useModularNavigation.ts b/src/composables/useModularNavigation.ts index af47f66..e48f209 100644 --- a/src/composables/useModularNavigation.ts +++ b/src/composables/useModularNavigation.ts @@ -79,13 +79,13 @@ export function useModularNavigation() { }) } - // Base module items (always available) - items.push({ - name: 'Relay Hub Status', - href: '/relay-hub-status', - icon: 'Activity', - requiresAuth: true - }) + // TODO: Review implementing Relay Hub Status page in the future + // items.push({ + // name: 'Relay Hub Status', + // href: '/relay-hub-status', + // icon: 'Activity', + // requiresAuth: true + // }) return items }) diff --git a/src/core/di-container.ts b/src/core/di-container.ts index 32221f5..f9d65f9 100644 --- a/src/core/di-container.ts +++ b/src/core/di-container.ts @@ -137,6 +137,11 @@ export const SERVICE_TOKENS = { PROFILE_SERVICE: Symbol('profileService'), REACTION_SERVICE: Symbol('reactionService'), + // Link aggregator services + SUBMISSION_SERVICE: Symbol('submissionService'), + LINK_PREVIEW_SERVICE: Symbol('linkPreviewService'), + COMMUNITY_SERVICE: Symbol('communityService'), + // Nostr metadata services NOSTR_METADATA_SERVICE: Symbol('nostrMetadataService'), diff --git a/src/lib/config/index.ts b/src/lib/config/index.ts index 43b7203..c9dcab8 100644 --- a/src/lib/config/index.ts +++ b/src/lib/config/index.ts @@ -19,8 +19,10 @@ interface PushConfig { interface MarketConfig { defaultNaddr: string - lightningEnabled: boolean - defaultCurrency: string + // OBSOLETE: lightningEnabled is never consumed in the codebase + // lightningEnabled: boolean + // OBSOLETE: defaultCurrency is never consumed in the codebase + // defaultCurrency: string } interface AppConfig { @@ -28,13 +30,15 @@ interface AppConfig { api: ApiConfig push: PushConfig market: MarketConfig - nostrclient: { - url: string - enabled: boolean - } - support: { - npub: string - } + // OBSOLETE: nostrclient config is never consumed in the codebase + // nostrclient: { + // url: string + // enabled: boolean + // } + // OBSOLETE: support config is never consumed in the codebase + // support: { + // npub: string + // } } // Parse JSON environment variables safely @@ -65,17 +69,21 @@ export const config: AppConfig = { enabled: Boolean(import.meta.env.VITE_PUSH_NOTIFICATIONS_ENABLED) }, market: { - defaultNaddr: import.meta.env.VITE_MARKET_NADDR || '', - lightningEnabled: Boolean(import.meta.env.VITE_LIGHTNING_ENABLED), - defaultCurrency: import.meta.env.VITE_MARKET_DEFAULT_CURRENCY || 'sat' - }, - nostrclient: { - url: import.meta.env.VITE_NOSTRCLIENT_URL || 'wss://localhost:5000/nostrclient/api/v1', - enabled: Boolean(import.meta.env.VITE_NOSTRCLIENT_ENABLED) - }, - support: { - npub: import.meta.env.VITE_SUPPORT_NPUB || '' + defaultNaddr: import.meta.env.VITE_MARKET_NADDR || '' + // OBSOLETE: lightningEnabled is never consumed in the codebase + // lightningEnabled: Boolean(import.meta.env.VITE_LIGHTNING_ENABLED), + // OBSOLETE: defaultCurrency is never consumed in the codebase + // defaultCurrency: import.meta.env.VITE_MARKET_DEFAULT_CURRENCY || 'sat' } + // OBSOLETE: nostrclient config is never consumed in the codebase + // nostrclient: { + // url: import.meta.env.VITE_NOSTRCLIENT_URL || 'wss://localhost:5000/nostrclient/api/v1', + // enabled: Boolean(import.meta.env.VITE_NOSTRCLIENT_ENABLED) + // }, + // OBSOLETE: support config is never consumed in the codebase + // support: { + // npub: import.meta.env.VITE_SUPPORT_NPUB || '' + // } } as const // Debug logging diff --git a/src/modules/chat/components/ChatComponent.vue b/src/modules/chat/components/ChatComponent.vue index f893e2d..82ab49f 100644 --- a/src/modules/chat/components/ChatComponent.vue +++ b/src/modules/chat/components/ChatComponent.vue @@ -158,7 +158,7 @@ : 'bg-muted' ]" > -

{{ message.content }}

+

{{ formatTime(message.created_at) }}

@@ -325,7 +325,7 @@ : 'bg-muted' ]" > -

{{ message.content }}

+

{{ formatTime(message.created_at) }}

@@ -376,6 +376,7 @@ import { Badge } from '@/components/ui/badge' import { ScrollArea } from '@/components/ui/scroll-area' import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar' import { useChat } from '../composables/useChat' +import ChatMessageContent from './ChatMessageContent.vue' import { useFuzzySearch } from '@/composables/useFuzzySearch' diff --git a/src/modules/chat/components/ChatMessageContent.vue b/src/modules/chat/components/ChatMessageContent.vue new file mode 100644 index 0000000..f6d1ef9 --- /dev/null +++ b/src/modules/chat/components/ChatMessageContent.vue @@ -0,0 +1,115 @@ + + + diff --git a/src/modules/chat/services/chat-service.ts b/src/modules/chat/services/chat-service.ts index 37cb14c..767636b 100644 --- a/src/modules/chat/services/chat-service.ts +++ b/src/modules/chat/services/chat-service.ts @@ -702,7 +702,8 @@ export class ChatService extends BaseService { } } /** - * Process an incoming message event + * Process a message event (incoming or outgoing) + * Note: This is called for both directions from loadRecentMessagesForPeer */ private async processIncomingMessage(event: any): Promise { try { @@ -715,10 +716,29 @@ export class ChatService extends BaseService { console.warn('Cannot process message: user not authenticated') return } - // Get sender pubkey from event - const senderPubkey = event.pubkey - // Decrypt the message content - const decryptedContent = await nip04.decrypt(userPrivkey, senderPubkey, event.content) + + // Determine if this is an outgoing message (sent by us) + const isOutgoing = event.pubkey === userPubkey + + // For NIP-04 decryption, we need the OTHER party's pubkey + // - For incoming messages: sender is the other party (event.pubkey) + // - For outgoing messages: recipient is the other party (from p-tag) + let otherPartyPubkey: string + if (isOutgoing) { + // Outgoing: get recipient from p-tag + const pTag = event.tags.find((tag: string[]) => tag[0] === 'p') + if (!pTag || !pTag[1]) { + console.warn('Cannot process outgoing message: no recipient p-tag') + return + } + otherPartyPubkey = pTag[1] + } else { + // Incoming: sender is the other party + otherPartyPubkey = event.pubkey + } + + // Decrypt the message content using the other party's pubkey + const decryptedContent = await nip04.decrypt(userPrivkey, otherPartyPubkey, event.content) // Check if this is a market-related message let isMarketMessage = false try { @@ -764,13 +784,13 @@ export class ChatService extends BaseService { id: event.id, content: displayContent, created_at: event.created_at, - sent: false, - pubkey: senderPubkey + sent: isOutgoing, + pubkey: event.pubkey } - // Ensure we have a peer record for the sender - this.addPeer(senderPubkey) - // Add the message - this.addMessage(senderPubkey, message) + // Ensure we have a peer record for the other party (the peer we're chatting with) + this.addPeer(otherPartyPubkey) + // Add the message to the peer's conversation + this.addMessage(otherPartyPubkey, message) } } catch (error) { console.error('Failed to process incoming message:', error) diff --git a/src/modules/market/components/CreateStoreDialog.vue b/src/modules/market/components/CreateStoreDialog.vue index 613c005..78ef1b3 100644 --- a/src/modules/market/components/CreateStoreDialog.vue +++ b/src/modules/market/components/CreateStoreDialog.vue @@ -47,10 +47,14 @@ Currency * - - + @@ -275,6 +279,7 @@ const toast = useToast() // Local state const isCreating = ref(false) const createError = ref(null) +const isLoadingCurrencies = ref(false) const availableCurrencies = ref(['sat']) const availableZones = ref([]) const showNewZoneForm = ref(false) @@ -331,11 +336,27 @@ const onSubmit = form.handleSubmit(async (values) => { // Methods const loadAvailableCurrencies = async () => { + isLoadingCurrencies.value = true try { const currencies = await nostrmarketAPI.getCurrencies() - availableCurrencies.value = currencies + if (currencies.length > 0) { + // Ensure 'sat' is always first in the list + const satIndex = currencies.indexOf('sat') + if (satIndex === -1) { + // Add 'sat' at the beginning if not present + availableCurrencies.value = ['sat', ...currencies] + } else if (satIndex > 0) { + // Move 'sat' to the beginning if present but not first + const withoutSat = currencies.filter(c => c !== 'sat') + availableCurrencies.value = ['sat', ...withoutSat] + } else { + availableCurrencies.value = currencies + } + } } catch (error) { console.error('Failed to load currencies:', error) + } finally { + isLoadingCurrencies.value = false } } diff --git a/src/modules/market/components/DashboardOverview.vue b/src/modules/market/components/DashboardOverview.vue index 103c07a..804d77c 100644 --- a/src/modules/market/components/DashboardOverview.vue +++ b/src/modules/market/components/DashboardOverview.vue @@ -77,77 +77,6 @@ - -
- -
-

- - Customer Actions -

-
- - - -
-
- - -
-

- - Merchant Actions -

-
- - - -
-
-
-

Recent Activity

@@ -216,15 +145,12 @@ - diff --git a/src/modules/market/components/MerchantStore.vue b/src/modules/market/components/MerchantStore.vue index 50da407..381fcae 100644 --- a/src/modules/market/components/MerchantStore.vue +++ b/src/modules/market/components/MerchantStore.vue @@ -49,84 +49,47 @@
- -
-
-
-

My Stores

-

- Manage your stores and products -

+ +
+
+
+ + +
+
+
-
-
- -
-
-
- - -
- - - - -
- -
-
- - -
+ +
- -
- -
- {{ activeStall.currency }} -
-
-

{{ activeStall.name }}

-

{{ activeStall.config?.description || 'Manage incoming orders and your products' }}

-
-
- - +
+

{{ activeStall.name }}

+ {{ activeStall.currency }} +
+

{{ activeStall.config?.description || 'Manage incoming orders and your products' }}

+
@@ -188,20 +151,23 @@
- -
+ +
+
+ Coming Soon +

Satisfaction

-

{{ storeStats.satisfaction }}%

+

--%

-
- +
+
- {{ storeStats.totalReviews }} reviews + No reviews yet
@@ -430,7 +396,6 @@ import { injectService, SERVICE_TOKENS } from '@/core/di-container' import CreateStoreDialog from './CreateStoreDialog.vue' import CreateProductDialog from './CreateProductDialog.vue' import DeleteConfirmDialog from './DeleteConfirmDialog.vue' -import StoreCard from './StoreCard.vue' import MerchantOrders from './MerchantOrders.vue' const router = useRouter() @@ -652,14 +617,6 @@ const loadStallProducts = async () => { } } -const manageStall = (stallId: string) => { - activeStallId.value = stallId -} - -const viewStallProducts = (stallId: string) => { - activeStallId.value = stallId -} - const navigateToMarket = () => router.push('/market') const checkMerchantProfile = async () => { @@ -697,7 +654,6 @@ const checkMerchantProfile = async () => { // Event handlers const onStoreCreated = async (_stall: Stall) => { await loadStallsList() - toast.success('Store created successfully!') } const onProductCreated = async (_product: Product) => { diff --git a/src/modules/market/components/OrderHistory.vue b/src/modules/market/components/OrderHistory.vue index 0807c97..54401fa 100644 --- a/src/modules/market/components/OrderHistory.vue +++ b/src/modules/market/components/OrderHistory.vue @@ -212,19 +212,6 @@
- -
-

Debug Information

-
-
Total Orders in Store: {{ Object.keys(marketStore.orders).length }}
-
Filtered Orders: {{ filteredOrders.length }}
-
Order Events Subscribed: {{ orderEvents.isSubscribed ? 'Yes' : 'No' }}
-
Relay Hub Connected: {{ relayHub.isConnected ? 'Yes' : 'No' }}
-
Auth Status: {{ auth.isAuthenticated ? 'Authenticated' : 'Not Authenticated' }}
-
Current User: {{ auth.currentUser?.value?.pubkey ? 'Yes' : 'No' }}
-
-
-
@@ -312,8 +299,6 @@ const pendingOrders = computed(() => allOrders.value.filter(o => o.status === 'p const paidOrders = computed(() => allOrders.value.filter(o => o.status === 'paid').length) const pendingPayments = computed(() => allOrders.value.filter(o => !isOrderPaid(o)).length) -const isDevelopment = computed(() => import.meta.env.DEV) - // Methods const isOrderPaid = (order: any) => { // Prioritize the 'paid' field from Nostr status updates (type 2) @@ -497,34 +482,9 @@ onMounted(() => { paymentService.forceResetPaymentState() } - // Orders are already loaded in the market store - console.log('Order History component loaded with', allOrders.value.length, 'orders') - console.log('Market store orders:', marketStore.orders) - - // Debug: Log order details for orders with payment requests - allOrders.value.forEach(order => { - if (order.paymentRequest) { - console.log('Order with payment request:', { - id: order.id, - paymentRequest: order.paymentRequest.substring(0, 50) + '...', - hasPaymentRequest: !!order.paymentRequest, - status: order.status, - paymentStatus: order.paymentStatus - }) - } - }) - - console.log('Order events status:', orderEvents.isSubscribed.value) - console.log('Relay hub connected:', relayHub.isConnected.value) - console.log('Auth status:', auth.isAuthenticated) - console.log('Current user:', auth.currentUser?.value?.pubkey) - // Start listening for order events if not already listening if (!orderEvents.isSubscribed.value) { - console.log('Starting order events listener...') orderEvents.initialize() - } else { - console.log('Order events already listening') } }) diff --git a/src/modules/market/services/nostrmarketAPI.ts b/src/modules/market/services/nostrmarketAPI.ts index 4913aa0..170cee7 100644 --- a/src/modules/market/services/nostrmarketAPI.ts +++ b/src/modules/market/services/nostrmarketAPI.ts @@ -329,6 +329,28 @@ export class NostrmarketAPI extends BaseService { return stall } + /** + * Update an existing stall + * Note: The LNbits API uses PUT and expects the full stall object + */ + async updateStall( + walletAdminkey: string, + stallData: Stall + ): Promise { + const stall = await this.request( + `/api/v1/stall/${stallData.id}`, + walletAdminkey, + { + method: 'PUT', + body: JSON.stringify(stallData), + } + ) + + this.debug('Updated stall:', { stallId: stall.id, stallName: stall.name }) + + return stall + } + /** * Get available shipping zones */ @@ -371,30 +393,70 @@ export class NostrmarketAPI extends BaseService { } /** - * Get available currencies + * Update an existing shipping zone + */ + async updateZone( + walletAdminkey: string, + zoneId: string, + zoneData: Zone + ): Promise { + const zone = await this.request( + `/api/v1/zone/${zoneId}`, + walletAdminkey, + { + method: 'PATCH', + body: JSON.stringify(zoneData), + } + ) + + this.debug('Updated zone:', { zoneId: zone.id, zoneName: zone.name }) + + return zone + } + + /** + * Delete a shipping zone + */ + async deleteZone(walletAdminkey: string, zoneId: string): Promise { + await this.request( + `/api/v1/zone/${zoneId}`, + walletAdminkey, + { method: 'DELETE' } + ) + + this.debug('Deleted zone:', { zoneId }) + } + + /** + * Get available currencies from the LNbits core API + * This endpoint returns currencies allowed by the server configuration */ async getCurrencies(): Promise { - const baseCurrencies = ['sat'] + // Call the LNbits core API directly (not under /nostrmarket) + const url = `${this.baseUrl}/api/v1/currencies` try { - const apiCurrencies = await this.request( - '/api/v1/currencies', - '', // No authentication needed for currencies endpoint - { method: 'GET' } - ) + const response = await fetch(url, { + method: 'GET', + headers: { 'Content-Type': 'application/json' } + }) - if (apiCurrencies && Array.isArray(apiCurrencies)) { - // Combine base currencies with API currencies, removing duplicates - const allCurrencies = [...baseCurrencies, ...apiCurrencies.filter(currency => !baseCurrencies.includes(currency))] - this.debug('Retrieved currencies:', { count: allCurrencies.length, currencies: allCurrencies }) - return allCurrencies + if (!response.ok) { + throw new Error(`Failed to fetch currencies: ${response.status}`) } - this.debug('No API currencies returned, using base currencies only') - return baseCurrencies + const apiCurrencies = await response.json() + + if (apiCurrencies && Array.isArray(apiCurrencies)) { + this.debug('Retrieved currencies from LNbits core:', { count: apiCurrencies.length, currencies: apiCurrencies }) + return apiCurrencies + } + + this.debug('No currencies returned from server, using default') + return ['sat'] } catch (error) { - this.debug('Failed to get currencies, falling back to base currencies:', error) - return baseCurrencies + this.debug('Failed to get currencies, using default:', error) + return ['sat'] } } diff --git a/src/modules/market/views/CheckoutPage.vue b/src/modules/market/views/CheckoutPage.vue index a5cbdb7..8cb5378 100644 --- a/src/modules/market/views/CheckoutPage.vue +++ b/src/modules/market/views/CheckoutPage.vue @@ -14,7 +14,7 @@ -
@@ -46,8 +46,8 @@
-
@@ -68,7 +68,7 @@
- +

{{ item.product.name }}

@@ -76,7 +76,7 @@

Quantity: {{ item.quantity }}

- +

@@ -108,121 +108,76 @@ - - + + - Shipping Information - Select your shipping zone + Shipping & Contact + Select shipping and provide your contact details - + -

-
-
-
-

{{ zone.name }}

-

- {{ zone.countries?.join(', ') || 'Available' }} - - • No shipping required - -

-

- {{ zone.description }} -

-
-
-

- {{ formatPrice(zone.cost, checkoutCart.currency) }} -

-

shipping

+
+ +
+
+
+
+

{{ zone.name }}

+

+ {{ zone.countries?.join(', ') || 'Available' }} + + • No shipping required + +

+

+ {{ zone.description }} +

+
+
+

+ {{ formatPrice(zone.cost, checkoutCart.currency) }} +

+

shipping

+
- -
+ +

This merchant hasn't configured shipping zones yet.

Please contact the merchant for shipping information.

- -
- -
- - + +
- - - - Contact & Payment Information - Provide your details for order processing - - - -
-
- - -

Merchant may not use email

-
- -
- - -

Different Npub for communication

-
-
- -
- -