diff --git a/package-lock.json b/package-lock.json index 3486759..b1a2cf4 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.7.0", + "reka-ui": "^2.5.0", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "unique-names-generator": "^4.7.1", @@ -12172,9 +12172,9 @@ } }, "node_modules/reka-ui": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.7.0.tgz", - "integrity": "sha512-m+XmxQN2xtFzBP3OAdIafKq7C8OETo2fqfxcIIxYmNN2Ch3r5oAf6yEYCIJg5tL/yJU2mHqF70dCCekUkrAnXA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.5.0.tgz", + "integrity": "sha512-81aMAmJeVCy2k0E6x7n1kypDY6aM1ldLis5+zcdV1/JtoAlSDck5OBsyLRJU9CfgbrQp1ImnRnBSmC4fZ2fkZQ==", "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.6.13", diff --git a/package.json b/package.json index 00b5554..304528e 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.7.0", + "reka-ui": "^2.5.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 82ca06c..ba8df07 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 8d9e452..84495b0 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 4e6b3a3..17abda4 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 94f8c6b..3819dee 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 738f5f1..b280cd5 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 3c734e6..bdd4754 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 559d0bf..127cdd6 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,7 +1,8 @@ - - diff --git a/src/components/layout/AppSidebar.vue b/src/components/layout/AppSidebar.vue deleted file mode 100644 index 7b5accf..0000000 --- a/src/components/layout/AppSidebar.vue +++ /dev/null @@ -1,149 +0,0 @@ - - - diff --git a/src/components/layout/AppTopBar.vue b/src/components/layout/AppTopBar.vue deleted file mode 100644 index eb1fe00..0000000 --- a/src/components/layout/AppTopBar.vue +++ /dev/null @@ -1,242 +0,0 @@ - - - diff --git a/src/components/layout/MobileDrawer.vue b/src/components/layout/MobileDrawer.vue deleted file mode 100644 index 98b0740..0000000 --- a/src/components/layout/MobileDrawer.vue +++ /dev/null @@ -1,172 +0,0 @@ - - - diff --git a/src/components/layout/Navbar.old.vue b/src/components/layout/Navbar.vue similarity index 97% rename from src/components/layout/Navbar.old.vue rename to src/components/layout/Navbar.vue index 6eb160f..07fbba1 100644 --- a/src/components/layout/Navbar.old.vue +++ b/src/components/layout/Navbar.vue @@ -1,13 +1,3 @@ - - - diff --git a/src/components/ui/sheet/SheetClose.vue b/src/components/ui/sheet/SheetClose.vue deleted file mode 100644 index 0295976..0000000 --- a/src/components/ui/sheet/SheetClose.vue +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/src/components/ui/sheet/SheetContent.vue b/src/components/ui/sheet/SheetContent.vue deleted file mode 100644 index 50f3de6..0000000 --- a/src/components/ui/sheet/SheetContent.vue +++ /dev/null @@ -1,53 +0,0 @@ - - - diff --git a/src/components/ui/sheet/SheetDescription.vue b/src/components/ui/sheet/SheetDescription.vue deleted file mode 100644 index 455c2f4..0000000 --- a/src/components/ui/sheet/SheetDescription.vue +++ /dev/null @@ -1,20 +0,0 @@ - - - diff --git a/src/components/ui/sheet/SheetFooter.vue b/src/components/ui/sheet/SheetFooter.vue deleted file mode 100644 index 5f481e5..0000000 --- a/src/components/ui/sheet/SheetFooter.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/src/components/ui/sheet/SheetHeader.vue b/src/components/ui/sheet/SheetHeader.vue deleted file mode 100644 index f97d24a..0000000 --- a/src/components/ui/sheet/SheetHeader.vue +++ /dev/null @@ -1,16 +0,0 @@ - - - diff --git a/src/components/ui/sheet/SheetTitle.vue b/src/components/ui/sheet/SheetTitle.vue deleted file mode 100644 index 5870787..0000000 --- a/src/components/ui/sheet/SheetTitle.vue +++ /dev/null @@ -1,20 +0,0 @@ - - - diff --git a/src/components/ui/sheet/SheetTrigger.vue b/src/components/ui/sheet/SheetTrigger.vue deleted file mode 100644 index a4fc3ee..0000000 --- a/src/components/ui/sheet/SheetTrigger.vue +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/src/components/ui/sheet/index.ts b/src/components/ui/sheet/index.ts deleted file mode 100644 index a370633..0000000 --- a/src/components/ui/sheet/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -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 e48f209..af47f66 100644 --- a/src/composables/useModularNavigation.ts +++ b/src/composables/useModularNavigation.ts @@ -79,13 +79,13 @@ export function useModularNavigation() { }) } - // TODO: Review implementing Relay Hub Status page in the future - // items.push({ - // name: 'Relay Hub Status', - // href: '/relay-hub-status', - // icon: 'Activity', - // requiresAuth: true - // }) + // Base module items (always available) + 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 f9d65f9..32221f5 100644 --- a/src/core/di-container.ts +++ b/src/core/di-container.ts @@ -137,11 +137,6 @@ 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/modules/chat/components/ChatComponent.vue b/src/modules/chat/components/ChatComponent.vue index 82ab49f..f893e2d 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,7 +376,6 @@ 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 deleted file mode 100644 index f6d1ef9..0000000 --- a/src/modules/chat/components/ChatMessageContent.vue +++ /dev/null @@ -1,115 +0,0 @@ - - - diff --git a/src/modules/chat/services/chat-service.ts b/src/modules/chat/services/chat-service.ts index 767636b..37cb14c 100644 --- a/src/modules/chat/services/chat-service.ts +++ b/src/modules/chat/services/chat-service.ts @@ -702,8 +702,7 @@ export class ChatService extends BaseService { } } /** - * Process a message event (incoming or outgoing) - * Note: This is called for both directions from loadRecentMessagesForPeer + * Process an incoming message event */ private async processIncomingMessage(event: any): Promise { try { @@ -716,29 +715,10 @@ export class ChatService extends BaseService { console.warn('Cannot process message: user not authenticated') return } - - // 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) + // Get sender pubkey from event + const senderPubkey = event.pubkey + // Decrypt the message content + const decryptedContent = await nip04.decrypt(userPrivkey, senderPubkey, event.content) // Check if this is a market-related message let isMarketMessage = false try { @@ -784,13 +764,13 @@ export class ChatService extends BaseService { id: event.id, content: displayContent, created_at: event.created_at, - sent: isOutgoing, - pubkey: event.pubkey + sent: false, + pubkey: senderPubkey } - // 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) + // Ensure we have a peer record for the sender + this.addPeer(senderPubkey) + // Add the message + this.addMessage(senderPubkey, 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 78ef1b3..613c005 100644 --- a/src/modules/market/components/CreateStoreDialog.vue +++ b/src/modules/market/components/CreateStoreDialog.vue @@ -47,14 +47,10 @@ Currency * - - + @@ -279,7 +275,6 @@ 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) @@ -336,27 +331,11 @@ const onSubmit = form.handleSubmit(async (values) => { // Methods const loadAvailableCurrencies = async () => { - isLoadingCurrencies.value = true try { const currencies = await nostrmarketAPI.getCurrencies() - 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 - } - } + 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 804d77c..103c07a 100644 --- a/src/modules/market/components/DashboardOverview.vue +++ b/src/modules/market/components/DashboardOverview.vue @@ -77,6 +77,77 @@ + +
+ +
+

