Merge pull request 'feat: add required fields for signing city and signature to subscription process' (#18) from bigTypeShii into dev
Reviewed-on: #18
This commit is contained in:
commit
17f4bc12b8
@ -6,9 +6,11 @@ type Props = {
|
||||
value: string
|
||||
onChange: (dataUrl: string) => void
|
||||
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 isDrawing = useRef(false)
|
||||
|
||||
@ -137,7 +139,9 @@ export default function SignaturePad({ value, onChange, className }: Props) {
|
||||
return (
|
||||
<div className={className}>
|
||||
<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
|
||||
type="button"
|
||||
onClick={clear}
|
||||
@ -146,7 +150,7 @@ export default function SignaturePad({ value, onChange, className }: Props) {
|
||||
Clear
|
||||
</button>
|
||||
</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
|
||||
ref={canvasRef}
|
||||
className="block w-full h-36 touch-none"
|
||||
@ -159,8 +163,8 @@ export default function SignaturePad({ value, onChange, className }: Props) {
|
||||
onTouchEnd={endDrawing}
|
||||
/>
|
||||
</div>
|
||||
<p className="mt-2 text-xs text-gray-500">
|
||||
{value ? 'Signature captured.' : 'Draw your signature in the box.'}
|
||||
<p className={`mt-2 text-xs ${error ? 'text-red-700' : 'text-gray-500'}`}>
|
||||
{error || (value ? 'Signature captured.' : 'Draw your signature in the box.')}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -70,6 +70,14 @@ export async function subscribeAbo(input: SubscribeAboInput) {
|
||||
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 = {
|
||||
billing_interval: input.billing_interval ?? 'month',
|
||||
interval_count: input.interval_count ?? 1,
|
||||
|
||||
@ -510,12 +510,16 @@ export default function SummaryPage() {
|
||||
|
||||
const hasRequiredSelfFields = requiredSelfFields.every(k => String(form[k]).trim() !== '')
|
||||
const hasRequiredInvoiceFields = form.invoiceSameAsShipping || form.invoiceEmail.trim() !== ''
|
||||
const hasSigningCity = form.signingCity.trim() !== ''
|
||||
const hasSignature = signatureDataUrl.trim() !== ''
|
||||
|
||||
const canSubmit =
|
||||
selectedEntries.length > 0 &&
|
||||
totalPacks === requiredPacks &&
|
||||
hasRequiredSelfFields &&
|
||||
hasRequiredInvoiceFields;
|
||||
hasRequiredInvoiceFields &&
|
||||
hasSigningCity &&
|
||||
hasSignature;
|
||||
|
||||
const backToSelection = () => router.push('/coffee-abonnements');
|
||||
|
||||
@ -527,6 +531,16 @@ export default function SummaryPage() {
|
||||
return
|
||||
}
|
||||
|
||||
if (!hasSigningCity) {
|
||||
setSubmitError('Signing city is required.')
|
||||
return
|
||||
}
|
||||
|
||||
if (!hasSignature) {
|
||||
setSubmitError('Signature is required.')
|
||||
return
|
||||
}
|
||||
|
||||
setSubmitError(null)
|
||||
setSubmitLoading(true)
|
||||
try {
|
||||
@ -781,10 +795,13 @@ export default function SummaryPage() {
|
||||
|
||||
<div className="mt-4 space-y-3">
|
||||
<div>
|
||||
<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" />
|
||||
<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 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>
|
||||
<SignaturePad value={signatureDataUrl} onChange={setSignatureDataUrl} />
|
||||
<SignaturePad value={signatureDataUrl} onChange={setSignatureDataUrl} required error={!hasSignature && submitError ? 'Signature is required.' : null} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -838,7 +855,7 @@ export default function SummaryPage() {
|
||||
</button>
|
||||
{!canSubmit && (
|
||||
<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>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user