From 36638d10809f102cfbd9a937f03c079a0dd1483e Mon Sep 17 00:00:00 2001 From: padreug Date: Fri, 5 Sep 2025 04:22:54 +0200 Subject: [PATCH] Remove useNostrOrders composable and related Checkout page - Delete the useNostrOrders composable as it is no longer needed. - Update MerchantStore.vue to utilize nostrmarketService for publishing orders instead of the removed composable. - Refactor market store to check the readiness of nostrmarketService instead of useNostrOrders. - Remove the Checkout.vue page, streamlining the checkout process and improving code maintainability. --- src/composables/useNostrOrders.ts | 248 ---------- .../market/components/MerchantStore.vue | 5 +- .../market/services/nostrmarketService.ts | 12 + src/modules/market/stores/market.ts | 5 +- src/pages/Checkout.vue | 438 ------------------ src/router/index.ts | 9 - 6 files changed, 16 insertions(+), 701 deletions(-) delete mode 100644 src/composables/useNostrOrders.ts delete mode 100644 src/pages/Checkout.vue diff --git a/src/composables/useNostrOrders.ts b/src/composables/useNostrOrders.ts deleted file mode 100644 index 1794322..0000000 --- a/src/composables/useNostrOrders.ts +++ /dev/null @@ -1,248 +0,0 @@ -import { ref, computed, readonly } from 'vue' -import { finalizeEvent, type EventTemplate, nip04 } from 'nostr-tools' -import { relayHub } from '@/lib/nostr/relayHub' -import { auth } from '@/composables/useAuth' -import { hexToBytes } from '@/lib/utils/crypto' -import type { Order } from '@/stores/market' - -export function useNostrOrders() { - // State - const isPublishing = ref(false) - const lastError = ref(null) - const publishedEvents = ref>({}) // orderId -> eventId - - // Computed - const isReady = computed(() => { - return auth.isAuthenticated.value && - !!auth.currentUser.value?.pubkey && - !!auth.currentUser.value?.prvkey - }) - - const currentUserPubkey = computed(() => auth.currentUser.value?.pubkey || '') - const currentUserPrvkey = computed(() => auth.currentUser.value?.prvkey || '') - - // Methods - const validateAuth = (): { valid: boolean; error?: string } => { - if (!auth.isAuthenticated.value) { - return { valid: false, error: 'User not authenticated' } - } - - if (!currentUserPubkey.value) { - return { valid: false, error: 'User public key not available' } - } - - if (!currentUserPrvkey.value) { - return { valid: false, error: 'User private key not available' } - } - - // Validate key formats - if (currentUserPubkey.value.length !== 64) { - return { valid: false, error: 'Invalid public key format' } - } - - if (currentUserPrvkey.value.length !== 64) { - return { valid: false, error: 'Invalid private key format' } - } - - return { valid: true } - } - - const createEventTemplate = (recipientPubkey: string, content: string): EventTemplate => { - return { - kind: 4, // Encrypted Direct Message - tags: [['p', recipientPubkey]], // Recipient tag - content: content, - created_at: Math.floor(Date.now() / 1000) - } - } - - const encryptOrderContent = async (order: Order, recipientPubkey: string): Promise => { - try { - console.log('Encrypting order content:', { - orderId: order.id, - recipientPubkey, - hasPrivateKey: !!currentUserPrvkey.value, - privateKeyLength: currentUserPrvkey.value?.length - }) - - // Validate keys - if (!currentUserPrvkey.value || !recipientPubkey) { - throw new Error('Missing private key or recipient public key') - } - - if (currentUserPrvkey.value.length !== 64) { - throw new Error(`Invalid private key length: ${currentUserPrvkey.value.length} (expected 64)`) - } - - if (recipientPubkey.length !== 64) { - throw new Error(`Invalid recipient public key length: ${recipientPubkey.length} (expected 64)`) - } - - // Create the order payload - const orderPayload = { - type: 'market_order', - orderId: order.id, - items: order.items, - contactInfo: order.contactInfo, - shippingZone: order.shippingZone, - paymentMethod: order.paymentMethod, - subtotal: order.subtotal, - shippingCost: order.shippingCost, - total: order.total, - currency: order.currency, - createdAt: order.createdAt, - buyerPubkey: order.buyerPubkey - } - - // Convert to JSON string - const orderJson = JSON.stringify(orderPayload) - console.log('Order payload created:', orderPayload) - - // Encrypt the order content using NIP-04 - const encryptedContent = await nip04.encrypt( - hexToBytes(currentUserPrvkey.value), - recipientPubkey, - orderJson - ) - - console.log('Order content encrypted successfully:', { - originalLength: orderJson.length, - encryptedLength: encryptedContent.length, - encryptedPreview: encryptedContent.substring(0, 50) + '...' - }) - - return encryptedContent - } catch (error) { - console.error('Failed to encrypt order content:', error) - throw new Error('Failed to encrypt order content') - } - } - - const publishOrderEvent = async (order: Order, recipientPubkey: string): Promise<{ id: string; sig: string }> => { - try { - // Validate authentication - const authValidation = validateAuth() - if (!authValidation.valid) { - throw new Error(authValidation.error) - } - - // Set publishing state - isPublishing.value = true - lastError.value = null - - // Encrypt the order content - const encryptedContent = await encryptOrderContent(order, recipientPubkey) - - // Create event template - const eventTemplate = createEventTemplate(recipientPubkey, encryptedContent) - - // Finalize the event (sign and generate ID) - const event = finalizeEvent(eventTemplate, hexToBytes(currentUserPrvkey.value)) - - // Publish via relay hub - await relayHub.publishEvent(event) - - // Store the published event - publishedEvents.value[order.id] = event.id - - console.log('Order event published successfully:', { - orderId: order.id, - eventId: event.id, - recipient: recipientPubkey, - timestamp: new Date().toISOString() - }) - - return { id: event.id, sig: event.sig } - } catch (error) { - const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred' - lastError.value = errorMessage - console.error('Failed to publish order event:', error) - throw new Error(`Failed to publish order: ${errorMessage}`) - } finally { - isPublishing.value = false - } - } - - const getPublishedEventId = (orderId: string): string | undefined => { - return publishedEvents.value[orderId] - } - - const clearError = () => { - lastError.value = null - } - - const reset = () => { - isPublishing.value = false - lastError.value = null - publishedEvents.value = {} - } - - const testEncryption = async (): Promise => { - try { - if (!isReady.value) { - console.log('Nostr not ready for testing') - return false - } - - const testMessage = 'Hello, this is a test message for NIP-04 encryption!' - const testRecipient = currentUserPubkey.value // Encrypt to ourselves for testing - - console.log('Testing NIP-04 encryption with:', { - message: testMessage, - recipient: testRecipient, - sender: currentUserPubkey.value - }) - - // Encrypt - const encrypted = await nip04.encrypt( - hexToBytes(currentUserPrvkey.value), - testRecipient, - testMessage - ) - - console.log('Test message encrypted:', encrypted) - - // Decrypt - const decrypted = await nip04.decrypt( - currentUserPrvkey.value, - currentUserPubkey.value, - encrypted - ) - - console.log('Test message decrypted:', decrypted) - - const success = decrypted === testMessage - console.log('NIP-04 test result:', success ? 'PASSED' : 'FAILED') - - return success - } catch (error) { - console.error('NIP-04 test failed:', error) - return false - } - } - - return { - // State - isPublishing: readonly(isPublishing), - lastError: readonly(lastError), - publishedEvents: readonly(publishedEvents), - - // Computed - isReady, - currentUserPubkey, - currentUserPrvkey, - - // Methods - validateAuth, - createEventTemplate, - encryptOrderContent, - publishOrderEvent, - getPublishedEventId, - clearError, - reset, - testEncryption - } -} - -// Export singleton instance -export const nostrOrders = useNostrOrders() diff --git a/src/modules/market/components/MerchantStore.vue b/src/modules/market/components/MerchantStore.vue index a3d9bd2..f2f6ac9 100644 --- a/src/modules/market/components/MerchantStore.vue +++ b/src/modules/market/components/MerchantStore.vue @@ -320,12 +320,11 @@ import { BarChart3 } from 'lucide-vue-next' import type { OrderStatus } from '@/stores/market' -import { nostrOrders } from '@/composables/useNostrOrders' +import { nostrmarketService } from '../services/nostrmarketService' import { auth } from '@/composables/useAuth' const router = useRouter() const marketStore = useMarketStore() -const nostrOrdersComposable = nostrOrders // Local state const isGeneratingInvoice = ref(null) @@ -502,7 +501,7 @@ const sendInvoiceToCustomer = async (order: any, invoice: any) => { // Send the updated order to the customer via Nostr // This will include the invoice information - await nostrOrdersComposable.publishOrderEvent(updatedOrder, order.buyerPubkey) + await nostrmarketService.publishOrder(updatedOrder, order.buyerPubkey) console.log('Updated order with invoice sent via Nostr to customer:', order.buyerPubkey) } catch (error) { diff --git a/src/modules/market/services/nostrmarketService.ts b/src/modules/market/services/nostrmarketService.ts index 0c74a67..1813548 100644 --- a/src/modules/market/services/nostrmarketService.ts +++ b/src/modules/market/services/nostrmarketService.ts @@ -76,6 +76,18 @@ export class NostrmarketService { return hub } + /** + * Check if the service is ready for Nostr operations + */ + get isReady(): boolean { + try { + this.getAuth() + return true + } catch { + return false + } + } + /** * Convert hex string to Uint8Array (browser-compatible) */ diff --git a/src/modules/market/stores/market.ts b/src/modules/market/stores/market.ts index e9cbdaf..517a7ad 100644 --- a/src/modules/market/stores/market.ts +++ b/src/modules/market/stores/market.ts @@ -1,6 +1,5 @@ import { defineStore } from 'pinia' import { ref, computed, readonly, watch } from 'vue' -import { nostrOrders } from '@/composables/useNostrOrders' import { invoiceService } from '@/lib/services/invoiceService' import { paymentMonitor } from '@/lib/services/paymentMonitor' import { nostrmarketService } from '../services/nostrmarketService' @@ -595,7 +594,7 @@ export const useMarketStore = defineStore('market', () => { const sendPaymentConfirmation = async (order: Order) => { try { - if (!nostrOrders.isReady.value) { + if (!nostrmarketService.isReady) { console.warn('Nostr not ready for payment confirmation') return } @@ -612,7 +611,7 @@ export const useMarketStore = defineStore('market', () => { // } // Send confirmation to customer - await nostrOrders.publishOrderEvent(order, order.buyerPubkey) + await nostrmarketService.publishOrder(order, order.buyerPubkey) console.log('Payment confirmation sent via Nostr') } catch (error) { diff --git a/src/pages/Checkout.vue b/src/pages/Checkout.vue deleted file mode 100644 index b92ab1b..0000000 --- a/src/pages/Checkout.vue +++ /dev/null @@ -1,438 +0,0 @@ - - - diff --git a/src/router/index.ts b/src/router/index.ts index ea68793..c06616d 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -31,15 +31,6 @@ const router = createRouter({ requiresAuth: true } }, - { - path: '/checkout/:stallId', - name: 'checkout', - component: () => import('@/pages/Checkout.vue'), - meta: { - title: 'Checkout', - requiresAuth: true - } - }, { path: '/order-history', name: 'OrderHistory',