feat(profile): add profile template, employee tabs and panels, add some logic to validate entries, i18n implementation
This commit is contained in:
parent
f5ec3025ef
commit
b9a549b9f9
BIN
src/assets/profile_header_default.png
Normal file
BIN
src/assets/profile_header_default.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
|
|
@ -1,5 +1,5 @@
|
|||
// app global css in SCSS form
|
||||
@each $size in (5, 10, 15, 20, 25) {
|
||||
@each $size in (5, 10, 15, 20, 25, 50, 75, 100) {
|
||||
.rounded-#{$size} {
|
||||
border-radius: #{$size}px !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,25 +114,36 @@ export default {
|
|||
close: 'Close',
|
||||
},
|
||||
profilePage: {
|
||||
title: 'Profile',
|
||||
firstName: 'First name',
|
||||
lastName: 'Last name',
|
||||
email: 'Email',
|
||||
phoneNumber: 'Phone number',
|
||||
job_title: 'Job title',
|
||||
company: 'Company',
|
||||
supervisor: 'Supervisor',
|
||||
role: 'Role',
|
||||
address: 'Address',
|
||||
job_titleValidation: 'Job title must be filled in.',
|
||||
companyValidation: 'Company must be filled in.',
|
||||
supervisorValidation: 'Supervisor must be filled in.',
|
||||
roleValidation: 'Role must be filled in.',
|
||||
addressValidation: 'Address must be filled in.',
|
||||
firstNameValidation: 'First Name must be filled in.',
|
||||
lastNameValidation: 'Last Name must be filled in.',
|
||||
phoneNumberValidation: 'Phone number must be filled in.',
|
||||
submit: 'Update Profile',
|
||||
personalInfo: {
|
||||
title: 'Profile',
|
||||
firstName: 'First name',
|
||||
lastName: 'Last name',
|
||||
gender: 'Gender',
|
||||
genderMale: 'Man',
|
||||
genderFemale: 'Woman',
|
||||
genderNonBinary: 'Non-binary',
|
||||
genderUnspecified: 'Unspecified',
|
||||
phoneNumber: 'Phone number',
|
||||
jobTitle: 'Job title',
|
||||
company: 'Company',
|
||||
supervisor: 'Supervisor',
|
||||
role: 'Role',
|
||||
address: 'Address',
|
||||
addressPlaceholder: '# address, city, region, country',
|
||||
birthDate: 'Date of birth',
|
||||
submitInfo: 'Update Profile',
|
||||
},
|
||||
employeeInfo: {
|
||||
title: 'Employee info',
|
||||
workEmail: 'Work e-mail',
|
||||
jobTitle: 'Job Title',
|
||||
companyName: 'Company',
|
||||
supervisorName: 'Supervisor',
|
||||
hiredDate: 'Hiring date',
|
||||
},
|
||||
errors: {
|
||||
mustEnterBirthdate: 'You must enter a valid birthdate',
|
||||
}
|
||||
},
|
||||
indexAdminPage: {
|
||||
card_1: 'Administrators',
|
||||
|
|
|
|||
|
|
@ -190,25 +190,36 @@ export default {
|
|||
timeSheetValidations: 'Validation cartes de temps',
|
||||
},
|
||||
profilePage: {
|
||||
title: 'Profil',
|
||||
firstName: 'Prénom',
|
||||
lastName: 'Nom de famille',
|
||||
email: 'Email',
|
||||
phoneNumber: 'Numéro de téléphone',
|
||||
job_title: 'Titre du poste',
|
||||
company: 'Entreprise',
|
||||
supervisor: 'Superviseur',
|
||||
role: 'Role',
|
||||
address: 'Adresse',
|
||||
job_titleValidation: 'Le champ "titre du poste" doit être rempli.',
|
||||
companyValidation: 'Le champ "entreprise" doit être rempli.',
|
||||
supervisorValidation: 'Un employé qui n’a pas le rôle de superviseur doit être attribué à un superviseur.',
|
||||
roleValidation: 'Le champ "rôle" doit être rempli.',
|
||||
addressValidation: 'Le champ "adresse" doit être rempli.',
|
||||
firstNameValidation: 'Le champ "prénom" doit être rempli.',
|
||||
lastNameValidation: 'Le champ "nom de famille" doit être rempli.',
|
||||
phoneNumberValidation: 'Le champ "numéro de téléphone" doit être rempli.',
|
||||
submit: 'Modifier Profil',
|
||||
personalInfo: {
|
||||
title: 'Info personnel',
|
||||
firstName: 'Prénom',
|
||||
lastName: 'Nom de famille',
|
||||
gender: 'Genre',
|
||||
genderMale: 'Homme',
|
||||
genderFemale: 'Femme',
|
||||
genderNonBinary: 'Non-binaire',
|
||||
genderUnspecified: 'Non-spécifié',
|
||||
phoneNumber: 'Numéro de téléphone',
|
||||
jobTitle: 'Titre du poste',
|
||||
company: 'Entreprise',
|
||||
supervisor: 'Superviseur',
|
||||
role: 'Role',
|
||||
address: 'Adresse',
|
||||
addressPlaceholder: '# addresse, ville, région, pays',
|
||||
birthDate: 'Date de naissance',
|
||||
submitInfo: 'Modifier Profil',
|
||||
},
|
||||
employeeInfo: {
|
||||
title: 'Info Employé',
|
||||
workEmail: 'Courriel employé',
|
||||
jobTitle: 'Poste',
|
||||
companyName: 'Compagnie',
|
||||
supervisorName: 'Nom du superviseur',
|
||||
hiredDate: 'Date embauché',
|
||||
},
|
||||
errors: {
|
||||
mustEnterBirthdate: 'Vous devez entrer une date de naissance valide',
|
||||
}
|
||||
},
|
||||
resetPage: {
|
||||
title: 'Réinitialiser votre mot de passe',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { default_employee_job_info, type EmployeeJobInfo } from 'src/modules/profile/types/profile-employee-interface';
|
||||
import ProfileInputField from 'src/modules/profile/components/shared/profile-input-field.vue';
|
||||
import { deepEqual } from 'src/utils/deep-equal';
|
||||
// import ProfileSelectField from 'src/modules/profile/components/shared/profile-select-field.vue';
|
||||
|
||||
const props = withDefaults( defineProps<{
|
||||
employeeInfo?: EmployeeJobInfo;
|
||||
}>(), {
|
||||
employeeInfo: () => default_employee_job_info,
|
||||
});
|
||||
|
||||
const initial_info = props.employeeInfo;
|
||||
|
||||
const job_info = ref<EmployeeJobInfo>(props.employeeInfo);
|
||||
const is_editing = ref<boolean>(false);
|
||||
|
||||
const onSubmit = () => {
|
||||
if (!deepEqual(job_info.value, initial_info)) {
|
||||
// saving profile logic here
|
||||
console.log('Changes saved!');
|
||||
}
|
||||
console.log('Nothing was changed...');
|
||||
};
|
||||
|
||||
const onReset = () => {
|
||||
job_info.value = initial_info;
|
||||
is_editing.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-form
|
||||
class="q-pa-md full-height"
|
||||
@submit="onSubmit"
|
||||
@reset="onReset"
|
||||
>
|
||||
<div :class="$q.screen.lt.md ? 'column' : 'row'">
|
||||
<ProfileInputField
|
||||
class="col"
|
||||
:model-reference="job_info.company"
|
||||
:is-editing="is_editing"
|
||||
:label-string="$t('profilePage.employeeInfo.firstName')"
|
||||
/>
|
||||
<ProfileInputField
|
||||
class="col"
|
||||
:model-reference="job_info.email"
|
||||
:is-editing="is_editing"
|
||||
:label-string="$t('profilePage.employeeInfo.lastName')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="absolute-bottom" :class="$q.screen.lt.md ? 'column' : 'row'">
|
||||
<q-space />
|
||||
<q-btn
|
||||
v-if="is_editing"
|
||||
push
|
||||
size="sm"
|
||||
color="negative"
|
||||
type="reset"
|
||||
icon="cancel"
|
||||
class="q-ma-sm"
|
||||
:label="$t('timesheet.cancel_button')"
|
||||
/>
|
||||
<q-btn
|
||||
push
|
||||
size="sm"
|
||||
color="primary"
|
||||
:icon="is_editing ? 'save_alt' : 'create'"
|
||||
class="q-ma-sm"
|
||||
:label="is_editing ? $t('timesheet.saveButton') : $t('shiftsTemplate.updateButton')"
|
||||
@click="is_editing = !is_editing"
|
||||
/>
|
||||
</div>
|
||||
</q-form>
|
||||
</template>
|
||||
147
src/modules/profile/components/employee/panel-info-personal.vue
Normal file
147
src/modules/profile/components/employee/panel-info-personal.vue
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { default_employee_personal_info, type EmployeePersonalInfo } from 'src/modules/profile/types/profile-employee-interface';
|
||||
import ProfileInputField from 'src/modules/profile/components/shared/profile-input-field.vue';
|
||||
import ProfileSelectField from 'src/modules/profile/components/shared/profile-select-field.vue';
|
||||
import { deepEqual } from 'src/utils/deep-equal';
|
||||
|
||||
const props = withDefaults( defineProps<{
|
||||
personalInfo?: EmployeePersonalInfo;
|
||||
}>(), {
|
||||
personalInfo: () => default_employee_personal_info,
|
||||
});
|
||||
|
||||
const initial_info = { ...props.personalInfo };
|
||||
const personal_info = ref<EmployeePersonalInfo>(props.personalInfo);
|
||||
const is_editing = ref<boolean>(false);
|
||||
const gender = props.personalInfo.gender === '' ?
|
||||
'profilePage.personalInfo.genderUnspecified' :
|
||||
personal_info.value.gender;
|
||||
|
||||
const gender_options = [
|
||||
'profilePage.personalInfo.genderMale',
|
||||
'profilePage.personalInfo.genderFemale',
|
||||
'profilePage.personalInfo.genderUnspecified',
|
||||
// 'profilePage.personalInfo.genderNonBinary',
|
||||
|
||||
];
|
||||
|
||||
const changeFieldValue = (value: string | number | null, property: keyof EmployeePersonalInfo) => {
|
||||
if ( typeof value === 'string' ) personal_info.value[property] = value;
|
||||
else if ( typeof value === 'number' ) personal_info.value[property] = value.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
const onSubmit = () => {
|
||||
if (!is_editing.value) {
|
||||
is_editing.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
is_editing.value = false;
|
||||
if (!deepEqual(personal_info.value, initial_info)) {
|
||||
// saving profile logic here
|
||||
console.log('Changes saved! ', initial_info, personal_info.value);
|
||||
return;
|
||||
}
|
||||
console.log('Nothing was changed...', initial_info, personal_info.value);
|
||||
};
|
||||
|
||||
const onReset = () => {
|
||||
personal_info.value = initial_info;
|
||||
is_editing.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-form
|
||||
class="q-pa-md full-height"
|
||||
@submit="onSubmit"
|
||||
@reset="onReset"
|
||||
>
|
||||
<div :class="$q.screen.lt.md ? 'column' : 'row'">
|
||||
<ProfileInputField
|
||||
class="col"
|
||||
type="text"
|
||||
:model-reference="personal_info.first_name"
|
||||
:is-editing="is_editing"
|
||||
:label-string="$t('profilePage.personalInfo.firstName')"
|
||||
@is-value-changed="value => changeFieldValue( value, 'first_name')"
|
||||
/>
|
||||
<ProfileInputField
|
||||
class="col"
|
||||
type="text"
|
||||
:model-reference="personal_info.last_name"
|
||||
:is-editing="is_editing"
|
||||
:label-string="$t('profilePage.personalInfo.lastName')"
|
||||
@is-value-changed="value => changeFieldValue( value, 'last_name' )"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div :class="$q.screen.lt.md ? 'column' : 'row'">
|
||||
<ProfileInputField
|
||||
class="col"
|
||||
type="text"
|
||||
:model-reference="personal_info.phone_number"
|
||||
:is-editing="is_editing"
|
||||
:label-string="$t('profilePage.personalInfo.phoneNumber')"
|
||||
@is-value-changed="value => changeFieldValue( value, 'phone_number' )"
|
||||
/>
|
||||
<ProfileSelectField
|
||||
class="col"
|
||||
:model-reference="gender"
|
||||
:options="gender_options"
|
||||
:is-editing="is_editing"
|
||||
:label-string="$t('profilePage.personalInfo.gender')"
|
||||
@is-value-changed="value => changeFieldValue( value, 'gender' )"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div :class="$q.screen.lt.md ? 'column' : 'row'">
|
||||
<ProfileInputField
|
||||
class="col"
|
||||
:model-reference="personal_info.address"
|
||||
:is-editing="is_editing"
|
||||
:label-string="$t('profilePage.personalInfo.address')"
|
||||
:hint="$t('profilePage.personalInfo.addressPlaceholder')"
|
||||
@is-value-changed="value => changeFieldValue( value, 'address' )"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div :class="$q.screen.lt.md ? 'column' : 'row'">
|
||||
<ProfileInputField
|
||||
class="col"
|
||||
mask="#### / ## / ##"
|
||||
hint="ex: 1970 / 01 / 01"
|
||||
:rules="[ val => val.length === 14 || $t('profilePage.errors.mustEnterBirthdate') ]"
|
||||
:model-reference="personal_info.birth_date"
|
||||
:is-editing="is_editing"
|
||||
:label-string="$t('profilePage.personalInfo.birthDate')"
|
||||
@is-value-changed="value => changeFieldValue( value, 'birth_date' )"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="absolute-bottom" :class="$q.screen.lt.md ? 'column' : 'row'">
|
||||
<q-space />
|
||||
<q-btn
|
||||
v-if="is_editing"
|
||||
push
|
||||
size="sm"
|
||||
color="negative"
|
||||
type="reset"
|
||||
icon="cancel"
|
||||
class="q-ma-sm"
|
||||
:label="$t('timesheet.cancel_button')"
|
||||
/>
|
||||
<q-btn
|
||||
push
|
||||
size="sm"
|
||||
color="primary"
|
||||
type="submit"
|
||||
:icon="is_editing ? 'save_alt' : 'create'"
|
||||
class="q-ma-sm"
|
||||
:label="is_editing ? $t('timesheet.saveButton') : $t('shiftsTemplate.updateButton')"
|
||||
/>
|
||||
</div>
|
||||
</q-form>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<script setup lang="ts">
|
||||
import type { ValidationRule } from 'quasar';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const props = withDefaults( defineProps<{
|
||||
modelReference: string;
|
||||
labelString: string;
|
||||
isEditing: boolean;
|
||||
readonly?: boolean;
|
||||
type?: "number" | "textarea" | "time" | "text" | "tel" | "password" | "email" | "search" | "file" | "url" | "date" | "datetime-local" | undefined;
|
||||
hint?: string;
|
||||
mask?: string;
|
||||
rules?: ValidationRule[];
|
||||
}>(), {
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
isValueChanged: [value: string | number | null];
|
||||
}>();
|
||||
|
||||
const input_ref = ref<string>(props.modelReference);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-input
|
||||
v-model="input_ref"
|
||||
dense
|
||||
stack-label
|
||||
autogrow
|
||||
hide-bottom-space
|
||||
debounce="500"
|
||||
label-color="primary"
|
||||
class="q-ma-xs"
|
||||
input-class="text-weight-bolder text-h6 text-grey-8"
|
||||
:hint="props.isEditing ? props.hint : ''"
|
||||
:mask="props.mask"
|
||||
:readonly="props.readonly || !props.isEditing"
|
||||
:outlined="props.isEditing"
|
||||
:borderless="!props.isEditing"
|
||||
:type="props.type"
|
||||
:label="props.labelString"
|
||||
:rules="props.rules"
|
||||
@update:model-value="value => emit('isValueChanged', value)"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
const props = withDefaults( defineProps<{
|
||||
modelReference: string;
|
||||
options: string[];
|
||||
readonly?: boolean;
|
||||
labelString: string;
|
||||
isEditing: boolean;
|
||||
type?: "number" | "textarea" | "time" | "text" | "tel" | "password" | "email" | "search" | "file" | "url" | "date" | "datetime-local" | undefined;
|
||||
}>(), {
|
||||
readonly: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
isValueChanged: [value: string];
|
||||
}>();
|
||||
|
||||
const select_ref = ref(props.modelReference);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-select
|
||||
v-model="select_ref"
|
||||
dense
|
||||
options-dense
|
||||
stack-label
|
||||
color="primary"
|
||||
label-color="primary"
|
||||
class="q-ma-xs"
|
||||
:options="props.options"
|
||||
:outlined="props.isEditing"
|
||||
:borderless="!props.isEditing"
|
||||
:readonly="props.readonly || !props.isEditing"
|
||||
:hide-dropdown-icon="!props.isEditing"
|
||||
:label="props.labelString"
|
||||
:option-label="opt => $t(opt)"
|
||||
@update:model-value="value => emit('isValueChanged', value.toString())"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<script setup lang="ts">
|
||||
import { type Component, ref } from 'vue';
|
||||
|
||||
interface MenuTab {
|
||||
name: string;
|
||||
icon: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
menuTabs: MenuTab[];
|
||||
tabContents: Component[];
|
||||
currentMenu?: string | undefined;
|
||||
}>();
|
||||
|
||||
const current_menu = ref<string>(props.currentMenu || '');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row" :class="$q.screen.lt.md ? 'full-width' : ''">
|
||||
<div class="col-auto column">
|
||||
<q-card class="col-auto q-mr-sm q-pa-xs">
|
||||
<q-tabs
|
||||
v-model="current_menu"
|
||||
vertical
|
||||
dense
|
||||
active-color="primary"
|
||||
indicator-color="primary"
|
||||
content-class=""
|
||||
inline-label
|
||||
align="left"
|
||||
>
|
||||
<q-tab
|
||||
v-for="tab, index in props.menuTabs"
|
||||
:key="index"
|
||||
:name="tab.name"
|
||||
:icon="tab.icon"
|
||||
:label="$q.screen.lt.md ? '' : tab.label"
|
||||
content-class="items-start"
|
||||
/>
|
||||
</q-tabs>
|
||||
</q-card>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
|
||||
<q-card class="col q-ml-sm">
|
||||
<q-tab-panels
|
||||
v-model="current_menu"
|
||||
animated
|
||||
vertical
|
||||
transition-prev="jump-up"
|
||||
transition-next="jump-up"
|
||||
class="rounded-5"
|
||||
:style="$q.screen.lt.md ? 'height: 70vh;' : 'height: 50vh; width: 40vw;'"
|
||||
>
|
||||
<q-tab-panel
|
||||
v-for="content, index in props.tabContents"
|
||||
:key="index"
|
||||
:name="props.menuTabs[index]?.name"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<component :is="content" />
|
||||
</q-tab-panel>
|
||||
</q-tab-panels>
|
||||
</q-card>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
32
src/modules/profile/pages/employee/profile-employee.vue
Normal file
32
src/modules/profile/pages/employee/profile-employee.vue
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import PanelInfoPersonal from 'src/modules/profile/components/employee/panel-info-personal.vue';
|
||||
import ProfileTabMenuTemplate from 'src/modules/profile/components/shared/profile-tab-menu-template.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
name: 'personal_info',
|
||||
icon: 'badge',
|
||||
label: t('profilePage.personalInfo.title'),
|
||||
},
|
||||
{
|
||||
name: 'employee_info',
|
||||
icon: 'business',
|
||||
label: t('profilePage.employeeInfo.title'),
|
||||
},
|
||||
];
|
||||
|
||||
const components = [ PanelInfoPersonal, ];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-card flat class="rounded-5 bg-transparent q-pa-none">
|
||||
<ProfileTabMenuTemplate
|
||||
:menu-tabs="tabs"
|
||||
:tab-contents="components"
|
||||
:current-menu="tabs[0]?.name"
|
||||
/>
|
||||
</q-card>
|
||||
</template>
|
||||
31
src/modules/profile/pages/profile-container.vue
Normal file
31
src/modules/profile/pages/profile-container.vue
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<script setup lang="ts">
|
||||
import { useAuthStore } from 'src/stores/auth-store';
|
||||
import { type Component, h } from 'vue';
|
||||
import ProfileEmployee from 'src/modules/profile/pages/employee/profile-employee.vue';
|
||||
|
||||
const auth_store = useAuthStore();
|
||||
|
||||
const getUserProfileComponent = (): Component => {
|
||||
console.log('user role: ', auth_store.user.role);
|
||||
|
||||
switch (auth_store.user.role.toUpperCase()) {
|
||||
case 'SUPERVISOR': return ProfileEmployee;
|
||||
default: return h('div', { class: 'empty' }, '');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-page class="bg-secondary column items-center justify-center">
|
||||
<q-img
|
||||
src="src/assets/profile_header_default.png"
|
||||
height="15vh"
|
||||
width="50vw"
|
||||
class="rounded-5 q-mb-md shadow-5"
|
||||
fit="cover"
|
||||
>
|
||||
<div class="absolute-bottom text-h5 text-uppercase text-weight-bolder" style="line-height: 0.8em;">{{ auth_store.user.firstName }} {{ auth_store.user.lastName }}</div>
|
||||
</q-img>
|
||||
<component :is="getUserProfileComponent()" class="col-auto"/>
|
||||
</q-page>
|
||||
</template>
|
||||
33
src/modules/profile/types/profile-employee-interface.ts
Normal file
33
src/modules/profile/types/profile-employee-interface.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
export interface EmployeePersonalInfo {
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
gender: string;
|
||||
phone_number: string;
|
||||
address: string;
|
||||
birth_date: string;
|
||||
}
|
||||
|
||||
export interface EmployeeJobInfo {
|
||||
email: string;
|
||||
job_title: string;
|
||||
company: string;
|
||||
supervisor: string;
|
||||
hired_date: string;
|
||||
}
|
||||
|
||||
export const default_employee_personal_info: EmployeePersonalInfo = {
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
gender: '',
|
||||
phone_number: '',
|
||||
address: '',
|
||||
birth_date: '1970 / 01 / 01'
|
||||
}
|
||||
|
||||
export const default_employee_job_info: EmployeeJobInfo = {
|
||||
email: '',
|
||||
job_title: '',
|
||||
company: '',
|
||||
supervisor: '',
|
||||
hired_date: '',
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
import type { QDateDetails } from 'src/modules/shared/types/q-date-details';
|
||||
|
||||
const is_showing_calendar_picker = ref(false);
|
||||
const calendar_date = ref(date.formatDate( Date.now(), 'YYYY/MM/DD' ));
|
||||
const calendar_date = ref(date.formatDate( Date.now(), 'YYYY-MM-DD' ));
|
||||
|
||||
const props = defineProps<{
|
||||
isDisabled: boolean,
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
class="q-mt-xl"
|
||||
today-btn
|
||||
mask="YYYY-MM-DD"
|
||||
:options="date => date > '2023-12-16'"
|
||||
:options="date => date > '2023/12/16'"
|
||||
@update:model-value="onDateSelected"
|
||||
/>
|
||||
</q-dialog>
|
||||
|
|
|
|||
|
|
@ -25,8 +25,13 @@ const routes: RouteRecordRaw[] = [
|
|||
{
|
||||
path: 'timesheet-temp',
|
||||
name: RouteNames.TIMESHEET_TEMP,
|
||||
component: () => import('src/modules/timesheets/pages/timesheet-temp-page.vue')
|
||||
}
|
||||
component: () => import('src/modules/timesheets/pages/timesheet-temp-page.vue'),
|
||||
},
|
||||
{
|
||||
path: 'user/profile',
|
||||
name: RouteNames.PROFILE,
|
||||
component: () => import('src/modules/profile/pages/profile-container.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user