admin/components/events/create/steps/Step3PricingCapacity.tsx

204 lines
8.1 KiB
TypeScript

'use client'
import { zodResolver } from '@hookform/resolvers/zod'
import { useEffect } from 'react'
import { FormProvider, useForm } from 'react-hook-form'
import { texts } from '@/texts'
import type { EventWizardFormData } from '@/components/events/create/types'
import AudienceRestrictionSelector from '@/components/events/create/AudienceRestrictionSelector'
import CancellationPolicyEditor from '@/components/events/create/CancellationPolicyEditor'
import TicketTypeSelector from '@/components/events/create/TicketTypeSelector'
import Input from '@/components/formElements/Input'
import { WizardFormFullWidth, WizardFormGrid, WizardSectionTitle, WizardStepFooter } from '@/components/events/create/WizardFormLayout'
import { EventWizardStep3Validation, type EventWizardStep3Values } from '@/validation/eventWizard'
import { showFormValidationToast } from '@/lib/formValidationToast'
interface Step3PricingCapacityProps {
data: EventWizardFormData
onBack: () => void
onChange: (patch: Partial<EventWizardFormData>) => void
onNext: (patch: Partial<EventWizardFormData>) => void
}
export default function Step3PricingCapacity({ data, onBack, onChange, onNext }: Step3PricingCapacityProps) {
const form = useForm<EventWizardStep3Values>({
resolver: zodResolver(EventWizardStep3Validation),
defaultValues: {
isFree: data.isFree,
price: data.price,
capacity: data.capacity,
reservedCapacity: data.reservedCapacity,
genderRestriction: data.genderRestriction,
ageRestriction: data.ageRestriction,
cancellationFeePercent: data.cancellationFeePercent,
cancellationFeePercent12To24Hours: data.cancellationFeePercent12To24Hours,
cancellationFeePercentMoreThan24Hours: data.cancellationFeePercentMoreThan24Hours,
isDiscoverable: data.isDiscoverable,
autoCreateGroup: data.autoCreateGroup,
waitlistAutoOffer: data.waitlistAutoOffer,
sendReviewRequestSms: data.sendReviewRequestSms,
},
})
const isFree = form.watch('isFree')
useEffect(() => {
const subscription = form.watch((values) => {
onChange({
isFree: values.isFree ?? false,
price: Number(values.price ?? 0),
capacity: Number(values.capacity ?? 0),
reservedCapacity: Number(values.reservedCapacity ?? 0),
genderRestriction: values.genderRestriction ?? 'open',
ageRestriction: values.ageRestriction ?? 'open',
cancellationFeePercent: Number(values.cancellationFeePercent ?? 0),
cancellationFeePercent12To24Hours: Number(values.cancellationFeePercent12To24Hours ?? 0),
cancellationFeePercentMoreThan24Hours: Number(values.cancellationFeePercentMoreThan24Hours ?? 0),
isDiscoverable: values.isDiscoverable ?? false,
autoCreateGroup: values.autoCreateGroup ?? true,
waitlistAutoOffer: values.waitlistAutoOffer ?? true,
sendReviewRequestSms: values.sendReviewRequestSms ?? false,
})
})
return () => {
subscription.unsubscribe()
}
}, [form, onChange])
const handleSubmit = form.handleSubmit((values) => {
onNext({
isFree: values.isFree,
price: values.isFree ? 0 : values.price,
capacity: values.capacity,
reservedCapacity: values.reservedCapacity,
genderRestriction: values.genderRestriction,
ageRestriction: values.ageRestriction,
cancellationFeePercent: values.cancellationFeePercent,
cancellationFeePercent12To24Hours: values.cancellationFeePercent12To24Hours,
cancellationFeePercentMoreThan24Hours: values.cancellationFeePercentMoreThan24Hours,
isDiscoverable: values.isDiscoverable,
autoCreateGroup: values.autoCreateGroup,
waitlistAutoOffer: values.waitlistAutoOffer,
sendReviewRequestSms: values.sendReviewRequestSms,
})
}, showFormValidationToast)
return (
<FormProvider {...form}>
<form onSubmit={handleSubmit}>
<WizardFormGrid>
<WizardSectionTitle description={texts.events.pricingSectionDescription}>
{texts.events.ticketTypeSectionTitle}
</WizardSectionTitle>
<WizardFormFullWidth>
<TicketTypeSelector
isFree={isFree}
onChange={(nextIsFree) => {
form.setValue('isFree', nextIsFree, { shouldDirty: true, shouldValidate: true })
}}
/>
</WizardFormFullWidth>
{!isFree ? (
<Input
required
formatOptions={{ style: 'decimal' }}
generalType="numberInput"
label={texts.events.pricePerTicketLabel}
minValue={0}
name="price"
/>
) : null}
<Input
required
generalType="numberInput"
label={texts.events.capacity}
minValue={1}
name="capacity"
/>
<WizardFormFullWidth>
<Input
generalType="numberInput"
label={texts.events.reservedCapacityLabel}
minValue={0}
name="reservedCapacity"
/>
<p className="mt-2 text-xs text-secondary-20">{texts.events.reservedCapacityWizardHint}</p>
</WizardFormFullWidth>
<WizardSectionTitle description={texts.events.audienceSectionDescription}>{texts.events.audienceSectionTitle}</WizardSectionTitle>
<WizardFormFullWidth>
<AudienceRestrictionSelector
ageRestriction={form.watch('ageRestriction')}
genderRestriction={form.watch('genderRestriction')}
onAgeRestrictionChange={(ageRestriction) => {
form.setValue('ageRestriction', ageRestriction, { shouldDirty: true, shouldValidate: true })
}}
onGenderRestrictionChange={(genderRestriction) => {
form.setValue('genderRestriction', genderRestriction, { shouldDirty: true, shouldValidate: true })
}}
/>
</WizardFormFullWidth>
<WizardSectionTitle description={texts.events.cancellationSectionDescription}>
{texts.events.cancellationSectionTitle}
</WizardSectionTitle>
<WizardFormFullWidth>
<CancellationPolicyEditor
cancellationFeePercent={form.watch('cancellationFeePercent')}
cancellationFeePercent12To24Hours={form.watch('cancellationFeePercent12To24Hours')}
cancellationFeePercentMoreThan24Hours={form.watch('cancellationFeePercentMoreThan24Hours')}
onChange={(field, value) => {
form.setValue(field, value, { shouldDirty: true, shouldValidate: true })
}}
/>
</WizardFormFullWidth>
<WizardFormFullWidth>
<details className="group rounded-2xl border border-consumer-border bg-consumer-surface-muted p-4">
<summary className="cursor-pointer list-none text-sm font-bold text-consumer-text marker:hidden">
{texts.events.moreSettings}
<span className="me-2 text-xs font-normal text-secondary-20">{texts.events.advancedSettingsHint}</span>
</summary>
<div className="mt-4 grid gap-5 border-t border-consumer-border pt-4 md:grid-cols-2">
<Input
generalType="switch"
label={texts.events.discoverableLabel}
name="isDiscoverable"
/>
<Input
generalType="switch"
label={texts.events.autoCreateGroupLabel}
name="autoCreateGroup"
/>
<Input
generalType="switch"
label={texts.events.waitlistAutoOfferLabel}
name="waitlistAutoOffer"
/>
<Input
generalType="switch"
label={texts.events.sendReviewSmsLabel}
name="sendReviewRequestSms"
/>
</div>
</details>
</WizardFormFullWidth>
<WizardStepFooter
primaryLabel={texts.events.nextStep}
onBack={onBack}
onPrimary={handleSubmit}
/>
</WizardFormGrid>
</form>
</FormProvider>
)
}