Merge branch 'dev/phat-2' into develop

This commit is contained in:
puriphatt 2024-04-18 09:07:22 +07:00
commit 2869780234
8 changed files with 151 additions and 108 deletions

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from 'vue'; import { onMounted, ref, watch, reactive } from 'vue';
import useAddressStore, { import useAddressStore, {
District, District,
Province, Province,
@ -22,60 +22,44 @@ const addressEN = defineModel('addressEN', { default: '' });
const provinceId = defineModel<string | null | undefined>('provinceId'); const provinceId = defineModel<string | null | undefined>('provinceId');
const districtId = defineModel<string | null | undefined>('districtId'); const districtId = defineModel<string | null | undefined>('districtId');
const subDistrictId = defineModel<string | null | undefined>('subDistrictId'); const subDistrictId = defineModel<string | null | undefined>('subDistrictId');
const zipCode = defineModel<string>('zipCode', { default: '' }); const zipCode = defineModel<string | null | undefined>('zipCode');
const isOpen = defineModel<boolean>('isOpen', { default: false });
const addrOptions = ref<{ const addrOptions = reactive<{
provinceOps?: Province[]; provinceOps: Province[];
districtOps?: District[]; districtOps: District[];
subDistrictOps?: SubDistrict[]; subDistrictOps: SubDistrict[];
}>({}); }>({
provinceOps: [],
districtOps: [],
subDistrictOps: [],
});
async function fetchProvince() { async function fetchProvince() {
const result = await adrressStore.fetchProvince(); const result = await adrressStore.fetchProvince();
if (result) {
addrOptions.value.provinceOps = result; if (result) addrOptions.provinceOps = result;
}
} }
async function fetchDistrict(id: string | undefined) { async function fetchDistrict() {
if (id) { if (!provinceId.value) return;
const result = await adrressStore.fetchDistrictByProvinceId(id);
if (result) { const result = await adrressStore.fetchDistrictByProvinceId(provinceId.value);
addrOptions.value.districtOps = result; if (result) addrOptions.districtOps = result;
}
}
} }
async function fetchSubDistrict(id: string | undefined) { async function fetchSubDistrict() {
if (id) { if (!districtId.value) return;
const result = await adrressStore.fetchSubDistrictByProvinceId(id); const result = await adrressStore.fetchSubDistrictByProvinceId(
if (result) { districtId.value,
addrOptions.value.subDistrictOps = result; );
} if (result) addrOptions.subDistrictOps = result;
}
}
async function selectProvince(id: string) {
if (!id) return;
districtId.value = undefined;
subDistrictId.value = undefined;
addrOptions.value.districtOps = [];
addrOptions.value.subDistrictOps = [];
zipCode.value = '';
await fetchDistrict(id);
}
async function selectDistrict(id: string) {
if (!id) return;
subDistrictId.value = undefined;
zipCode.value = '';
await fetchSubDistrict(id);
} }
async function selectSubDistrict(id: string) { async function selectSubDistrict(id: string) {
if (!id) return; if (!id) return;
zipCode.value = zipCode.value =
addrOptions.value.subDistrictOps addrOptions.subDistrictOps
?.filter((x) => x.id === id) ?.filter((x) => x.id === id)
.map((x) => x.zipCode)[0] ?? ''; .map((x) => x.zipCode)[0] ?? '';
} }
@ -83,6 +67,10 @@ async function selectSubDistrict(id: string) {
onMounted(async () => { onMounted(async () => {
await fetchProvince(); await fetchProvince();
}); });
watch(isOpen, fetchDistrict);
watch(provinceId, fetchDistrict);
watch(districtId, fetchSubDistrict);
</script> </script>
<template> <template>
<div class="col-12 app-text-muted"> <div class="col-12 app-text-muted">
@ -123,12 +111,12 @@ onMounted(async () => {
:label="$t('province')" :label="$t('province')"
class="col-3" class="col-3"
:options="addrOptions.provinceOps" :options="addrOptions.provinceOps"
@update:model-value="(v: string) => selectProvince(v)"
lazy-rules lazy-rules
:rules="[ :rules="[
(val) => (val) =>
(val && val.length > 0) || $t('formDialogInputProvinceValidate'), (val && val.length > 0) || $t('formDialogInputProvinceValidate'),
]" ]"
@update:model-value="districtId = subDistrictId = zipCode = null"
/> />
<q-select <q-select
:dense="dense" :dense="dense"
@ -145,12 +133,12 @@ onMounted(async () => {
:label="$t('district')" :label="$t('district')"
class="col-3" class="col-3"
:options="addrOptions.districtOps" :options="addrOptions.districtOps"
@update:model-value="(v: string) => selectDistrict(v)"
lazy-rules lazy-rules
:rules="[ :rules="[
(val) => (val) =>
(val && val.length > 0) || $t('formDialogInputDistrictValidate'), (val && val.length > 0) || $t('formDialogInputDistrictValidate'),
]" ]"
@update:model-value="subDistrictId = zipCode = null"
/> />
<q-select <q-select
:dense="dense" :dense="dense"
@ -161,18 +149,22 @@ onMounted(async () => {
emit-value emit-value
map-options map-options
id="select-sub-district" id="select-sub-district"
v-model="subDistrictId" :model-value="
addrOptions.subDistrictOps.length === 1
? (subDistrictId = addrOptions.subDistrictOps[0].id)
: ''
"
option-value="id" option-value="id"
option-label="name" option-label="name"
:label="$t('subDistrict')" :label="$t('subDistrict')"
class="col-3" class="col-3"
:options="addrOptions.subDistrictOps" :options="addrOptions.subDistrictOps"
@update:model-value="(v: string) => selectSubDistrict(v)"
lazy-rules lazy-rules
:rules="[ :rules="[
(val) => (val) =>
(val && val.length > 0) || $t('formDialogInputSubDistrictValidate'), (val && val.length > 0) || $t('formDialogInputSubDistrictValidate'),
]" ]"
@update:model-value="(v: string) => selectSubDistrict(v)"
/> />
<q-input <q-input
:dense="dense" :dense="dense"
@ -217,7 +209,6 @@ onMounted(async () => {
:label="$t('province')" :label="$t('province')"
class="col-3" class="col-3"
:options="addrOptions.provinceOps" :options="addrOptions.provinceOps"
@update:model-value="(v: string) => selectProvince(v)"
/> />
<q-select <q-select
:dense="dense" :dense="dense"
@ -233,7 +224,6 @@ onMounted(async () => {
:label="$t('district')" :label="$t('district')"
class="col-3" class="col-3"
:options="addrOptions.districtOps" :options="addrOptions.districtOps"
@update:model-value="(v: string) => selectDistrict(v)"
/> />
<q-select <q-select
:dense="dense" :dense="dense"

View file

@ -8,7 +8,9 @@ const userType = defineModel<string>('userType');
const registrationNo = defineModel<string | null>('registrationNo'); const registrationNo = defineModel<string | null>('registrationNo');
const startDate = defineModel<Date | null>('startDate'); const startDate = defineModel<Date | null>('startDate');
const retireDate = defineModel<Date | null>('retireDate'); const retireDate = defineModel<Date | null>('retireDate');
const responsibleArea = defineModel<string>('responsibleArea'); const responsibleArea = defineModel<string | null | undefined>(
'responsibleArea',
);
const discountCondition = defineModel<string | null | undefined>( const discountCondition = defineModel<string | null | undefined>(
'discountCondition', 'discountCondition',
); );
@ -137,7 +139,6 @@ defineProps<{
options-dense options-dense
label="พื้นที่ ที่รับผิดชอบในการส่งเอกสาร" label="พื้นที่ ที่รับผิดชอบในการส่งเอกสาร"
class="col-12" class="col-12"
bg-color="white"
option-label="label" option-label="label"
option-value="value" option-value="value"
v-model="responsibleArea" v-model="responsibleArea"
@ -174,7 +175,6 @@ defineProps<{
options-dense options-dense
label="สัญชาติต้นทาง" label="สัญชาติต้นทาง"
class="col-3" class="col-3"
bg-color="white"
option-label="label" option-label="label"
option-value="label" option-value="label"
v-model="sourceNationality" v-model="sourceNationality"

View file

@ -7,7 +7,7 @@ const hqId = defineModel<string | null | undefined>('hqId');
const brId = defineModel<string | null | undefined>('brId'); const brId = defineModel<string | null | undefined>('brId');
const userType = defineModel<string>('userType'); const userType = defineModel<string>('userType');
const userRole = defineModel<string>('userRole'); const userRole = defineModel<string>('userRole');
const userName = defineModel<string | null | undefined>('userName'); const username = defineModel<string | null | undefined>('username');
const userCode = defineModel<string>('userCode'); const userCode = defineModel<string>('userCode');
defineProps<{ defineProps<{
@ -15,6 +15,7 @@ defineProps<{
outlined?: boolean; outlined?: boolean;
readonly?: boolean; readonly?: boolean;
separator?: boolean; separator?: boolean;
usernameReadonly?: boolean;
}>(); }>();
async function selectHq(id: string) { async function selectHq(id: string) {
@ -37,7 +38,6 @@ async function selectHq(id: string) {
options-dense options-dense
hide-bottom-space hide-bottom-space
class="col-6" class="col-6"
bg-color="white"
option-label="label" option-label="label"
option-value="value" option-value="value"
label="รหัสสำนักงานใหญ่" label="รหัสสำนักงานใหญ่"
@ -57,7 +57,6 @@ async function selectHq(id: string) {
hide-bottom-space hide-bottom-space
class="col-6" class="col-6"
label="รหัสสาขา" label="รหัสสาขา"
bg-color="white"
option-label="label" option-label="label"
option-value="value" option-value="value"
v-model="brId" v-model="brId"
@ -73,7 +72,6 @@ async function selectHq(id: string) {
options-dense options-dense
hide-bottom-space hide-bottom-space
class="col-3" class="col-3"
bg-color="white"
option-value="value" option-value="value"
option-label="label" option-label="label"
label="ประเภทผู้ใช้งาน" label="ประเภทผู้ใช้งาน"
@ -91,7 +89,6 @@ async function selectHq(id: string) {
options-dense options-dense
hide-bottom-space hide-bottom-space
class="col-3" class="col-3"
bg-color="white"
label="สิทธิ์ผู้ใช้งาน" label="สิทธิ์ผู้ใช้งาน"
option-label="label" option-label="label"
option-value="value" option-value="value"
@ -102,15 +99,14 @@ async function selectHq(id: string) {
<q-input <q-input
:dense="dense" :dense="dense"
:outlined="outlined" :outlined="outlined"
:readonly="readonly" :readonly="usernameReadonly"
emit-value emit-value
map-options map-options
options-dense options-dense
hide-bottom-space hide-bottom-space
class="col-3" class="col-3"
bg-color="white"
label="ชื่อผู้ใช้งาน (Username)" label="ชื่อผู้ใช้งาน (Username)"
v-model="userName" v-model="username"
:rules="[(val: string) => val.length > 2 || 'กรุณากรอกชื่อผู้ใช้งาน']" :rules="[(val: string) => val.length > 2 || 'กรุณากรอกชื่อผู้ใช้งาน']"
/> />
<q-input <q-input
@ -119,7 +115,6 @@ async function selectHq(id: string) {
readonly readonly
hide-bottom-space hide-bottom-space
class="col-3" class="col-3"
bg-color="white"
label="รหัสพนักงาน" label="รหัสพนักงาน"
v-model="userCode" v-model="userCode"
/> />

View file

@ -89,7 +89,6 @@ defineProps<{
map-options map-options
label="เพศ" label="เพศ"
class="col-3" class="col-3"
bg-color="white"
option-label="label" option-label="label"
option-value="value" option-value="value"
v-model="gender" v-model="gender"

View file

@ -31,8 +31,9 @@ const zipCode = defineModel<string>('zipCode', { default: '' });
> >
<q-form greedy @submit.prevent @validation-success="submit"> <q-form greedy @submit.prevent @validation-success="submit">
<!-- header --> <!-- header -->
<div class="form-header q-py-sm q-pr-lg"> <div class="form-header q-py-sm q-px-lg">
<div class="row items-center"> <div class="row items-center">
<div style="width: 31.98px"></div>
<div class="col text-subtitle1 text-weight-bold text-center"> <div class="col text-subtitle1 text-weight-bold text-center">
{{ title }} {{ title }}
</div> </div>
@ -70,10 +71,10 @@ const zipCode = defineModel<string>('zipCode', { default: '' });
bordered bordered
class="column full-height" class="column full-height"
:class="`${$slots.prepend ? ($q.screen.gt.sm ? 'col-10' : 'col-12') : $slots.append ? 'col-6' : 'col-12'}`" :class="`${$slots.prepend ? ($q.screen.gt.sm ? 'col-10' : 'col-12') : $slots.append ? 'col-6' : 'col-12'}`"
style="padding-right: 0" style="padding-right: 0; padding-bottom: 0"
> >
<div <div
class="row col-12 q-col-gutter-y-md q-pr-md" class="row col-12 q-col-gutter-y-md q-pr-md q-mb-md"
:style="$q.screen.gt.sm ? 'overflow-y: auto; height: 60vh' : ''" :style="$q.screen.gt.sm ? 'overflow-y: auto; height: 60vh' : ''"
> >
<slot name="information"></slot> <slot name="information"></slot>
@ -83,6 +84,7 @@ const zipCode = defineModel<string>('zipCode', { default: '' });
dense dense
outlined outlined
:separator="addressSeparator" :separator="addressSeparator"
v-model:isOpen="modal"
v-model:address="address" v-model:address="address"
v-model:addressEN="addressEN" v-model:addressEN="addressEN"
v-model:provinceId="provinceId" v-model:provinceId="provinceId"

View file

@ -23,6 +23,9 @@ html {
--negative-fg: 0 0% 100%; --negative-fg: 0 0% 100%;
--negative-bg: var(--red-9-hsl); --negative-bg: var(--red-9-hsl);
--positive-fg: 0 0% 100%;
--positive-bg: var(--teal-7-hsl);
--gender-male: var(--blue-5-hsl); --gender-male: var(--blue-5-hsl);
--gender-female: var(--pink-7-hsl); --gender-female: var(--pink-7-hsl);
@ -133,3 +136,12 @@ html {
color: hsl(var(--negative-fg)); color: hsl(var(--negative-fg));
background-color: hsl(var(--negative-bg)); background-color: hsl(var(--negative-bg));
} }
.app-text-positive {
color: hsl(var(--positive-bg)) !important;
}
.app-bg-positive {
color: hsl(var(--positive-fg));
background-color: hsl(var(--positive-bg));
}

View file

@ -42,7 +42,7 @@ const defaultFormData = {
licenseExpireDate: null, licenseExpireDate: null,
licenseIssueDate: null, licenseIssueDate: null,
licenseNo: null, licenseNo: null,
discountCondition: '', discountCondition: null,
retireDate: null, retireDate: null,
startDate: null, startDate: null,
registrationNo: null, registrationNo: null,
@ -54,9 +54,11 @@ const defaultFormData = {
userType: '', userType: '',
profileImage: null, profileImage: null,
birthDate: null, birthDate: null,
responsibleArea: '', responsibleArea: null,
username: '',
}; };
const profileSubmit = ref(false);
const urlProfile = ref<string>(); const urlProfile = ref<string>();
const isEdit = ref(false); const isEdit = ref(false);
const modal = ref(false); const modal = ref(false);
@ -65,7 +67,6 @@ const userId = ref('');
const selectorLabel = ref(''); const selectorLabel = ref('');
const hqId = ref(''); const hqId = ref('');
const brId = ref(''); const brId = ref('');
const username = ref('');
const code = ref(''); const code = ref('');
const formDialogRef = ref(); const formDialogRef = ref();
const userStats = ref<BranchUserStats[]>(); const userStats = ref<BranchUserStats[]>();
@ -98,7 +99,10 @@ const formData = ref<UserCreate>({
userType: '', userType: '',
profileImage: null, profileImage: null,
birthDate: null, birthDate: null,
responsibleArea: '', responsibleArea: null,
checkpoint: null,
checkpointEN: null,
username: '',
}); });
const profileFile = ref<File | undefined>(undefined); const profileFile = ref<File | undefined>(undefined);
@ -131,6 +135,7 @@ const selectorList = computed(() => [
async function openDialog(idEdit?: string) { async function openDialog(idEdit?: string) {
modal.value = true; modal.value = true;
profileSubmit.value = false;
userStore.userOption.brOpts = []; userStore.userOption.brOpts = [];
userStore.userOption.hqOpts.length === 0 userStore.userOption.hqOpts.length === 0
@ -166,6 +171,7 @@ async function openDialog(idEdit?: string) {
firstName: foundUser.firstName, firstName: foundUser.firstName,
userRole: foundUser.userRole, userRole: foundUser.userRole,
userType: foundUser.userType, userType: foundUser.userType,
username: foundUser.username,
responsibleArea: foundUser.responsibleArea, responsibleArea: foundUser.responsibleArea,
licenseExpireDate: licenseExpireDate:
(foundUser.licenseExpireDate && (foundUser.licenseExpireDate &&
@ -192,9 +198,10 @@ async function openDialog(idEdit?: string) {
code.value = foundUser.code; code.value = foundUser.code;
urlProfile.value = foundUser.profileImageUrl; urlProfile.value = foundUser.profileImageUrl;
isEdit.value = true; isEdit.value = true;
profileSubmit.value = true;
await userStore.fetchBrOption(hqId.value); await userStore.fetchBrOption(hqId.value);
await formDialogRef.value.fetchSubDistrict(formData.value.districtId); // await formDialogRef.value.fetchSubDistrict(formData.value.districtId);
await formDialogRef.value.fetchDistrict(formData.value.provinceId); // await formDialogRef.value.fetchDistrict(formData.value.provinceId);
} }
} }
} }
@ -204,13 +211,13 @@ function onClose() {
hqId.value = ''; hqId.value = '';
brId.value = ''; brId.value = '';
userId.value = ''; userId.value = '';
username.value = '';
urlProfile.value = ''; urlProfile.value = '';
profileSubmit.value = false;
modal.value = false; modal.value = false;
status.value = false; status.value = false;
isEdit.value = false; isEdit.value = false;
mapUserType(selectorLabel.value);
Object.assign(formData.value, defaultFormData); Object.assign(formData.value, defaultFormData);
mapUserType(selectorLabel.value);
} }
async function onSubmit() { async function onSubmit() {
@ -270,15 +277,14 @@ function cardClick(id: string) {
} }
function mapUserType(label: string) { function mapUserType(label: string) {
if (label === 'personnelSelector1') { const userTypeMap: { [key: string]: string } = {
formData.value.userType = 'USER'; USER: 'USER',
} else if (label === 'personnelSelector2') { MESSENGER: 'MESSENGER',
formData.value.userType = 'MESSENGER'; DELEGATE: 'DELEGATE',
} else if (label === 'personnelSelector3') { AGENCY: 'AGENCY',
formData.value.userType = 'DELEGATE'; };
} else if (label === 'personnelSelector4') {
formData.value.userType = 'AGENCY'; formData.value.userType = userTypeMap[label];
}
} }
onMounted(async () => { onMounted(async () => {
@ -377,14 +383,6 @@ watch(
female: v.gender === 'female', female: v.gender === 'female',
detail: [ detail: [
{ label: 'ประเภท', value: $t(v.userType) }, { label: 'ประเภท', value: $t(v.userType) },
{
label: 'ตำแหน่ง',
value: v.userRole
? userStore.userOption.roleOpts.find(
(r) => r.value === v.userRole,
)?.label || ''
: '',
},
{ label: 'โทรศัพท์', value: v.telephoneNo }, { label: 'โทรศัพท์', value: v.telephoneNo },
{ {
label: 'อายุ', label: 'อายุ',
@ -427,15 +425,17 @@ watch(
<!-- form --> <!-- form -->
<FormDialog <FormDialog
ref="formDialogRef" ref="formDialogRef"
v-model:formData="formData"
v-model:modal="modal"
v-model:hqId="hqId"
v-model:brId="brId"
v-model:username="username"
v-model:code="code"
title="เพิ่มบุคลากร" title="เพิ่มบุคลากร"
addressTitle="ที่อยู่พนักงาน" addressTitle="ที่อยู่พนักงาน"
addressENTitle="ที่อยู่พนักงาน ENG" addressENTitle="ที่อยู่พนักงาน ENG"
v-model:modal="modal"
v-model:address="formData.address"
v-model:addressEN="formData.addressEN"
v-model:provinceId="formData.provinceId"
v-model:districtId="formData.districtId"
v-model:subDistrictId="formData.subDistrictId"
v-model:zipCode="formData.zipCode"
:addressSeparator="formData.userType !== ''"
:submit="() => onSubmit()" :submit="() => onSubmit()"
:close="() => onClose()" :close="() => onClose()"
> >
@ -454,33 +454,61 @@ watch(
style="color: var(--border-color)" style="color: var(--border-color)"
/> />
</div> </div>
<div
v-if="urlProfile && !profileSubmit"
class="col-12 row q-mt-md q-col-gutter-x-md"
>
<div class="col-6">
<q-btn <q-btn
v-if="urlProfile" dense
unelevated
outlined
padding="8px"
class="cancel-img-btn full-width"
label="ยกเลิก"
@click="urlProfile = ''"
/>
</div>
<div class="col-6">
<q-btn
dense
unelevated
outlined
padding="8px"
class="submit-img-btn full-width"
label="บันทึก"
@click="profileSubmit = true"
/>
</div>
</div>
<q-btn
v-else-if="urlProfile && profileSubmit"
dense dense
unelevated unelevated
outlined outlined
padding="8px" padding="8px"
icon="mdi-pencil-outline" icon="mdi-pencil-outline"
class="edit-img-btn q-my-md full-width" class="edit-img-btn q-mt-md full-width"
label="แก้ไขโปรไฟล์" label="แก้ไขโปรไฟล์"
@click="inputFile.click()" @click.prevent="inputFile.click(), (profileSubmit = false)"
/> />
<q-btn <q-btn
v-else v-else
dense dense
unelevated unelevated
outlined outlined
padding="8px" padding="8px"
class="upload-img-btn q-my-md full-width" class="upload-img-btn q-mt-md full-width"
label="อัปโหลดรูปภาพ" label="อัปโหลดรูปภาพ"
:class="{ dark: $q.dark.isActive }" :class="{ dark: $q.dark.isActive }"
@click="inputFile.click()" @click="inputFile.click()"
/> />
<div class="text-left"> <q-separator class="col-12 q-my-md" />
<div class="text-left q-pt-md">
<q-toggle <q-toggle
dense dense
size="md" size="md"
color="primary"
v-model="status" v-model="status"
padding="none" padding="none"
class="q-pr-md" class="q-pr-md"
@ -495,12 +523,12 @@ watch(
dense dense
outlined outlined
separator separator
:addressSeparator="formData.userType" :usernameReadonly="isEdit"
v-model:hqId="hqId" v-model:hqId="hqId"
v-model:brId="brId" v-model:brId="brId"
v-model:userType="formData.userType" v-model:userType="formData.userType"
v-model:userRole="formData.userRole" v-model:userRole="formData.userRole"
v-model:userName="username" v-model:username="formData.username"
v-model:userCode="code" v-model:userCode="code"
/> />
</template> </template>
@ -538,14 +566,11 @@ watch(
</FormDialog> </FormDialog>
</template> </template>
<style> <style>
.bg-white {
background-color: var(--surface-1) !important;
}
.upload-img-preview { .upload-img-preview {
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
border-radius: var(--radius-2); border-radius: var(--radius-2);
height: 12vw; height: 12vw;
background-color: var(--surface-1);
} }
.upload-img-btn { .upload-img-btn {
@ -565,4 +590,18 @@ watch(
background-color: transparent; background-color: transparent;
border-radius: var(--radius-2); border-radius: var(--radius-2);
} }
.cancel-img-btn {
color: hsl(var(--negative-bg));
border: 1px solid hsl(var(--negative-bg));
background-color: transparent;
border-radius: var(--radius-2);
}
.submit-img-btn {
color: var(--surface-1);
border: 1px solid hsl(var(--positive-bg));
background-color: hsl(var(--positive-bg));
border-radius: var(--radius-2);
}
</style> </style>

View file

@ -21,6 +21,7 @@ export type User = {
gender: string; gender: string;
userRole: string; userRole: string;
userType: string; userType: string;
username: string;
retireDate: Date | null; retireDate: Date | null;
startDate: Date | null; startDate: Date | null;
registrationNo: string | null; registrationNo: string | null;
@ -41,6 +42,8 @@ export type User = {
code: string; code: string;
birthDate?: Date | null; birthDate?: Date | null;
responsibleArea: string; responsibleArea: string;
checkpoint?: string | null;
checkpointEN?: string | null;
branch: Branch[]; branch: Branch[];
}; };
@ -70,9 +73,12 @@ export type UserCreate = {
firstName: string; firstName: string;
userRole: string; userRole: string;
userType: string; userType: string;
username: string;
profileImage?: File | null; // required but not strict profileImage?: File | null; // required but not strict
birthDate?: Date | null; birthDate?: Date | null;
responsibleArea: string; responsibleArea?: string | null;
checkpoint?: string | null;
checkpointEN?: string | null;
}; };
export type UserAttachment = { export type UserAttachment = {