feat(profile): Profile module nearly complete, technically modular and could be used in employee list. Mobile friendly. Implement Dark Mode.
This commit is contained in:
parent
b9a549b9f9
commit
e9a8350b09
|
|
@ -105,7 +105,8 @@ export default defineConfig((ctx) => {
|
||||||
notify: {
|
notify: {
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
avatar: 'https://cdn.quasar.dev/img/boy-avatar.png',
|
avatar: 'https://cdn.quasar.dev/img/boy-avatar.png',
|
||||||
}
|
},
|
||||||
|
dark: 'auto',
|
||||||
},
|
},
|
||||||
|
|
||||||
// iconSet: 'material-icons', // Quasar icon set
|
// iconSet: 'material-icons', // Quasar icon set
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// app global css in SCSS form
|
// app global css in SCSS form
|
||||||
@each $size in (5, 10, 15, 20, 25, 50, 75, 100) {
|
@each $size in (1, 2, 3, 4, 5, 10, 15, 20, 25, 50, 75, 100) {
|
||||||
.rounded-#{$size} {
|
.rounded-#{$size} {
|
||||||
border-radius: #{$size}px !important;
|
border-radius: #{$size}px !important;
|
||||||
}
|
}
|
||||||
|
|
@ -22,4 +22,14 @@
|
||||||
|
|
||||||
.q-table tbody tr:hover {
|
.q-table tbody tr:hover {
|
||||||
background: #00ff260c;
|
background: #00ff260c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body--dark {
|
||||||
|
--q-secondary: #0f1114;
|
||||||
|
color: $grey-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body--light {
|
||||||
|
--q-dark: #FFF;
|
||||||
|
color: $grey-8;
|
||||||
}
|
}
|
||||||
|
|
@ -20,8 +20,8 @@ $verdigris: #6EBAB0;
|
||||||
$mint: #56B586;
|
$mint: #56B586;
|
||||||
|
|
||||||
$dark-font: #1f3a1f;
|
$dark-font: #1f3a1f;
|
||||||
$dark: #000;
|
$dark: #333;
|
||||||
$dark-page: #323232;
|
$dark-page: #343434;
|
||||||
|
|
||||||
$positive: #21ba45;
|
$positive: #21ba45;
|
||||||
$negative: #e6364b;
|
$negative: #e6364b;
|
||||||
|
|
|
||||||
|
|
@ -115,31 +115,28 @@ export default {
|
||||||
},
|
},
|
||||||
profilePage: {
|
profilePage: {
|
||||||
personalInfo: {
|
personalInfo: {
|
||||||
title: 'Profile',
|
title: 'PERSONAL',
|
||||||
firstName: 'First name',
|
firstName: 'FIRST NAME',
|
||||||
lastName: 'Last name',
|
lastName: 'LAST NAME',
|
||||||
gender: 'Gender',
|
phoneNumber: 'PHONE NUMBER',
|
||||||
genderMale: 'Man',
|
address: 'ADDRESS',
|
||||||
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',
|
addressPlaceholder: '# address, city, region, country',
|
||||||
birthDate: 'Date of birth',
|
birthDate: 'DATE OF BIRTH',
|
||||||
submitInfo: 'Update Profile',
|
|
||||||
},
|
},
|
||||||
employeeInfo: {
|
employeeInfo: {
|
||||||
title: 'Employee info',
|
title: 'CAREER',
|
||||||
workEmail: 'Work e-mail',
|
workEmail: 'E-MAIL',
|
||||||
jobTitle: 'Job Title',
|
jobTitle: 'JOB TITLE',
|
||||||
companyName: 'Company',
|
companyName: 'COMPANY',
|
||||||
supervisorName: 'Supervisor',
|
supervisorName: 'SUPERVISOR',
|
||||||
hiredDate: 'Hiring date',
|
hiredDate: 'HIRING DATE',
|
||||||
|
},
|
||||||
|
preferences: {
|
||||||
|
title: 'PREFERENCES',
|
||||||
|
display_options: "display options",
|
||||||
|
language_options: "language options",
|
||||||
|
dark_mode: 'dark',
|
||||||
|
light_mode: 'light',
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
mustEnterBirthdate: 'You must enter a valid birthdate',
|
mustEnterBirthdate: 'You must enter a valid birthdate',
|
||||||
|
|
|
||||||
|
|
@ -191,31 +191,28 @@ export default {
|
||||||
},
|
},
|
||||||
profilePage: {
|
profilePage: {
|
||||||
personalInfo: {
|
personalInfo: {
|
||||||
title: 'Info personnel',
|
title: 'PERSONNELLE',
|
||||||
firstName: 'Prénom',
|
firstName: 'PRENOM',
|
||||||
lastName: 'Nom de famille',
|
lastName: 'NOM DE FAMILLE',
|
||||||
gender: 'Genre',
|
phoneNumber: 'NUMERO DE TELEPHONE',
|
||||||
genderMale: 'Homme',
|
address: 'ADRESSE',
|
||||||
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',
|
addressPlaceholder: '# addresse, ville, région, pays',
|
||||||
birthDate: 'Date de naissance',
|
birthDate: 'DATE DE NAISSANCE',
|
||||||
submitInfo: 'Modifier Profil',
|
|
||||||
},
|
},
|
||||||
employeeInfo: {
|
employeeInfo: {
|
||||||
title: 'Info Employé',
|
title: 'CARRIÈRE',
|
||||||
workEmail: 'Courriel employé',
|
workEmail: 'COURRIEL',
|
||||||
jobTitle: 'Poste',
|
jobTitle: 'POSTE',
|
||||||
companyName: 'Compagnie',
|
companyName: 'COMPAGNIE',
|
||||||
supervisorName: 'Nom du superviseur',
|
supervisorName: 'NOM DU SUPERVISEUR',
|
||||||
hiredDate: 'Date embauché',
|
hiredDate: 'DATE EMBAUCHE',
|
||||||
|
},
|
||||||
|
preferences: {
|
||||||
|
title: 'PRÉFÉRENCES',
|
||||||
|
display_options: "Options d'affichage",
|
||||||
|
language_options: "Options de langue",
|
||||||
|
dark_mode: 'sombre',
|
||||||
|
light_mode: 'clair',
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
mustEnterBirthdate: 'Vous devez entrer une date de naissance valide',
|
mustEnterBirthdate: 'Vous devez entrer une date de naissance valide',
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
<div class="q-pt-sm q-px-xl q-pb-lg">
|
<div class="q-pt-sm q-px-xl q-pb-lg">
|
||||||
<q-card-section class="text-center">
|
<q-card-section class="text-center">
|
||||||
<div class="text-h6 text-grey-9 text-weight-bold">
|
<div class="text-h6 text-weight-bold">
|
||||||
{{ $t('loginPage.title') }}
|
{{ $t('loginPage.title') }}
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
<template>
|
<template>
|
||||||
<q-card
|
<q-card
|
||||||
v-ripple
|
v-ripple
|
||||||
class="rounded-15 bg-white col-xs-6 col-sm-4 col-md-3 col-lg-2 column no-wrap cursor-pointer q-ma-sm"
|
class="rounded-15 col-xs-6 col-sm-4 col-md-3 col-lg-2 column no-wrap cursor-pointer q-ma-sm"
|
||||||
style="max-width: 230px;"
|
style="max-width: 230px;"
|
||||||
@click="emit('onProfileClick', props.row.email)"
|
@click="emit('onProfileClick', props.row.email)"
|
||||||
>
|
>
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-separator color="primary" class="q-mx-sm q-mt-xs" />
|
<q-separator color="primary" class="q-mx-sm q-mt-xs" />
|
||||||
<q-card-section class="text-caption text-grey-8 text-body2 text-uppercase q-pt-none text-center col content-start" style="min-height: 5em;">
|
<q-card-section class="text-caption text-body2 text-uppercase q-pt-none text-center col content-start" style="min-height: 5em;">
|
||||||
<div class=" ellipsis-2-lines">
|
<div class=" ellipsis-2-lines">
|
||||||
{{ props.row.job_title }}
|
{{ props.row.job_title }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@
|
||||||
:rows-per-page-options="[0]"
|
:rows-per-page-options="[0]"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
class="q-pa-md bg-transparent"
|
class="q-pa-md bg-transparent"
|
||||||
|
:class="isGridMode ? '': 'my-sticky-header-table'"
|
||||||
|
:table-class="$q.dark.isActive ? 'q-px-md q-py-none q-mx-md rounded-10 bg-dark' : 'q-px-md q-py-none q-mx-md rounded-10 bg-white'"
|
||||||
color="primary"
|
color="primary"
|
||||||
table-header-class="text-primary text-uppercase"
|
table-header-class="text-primary text-uppercase"
|
||||||
card-container-class="justify-center"
|
card-container-class="justify-center"
|
||||||
|
|
@ -57,8 +59,6 @@
|
||||||
:no-data-label="$t('shared.failedToLoad')"
|
:no-data-label="$t('shared.failedToLoad')"
|
||||||
:no-results-label="$t('shared.failedToSearch')"
|
:no-results-label="$t('shared.failedToSearch')"
|
||||||
:loading-label="$t('shared.loading')"
|
:loading-label="$t('shared.loading')"
|
||||||
table-class="bg-white q-pa-md q-mx-md rounded-10 shadow-12"
|
|
||||||
table-style=""
|
|
||||||
@row-click="() => console.log('click!')"
|
@row-click="() => console.log('click!')"
|
||||||
>
|
>
|
||||||
<template v-slot:item="props">
|
<template v-slot:item="props">
|
||||||
|
|
@ -102,4 +102,23 @@
|
||||||
</template>
|
</template>
|
||||||
</q-table>
|
</q-table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
.my-sticky-header-table
|
||||||
|
thead tr:first-child th
|
||||||
|
background-color: var(--q-dark)
|
||||||
|
margin-top: none
|
||||||
|
|
||||||
|
thead tr th
|
||||||
|
position: sticky
|
||||||
|
z-index: 1
|
||||||
|
thead tr:first-child th
|
||||||
|
top: 0
|
||||||
|
|
||||||
|
&.q-table--loading thead tr:last-child th
|
||||||
|
top: 48px
|
||||||
|
|
||||||
|
tbody
|
||||||
|
scroll-margin-top: 48px
|
||||||
|
</style>
|
||||||
|
|
@ -9,4 +9,19 @@ export interface EmployeeProfile {
|
||||||
first_work_day: string;
|
first_work_day: string;
|
||||||
last_work_day: string;
|
last_work_day: string;
|
||||||
residence: string;
|
residence: string;
|
||||||
|
birth_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const default_employee_profile: EmployeeProfile = {
|
||||||
|
first_name: '',
|
||||||
|
last_name: '',
|
||||||
|
supervisor_full_name: '',
|
||||||
|
company_name: -1,
|
||||||
|
job_title: '',
|
||||||
|
email: '',
|
||||||
|
phone_number: '',
|
||||||
|
first_work_day: '',
|
||||||
|
last_work_day: '',
|
||||||
|
residence: '',
|
||||||
|
birth_date: '',
|
||||||
}
|
}
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
<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>
|
|
||||||
|
|
@ -1,147 +0,0 @@
|
||||||
<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,109 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { deepEqual } from 'src/utils/deep-equal';
|
||||||
|
import ProfileInputField from 'src/modules/profile/components/shared/profile-panel-input-field.vue';
|
||||||
|
import ProfileSelectField from 'src/modules/profile/components/shared/profile-panel-select-field.vue';
|
||||||
|
import { type EmployeeProfile } from 'src/modules/employee-list/types/employee-profile-interface';
|
||||||
|
|
||||||
|
const { employeeProfile } = defineProps<{
|
||||||
|
employeeProfile: EmployeeProfile;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
let initial_info: EmployeeProfile = employeeProfile;
|
||||||
|
let employee_form_data = ref<EmployeeProfile>({ ...employeeProfile });
|
||||||
|
const is_editing = ref<boolean>(false);
|
||||||
|
|
||||||
|
const supervisor_options = [{ label: 'AAA', value: '1' }, { label: 'BBB', value: '2' }, { label: 'CCC', value: '3' }, { label: 'DDD', value: '4' }];
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
if (!is_editing.value) {
|
||||||
|
is_editing.value = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_editing.value = false;
|
||||||
|
initial_info = { ...employee_form_data.value }; // update initial value for future possible resets
|
||||||
|
|
||||||
|
if (!deepEqual(employee_form_data, initial_info)) {
|
||||||
|
// save the new data here
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onReset = () => {
|
||||||
|
employee_form_data = ref<EmployeeProfile>(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
|
||||||
|
v-model="employee_form_data.job_title"
|
||||||
|
class="col"
|
||||||
|
:is-editing="is_editing"
|
||||||
|
:label-string="$t('profilePage.employeeInfo.jobTitle')"
|
||||||
|
/>
|
||||||
|
<ProfileInputField
|
||||||
|
v-model="employee_form_data.company_name"
|
||||||
|
class="col"
|
||||||
|
:is-editing="is_editing"
|
||||||
|
:label-string="$t('profilePage.employeeInfo.companyName')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="q-mx-xs">
|
||||||
|
<ProfileSelectField
|
||||||
|
v-model="employee_form_data.supervisor_full_name"
|
||||||
|
:options="supervisor_options"
|
||||||
|
:label-string="$t('profilePage.employeeInfo.supervisorName')"
|
||||||
|
:is-editing="is_editing"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div :class="$q.screen.lt.md ? 'column' : 'row'">
|
||||||
|
<ProfileInputField
|
||||||
|
v-model="employee_form_data.email"
|
||||||
|
class="col"
|
||||||
|
:is-editing="is_editing"
|
||||||
|
:label-string="$t('profilePage.employeeInfo.workEmail')"
|
||||||
|
/>
|
||||||
|
<ProfileInputField
|
||||||
|
v-model="employee_form_data.first_work_day"
|
||||||
|
readonly
|
||||||
|
class="col"
|
||||||
|
type="date"
|
||||||
|
:is-editing="is_editing"
|
||||||
|
:label-string="$t('profilePage.employeeInfo.hiredDate')"
|
||||||
|
/>
|
||||||
|
</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')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-form>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { deepEqual } from 'src/utils/deep-equal';
|
||||||
|
import ProfileInputField from 'src/modules/profile/components/shared/profile-panel-input-field.vue';
|
||||||
|
import { type EmployeeProfile } from 'src/modules/employee-list/types/employee-profile-interface';
|
||||||
|
|
||||||
|
const { employeeProfile } = defineProps<{
|
||||||
|
employeeProfile: EmployeeProfile;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const is_editing = ref<boolean>(false);
|
||||||
|
|
||||||
|
let initial_info: EmployeeProfile = employeeProfile;
|
||||||
|
const personal_form_data = ref<EmployeeProfile>({ ...employeeProfile });
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
if (!is_editing.value) {
|
||||||
|
is_editing.value = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_editing.value = false;
|
||||||
|
initial_info = { ...personal_form_data.value }; // update initial value for future possible resets
|
||||||
|
|
||||||
|
if (!deepEqual(personal_form_data.value, initial_info)) {
|
||||||
|
// save the new data here
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onReset = () => {
|
||||||
|
personal_form_data.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
|
||||||
|
v-model="personal_form_data.first_name"
|
||||||
|
type="text"
|
||||||
|
class="col"
|
||||||
|
:is-editing="is_editing"
|
||||||
|
:label-string="$t('profilePage.personalInfo.firstName')"
|
||||||
|
/>
|
||||||
|
<ProfileInputField
|
||||||
|
v-model="personal_form_data.last_name"
|
||||||
|
class="col"
|
||||||
|
type="text"
|
||||||
|
:is-editing="is_editing"
|
||||||
|
:label-string="$t('profilePage.personalInfo.lastName')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :class="$q.screen.lt.md ? 'column' : 'row'">
|
||||||
|
<ProfileInputField
|
||||||
|
v-model="personal_form_data.phone_number"
|
||||||
|
class="col"
|
||||||
|
type="text"
|
||||||
|
:is-editing="is_editing"
|
||||||
|
:label-string="$t('profilePage.personalInfo.phoneNumber')"
|
||||||
|
/>
|
||||||
|
<ProfileInputField
|
||||||
|
v-model="personal_form_data.birth_date"
|
||||||
|
class="col"
|
||||||
|
mask="#### / ## / ##"
|
||||||
|
hint="ex: 1970 / 01 / 01"
|
||||||
|
:is-editing="is_editing"
|
||||||
|
:label-string="$t('profilePage.personalInfo.birthDate')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :class="$q.screen.lt.md ? 'column' : 'row'">
|
||||||
|
<ProfileInputField
|
||||||
|
v-model="personal_form_data.residence"
|
||||||
|
class="col"
|
||||||
|
:is-editing="is_editing"
|
||||||
|
:label-string="$t('profilePage.personalInfo.address')"
|
||||||
|
:hint="$t('profilePage.personalInfo.addressPlaceholder')"
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
18
src/modules/profile/components/shared/profile-header.vue
Normal file
18
src/modules/profile/components/shared/profile-header.vue
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const { userFirstName = '', userLastName = '' } = defineProps<{
|
||||||
|
userFirstName: string;
|
||||||
|
userLastName: string;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-img
|
||||||
|
src="src/assets/profile_header_default.png"
|
||||||
|
height="15vh"
|
||||||
|
:width="$q.screen.lt.md ? '80vw' : '40vw'"
|
||||||
|
class="rounded-5 q-mb-md shadow-2 col-auto"
|
||||||
|
fit="cover"
|
||||||
|
>
|
||||||
|
<div class="absolute-bottom text-h5 text-uppercase text-weight-bolder" style="line-height: 0.8em;">{{ userFirstName }} {{ userLastName }}</div>
|
||||||
|
</q-img>
|
||||||
|
</template>
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
<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,36 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { ValidationRule } from 'quasar';
|
||||||
|
|
||||||
|
const model = defineModel<string | number>({ required: true });
|
||||||
|
|
||||||
|
const { readonly = false, hint = '' } = defineProps<{
|
||||||
|
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[];
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-input
|
||||||
|
v-model="model"
|
||||||
|
dense
|
||||||
|
:stack-label="!isEditing"
|
||||||
|
autogrow
|
||||||
|
filled
|
||||||
|
debounce="500"
|
||||||
|
label-color="primary"
|
||||||
|
class="q-ma-xs"
|
||||||
|
input-class="text-weight-medium text-h6"
|
||||||
|
:hide-hint="hint === ''"
|
||||||
|
:hint="isEditing ? hint : ''"
|
||||||
|
:mask="mask"
|
||||||
|
:readonly="readonly || !isEditing"
|
||||||
|
:type="type"
|
||||||
|
:label="labelString"
|
||||||
|
:rules="rules"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { Dark } from 'quasar';
|
||||||
|
import LanguageSwitch from 'src/modules/shared/components/language-switch.vue';
|
||||||
|
|
||||||
|
const initial_dark_mode_value = Dark.isActive;
|
||||||
|
const is_dark_mode = ref<boolean>(initial_dark_mode_value);
|
||||||
|
|
||||||
|
const toggle_dark_mode = (value: boolean) => {
|
||||||
|
is_dark_mode.value = value;
|
||||||
|
Dark.set(value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-form class="q-pa-md column fit">
|
||||||
|
<div class="col-auto text-uppercase rounded-5" style="line-height: 1em;">{{ $t('profilePage.preferences.display_options') }}</div>
|
||||||
|
<q-card
|
||||||
|
flat
|
||||||
|
class="col-auto column justify-center items-center content-center q-mb-lg q-pa-md"
|
||||||
|
style="border: solid #AAA 1px;"
|
||||||
|
>
|
||||||
|
|
||||||
|
<div class="row col">
|
||||||
|
<q-card flat class="col column q-pa-xs bg-white" style="border: solid 1px var(--q-primary);">
|
||||||
|
<div
|
||||||
|
class="col-auto column rounded-4 ellipsis"
|
||||||
|
style="height: 90px; min-width: 80px; background-color: #DAE0E7;"
|
||||||
|
>
|
||||||
|
<div class="bg-primary col-1"></div>
|
||||||
|
<div class=" row col">
|
||||||
|
<div class="col-8 q-ma-xs rounded-borders" style="background-color: white;"></div>
|
||||||
|
<div class="col column q-gutter-xs q-py-xs q-pr-xs">
|
||||||
|
<div class="col rounded-borders" style="background-color: white;"></div>
|
||||||
|
<div class="col rounded-borders" style="background-color: white;"></div>
|
||||||
|
<div class="col rounded-borders" style="background-color: white;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-primary col-1"></div>
|
||||||
|
</div>
|
||||||
|
<span class="col-auto text-subtitle2 text-primary text-center text-uppercase">{{$t('profilePage.preferences.light_mode')}}</span>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
|
<q-toggle
|
||||||
|
v-model="is_dark_mode"
|
||||||
|
@update:model-value="value => toggle_dark_mode(value)"
|
||||||
|
size="xl"
|
||||||
|
class="col-auto"
|
||||||
|
checked-icon="dark_mode"
|
||||||
|
unchecked-icon="light_mode"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-card flat class="col column q-pa-xs bg-white" style="border: solid 1px var(--q-primary);">
|
||||||
|
<div
|
||||||
|
class="col-auto column rounded-4 ellipsis"
|
||||||
|
style="height: 90px; min-width: 80px; background-color: #0f1114;"
|
||||||
|
>
|
||||||
|
<div class="bg-primary col-1"></div>
|
||||||
|
<div class=" row col">
|
||||||
|
<div class="col-8 q-ma-xs rounded-borders" style="background-color: #333;"></div>
|
||||||
|
<div class="col column q-gutter-xs q-py-xs q-pr-xs">
|
||||||
|
<div class="col rounded-borders" style="background-color: #333;"></div>
|
||||||
|
<div class="col rounded-borders" style="background-color: #333;"></div>
|
||||||
|
<div class="col rounded-borders" style="background-color: #333;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-primary col-1"></div>
|
||||||
|
</div>
|
||||||
|
<span class="col-auto text-subtitle2 text-primary text-center text-uppercase">{{$t('profilePage.preferences.dark_mode')}}</span>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
|
<div class="col-auto text-uppercase rounded-5" style="line-height: 1em;">{{ $t('profilePage.preferences.language_options') }}</div>
|
||||||
|
<q-card
|
||||||
|
flat
|
||||||
|
class="col-auto column justify-center items-center content-center q-mb-lg q-pa-md"
|
||||||
|
style="border: solid #AAA 1px;"
|
||||||
|
>
|
||||||
|
|
||||||
|
<LanguageSwitch class="q-mr-xs col-auto" />
|
||||||
|
</q-card>
|
||||||
|
</q-form>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const model = defineModel<string>();
|
||||||
|
|
||||||
|
const { readonly = false, localizeOptions = false } = defineProps<{
|
||||||
|
options: { label: string, value: string }[];
|
||||||
|
labelString: string;
|
||||||
|
isEditing: boolean;
|
||||||
|
readonly?: boolean;
|
||||||
|
localizeOptions?: boolean;
|
||||||
|
type?: "number" | "textarea" | "time" | "text" | "tel" | "password" | "email" | "search" | "file" | "url" | "date" | "datetime-local" | undefined;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-select
|
||||||
|
v-model="model"
|
||||||
|
dense
|
||||||
|
:stack-label="!isEditing"
|
||||||
|
filled
|
||||||
|
label-color="primary"
|
||||||
|
class="q-ma-xs text-h6"
|
||||||
|
popup-content-class="text-weight-medium text-h6"
|
||||||
|
input-class="text-weight-medium"
|
||||||
|
:options="options"
|
||||||
|
:readonly="readonly || !isEditing"
|
||||||
|
:hide-dropdown-icon="!isEditing"
|
||||||
|
:label="labelString"
|
||||||
|
:option-label="opt => localizeOptions ? $t(opt) : opt"
|
||||||
|
hint=''
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
<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>
|
|
||||||
|
|
@ -1,49 +1,51 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type Component, ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import ProfileHeader from 'src/modules/profile/components/shared/profile-header.vue';
|
||||||
|
|
||||||
interface MenuTab {
|
const { firstName, lastName, initialMenu } = defineProps<{
|
||||||
name: string;
|
firstName: string;
|
||||||
icon: string;
|
lastName: string;
|
||||||
label: string;
|
initialMenu: string;
|
||||||
};
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
menuTabs: MenuTab[];
|
|
||||||
tabContents: Component[];
|
|
||||||
currentMenu?: string | undefined;
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const current_menu = ref<string>(props.currentMenu || '');
|
const current_menu = ref<string>(initialMenu);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="row" :class="$q.screen.lt.md ? 'full-width' : ''">
|
<div
|
||||||
<div class="col-auto column">
|
:class="$q.screen.lt.md ? 'column no-wrap' : 'row'"
|
||||||
<q-card class="col-auto q-mr-sm q-pa-xs">
|
:style="$q.screen.lt.md ? 'width: 90vw;' : 'width: 40vw;'"
|
||||||
|
>
|
||||||
|
<ProfileHeader
|
||||||
|
:user-first-name="firstName"
|
||||||
|
:user-last-name="lastName"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="col-3 no-wrap"
|
||||||
|
:class="$q.screen.lt.md ? '' : 'column'"
|
||||||
|
>
|
||||||
|
<q-card
|
||||||
|
class="col-auto q-pa-xs"
|
||||||
|
:class="$q.screen.lt.md ? 'q-mb-sm' : 'q-mr-sm'"
|
||||||
|
>
|
||||||
<q-tabs
|
<q-tabs
|
||||||
v-model="current_menu"
|
v-model="current_menu"
|
||||||
vertical
|
:vertical="$q.screen.gt.sm"
|
||||||
dense
|
dense
|
||||||
active-color="primary"
|
active-color="primary"
|
||||||
indicator-color="primary"
|
indicator-color="primary"
|
||||||
content-class=""
|
|
||||||
inline-label
|
|
||||||
align="left"
|
|
||||||
>
|
>
|
||||||
<q-tab
|
<slot name="tabs"></slot>
|
||||||
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-tabs>
|
||||||
</q-card>
|
</q-card>
|
||||||
<div class="col"></div>
|
<div class="col"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-card class="col q-ml-sm">
|
<q-card
|
||||||
|
class="col"
|
||||||
|
:class="$q.screen.lt.md ? '' : 'q-ml-sm'"
|
||||||
|
>
|
||||||
<q-tab-panels
|
<q-tab-panels
|
||||||
v-model="current_menu"
|
v-model="current_menu"
|
||||||
animated
|
animated
|
||||||
|
|
@ -51,16 +53,9 @@
|
||||||
transition-prev="jump-up"
|
transition-prev="jump-up"
|
||||||
transition-next="jump-up"
|
transition-next="jump-up"
|
||||||
class="rounded-5"
|
class="rounded-5"
|
||||||
:style="$q.screen.lt.md ? 'height: 70vh;' : 'height: 50vh; width: 40vw;'"
|
style="height: 50vh;"
|
||||||
>
|
>
|
||||||
<q-tab-panel
|
<slot name="panels"></slot>
|
||||||
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-tab-panels>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,60 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18n } from 'vue-i18n';
|
import PanelInfoPersonal from 'src/modules/profile/components/employee/profile-panel-info-personal.vue';
|
||||||
import PanelInfoPersonal from 'src/modules/profile/components/employee/panel-info-personal.vue';
|
import PanelInfoEmployee from 'src/modules/profile/components/employee/profile-panel-info-employee.vue';
|
||||||
|
import PanelPreferences from 'src/modules/profile/components/shared/profile-panel-preferences.vue';
|
||||||
import ProfileTabMenuTemplate from 'src/modules/profile/components/shared/profile-tab-menu-template.vue';
|
import ProfileTabMenuTemplate from 'src/modules/profile/components/shared/profile-tab-menu-template.vue';
|
||||||
|
import { default_employee_profile, type EmployeeProfile } from 'src/modules/employee-list/types/employee-profile-interface';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const PanelNames = {
|
||||||
|
PERSONAL_INFO: 'personal_info',
|
||||||
|
EMPLOYEE_INFO: 'employee_info',
|
||||||
|
PREFERENCES: 'references',
|
||||||
|
};
|
||||||
|
|
||||||
const tabs = [
|
const { employeeProfile = default_employee_profile } = defineProps<{
|
||||||
{
|
employeeProfile?: EmployeeProfile | undefined;
|
||||||
name: 'personal_info',
|
}>();
|
||||||
icon: 'badge',
|
|
||||||
label: t('profilePage.personalInfo.title'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'employee_info',
|
|
||||||
icon: 'business',
|
|
||||||
label: t('profilePage.employeeInfo.title'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const components = [ PanelInfoPersonal, ];
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-card flat class="rounded-5 bg-transparent q-pa-none">
|
<q-card flat class="rounded-5 bg-transparent q-pa-none">
|
||||||
<ProfileTabMenuTemplate
|
<ProfileTabMenuTemplate
|
||||||
:menu-tabs="tabs"
|
:first-name="employeeProfile.first_name"
|
||||||
:tab-contents="components"
|
:last-name="employeeProfile.last_name"
|
||||||
:current-menu="tabs[0]?.name"
|
:initial-menu="PanelNames.PERSONAL_INFO"
|
||||||
/>
|
>
|
||||||
|
<template #tabs>
|
||||||
|
<q-tab
|
||||||
|
:name='PanelNames.PERSONAL_INFO'
|
||||||
|
icon='person_outline'
|
||||||
|
:label="$q.screen.lt.md ? '' : $t('profilePage.personalInfo.title')"
|
||||||
|
/>
|
||||||
|
<q-tab
|
||||||
|
:name="PanelNames.EMPLOYEE_INFO"
|
||||||
|
icon="work_outline"
|
||||||
|
:label="$q.screen.lt.md ? '' : $t('profilePage.employeeInfo.title')"
|
||||||
|
/>
|
||||||
|
<q-tab
|
||||||
|
:name="PanelNames.PREFERENCES"
|
||||||
|
icon="display_settings"
|
||||||
|
:label="$q.screen.lt.md ? '' : $t('profilePage.preferences.title')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #panels>
|
||||||
|
<q-tab-panel :name="PanelNames.PERSONAL_INFO" class="q-pa-none">
|
||||||
|
<PanelInfoPersonal :employee-profile="employeeProfile" />
|
||||||
|
</q-tab-panel>
|
||||||
|
|
||||||
|
<q-tab-panel :name="PanelNames.EMPLOYEE_INFO" class="q-pa-none">
|
||||||
|
<PanelInfoEmployee :employee-profile="employeeProfile" />
|
||||||
|
</q-tab-panel>
|
||||||
|
|
||||||
|
<q-tab-panel :name="PanelNames.PREFERENCES" class="q-pa-none">
|
||||||
|
<PanelPreferences />
|
||||||
|
</q-tab-panel>
|
||||||
|
</template>
|
||||||
|
</ProfileTabMenuTemplate>
|
||||||
</q-card>
|
</q-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -1,31 +1,22 @@
|
||||||
<script setup lang="ts">
|
<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';
|
import ProfileEmployee from 'src/modules/profile/pages/employee/profile-employee.vue';
|
||||||
|
import { useAuthStore } from 'src/stores/auth-store';
|
||||||
|
import { type EmployeeProfile } from 'src/modules/employee-list/types/employee-profile-interface';
|
||||||
|
|
||||||
const auth_store = useAuthStore();
|
const auth_store = useAuthStore();
|
||||||
|
const employee_roles = [ 'SUPERVISOR', 'EMPLOYEE', 'ADMIN', 'HR', 'ACCOUNTING' ];
|
||||||
|
|
||||||
const getUserProfileComponent = (): Component => {
|
const { employeeProfile } = defineProps<{
|
||||||
console.log('user role: ', auth_store.user.role);
|
employeeProfile?: EmployeeProfile | undefined;
|
||||||
|
}>();
|
||||||
switch (auth_store.user.role.toUpperCase()) {
|
|
||||||
case 'SUPERVISOR': return ProfileEmployee;
|
|
||||||
default: return h('div', { class: 'empty' }, '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-page class="bg-secondary column items-center justify-center">
|
<q-page class="bg-secondary column items-center justify-center">
|
||||||
<q-img
|
<ProfileEmployee
|
||||||
src="src/assets/profile_header_default.png"
|
v-if="employee_roles.includes( auth_store.user.role.toUpperCase() )"
|
||||||
height="15vh"
|
class="col-auto"
|
||||||
width="50vw"
|
:employee-profile="employeeProfile"
|
||||||
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>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
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: '',
|
|
||||||
}
|
|
||||||
|
|
@ -9,26 +9,28 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-btn-dropdown flat :label="$t('shared.languageLabel')" class="rounded-borders" icon="language">
|
<div>
|
||||||
|
<q-list dense class="row">
|
||||||
|
<q-item v-for="option in localeOptions"
|
||||||
|
:key="option.value"
|
||||||
|
tag="label"
|
||||||
|
v-ripple
|
||||||
|
>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-radio v-model="locale" :val="option.value" />
|
||||||
|
</q-item-section>
|
||||||
|
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{ option.label }}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</div>
|
||||||
|
<!-- <q-btn-dropdown push color="primary" :label="$t('shared.languageLabel')" icon="language">
|
||||||
<q-list>
|
<q-list>
|
||||||
<q-item clickable v-close-popup v-for="option in localeOptions" :key="option.value" @click="locale = option.value">
|
<q-item clickable v-close-popup v-for="option in localeOptions" :key="option.value" @click="locale = option.value">
|
||||||
<q-item-section>{{ option.label }}</q-item-section>
|
<q-item-section>{{ option.label }}</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</q-btn-dropdown>
|
</q-btn-dropdown> -->
|
||||||
|
|
||||||
<!-- <q-select
|
|
||||||
v-model="locale"
|
|
||||||
:options="localeOptions"
|
|
||||||
dense
|
|
||||||
borderless
|
|
||||||
emit-value
|
|
||||||
map-options
|
|
||||||
hide-dropdown-icon
|
|
||||||
class="text-white"
|
|
||||||
>
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<q-icon name="language" color="white"/>
|
|
||||||
</template>
|
|
||||||
</q-select> -->
|
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import LanguageSwitch from '../language-switch.vue';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-footer elevated class="bg-primary text-white">
|
<q-footer elevated class="bg-primary text-white">
|
||||||
<q-toolbar>
|
<q-toolbar>
|
||||||
<q-toolbar-title>© 2025 Targo Communications inc.</q-toolbar-title>
|
<q-toolbar-title>© 2025 Targo Communications inc.</q-toolbar-title>
|
||||||
<LanguageSwitch class="q-mr-xs text-white" />
|
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</q-footer>
|
</q-footer>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
<q-icon name="home" color="primary" />
|
<q-icon name="home" color="primary" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label class="text-uppercase text-grey-8 text-weight-bold">{{ $t('navBar.userMenuHome') }}</q-item-label>
|
<q-item-label class="text-uppercase text-weight-bold">{{ $t('navBar.userMenuHome') }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
<q-icon name="event_available" color="primary" />
|
<q-icon name="event_available" color="primary" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label class="text-uppercase text-grey-8 text-weight-bold">{{ $t('navBar.userMenuShiftValidation') }}</q-item-label>
|
<q-item-label class="text-uppercase text-weight-bold">{{ $t('navBar.userMenuShiftValidation') }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
|
|
@ -58,7 +58,7 @@
|
||||||
<q-icon name="view_list" color="primary" />
|
<q-icon name="view_list" color="primary" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label class="text-uppercase text-grey-8 text-weight-bold">{{ $t('navBar.userMenuEmployeeList') }}</q-item-label>
|
<q-item-label class="text-uppercase text-weight-bold">{{ $t('navBar.userMenuEmployeeList') }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
<q-icon name="punch_clock" color="primary" />
|
<q-icon name="punch_clock" color="primary" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label class="text-uppercase text-grey-8 text-weight-bold">{{ $t('navBar.userMenuTimesheetTemp') }}</q-item-label>
|
<q-item-label class="text-uppercase text-weight-bold">{{ $t('navBar.userMenuTimesheetTemp') }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
|
|
@ -79,7 +79,7 @@
|
||||||
<q-icon name="account_box" color="primary" />
|
<q-icon name="account_box" color="primary" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label class="text-uppercase text-grey-8 text-weight-bold">{{ $t('navBar.userMenuProfile') }}</q-item-label>
|
<q-item-label class="text-uppercase text-weight-bold">{{ $t('navBar.userMenuProfile') }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
|
|
@ -89,7 +89,7 @@
|
||||||
<q-icon name="contact_support" color="primary" />
|
<q-icon name="contact_support" color="primary" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label class="text-uppercase text-grey-8 text-weight-bold">{{ $t('navBar.userMenuHelp') }}</q-item-label>
|
<q-item-label class="text-uppercase text-weight-bold">{{ $t('navBar.userMenuHelp') }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
<q-icon name="exit_to_app" color="primary" />
|
<q-icon name="exit_to_app" color="primary" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label class="text-uppercase text-grey-8 text-weight-bold">{{ $t('navBar.userMenuLogout') }}</q-item-label>
|
<q-item-label class="text-uppercase text-weight-bold">{{ $t('navBar.userMenuLogout') }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-scroll-area>
|
</q-scroll-area>
|
||||||
|
|
|
||||||
|
|
@ -20,25 +20,9 @@ import { ref } from 'vue';
|
||||||
default : return 'transparent';
|
default : return 'transparent';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTextColor = (type: string): string => {
|
|
||||||
switch(type) {
|
|
||||||
case 'REGULAR': return 'grey-8';
|
|
||||||
case '': return 'transparent';
|
|
||||||
default: return 'white';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-dialog
|
|
||||||
v-model="is_showing_time_popup"
|
|
||||||
>
|
|
||||||
<q-card class="q-pa-xl">
|
|
||||||
LOL
|
|
||||||
</q-card>
|
|
||||||
|
|
||||||
</q-dialog>
|
|
||||||
<q-card-section
|
<q-card-section
|
||||||
horizontal
|
horizontal
|
||||||
class="q-pa-none text-uppercase text-center items-center cursor-pointer rounded-10"
|
class="q-pa-none text-uppercase text-center items-center cursor-pointer rounded-10"
|
||||||
|
|
@ -49,7 +33,7 @@ import { ref } from 'vue';
|
||||||
<q-card-section class="q-pa-none col">
|
<q-card-section class="q-pa-none col">
|
||||||
<q-item-label
|
<q-item-label
|
||||||
class="text-weight-bolder q-pa-xs rounded-5"
|
class="text-weight-bolder q-pa-xs rounded-5"
|
||||||
:class="'bg-' + getShiftColor(props.shift.type) + ' text-' + getTextColor(props.shift.type)"
|
:class="'bg-' + getShiftColor(props.shift.type) + (!$q.dark.isActive && props.shift.type === 'REGULAR' ? '' : ' text-white')"
|
||||||
style="font-size: 1.5em; line-height: 80% !important;"
|
style="font-size: 1.5em; line-height: 80% !important;"
|
||||||
>
|
>
|
||||||
{{ props.shift.start_time }}
|
{{ props.shift.start_time }}
|
||||||
|
|
@ -80,8 +64,8 @@ import { ref } from 'vue';
|
||||||
<!-- punch-out timestamps -->
|
<!-- punch-out timestamps -->
|
||||||
<q-card-section class="q-pa-none col">
|
<q-card-section class="q-pa-none col">
|
||||||
<q-item-label
|
<q-item-label
|
||||||
class="text-weight-bolder text-white q-pa-xs rounded-5"
|
class="text-weight-bolder q-pa-xs rounded-5"
|
||||||
:class="'bg-' + getShiftColor(props.shift.type) + ' text-' + getTextColor(props.shift.type)"
|
:class="'bg-' + getShiftColor(props.shift.type) + (!$q.dark.isActive && props.shift.type === 'REGULAR' ? '' : ' text-white')"
|
||||||
style="font-size: 1.5em; line-height: 80% !important;"
|
style="font-size: 1.5em; line-height: 80% !important;"
|
||||||
>
|
>
|
||||||
{{ props.shift.end_time }}
|
{{ props.shift.end_time }}
|
||||||
|
|
@ -97,7 +81,6 @@ import { ref } from 'vue';
|
||||||
v-if="props.shift.type !== ''"
|
v-if="props.shift.type !== ''"
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
color='grey-8'
|
|
||||||
icon="chat_bubble_outline"
|
icon="chat_bubble_outline"
|
||||||
class="q-pa-none"
|
class="q-pa-none"
|
||||||
/>
|
/>
|
||||||
|
|
@ -107,7 +90,6 @@ import { ref } from 'vue';
|
||||||
v-if="props.shift.type !== ''"
|
v-if="props.shift.type !== ''"
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
color='grey-8'
|
|
||||||
icon="attach_money"
|
icon="attach_money"
|
||||||
class="q-pa-none q-mx-xs"
|
class="q-pa-none q-mx-xs"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -67,10 +67,7 @@
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
<q-separator
|
<q-separator size="2px" />
|
||||||
color="accent"
|
|
||||||
style="height: 2px;"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Main body of pay period card -->
|
<!-- Main body of pay period card -->
|
||||||
<q-card-section class="q-pa-none q-mt-xs q-mb-sm">
|
<q-card-section class="q-pa-none q-mt-xs q-mb-sm">
|
||||||
|
|
@ -89,15 +86,12 @@
|
||||||
<q-item-label class="text-weight-bold text-primary q-pa-none text-uppercase text-caption">
|
<q-item-label class="text-weight-bold text-primary q-pa-none text-uppercase text-caption">
|
||||||
{{ props.cols.find(c => c.name === 'regular_hours')?.label }}
|
{{ props.cols.find(c => c.name === 'regular_hours')?.label }}
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
<q-item-label class="text-weight-bolder text-h3 text-grey-8 q-py-none">
|
<q-item-label class="text-weight-bolder text-h3 q-py-none">
|
||||||
{{ props.cols.find(c => c.name === 'regular_hours')?.value }}
|
{{ props.cols.find(c => c.name === 'regular_hours')?.value }}
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
<q-separator
|
<q-separator class="q-mx-sm" />
|
||||||
color="accent"
|
|
||||||
class="q-mx-sm"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Other hour types segment -->
|
<!-- Other hour types segment -->
|
||||||
<div :class="$q.screen.lt.md ? 'column' : 'row no-wrap'">
|
<div :class="$q.screen.lt.md ? 'column' : 'row no-wrap'">
|
||||||
|
|
@ -113,16 +107,15 @@
|
||||||
>
|
>
|
||||||
{{ col.label }}
|
{{ col.label }}
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
<q-item-label class="text-weight-bolder q-pa-none text-h6 text-grey-8">
|
<q-item-label class="text-weight-bolder q-pa-none text-h6 ">
|
||||||
{{ col.value }}
|
{{ col.value }}
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
</q-item>
|
</q-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-separator
|
<q-separator
|
||||||
vertical
|
vertical
|
||||||
color="accent"
|
|
||||||
class="q-mt-xs q-mb-none"
|
class="q-mt-xs q-mb-none"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -140,7 +133,7 @@
|
||||||
>
|
>
|
||||||
{{ col.label }}
|
{{ col.label }}
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
<q-item-label class="text-weight-bolder q-pa-none text-h6 text-grey-8">
|
<q-item-label class="text-weight-bolder q-pa-none text-h6 ">
|
||||||
{{ col.value }}
|
{{ col.value }}
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
@ -157,7 +150,7 @@
|
||||||
<q-card-section
|
<q-card-section
|
||||||
horizontal
|
horizontal
|
||||||
class="q-pa-sm text-weight-bold"
|
class="q-pa-sm text-weight-bold"
|
||||||
:class="props.initialState ? 'text-white bg-primary' : 'text-primary bg-white'"
|
:class="props.initialState ? 'text-white bg-primary' : 'bg-dark'"
|
||||||
>
|
>
|
||||||
<q-item-label class="text-uppercase text-h6 q-ml-sm text-weight-bolder"> {{ props.row.total_hours + 'h' }} </q-item-label>
|
<q-item-label class="text-uppercase text-h6 q-ml-sm text-weight-bolder"> {{ props.row.total_hours + 'h' }} </q-item-label>
|
||||||
<q-item-label class="text-uppercase text-weight-bold q-ml-xs"> total </q-item-label>
|
<q-item-label class="text-uppercase text-weight-bold q-ml-xs"> total </q-item-label>
|
||||||
|
|
|
||||||
|
|
@ -169,8 +169,8 @@
|
||||||
:no-results-label="$t('shared.failedToSearch')"
|
:no-results-label="$t('shared.failedToSearch')"
|
||||||
:loading-label="$t('shared.loading')"
|
:loading-label="$t('shared.loading')"
|
||||||
>
|
>
|
||||||
<!-- Top Bar that contains Search, Title, Filters -->
|
<!-- Top Bar that contains Date Picker, Search, Filters, Print Report, etc -->
|
||||||
<template v-slot:top>
|
<template #top>
|
||||||
<div class="full-width" :class="$q.screen.lt.md ? 'text-center q-gutter-sm' : 'row'">
|
<div class="full-width" :class="$q.screen.lt.md ? 'text-center q-gutter-sm' : 'row'">
|
||||||
<!-- Date Picker -->
|
<!-- Date Picker -->
|
||||||
<TimesheetApprovalPeriodPicker
|
<TimesheetApprovalPeriodPicker
|
||||||
|
|
@ -232,7 +232,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Template for individual employee cards -->
|
<!-- Template for individual employee cards -->
|
||||||
<template v-slot:item="props: {
|
<template #item="props: {
|
||||||
cols: (QTableColumn<PayPeriodOverviewEmployee> & { value: unknown })[],
|
cols: (QTableColumn<PayPeriodOverviewEmployee> & { value: unknown })[],
|
||||||
row: PayPeriodOverviewEmployee,
|
row: PayPeriodOverviewEmployee,
|
||||||
key: string,
|
key: string,
|
||||||
|
|
@ -247,7 +247,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Template for custome failed-to-load state -->
|
<!-- Template for custome failed-to-load state -->
|
||||||
<template v-slot:no-data="{ message, filter }">
|
<template #no-data="{ message, filter }">
|
||||||
<div class="full-width column items-center text-primary q-gutter-sm">
|
<div class="full-width column items-center text-primary q-gutter-sm">
|
||||||
<span class="text-h6 q-mt-xl">
|
<span class="text-h6 q-mt-xl">
|
||||||
{{ message }}
|
{{ message }}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-card
|
<q-card
|
||||||
class="q-pa-sm bg-white shadow-12 rounded-15 column no-wrap relative"
|
class="q-pa-sm shadow-12 rounded-15 column no-wrap relative"
|
||||||
:style="$q.screen.gt.sm ? 'width: 70vw !important; height: 90vh !important;' : '' "
|
:style="$q.screen.gt.sm ? 'width: 70vw !important; height: 90vh !important;' : '' "
|
||||||
>
|
>
|
||||||
<!-- loader -->
|
<!-- loader -->
|
||||||
|
|
@ -88,7 +88,7 @@
|
||||||
>
|
>
|
||||||
{{ props.employeeName }}
|
{{ props.employeeName }}
|
||||||
|
|
||||||
<q-separator class="q-mb-sm" color="accent" size="2px" />
|
<q-separator class="q-mb-sm" size="2px" />
|
||||||
<q-card-actions align="center" class="q-pa-none">
|
<q-card-actions align="center" class="q-pa-none">
|
||||||
<q-card flat class="bg-secondary rounded-5 q-pa-xs">
|
<q-card flat class="bg-secondary rounded-5 q-pa-xs">
|
||||||
<q-btn-toggle
|
<q-btn-toggle
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { EmployeeListService } from "src/modules/employee-list/services/services-employee-list";
|
import { EmployeeListService } from "src/modules/employee-list/services/services-employee-list";
|
||||||
import type { EmployeeProfile } from "src/modules/employee-list/types/employee-profile-interface";
|
import { default_employee_profile, type EmployeeProfile } from "src/modules/employee-list/types/employee-profile-interface";
|
||||||
import type { EmployeeListTableItem } from "src/modules/employee-list/types/employee-list-table-interface";
|
import type { EmployeeListTableItem } from "src/modules/employee-list/types/employee-list-table-interface";
|
||||||
|
|
||||||
export const useEmployeeStore = defineStore('employee', () => {
|
export const useEmployeeStore = defineStore('employee', () => {
|
||||||
const employee = ref<EmployeeProfile>();
|
const employee = ref<EmployeeProfile>( default_employee_profile );
|
||||||
const employeeList = ref<EmployeeListTableItem[]>([]);
|
const employeeList = ref<EmployeeListTableItem[]>([]);
|
||||||
const isShowingEmployeeAddModifyWindow = ref<boolean>(false);
|
const isShowingEmployeeAddModifyWindow = ref<boolean>(false);
|
||||||
const isLoadingEmployeeProfile = ref(false);
|
const isLoadingEmployeeProfile = ref(false);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user