feat: add required fields for signing city and signature to subscription process
This commit is contained in:
parent
b47a517bd5
commit
ba28c54ae8
@ -6,9 +6,11 @@ type Props = {
|
|||||||
value: string
|
value: string
|
||||||
onChange: (dataUrl: string) => void
|
onChange: (dataUrl: string) => void
|
||||||
className?: string
|
className?: string
|
||||||
|
required?: boolean
|
||||||
|
error?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SignaturePad({ value, onChange, className }: Props) {
|
export default function SignaturePad({ value, onChange, className, required = false, error = null }: Props) {
|
||||||
const canvasRef = useRef<HTMLCanvasElement | null>(null)
|
const canvasRef = useRef<HTMLCanvasElement | null>(null)
|
||||||
const isDrawing = useRef(false)
|
const isDrawing = useRef(false)
|
||||||
|
|
||||||
@ -137,7 +139,9 @@ export default function SignaturePad({ value, onChange, className }: Props) {
|
|||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<div className="flex items-center justify-between gap-2 mb-2">
|
<div className="flex items-center justify-between gap-2 mb-2">
|
||||||
<p className="text-sm font-medium text-gray-900">Signature</p>
|
<p className="text-sm font-medium text-gray-900">
|
||||||
|
Signature{required ? ' *' : ''}
|
||||||
|
</p>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={clear}
|
onClick={clear}
|
||||||
@ -146,7 +150,7 @@ export default function SignaturePad({ value, onChange, className }: Props) {
|
|||||||
Clear
|
Clear
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-lg border border-gray-300 bg-white">
|
<div className={`rounded-lg border bg-white ${error ? 'border-red-400 ring-1 ring-red-200' : 'border-gray-300'}`}>
|
||||||
<canvas
|
<canvas
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
className="block w-full h-36 touch-none"
|
className="block w-full h-36 touch-none"
|
||||||
@ -159,8 +163,8 @@ export default function SignaturePad({ value, onChange, className }: Props) {
|
|||||||
onTouchEnd={endDrawing}
|
onTouchEnd={endDrawing}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-2 text-xs text-gray-500">
|
<p className={`mt-2 text-xs ${error ? 'text-red-700' : 'text-gray-500'}`}>
|
||||||
{value ? 'Signature captured.' : 'Draw your signature in the box.'}
|
{error || (value ? 'Signature captured.' : 'Draw your signature in the box.')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -70,6 +70,14 @@ export async function subscribeAbo(input: SubscribeAboInput) {
|
|||||||
throw new Error(`Missing required fields: ${missing.join(', ')}`)
|
throw new Error(`Missing required fields: ${missing.join(', ')}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof input.signingCity !== 'string' || input.signingCity.trim() === '') {
|
||||||
|
throw new Error('signingCity is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof input.signatureDataUrl !== 'string' || input.signatureDataUrl.trim() === '') {
|
||||||
|
throw new Error('signatureDataUrl is required')
|
||||||
|
}
|
||||||
|
|
||||||
const body: any = {
|
const body: any = {
|
||||||
billing_interval: input.billing_interval ?? 'month',
|
billing_interval: input.billing_interval ?? 'month',
|
||||||
interval_count: input.interval_count ?? 1,
|
interval_count: input.interval_count ?? 1,
|
||||||
|
|||||||
@ -510,12 +510,16 @@ export default function SummaryPage() {
|
|||||||
|
|
||||||
const hasRequiredSelfFields = requiredSelfFields.every(k => String(form[k]).trim() !== '')
|
const hasRequiredSelfFields = requiredSelfFields.every(k => String(form[k]).trim() !== '')
|
||||||
const hasRequiredInvoiceFields = form.invoiceSameAsShipping || form.invoiceEmail.trim() !== ''
|
const hasRequiredInvoiceFields = form.invoiceSameAsShipping || form.invoiceEmail.trim() !== ''
|
||||||
|
const hasSigningCity = form.signingCity.trim() !== ''
|
||||||
|
const hasSignature = signatureDataUrl.trim() !== ''
|
||||||
|
|
||||||
const canSubmit =
|
const canSubmit =
|
||||||
selectedEntries.length > 0 &&
|
selectedEntries.length > 0 &&
|
||||||
totalPacks === requiredPacks &&
|
totalPacks === requiredPacks &&
|
||||||
hasRequiredSelfFields &&
|
hasRequiredSelfFields &&
|
||||||
hasRequiredInvoiceFields;
|
hasRequiredInvoiceFields &&
|
||||||
|
hasSigningCity &&
|
||||||
|
hasSignature;
|
||||||
|
|
||||||
const backToSelection = () => router.push('/coffee-abonnements');
|
const backToSelection = () => router.push('/coffee-abonnements');
|
||||||
|
|
||||||
@ -527,6 +531,16 @@ export default function SummaryPage() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasSigningCity) {
|
||||||
|
setSubmitError('Signing city is required.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasSignature) {
|
||||||
|
setSubmitError('Signature is required.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
setSubmitError(null)
|
setSubmitError(null)
|
||||||
setSubmitLoading(true)
|
setSubmitLoading(true)
|
||||||
try {
|
try {
|
||||||
@ -781,10 +795,13 @@ export default function SummaryPage() {
|
|||||||
|
|
||||||
<div className="mt-4 space-y-3">
|
<div className="mt-4 space-y-3">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium mb-1">Ort (Signing City)</label>
|
<label className="block text-sm font-medium mb-1">Ort (Signing City) *</label>
|
||||||
<input type="text" name="signingCity" value={form.signingCity} onChange={handleInput} className="w-full max-w-xs rounded border px-3 py-2 bg-white border-gray-300 focus:outline-none focus:ring-2 focus:ring-[#1C2B4A]" placeholder="z.B. Wien" />
|
<input type="text" name="signingCity" value={form.signingCity} onChange={handleInput} className={`w-full max-w-xs rounded border px-3 py-2 bg-white focus:outline-none focus:ring-2 focus:ring-[#1C2B4A] ${!hasSigningCity && submitError ? 'border-red-400' : 'border-gray-300'}`} placeholder="z.B. Wien" />
|
||||||
|
{!hasSigningCity && submitError && (
|
||||||
|
<p className="mt-1 text-xs text-red-700">Ort ist erforderlich.</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<SignaturePad value={signatureDataUrl} onChange={setSignatureDataUrl} />
|
<SignaturePad value={signatureDataUrl} onChange={setSignatureDataUrl} required error={!hasSignature && submitError ? 'Signature is required.' : null} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -838,7 +855,7 @@ export default function SummaryPage() {
|
|||||||
</button>
|
</button>
|
||||||
{!canSubmit && (
|
{!canSubmit && (
|
||||||
<p className="text-xs text-gray-500 mt-2">
|
<p className="text-xs text-gray-500 mt-2">
|
||||||
Please select coffees and fill all required buyer fields.
|
Please select coffees and fill all required buyer fields, signing city, and signature.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user