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
|
// 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} {
|
.rounded-#{$size} {
|
||||||
border-radius: #{$size}px !important;
|
border-radius: #{$size}px !important;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,25 +114,36 @@ export default {
|
||||||
close: 'Close',
|
close: 'Close',
|
||||||
},
|
},
|
||||||
profilePage: {
|
profilePage: {
|
||||||
title: 'Profile',
|
personalInfo: {
|
||||||
firstName: 'First name',
|
title: 'Profile',
|
||||||
lastName: 'Last name',
|
firstName: 'First name',
|
||||||
email: 'Email',
|
lastName: 'Last name',
|
||||||
phoneNumber: 'Phone number',
|
gender: 'Gender',
|
||||||
job_title: 'Job title',
|
genderMale: 'Man',
|
||||||
company: 'Company',
|
genderFemale: 'Woman',
|
||||||
supervisor: 'Supervisor',
|
genderNonBinary: 'Non-binary',
|
||||||
role: 'Role',
|
genderUnspecified: 'Unspecified',
|
||||||
address: 'Address',
|
phoneNumber: 'Phone number',
|
||||||
job_titleValidation: 'Job title must be filled in.',
|
jobTitle: 'Job title',
|
||||||
companyValidation: 'Company must be filled in.',
|
company: 'Company',
|
||||||
supervisorValidation: 'Supervisor must be filled in.',
|
supervisor: 'Supervisor',
|
||||||
roleValidation: 'Role must be filled in.',
|
role: 'Role',
|
||||||
addressValidation: 'Address must be filled in.',
|
address: 'Address',
|
||||||
firstNameValidation: 'First Name must be filled in.',
|
addressPlaceholder: '# address, city, region, country',
|
||||||
lastNameValidation: 'Last Name must be filled in.',
|
birthDate: 'Date of birth',
|
||||||
phoneNumberValidation: 'Phone number must be filled in.',
|
submitInfo: 'Update Profile',
|
||||||
submit: '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: {
|
indexAdminPage: {
|
||||||
card_1: 'Administrators',
|
card_1: 'Administrators',
|
||||||
|
|
|
||||||
|
|
@ -190,25 +190,36 @@ export default {
|
||||||
timeSheetValidations: 'Validation cartes de temps',
|
timeSheetValidations: 'Validation cartes de temps',
|
||||||
},
|
},
|
||||||
profilePage: {
|
profilePage: {
|
||||||
title: 'Profil',
|
personalInfo: {
|
||||||
firstName: 'Prénom',
|
title: 'Info personnel',
|
||||||
lastName: 'Nom de famille',
|
firstName: 'Prénom',
|
||||||
email: 'Email',
|
lastName: 'Nom de famille',
|
||||||
phoneNumber: 'Numéro de téléphone',
|
gender: 'Genre',
|
||||||
job_title: 'Titre du poste',
|
genderMale: 'Homme',
|
||||||
company: 'Entreprise',
|
genderFemale: 'Femme',
|
||||||
supervisor: 'Superviseur',
|
genderNonBinary: 'Non-binaire',
|
||||||
role: 'Role',
|
genderUnspecified: 'Non-spécifié',
|
||||||
address: 'Adresse',
|
phoneNumber: 'Numéro de téléphone',
|
||||||
job_titleValidation: 'Le champ "titre du poste" doit être rempli.',
|
jobTitle: 'Titre du poste',
|
||||||
companyValidation: 'Le champ "entreprise" doit être rempli.',
|
company: 'Entreprise',
|
||||||
supervisorValidation: 'Un employé qui n’a pas le rôle de superviseur doit être attribué à un superviseur.',
|
supervisor: 'Superviseur',
|
||||||
roleValidation: 'Le champ "rôle" doit être rempli.',
|
role: 'Role',
|
||||||
addressValidation: 'Le champ "adresse" doit être rempli.',
|
address: 'Adresse',
|
||||||
firstNameValidation: 'Le champ "prénom" doit être rempli.',
|
addressPlaceholder: '# addresse, ville, région, pays',
|
||||||
lastNameValidation: 'Le champ "nom de famille" doit être rempli.',
|
birthDate: 'Date de naissance',
|
||||||
phoneNumberValidation: 'Le champ "numéro de téléphone" doit être rempli.',
|
submitInfo: 'Modifier Profil',
|
||||||
submit: '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: {
|
resetPage: {
|
||||||
title: 'Réinitialiser votre mot de passe',
|
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';
|
import type { QDateDetails } from 'src/modules/shared/types/q-date-details';
|
||||||
|
|
||||||
const is_showing_calendar_picker = ref(false);
|
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<{
|
const props = defineProps<{
|
||||||
isDisabled: boolean,
|
isDisabled: boolean,
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
calendar_date.value = value;
|
calendar_date.value = value;
|
||||||
is_showing_calendar_picker.value = false;
|
is_showing_calendar_picker.value = false;
|
||||||
emit('date-selected', value, reason, details);
|
emit('date-selected', value, reason, details);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
class="q-mt-xl"
|
class="q-mt-xl"
|
||||||
today-btn
|
today-btn
|
||||||
mask="YYYY-MM-DD"
|
mask="YYYY-MM-DD"
|
||||||
:options="date => date > '2023-12-16'"
|
:options="date => date > '2023/12/16'"
|
||||||
@update:model-value="onDateSelected"
|
@update:model-value="onDateSelected"
|
||||||
/>
|
/>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,13 @@ const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: 'timesheet-temp',
|
path: 'timesheet-temp',
|
||||||
name: RouteNames.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