DONE: use full name for date in letter, include password in email after membership is done, block ic_number to exclude - (#9)
Build Docker Image / build-backend (push) Successful in 44s
Build Docker Image / build-frontend (push) Successful in 18s

Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local>
Reviewed-on: #9
This commit was merged in pull request #9.
This commit is contained in:
2026-07-08 12:15:41 +08:00
parent 18c0d268b1
commit ebd3caecc6
23 changed files with 352 additions and 41 deletions
@@ -22,6 +22,7 @@ import { AlertRoot, AlertDescription, AlertTitle } from '@/components/ui/alert'
import { Lucide } from '@/components/ui/lucide'
import { getApiErrorMessage, getApiValidationErrors } from '@/core/utils/getApiErrorMessage'
import { submitMembershipApplication, lookupMemberByIcNumber } from '../services/membership-application.service'
import { sanitizeIcNumberInput } from '../utils/membership-application-form.utils'
import type {
MembershipApplicationFormState,
MembershipApplicationHeirForm,
@@ -37,7 +38,7 @@ const MIN_FEE_MONTHLY_CONTRIBUTION = 30
const steps = [
{ id: 1, label: 'Maklumat Peribadi' },
{ id: 2, label: 'Hubungan & Alamat' },
{ id: 2, label: 'No. Telefon & Alamat' },
{ id: 3, label: 'Maklumat Pekerjaan' },
{ id: 4, label: 'Maklumat Penama' },
{ id: 5, label: 'Dokumen & Hantar' },
@@ -221,9 +222,22 @@ function clearReference(role: 'proposer' | 'supporter') {
}
function handleReferenceIcInput(role: 'proposer' | 'supporter') {
form.references[role].ic_number = sanitizeIcNumberInput(form.references[role].ic_number)
clearReference(role)
}
function handleApplicantIcInput() {
form.applicant.ic_number = sanitizeIcNumberInput(form.applicant.ic_number)
delete fieldErrors['applicant.ic_number']
}
function handleHeirIcInput(index: number) {
const heir = form.heirs[index]
if (!heir) return
heir.ic_number = sanitizeIcNumberInput(heir.ic_number)
delete fieldErrors[`heirs.${index}.ic_number`]
}
async function lookupReference(role: 'proposer' | 'supporter') {
const reference = form.references[role]
const icNumber = reference.ic_number.trim()
@@ -618,7 +632,8 @@ function stepLabelClass(stepId: number) {
</Field>
<Field class="col-span-12 sm:col-span-6">
<FieldLabel for="ic_number">No. Kad Pengenalan</FieldLabel>
<Input id="ic_number" v-model="form.applicant.ic_number" type="text" />
<Input id="ic_number" v-model="form.applicant.ic_number" type="text" inputmode="numeric" maxlength="15"
placeholder="Contoh: 900101011234" @input="handleApplicantIcInput" />
<FieldError v-if="fieldErrors['applicant.ic_number']">{{ fieldErrors['applicant.ic_number'] }}
</FieldError>
</Field>
@@ -800,7 +815,8 @@ function stepLabelClass(stepId: number) {
</Field>
<Field class="col-span-12 sm:col-span-6">
<FieldLabel :for="`heir-ic-${index}`">No. Kad Pengenalan</FieldLabel>
<Input :id="`heir-ic-${index}`" v-model="heir.ic_number" type="text" />
<Input :id="`heir-ic-${index}`" v-model="heir.ic_number" type="text" inputmode="numeric"
maxlength="15" placeholder="Contoh: 900101011234" @input="handleHeirIcInput(index)" />
<FieldError v-if="fieldErrors[`heirs.${index}.ic_number`]">
{{ fieldErrors[`heirs.${index}.ic_number`] }}
</FieldError>
@@ -857,8 +873,9 @@ function stepLabelClass(stepId: number) {
<Field class="col-span-12 sm:col-span-6">
<FieldLabel for="proposer_ic_number">No. KP Pencadang</FieldLabel>
<Input id="proposer_ic_number" v-model="form.references.proposer.ic_number" type="text"
placeholder="Contoh: 900101011234" :disabled="referenceLookupLoading.proposer"
@input="handleReferenceIcInput('proposer')" @blur="lookupReference('proposer')" />
inputmode="numeric" maxlength="12" placeholder="Contoh: 900101011234"
:disabled="referenceLookupLoading.proposer" @input="handleReferenceIcInput('proposer')"
@blur="lookupReference('proposer')" />
<p v-if="form.references.proposer.name" class="mt-1 text-sm text-success">
{{ form.references.proposer.name }}
</p>
@@ -870,8 +887,9 @@ function stepLabelClass(stepId: number) {
<Field class="col-span-12 sm:col-span-6">
<FieldLabel for="supporter_ic_number">No. KP Penyokong</FieldLabel>
<Input id="supporter_ic_number" v-model="form.references.supporter.ic_number" type="text"
placeholder="Contoh: 850505055678" :disabled="referenceLookupLoading.supporter"
@input="handleReferenceIcInput('supporter')" @blur="lookupReference('supporter')" />
inputmode="numeric" maxlength="12" placeholder="Contoh: 850505055678"
:disabled="referenceLookupLoading.supporter" @input="handleReferenceIcInput('supporter')"
@blur="lookupReference('supporter')" />
<p v-if="form.references.supporter.name" class="mt-1 text-sm text-success">
{{ form.references.supporter.name }}
</p>
@@ -907,7 +925,7 @@ function stepLabelClass(stepId: number) {
<Input id="employer_letter" type="file" accept=".pdf,.jpg,.jpeg,.png"
@change="handleFileChange('employer_letter', $event)" />
<FieldError v-if="fieldErrors['documents.employer_letter']">{{ fieldErrors['documents.employer_letter']
}}</FieldError>
}}</FieldError>
</Field>
<div class="col-span-12 mt-2 rounded-lg border border-foreground/10 bg-foreground/5 p-4">