Enhance MerchantStore component with improved form handling and dialog management
- Introduce keys for reactivity in the stall creation dialog and form elements to ensure proper rendering and state management. - Implement autocomplete and spellcheck attributes for input fields to enhance user experience during store creation. - Refactor form initialization and reset logic to ensure a clean state upon dialog opening and closing, improving usability. - Add validation triggers after loading data to ensure form integrity and user feedback during the stall creation process. These changes streamline the store creation experience, providing a more responsive and user-friendly interface for merchants.
This commit is contained in:
parent
6f68c2320e
commit
c3e599b3e4
1 changed files with 97 additions and 30 deletions
|
|
@ -449,13 +449,13 @@
|
|||
</div> <!-- End of main container -->
|
||||
|
||||
<!-- Create Stall Dialog -->
|
||||
<Dialog v-model:open="showStallDialog">
|
||||
<Dialog v-model:open="showStallDialog" :key="dialogKey">
|
||||
<DialogContent class="sm:max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create New Store</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<form @submit="onSubmit" class="space-y-6 py-4">
|
||||
<form @submit="onSubmit" class="space-y-6 py-4" :key="formKey" autocomplete="off">
|
||||
<!-- Basic Store Info -->
|
||||
<div class="space-y-4">
|
||||
<FormField v-slot="{ componentField }" name="name">
|
||||
|
|
@ -466,6 +466,9 @@
|
|||
placeholder="Enter your store name"
|
||||
:disabled="isCreatingStall"
|
||||
v-bind="componentField"
|
||||
:key="`store-name-${formKey}`"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
|
|
@ -483,6 +486,9 @@
|
|||
placeholder="Describe your store and products"
|
||||
:disabled="isCreatingStall"
|
||||
v-bind="componentField"
|
||||
:key="`store-description-${formKey}`"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
|
|
@ -564,6 +570,9 @@
|
|||
placeholder="e.g., Europe, Worldwide"
|
||||
:disabled="isCreatingStall"
|
||||
v-bind="componentField"
|
||||
:key="`zone-name-${formKey}`"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
|
|
@ -578,6 +587,7 @@
|
|||
min="0"
|
||||
:placeholder="`Cost in ${getFieldValue('currency') || 'sat'}`"
|
||||
:disabled="isCreatingStall"
|
||||
:key="`zone-cost-${formKey}`"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
|
|
@ -634,7 +644,7 @@
|
|||
|
||||
<div class="flex justify-end space-x-2 pt-4">
|
||||
<Button
|
||||
@click="showStallDialog = false"
|
||||
@click="closeStallDialog"
|
||||
variant="outline"
|
||||
:disabled="isCreatingStall"
|
||||
>
|
||||
|
|
@ -654,7 +664,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, watch } from 'vue'
|
||||
import { ref, computed, onMounted, watch, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useForm } from 'vee-validate'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
|
|
@ -724,7 +734,9 @@ const activeStall = computed(() =>
|
|||
// Stall creation state
|
||||
const isCreatingStall = ref(false)
|
||||
const stallCreateError = ref<string | null>(null)
|
||||
const formKey = ref(0) // Force re-render of form
|
||||
const showStallDialog = ref(false)
|
||||
const dialogKey = ref(0) // Force complete dialog re-render
|
||||
const availableCurrencies = ref<string[]>(['sat'])
|
||||
const availableZones = ref<Zone[]>([])
|
||||
const countries = ref([
|
||||
|
|
@ -769,19 +781,20 @@ const form = useForm({
|
|||
})
|
||||
|
||||
// Destructure form methods for easier access
|
||||
const { setFieldValue, resetForm, values, meta } = form
|
||||
const { setFieldValue, resetForm, values, meta, validate } = form
|
||||
|
||||
// Helper function to get field values safely
|
||||
const getFieldValue = (fieldName: string) => {
|
||||
return fieldName.split('.').reduce((obj, key) => obj?.[key], values)
|
||||
}
|
||||
|
||||
// Form validation computed
|
||||
const isFormValid = computed(() => meta.value.valid)
|
||||
// Form validation computed with detailed debugging
|
||||
const isFormValid = computed(() => {
|
||||
return meta.value.valid
|
||||
})
|
||||
|
||||
// Form submit handler
|
||||
const onSubmit = form.handleSubmit(async (values) => {
|
||||
console.log('Form submitted with values:', values)
|
||||
await createStall(values)
|
||||
})
|
||||
|
||||
|
|
@ -1076,8 +1089,45 @@ const initializeStallCreation = async () => {
|
|||
return
|
||||
}
|
||||
|
||||
// Set default wallet
|
||||
setFieldValue('wallet', currentUser.wallets[0].id)
|
||||
// Reset form to initial state first
|
||||
resetForm({
|
||||
values: {
|
||||
name: '',
|
||||
description: '',
|
||||
currency: 'sat',
|
||||
wallet: currentUser.wallets[0].id,
|
||||
selectedZones: [],
|
||||
newZone: {
|
||||
name: '',
|
||||
cost: 0,
|
||||
selectedCountries: []
|
||||
}
|
||||
},
|
||||
errors: {},
|
||||
touched: {},
|
||||
initialValues: {
|
||||
name: '',
|
||||
description: '',
|
||||
currency: 'sat',
|
||||
wallet: currentUser.wallets[0].id,
|
||||
selectedZones: [],
|
||||
newZone: {
|
||||
name: '',
|
||||
cost: 0,
|
||||
selectedCountries: []
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Wait for Vue's reactivity to update
|
||||
await nextTick()
|
||||
|
||||
// Force complete dialog re-render
|
||||
dialogKey.value++
|
||||
formKey.value++
|
||||
|
||||
// Clear any previous errors
|
||||
stallCreateError.value = null
|
||||
|
||||
// Load currencies and zones
|
||||
await Promise.all([
|
||||
|
|
@ -1085,6 +1135,9 @@ const initializeStallCreation = async () => {
|
|||
loadAvailableZones()
|
||||
])
|
||||
|
||||
// Trigger validation after data is loaded to ensure form state is correct
|
||||
await validate()
|
||||
|
||||
showStallDialog.value = true
|
||||
}
|
||||
|
||||
|
|
@ -1105,6 +1158,14 @@ const loadAvailableZones = async () => {
|
|||
try {
|
||||
const zones = await nostrmarketAPI.getZones(currentUser.wallets[0].inkey)
|
||||
availableZones.value = zones
|
||||
|
||||
// Auto-select the first available zone to make form valid
|
||||
if (zones.length > 0) {
|
||||
const currentSelectedZones = getFieldValue('selectedZones') || []
|
||||
if (currentSelectedZones.length === 0) {
|
||||
setFieldValue('selectedZones', [zones[0].id])
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load zones:', error)
|
||||
}
|
||||
|
|
@ -1112,27 +1173,19 @@ const loadAvailableZones = async () => {
|
|||
|
||||
const loadStallsList = async () => {
|
||||
const currentUser = auth.currentUser?.value
|
||||
console.log('Loading stalls list - currentUser:', !!currentUser, 'wallets:', currentUser?.wallets?.length)
|
||||
|
||||
if (!currentUser?.wallets?.length) {
|
||||
console.log('No user or wallets available, skipping stalls loading')
|
||||
return
|
||||
}
|
||||
|
||||
isLoadingStalls.value = true
|
||||
try {
|
||||
console.log('Calling getStalls with inkey:', currentUser.wallets[0].inkey.substring(0, 8) + '...')
|
||||
const stalls = await nostrmarketAPI.getStalls(currentUser.wallets[0].inkey)
|
||||
userStalls.value = stalls || []
|
||||
console.log('Loaded user stalls:', {
|
||||
stallsCount: stalls?.length || 0,
|
||||
stalls: stalls?.map(s => ({ id: s.id, name: s.name }))
|
||||
})
|
||||
|
||||
// If there are stalls but no active one selected, select the first
|
||||
if (stalls?.length > 0 && !activeStallId.value) {
|
||||
activeStallId.value = stalls[0].id
|
||||
console.log('Set active stall ID to:', stalls[0].id)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load stalls:', error)
|
||||
|
|
@ -1215,26 +1268,15 @@ const createStall = async (formData: any) => {
|
|||
}
|
||||
}
|
||||
|
||||
console.log('Creating stall:', {
|
||||
name,
|
||||
currency,
|
||||
zonesCount: selectedZoneData.length
|
||||
})
|
||||
|
||||
const newStall = await nostrmarketAPI.createStall(
|
||||
currentUser.wallets[0].adminkey,
|
||||
stallData
|
||||
)
|
||||
|
||||
console.log('Stall created successfully:', {
|
||||
stallId: newStall.id,
|
||||
stallName: newStall.name
|
||||
})
|
||||
|
||||
// Update stalls list
|
||||
await loadStallsList()
|
||||
|
||||
// Reset form and close dialog
|
||||
// Reset form and close dialog using standard Shadcn pattern
|
||||
resetForm({
|
||||
values: {
|
||||
name: '',
|
||||
|
|
@ -1247,8 +1289,27 @@ const createStall = async (formData: any) => {
|
|||
cost: 0,
|
||||
selectedCountries: []
|
||||
}
|
||||
},
|
||||
errors: {},
|
||||
touched: {},
|
||||
initialValues: {
|
||||
name: '',
|
||||
description: '',
|
||||
currency: 'sat',
|
||||
wallet: currentUser.wallets[0].id,
|
||||
selectedZones: [],
|
||||
newZone: {
|
||||
name: '',
|
||||
cost: 0,
|
||||
selectedCountries: []
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Force complete dialog re-render
|
||||
dialogKey.value++
|
||||
formKey.value++
|
||||
|
||||
showStallDialog.value = false
|
||||
|
||||
toast.success('Store created successfully! You can now add products.')
|
||||
|
|
@ -1277,6 +1338,12 @@ const viewStallProducts = (stallId: string) => {
|
|||
activeStallId.value = stallId
|
||||
}
|
||||
|
||||
const closeStallDialog = () => {
|
||||
// Reset form and clear errors when closing the dialog
|
||||
stallCreateError.value = null
|
||||
showStallDialog.value = false
|
||||
}
|
||||
|
||||
const navigateToMarket = () => router.push('/market')
|
||||
const viewAllOrders = () => router.push('/market-dashboard?tab=orders')
|
||||
const generateBulkInvoices = () => console.log('Generate bulk invoices')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue