Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split the Porting Embed Form into a Wizard #4

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions lib/PortingEmbed/EmbedField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type Props = {
children: React.ReactNode
}

export function EmbedField({ children }: Props) {
// TODO: customizable classNames
return (
<div className="GigsEmbeds GigsPortingEmbed GigsEmbeds-field">
{children}
</div>
)
}
16 changes: 16 additions & 0 deletions lib/PortingEmbed/EmbedFieldError.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
type Props = {
error: string
}

export function EmbedFieldError({ error }: Props) {
if (!error) {
return null
}

// TODO: customizable classNames
return (
<div className="GigsEmbeds GigsPortingEmbed GigsEmbeds-fieldError">
{error}
</div>
)
}
11 changes: 11 additions & 0 deletions lib/PortingEmbed/EmbedFieldInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type Props = React.HTMLAttributes<HTMLInputElement>

export function EmbedFieldInput(props: Props) {
// TODO: customizable classNames
return (
<input
className="GigsEmbeds GigsPortingEmbed GigsEmbeds-fieldInput"
{...props}
/>
)
}
11 changes: 11 additions & 0 deletions lib/PortingEmbed/EmbedFieldLabel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type Props = React.HTMLAttributes<HTMLLabelElement>

export function EmbedFieldLabel(props: Props) {
// TODO: customizable classNames
return (
<label
className="GigsEmbeds GigsPortingEmbed GigsEmbeds-fieldLabel"
{...props}
/>
)
}
2 changes: 1 addition & 1 deletion lib/PortingEmbed/PortingEmbed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function PortingEmbed({
onValidationChange,
}: PortingEmbedProps) {
return (
<div className="__gigsPortingEmbed">
<div className="__ge_portingRoot">
<PortingForm
porting={porting}
onValidationChange={onValidationChange}
Expand Down
155 changes: 58 additions & 97 deletions lib/PortingEmbed/PortingForm.tsx
Original file line number Diff line number Diff line change
@@ -1,112 +1,73 @@
import { required, useForm } from '@modular-forms/preact'
import { useSignalEffect } from '@preact/signals'

import { Porting } from '../types'
import { sanitizeSubmitData } from './sanitizeSubmitData'
import { StepAddressForm, StepAddressFormData } from './StepAddressForm'
import {
StepCarrierDetailsForm,
StepCarrierDetailsFormData,
} from './StepCarrierDetailsForm'
import {
StepDonorProviderApprovalForm,
StepDonorProviderApprovalFormData,
} from './StepDonorProviderApprovalForm'
import {
StepHolderDetailsForm,
StepHolderDetailsFormData,
} from './StepHolderDetailsForm'
import { wizardStep } from './wizardStep'

type Props = {
porting: Porting
onValidationChange?: (event: { isValid: boolean }) => unknown
onSubmit: (data: Partial<PortingForm>) => unknown
onSubmit: (data: Partial<PortingFormData>) => unknown
}

type PortingForm = {
accountPin: string
accountNumber: string
birthday: string
firstName: string
lastName: string
}
type PortingFormData =
| StepCarrierDetailsFormData
| StepHolderDetailsFormData
| { address?: StepAddressFormData }
| StepDonorProviderApprovalFormData

export function PortingForm({ porting, onValidationChange, onSubmit }: Props) {
const [portingForm, { Form, Field }] = useForm<PortingForm>({
initialValues: {
accountNumber: porting.accountNumber || '',
accountPin: '',
birthday: porting.birthday || '',
firstName: porting.firstName || '',
lastName: porting.lastName || '',
},
validateOn: 'blur',
})

useSignalEffect(() => {
const isValid = !portingForm.invalid.value
onValidationChange?.({ isValid })
})
const step = wizardStep(porting)

return (
<Form
id="gigsPortingEmbedForm" // TODO: make customizable
role="form"
shouldDirty // only include changed fields in the onSubmit handler
onSubmit={(data) => {
const sanitizedData = sanitizeSubmitData(data)
return onSubmit(sanitizedData)
}}
>
<Field name="accountNumber" validate={[required('Please enter')]}>
{(field, props) => (
<div>
<label for="accountNumber">Account Number</label>
<input
id="accountNumber"
type="text"
value={field.value}
{...props}
/>
{field.error && <div>{field.error}</div>}
</div>
)}
</Field>
if (step === 'carrierDetails') {
return (
<StepCarrierDetailsForm
porting={porting}
onValidationChange={onValidationChange}
onSubmit={(data) => onSubmit(data)}
/>
)
}

<Field
name="accountPin"
validate={porting.accountPinExists ? [] : [required('Please enter')]}
>
{(field, props) => (
<div>
<label for="accountPin">Account PIN</label>
<input
id="accountPin"
type="text"
placeholder={porting.accountPinExists ? '••••' : undefined}
{...props}
/>
{field.error && <div>{field.error}</div>}
</div>
)}
</Field>
if (step === 'holderDetails') {
return (
<StepHolderDetailsForm
porting={porting}
onValidationChange={onValidationChange}
onSubmit={(data) => onSubmit(data)}
/>
)
}

<Field name="birthday" validate={[required('Please enter')]}>
{(field, props) => (
<div>
<label for="birthday">Birthday</label>
<input id="birthday" type="text" value={field.value} {...props} />
{field.error && <div>{field.error}</div>}
</div>
)}
</Field>
if (step === 'address') {
return (
<StepAddressForm
porting={porting}
onValidationChange={onValidationChange}
onSubmit={(data) => onSubmit({ address: data })}
/>
)
}

<Field name="firstName" validate={[required('Please enter')]}>
{(field, props) => (
<div>
<label for="firstName">First Name</label>
<input id="firstName" type="text" value={field.value} {...props} />
{field.error && <div>{field.error}</div>}
</div>
)}
</Field>
if (step === 'donorApproval') {
return (
<StepDonorProviderApprovalForm
porting={porting}
onValidationChange={onValidationChange}
onSubmit={(data) => onSubmit(data)}
/>
)
}

<Field name="lastName" validate={[required('Please enter')]}>
{(field, props) => (
<div>
<label for="lastName">Last Name</label>
<input id="lastName" type="text" value={field.value} {...props} />
{field.error && <div>{field.error}</div>}
</div>
)}
</Field>
</Form>
)
return null
}
Loading