+ + Customer Actions +

+
+ + + +
+
+ + +
+

+ + Merchant Actions +

+
+ + + +
+
+
+

Recent Activity

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

My Stores

+

+ Manage your stores and products +

-

Create Your Store

-

- Set up your store to start selling products on the Nostr marketplace. -

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

{{ activeStall.name }}

- {{ activeStall.currency }} -
-

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

+

{{ activeStall.name }}

+

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

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

Satisfaction

-

--%

+

{{ storeStats.satisfaction }}%

-
- +
+
- No reviews yet + {{ storeStats.totalReviews }} reviews
@@ -396,6 +430,7 @@ 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() @@ -617,6 +652,14 @@ 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 () => { @@ -654,6 +697,7 @@ 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 54401fa..0807c97 100644 --- a/src/modules/market/components/OrderHistory.vue +++ b/src/modules/market/components/OrderHistory.vue @@ -212,6 +212,19 @@
+ +
+

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' }}
+
+
+
@@ -299,6 +312,8 @@ 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) @@ -482,9 +497,34 @@ 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 170cee7..4913aa0 100644 --- a/src/modules/market/services/nostrmarketAPI.ts +++ b/src/modules/market/services/nostrmarketAPI.ts @@ -329,28 +329,6 @@ 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 */ @@ -393,70 +371,30 @@ export class NostrmarketAPI extends BaseService { } /** - * 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 + * Get available currencies */ async getCurrencies(): Promise { - // Call the LNbits core API directly (not under /nostrmarket) - const url = `${this.baseUrl}/api/v1/currencies` + const baseCurrencies = ['sat'] try { - const response = await fetch(url, { - method: 'GET', - headers: { 'Content-Type': 'application/json' } - }) - - if (!response.ok) { - throw new Error(`Failed to fetch currencies: ${response.status}`) - } - - const apiCurrencies = await response.json() + const apiCurrencies = await this.request( + '/api/v1/currencies', + '', // No authentication needed for currencies endpoint + { method: 'GET' } + ) if (apiCurrencies && Array.isArray(apiCurrencies)) { - this.debug('Retrieved currencies from LNbits core:', { count: apiCurrencies.length, currencies: apiCurrencies }) - return 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 } - this.debug('No currencies returned from server, using default') - return ['sat'] + this.debug('No API currencies returned, using base currencies only') + return baseCurrencies } catch (error) { - this.debug('Failed to get currencies, using default:', error) - return ['sat'] + this.debug('Failed to get currencies, falling back to base currencies:', error) + return baseCurrencies } } diff --git a/src/modules/market/views/CheckoutPage.vue b/src/modules/market/views/CheckoutPage.vue index 8cb5378..a5cbdb7 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,76 +108,121 @@ - - + + - Shipping & Contact - Select shipping and provide your contact details + Shipping Information + Select your shipping zone - + -

- -
-
-
-
-

{{ 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.

- -
+ +
+ +
+ + - -
- -