Compare commits

..

No commits in common. "9b48ba73e2e1c0a141d2e102915e0a1c3e8492b5" and "d9de0fdd73a560d960a572c66b37cb780519ad96" have entirely different histories.

View file

@ -428,34 +428,13 @@ watch(
}, },
); );
const { resetForm } = form; const { resetForm, meta } = form;
const isFormValid = computed(
/** Field name -> what the organiser calls it, for the invalid-submit toast. */ () =>
const FIELD_LABELS: Record<string, string> = { meta.value.valid &&
name: "Title", !hasPromoErrors(promoErrors.value) &&
info: "Description", !hasWaveErrors.value,
event_start_date: "Start date", );
event_start_time: "Start time",
event_end_date: "End date",
event_end_time: "End time",
location: "Location",
currency: "Price currency",
payment_methods: "Payment methods",
fiat_currency: "Fiat currency",
amount_tickets: "Tickets",
price_per_ticket: "Price",
notification_subject: "Subject",
notification_body: "Body",
};
/**
* Open whichever collapsible section holds a problem, so the reason is on
* screen rather than hidden behind a closed panel.
*/
function revealSectionFor(field: string) {
if (field === "promo_codes") promoOpen.value = true;
if (field === "ticket_waves") wavesOpen.value = true;
}
const isLoading = ref(false); const isLoading = ref(false);
const today = computed(() => format(new Date(), "yyyy-MM-dd")); const today = computed(() => format(new Date(), "yyyy-MM-dd"));
@ -469,22 +448,8 @@ function toggleCategory(cat: string) {
} }
} }
const onSubmit = form.handleSubmit( const onSubmit = form.handleSubmit(async (formValues) => {
async (formValues) => { if (!isFormValid.value) return;
// Promo codes and ticket waves are not part of the Zod schema, so
// vee-validate cannot block on them. Check here and OPEN the section
// that holds the problem — both editors live inside collapsibles, and
// an error rendered inside a closed one is invisible.
if (hasWaveErrors.value) {
revealSectionFor("ticket_waves");
toastService.error("Check the ticket waves below");
return;
}
if (hasPromoErrors(promoErrors.value)) {
revealSectionFor("promo_codes");
toastService.error("Check the promo codes below");
return;
}
if (!paymentService) { if (!paymentService) {
toastService.error("Payment service not available"); toastService.error("Payment service not available");
@ -503,10 +468,7 @@ const onSubmit = form.handleSubmit(
const eventData: CreateEventRequest = { const eventData: CreateEventRequest = {
name: formValues.name, name: formValues.name,
event_start_date: withLocalTzOffset( event_start_date: withLocalTzOffset(
foldDateTime( foldDateTime(formValues.event_start_date, formValues.event_start_time),
formValues.event_start_date,
formValues.event_start_time,
),
), ),
}; };
if (!isEditMode.value) { if (!isEditMode.value) {
@ -524,9 +486,7 @@ const onSubmit = form.handleSubmit(
} }
if (formValues.location) eventData.location = formValues.location; if (formValues.location) eventData.location = formValues.location;
if (bannerImages.value.length > 0) { if (bannerImages.value.length > 0) {
eventData.banner = imageService.getImageUrl( eventData.banner = imageService.getImageUrl(bannerImages.value[0].alias);
bannerImages.value[0].alias,
);
} else if (isEditMode.value) { } else if (isEditMode.value) {
// User cleared the banner during edit — propagate the null so the // User cleared the banner during edit — propagate the null so the
// backend wipes the field instead of keeping the old image. // backend wipes the field instead of keeping the old image.
@ -641,28 +601,7 @@ const onSubmit = form.handleSubmit(
} finally { } finally {
isLoading.value = false; isLoading.value = false;
} }
}, });
// vee-validate blocks the submit when the schema fails. Say WHY: a field
// whose FormMessage sits inside a closed section — or is not rendered at
// all — otherwise leaves a dead button and no explanation, which is the
// dead end disabling the button used to create.
({ errors }) => {
const fields = Object.keys(errors);
fields.forEach(revealSectionFor);
const named = fields.map((f) => FIELD_LABELS[f] ?? f);
toastService.error(
named.length
? `Check ${named.join(", ")}`
: "Some details still need attention",
);
const first = fields[0];
if (first) {
document
.querySelector(`[name="${first}"], #${CSS.escape(first)}`)
?.scrollIntoView({ behavior: "smooth", block: "center" });
}
},
);
const handleOpenChange = (open: boolean) => { const handleOpenChange = (open: boolean) => {
if (!open && !isLoading.value) { if (!open && !isLoading.value) {
@ -1237,17 +1176,10 @@ const handleOpenChange = (open: boolean) => {
> >
Cancel Cancel
</Button> </Button>
<!-- Disabled only while a submit is genuinely in flight, NOT on
validity. vee-validate's `meta.valid` is false before the form
has ever validated, counts disabled and conditionally rendered
fields against you, and is documented to go stale
(logaretm/vee-validate#4630). Gating on it produced a dead
button with no visible reason; let the click through and the
invalid handler says what is wrong. -->
<Button <Button
type="submit" type="submit"
class="w-full sm:w-auto" class="w-full sm:w-auto"
:disabled="isLoading" :disabled="isLoading || !isFormValid"
> >
<Loader2 v-if="isLoading" class="w-4 h-4 mr-2 animate-spin" /> <Loader2 v-if="isLoading" class="w-4 h-4 mr-2 animate-spin" />
{{ {{