From 98544e2e79e05d7d68be41f28cb060989f5f8d8a Mon Sep 17 00:00:00 2001 From: padreug Date: Tue, 9 Sep 2025 03:35:43 +0200 Subject: [PATCH] Enhance CreateProductDialog and MerchantStore components for product editing functionality - Update CreateProductDialog to support both creating and editing products, with dynamic button text and pre-populated fields for existing products. - Refactor product submission logic to handle updates, including error handling and user feedback. - Modify MerchantStore to manage product editing state and integrate updated product handling in the dialog. These changes improve the user experience by allowing merchants to easily edit existing products, enhancing the overall product management workflow. --- .../market/components/CreateProductDialog.vue | 129 +++++++++++++++--- .../market/components/MerchantStore.vue | 26 +++- 2 files changed, 134 insertions(+), 21 deletions(-) diff --git a/src/modules/market/components/CreateProductDialog.vue b/src/modules/market/components/CreateProductDialog.vue index 20707d2..d03cff1 100644 --- a/src/modules/market/components/CreateProductDialog.vue +++ b/src/modules/market/components/CreateProductDialog.vue @@ -2,7 +2,7 @@ - Add New Product to {{ stall?.name }} + {{ product ? 'Edit' : 'Add New' }} Product{{ stall?.name ? ` ${product ? 'in' : 'to'} ${stall.name}` : '' }}
@@ -183,8 +183,7 @@ type="submit" :disabled="isCreating || !isFormValid" > - Creating... - Create Product + {{ submitButtonText }}
@@ -212,7 +211,7 @@ import { FormMessage, } from '@/components/ui/form' import { Package } from 'lucide-vue-next' -import type { NostrmarketAPI, Stall, CreateProductRequest } from '../services/nostrmarketAPI' +import type { NostrmarketAPI, Stall, Product, CreateProductRequest } from '../services/nostrmarketAPI' import { auth } from '@/composables/useAuthService' import { useToast } from '@/core/composables/useToast' import { injectService, SERVICE_TOKENS } from '@/core/di-container' @@ -221,12 +220,14 @@ import { injectService, SERVICE_TOKENS } from '@/core/di-container' interface Props { isOpen: boolean stall?: Stall | null + product?: Product | null // For editing existing products } const props = defineProps() const emit = defineEmits<{ close: [] created: [product: any] + updated: [product: any] }>() // Services @@ -237,6 +238,13 @@ const toast = useToast() const isCreating = ref(false) const createError = ref(null) +// Computed properties +const isEditMode = computed(() => !!props.product?.id) +const submitButtonText = computed(() => isCreating.value ? + (isEditMode.value ? 'Updating...' : 'Creating...') : + (isEditMode.value ? 'Update Product' : 'Create Product') +) + // Product form schema const productFormSchema = toTypedSchema(z.object({ name: z.string().min(1, "Product name is required").max(100, "Product name must be less than 100 characters"), @@ -274,10 +282,82 @@ const isFormValid = computed(() => meta.value.valid) // Product form submit handler const onSubmit = form.handleSubmit(async (values) => { - await createProduct(values) + await createOrUpdateProduct(values) }) // Methods +const createOrUpdateProduct = async (formData: any) => { + if (isEditMode.value) { + await updateProduct(formData) + } else { + await createProduct(formData) + } +} + +const updateProduct = async (formData: any) => { + const currentUser = auth.currentUser?.value + if (!currentUser?.wallets?.length || !props.product?.id) { + toast.error('No active store or product ID available') + return + } + + const { + name, + description, + price, + quantity, + categories, + images, + active, + use_autoreply, + autoreply_message + } = formData + + isCreating.value = true + createError.value = null + + try { + const productData: Product = { + id: props.product.id, + stall_id: props.product.stall_id, + name, + categories: categories || [], + images: images || [], + price: Number(price), + quantity: Number(quantity), + active, + pending: false, + config: { + description: description || '', + currency: props.stall?.currency || props.product.config.currency, + use_autoreply, + autoreply_message: use_autoreply ? autoreply_message || '' : '', + shipping: props.product.config.shipping || [] + } + } + + const updatedProduct = await nostrmarketAPI.updateProduct( + currentUser.wallets[0].adminkey, + props.product.id, + productData + ) + + // Reset form and close dialog + resetForm() + emit('updated', updatedProduct) + emit('close') + + toast.success(`Product "${name}" updated successfully!`) + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Failed to update product' + console.error('Error updating product:', error) + createError.value = errorMessage + toast.error(`Failed to update product: ${errorMessage}`) + } finally { + isCreating.value = false + } +} + const createProduct = async (formData: any) => { const currentUser = auth.currentUser?.value if (!currentUser?.wallets?.length || !props.stall) { @@ -342,20 +422,31 @@ const createProduct = async (formData: any) => { // Initialize data when dialog opens watch(() => props.isOpen, async (isOpen) => { if (isOpen) { - // Reset form to initial state - resetForm({ - values: { - name: '', - description: '', - price: 0, - quantity: 1, - categories: [], - images: [], - active: true, - use_autoreply: false, - autoreply_message: '' - } - }) + // If editing, pre-populate with existing product data + const initialValues = props.product ? { + name: props.product.name || '', + description: props.product.config?.description || '', + price: props.product.price || 0, + quantity: props.product.quantity || 1, + categories: props.product.categories || [], + images: props.product.images || [], + active: props.product.active ?? true, + use_autoreply: props.product.config?.use_autoreply || false, + autoreply_message: props.product.config?.autoreply_message || '' + } : { + name: '', + description: '', + price: 0, + quantity: 1, + categories: [], + images: [], + active: true, + use_autoreply: false, + autoreply_message: '' + } + + // Reset form with appropriate initial values + resetForm({ values: initialValues }) // Wait for reactivity await nextTick() diff --git a/src/modules/market/components/MerchantStore.vue b/src/modules/market/components/MerchantStore.vue index 92c8fb8..b4c9b6c 100644 --- a/src/modules/market/components/MerchantStore.vue +++ b/src/modules/market/components/MerchantStore.vue @@ -293,7 +293,11 @@
-
@@ -316,8 +320,10 @@ @@ -370,6 +376,7 @@ const isLoadingProducts = ref(false) // Dialog state const showCreateStoreDialog = ref(false) const showCreateProductDialog = ref(false) +const editingProduct = ref(null) // Computed properties const userHasMerchantProfile = computed(() => { @@ -556,6 +563,21 @@ const onProductCreated = async (_product: Product) => { toast.success('Product created successfully!') } +const onProductUpdated = async (_product: Product) => { + await loadStallProducts() + toast.success('Product updated successfully!') +} + +const editProduct = (product: Product) => { + editingProduct.value = product + showCreateProductDialog.value = true +} + +const closeProductDialog = () => { + showCreateProductDialog.value = false + editingProduct.value = null +} + // Lifecycle onMounted(async () => { console.log('Merchant Store component loaded')