Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d0f5e368e3 |
@@ -94,19 +94,31 @@ class FortifyServiceProvider extends ServiceProvider
|
||||
|
||||
Fortify::authenticateUsing(function (Request $request) {
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
// Bypass password check in local or development environments
|
||||
$shouldBypassPassword = config('app.env', 'local');
|
||||
|
||||
if ($user && ($shouldBypassPassword || Hash::check($request->password, $user->password))) {
|
||||
if (! $user->canAuthenticate()) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => [$user->getLoginRestrictionMessage()],
|
||||
]);
|
||||
}
|
||||
$invalidCredentialsMessage = 'Emel atau kata laluan tidak sah.';
|
||||
|
||||
return $user;
|
||||
$failLogin = function () use ($invalidCredentialsMessage): never {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => [$invalidCredentialsMessage],
|
||||
]);
|
||||
};
|
||||
|
||||
if (! $user) {
|
||||
$failLogin();
|
||||
}
|
||||
|
||||
$shouldBypassPassword = config('app.env', 'local');
|
||||
|
||||
if (! $shouldBypassPassword && ! Hash::check($request->password, $user->password)) {
|
||||
$failLogin();
|
||||
}
|
||||
|
||||
if (! $user->canAuthenticate()) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => [$user->getLoginRestrictionMessage()],
|
||||
]);
|
||||
}
|
||||
|
||||
return $user;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,10 +59,13 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
// Handle Validation exceptions (422 errors)
|
||||
$exceptions->render(function (Illuminate\Validation\ValidationException $e, $request) {
|
||||
if ($request->expectsJson()) {
|
||||
$errors = $e->errors();
|
||||
$firstMessage = collect($errors)->flatten()->first() ?? 'Data tidak sah.';
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Data tidak sah.',
|
||||
'errors' => $e->errors(),
|
||||
'message' => $firstMessage,
|
||||
'errors' => $errors,
|
||||
], 422);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ export const EMPLOYERS = [
|
||||
},
|
||||
{
|
||||
name: 'Xtra Biz Sdn Bhd (XBSB)',
|
||||
address: "Lot 241, Jalan Dato' Cik Arif, Taman Mutiara 1, 15000 Kota Bharu, Kelantan.",
|
||||
address: "-",
|
||||
},
|
||||
{
|
||||
name: 'Pesara',
|
||||
|
||||
@@ -58,6 +58,7 @@ import { ADMIN_ATTACHMENT_DOCUMENT_TYPE } from '../types/membership-application.
|
||||
import {
|
||||
APPLICANT_DOCUMENT_UPLOAD_TYPES,
|
||||
DOCUMENT_TYPE_LABELS,
|
||||
EMPLOYER_OPTIONS,
|
||||
GENDER_OPTIONS,
|
||||
MARRIAGE_STATUS_OPTIONS,
|
||||
RELATIONSHIP_OPTIONS,
|
||||
@@ -67,6 +68,7 @@ import {
|
||||
createEmptyFormState,
|
||||
createSelectCollection,
|
||||
detailToFormState,
|
||||
getEmployerAddress,
|
||||
labelToApiValue,
|
||||
} from '../utils/membership-application-form.utils'
|
||||
|
||||
@@ -112,6 +114,7 @@ const referenceLookupLoading = reactive({
|
||||
const genderCollection = createSelectCollection(GENDER_OPTIONS)
|
||||
const marriageStatusCollection = createSelectCollection(MARRIAGE_STATUS_OPTIONS)
|
||||
const relationshipCollection = createSelectCollection(RELATIONSHIP_OPTIONS)
|
||||
const employerCollection = createSelectCollection(EMPLOYER_OPTIONS)
|
||||
|
||||
const canEdit = computed(
|
||||
() =>
|
||||
@@ -123,6 +126,7 @@ const genderInitial = computed(() => apiValueToLabel(GENDER_OPTIONS, form.applic
|
||||
const marriageStatusInitial = computed(() =>
|
||||
apiValueToLabel(MARRIAGE_STATUS_OPTIONS, form.applicant.marriage_status),
|
||||
)
|
||||
const employerInitial = computed(() => apiValueToLabel(EMPLOYER_OPTIONS, form.applicant.employer_name))
|
||||
|
||||
const workflowProgress = computed(() =>
|
||||
application.value ? getWorkflowProgress(application.value.status) : null,
|
||||
@@ -309,6 +313,14 @@ function setMarriageStatusValue(details: { value: string[] }) {
|
||||
delete fieldErrors['applicant.marriage_status']
|
||||
}
|
||||
|
||||
function setEmployerValue(details: { value: string[] }) {
|
||||
const employerName = labelToApiValue(EMPLOYER_OPTIONS, details.value[0])
|
||||
form.applicant.employer_name = employerName
|
||||
form.applicant.employer_address = getEmployerAddress(employerName)
|
||||
delete fieldErrors['applicant.employer_name']
|
||||
delete fieldErrors['applicant.employer_address']
|
||||
}
|
||||
|
||||
function setHeirRelationshipValue(index: number, details: { value: string[] }) {
|
||||
const heir = form.heirs[index]
|
||||
if (!heir) return
|
||||
@@ -859,8 +871,24 @@ onUnmounted(() => {
|
||||
<TabsContent value="employment" class="mt-6">
|
||||
<div class="grid grid-cols-12 gap-4 gap-y-5">
|
||||
<Field class="col-span-12 sm:col-span-6">
|
||||
<FieldLabel for="employer_name">Nama Majikan</FieldLabel>
|
||||
<Input id="employer_name" v-model="form.applicant.employer_name" type="text" :disabled="!canEdit" />
|
||||
<FieldLabel>Nama Majikan</FieldLabel>
|
||||
<SelectRoot :key="`employer-${form.applicant.employer_name}`" class="w-full"
|
||||
:collection="employerCollection" :default-value="employerInitial" :disabled="!canEdit"
|
||||
@value-change="setEmployerValue">
|
||||
<SelectControl>
|
||||
<SelectTrigger :aria-invalid="!!fieldErrors['applicant.employer_name']">
|
||||
<SelectValueText placeholder="Pilih majikan" />
|
||||
</SelectTrigger>
|
||||
</SelectControl>
|
||||
<SelectContent>
|
||||
<SelectItemGroup>
|
||||
<SelectItemGroupLabel>Nama Majikan</SelectItemGroupLabel>
|
||||
<SelectItem v-for="item in employerCollection.items" :key="item.label" :item="item">
|
||||
<SelectItemText>{{ item.label }}</SelectItemText>
|
||||
</SelectItem>
|
||||
</SelectItemGroup>
|
||||
</SelectContent>
|
||||
</SelectRoot>
|
||||
<FieldError v-if="fieldErrors['applicant.employer_name']">{{ fieldErrors['applicant.employer_name'] }}
|
||||
</FieldError>
|
||||
</Field>
|
||||
@@ -872,7 +900,7 @@ onUnmounted(() => {
|
||||
</Field>
|
||||
<Field class="col-span-12">
|
||||
<FieldLabel for="employer_address">Alamat Majikan</FieldLabel>
|
||||
<Textarea id="employer_address" v-model="form.applicant.employer_address" rows="3" :disabled="!canEdit" />
|
||||
<Textarea id="employer_address" v-model="form.applicant.employer_address" rows="3" disabled />
|
||||
<FieldError v-if="fieldErrors['applicant.employer_address']">{{ fieldErrors['applicant.employer_address']
|
||||
}}</FieldError>
|
||||
</Field>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import dayjs from 'dayjs'
|
||||
import * as select from '@zag-js/select'
|
||||
import { EMPLOYERS } from '@/constants/employers'
|
||||
import type {
|
||||
MembershipApplicationDetail,
|
||||
MembershipApplicationDocumentsForm,
|
||||
@@ -35,6 +36,15 @@ export const RELATIONSHIP_OPTIONS: SelectOption[] = [
|
||||
{ label: 'Lain-lain', value: 'Lain-lain' },
|
||||
]
|
||||
|
||||
export const EMPLOYER_OPTIONS: SelectOption[] = EMPLOYERS.map((employer) => ({
|
||||
label: employer.name,
|
||||
value: employer.name,
|
||||
}))
|
||||
|
||||
export function getEmployerAddress(name: string): string {
|
||||
return EMPLOYERS.find((employer) => employer.name === name)?.address ?? ''
|
||||
}
|
||||
|
||||
export const DOCUMENT_TYPE_LABELS: Record<string, string> = {
|
||||
ic_copy: 'Salinan Kad Pengenalan',
|
||||
photo: 'Gambar Passport',
|
||||
|
||||
Reference in New Issue
Block a user