feat(lang)Clean landing dashboard page, footers, headers, language module to match with Quasar and/or Vue conventions

This commit is contained in:
Nicolas Drolet 2025-07-30 15:44:23 -04:00
parent 94604cda1b
commit 984ac83f67
60 changed files with 1132 additions and 268 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 859 B

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -101,7 +101,12 @@ export default defineConfig((ctx) => {
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#framework // https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#framework
framework: { framework: {
config: {}, config: {
notify: {
color: 'primary',
avatar: 'https://cdn.quasar.dev/img/boy-avatar.png',
}
},
// iconSet: 'material-icons', // Quasar icon set // iconSet: 'material-icons', // Quasar icon set
// lang: 'en-US', // Quasar language pack // lang: 'en-US', // Quasar language pack
@ -114,7 +119,9 @@ export default defineConfig((ctx) => {
// directives: [], // directives: [],
// Quasar plugins // Quasar plugins
plugins: [] plugins: [
'Notify'
]
}, },
// animations: 'all', // --- includes all animations // animations: 'all', // --- includes all animations

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

BIN
src/assets/line-truck-1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
<desc>Created with Fabric.js 5.2.4</desc>
<defs>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="transparent"></rect>
<g transform="matrix(1 0 0 1 540 540)" id="c0d40538-76c2-4703-b3cd-bdf3d5a21ef8" >
</g>
<g transform="matrix(1 0 0 1 540 540)" id="7afedaf1-4d8a-4d92-9575-5490d0131d9c" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
</g>
<g transform="matrix(1 0 0 1 570.76 504.11)" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
</g>
<g transform="matrix(16.1 0 0 14.35 540 540)" >
<path style="stroke: rgb(255,255,255); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-33.3, -35.18)" d="M 25.83 15 L 8.41 15 C 6.673265390558375 15.002017442566432 5.119885825128325 13.919842989529045 4.52 12.29 L 0 1.18 L 66.59 1.18 L 62.07 12.27 C 61.476757767300114 13.907725173754374 59.92186078409509 14.99895107713476 58.18 15 L 40.76 15 L 40.76 69.19 L 25.81 69.19 Z" stroke-linecap="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
<desc>Created with Fabric.js 5.2.4</desc>
<defs>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="transparent"></rect>
<g transform="matrix(1 0 0 1 540 540)" id="c0d40538-76c2-4703-b3cd-bdf3d5a21ef8" >
</g>
<g transform="matrix(1 0 0 1 540 540)" id="7afedaf1-4d8a-4d92-9575-5490d0131d9c" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
</g>
<g transform="matrix(1 0 0 1 570.76 504.11)" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
</g>
<g transform="matrix(9.62 0 0 9.62 540 540)" >
<circle style="stroke: rgb(255,255,255); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" cx="0" cy="0" r="35" />
</g>
<g transform="matrix(7.38 0 0 6.58 540 574.18)" >
<path style="stroke: rgb(255,255,255); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(1,149,71); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-33.3, -35.18)" d="M 25.83 15 L 8.41 15 C 6.673265390558375 15.002017442566432 5.119885825128325 13.919842989529045 4.52 12.29 L 0 1.18 L 66.59 1.18 L 62.07 12.27 C 61.476757767300114 13.907725173754374 59.92186078409509 14.99895107713476 58.18 15 L 40.76 15 L 40.76 69.19 L 25.81 69.19 Z" stroke-linecap="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 326.39 70.35"><defs><style>.cls-1{fill:#ffffff;}</style></defs><path class="cls-1" d="M25.83,15H8.41a4.14,4.14,0,0,1-3.89-2.71L0,1.18H66.59L62.07,12.27A4.14,4.14,0,0,1,58.18,15H40.76V69.19H25.81Z"/><path class="cls-1" d="M90.74.68h18.55a5.63,5.63,0,0,1,5.63,5.6l.26,62.91H99.55L99.76,54H71.87L66.41,65.51a6.45,6.45,0,0,1-5.84,3.68H49.35L73.53,12.11A18.7,18.7,0,0,1,90.74.68M100,40.73l.07-26h-8a6.75,6.75,0,0,0-6.26,4.18L76.73,40.73Z"/><path class="cls-1" d="M124.51,6.81a5.64,5.64,0,0,1,5.65-5.65H155.6c8.64,0,15.37,2.44,19.81,6.91,3.81,3.78,5.84,9.14,5.84,15.53v.18c0,11-5.92,17.87-14.59,21.1l16.61,24.29h-14a6.51,6.51,0,0,1-5.39-2.87L151.21,47.41H139.44V69.17h-15Zm30.12,27.41c7.28,0,11.45-3.89,11.45-9.62v-.21c0-6.42-4.46-9.7-11.74-9.7H139.46V34.22Z"/><path class="cls-1" d="M184.74,35.37v-.18C184.74,15.85,199.8,0,220.4,0,232.65,0,240,3.31,247.13,9.33l-6.28,7.57a5.18,5.18,0,0,1-6.84,1,23.71,23.71,0,0,0-14.11-4.13c-10.88,0-19.52,9.62-19.52,21.18v.19c0,12.43,8.54,21.57,20.6,21.57a24,24,0,0,0,14.09-4.07V42.91h-8.68A6.41,6.41,0,0,1,220,36.53V30h29.54V59.52a44,44,0,0,1-29,10.78c-21.18,0-35.74-14.8-35.74-34.93"/><path class="cls-1" d="M254.09,35.37v-.18C254.09,15.85,269.33,0,290.33,0s36.06,15.66,36.06,35v.18c0,19.34-15.27,35.19-36.24,35.19s-36.06-15.64-36.06-35m56.63,0v-.18c0-11.67-8.54-21.39-20.6-21.39S269.73,23.34,269.73,35v.18c0,11.67,8.54,21.37,20.6,21.37S310.72,47,310.72,35.37"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

28
src/assets/logo-targo.svg Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
<desc>Created with Fabric.js 5.2.4</desc>
<defs>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="transparent"></rect>
<g transform="matrix(1 0 0 1 540 540)" id="c0d40538-76c2-4703-b3cd-bdf3d5a21ef8" >
</g>
<g transform="matrix(1 0 0 1 540 540)" id="7afedaf1-4d8a-4d92-9575-5490d0131d9c" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
</g>
<g transform="matrix(1 0 0 1 570.76 504.11)" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
</g>
<g transform="matrix(9.62 0 0 9.62 540 540)" >
<circle style="stroke: rgb(255,255,255); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" cx="0" cy="0" r="35" />
</g>
<g transform="matrix(9.01 0 0 9.01 539.93 539.93)" >
<circle style="stroke: rgb(1,149,71); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(1,149,71); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" cx="0" cy="0" r="35" />
</g>
<g transform="matrix(6.76 0 0 6.76 540.03 540.03)" >
<circle style="stroke: rgb(1,149,71); stroke-width: 2; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" cx="0" cy="0" r="35" />
</g>
<g transform="matrix(5.5 0 0 4.9 539.9 573.66)" >
<path style="stroke: rgb(255,255,255); stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(1,149,71); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-33.3, -35.18)" d="M 25.83 15 L 8.41 15 C 6.673265390558375 15.002017442566432 5.119885825128325 13.919842989529045 4.52 12.29 L 0 1.18 L 66.59 1.18 L 62.07 12.27 C 61.476757767300114 13.907725173754374 59.92186078409509 14.99895107713476 58.18 15 L 40.76 15 L 40.76 69.19 L 25.81 69.19 Z" stroke-linecap="round" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -1,7 +1,7 @@
import { defineBoot } from '#q-app/wrappers'; import { defineBoot } from '#q-app/wrappers';
import { createI18n } from 'vue-i18n'; import { createI18n } from 'vue-i18n';
import messages from 'src/modules/i18n'; import messages from 'src/i18n';
export type MessageLanguages = keyof typeof messages; export type MessageLanguages = keyof typeof messages;
// Type-define 'en-US' as the master schema for the resource // Type-define 'en-US' as the master schema for the resource
@ -23,7 +23,7 @@ declare module 'vue-i18n' {
export default defineBoot(({ app }) => { export default defineBoot(({ app }) => {
const i18n = createI18n<{ message: MessageSchema }, MessageLanguages>({ const i18n = createI18n<{ message: MessageSchema }, MessageLanguages>({
locale: 'en-ca', locale: 'fr-ca',
legacy: false, legacy: false,
messages, messages,
}); });

View File

@ -12,14 +12,17 @@
// to match your app's branding. // to match your app's branding.
// Tip: Use the "Theme Builder" on Quasar's documentation website. // Tip: Use the "Theme Builder" on Quasar's documentation website.
$primary : #1976D2; $primary: #019547;
$secondary : #26A69A; $secondary: #dadded;
$accent : #9C27B0; $accent: #1976d2;
$dark : #1D1D1D; $dark-font: #305530;
$dark-page : #121212;
$positive : #21BA45; $dark: #111212;
$negative : #C10015; $dark-page: #121212;
$info : #31CCEC;
$warning : #F2C037; $positive: #21ba45;
$negative: #c10015;
$info: #31ccec;
$warning: #eeb10a;
$white: white;

View File

@ -1,7 +1,392 @@
// This is just an example,
// so you can safely delete all default props below
export default { export default {
failed: 'Action failed', mainLayout: {
success: 'Action was successful' backButton: 'Back to home',
clearFilter: 'Clear filter',
},
helpPage: {
title_1: 'Contact Us',
title_2:
'Please complete the form below and well get back to you as soon as possible.',
fullName: 'Full name*',
email: 'Email address*',
phoneNumber: 'Phone number*',
message:
'How can we help you? Please use this area to provide a detailed message, Thank you!*',
//form validation
fullNameValidation: 'Full name must be filled in.',
emailValidation: 'Email must be a valid email.',
phoneNumberValidation: 'Phone number must be filled in.',
messageValidation: 'Message must be a valid email.',
submit: 'Send',
},
navBar: {
navItem_1: 'Users list',
navItem_2: 'Shift validations',
menuItem_1: 'Profile',
menuItem_2: 'Help',
menuItem_3: 'Log Out',
menuItem_4: 'Time Sheet',
menuItem_5: 'Annual calendar',
mobileIndexTitle: 'Hi',
},
notFoundPage: {
pageTitle: 'Oops. Nothing here...',
backButton: 'Go to the home page',
},
footerLayout: {
title: `Targo Communications, 2005 - 2025)}. All rights reserved.`,
},
loginPage: {
title: 'Log in to Targo',
forgotPassword: 'Forgot Password?',
signUp: 'Dont have an account yet?',
email: 'Email',
password: 'Password',
submit: 'Sign in ',
authentik: 'Targo authentication',
emailValidation: 'Email must be a valid email.',
passwordValidation: 'Password must be a valid email.',
},
signUpPage: {
title: 'Create a new account',
firstName: 'First name',
lastName: 'Last name',
email: 'Email',
phoneNumber: 'Phone number',
password: 'New password',
confirmedPassword: 'Confirm your password',
signIn: 'Already have an account?',
submit: 'Sign up',
firstNameValidation: 'First Name must be filled in.',
lastNameValidation: 'Last Name must be filled in.',
emailValidation: 'Email must be a valid email.',
phoneNumberValidation: 'Phone number must be filled in.',
passwordValidationTitle: 'Password Criteria :',
passwordValidation: 'Password must meet all criteria.',
passwordLengthValidation: 'Must be at least 8 characters long.',
passwordCapitalValidation: 'Must contain at least one capital letter.',
passwordNumberValidation: 'Must contain at least one number.',
passwordSpecialCharacterValidation:
'Must contain at least one special character: !@#$%^&*()-_+=',
confirmPasswordValidation: 'Password must match new Password.',
},
forgotPage: {
title:
'Please enter your email to search for your account and send a verification code.',
email: 'Email',
emailValidation: 'Email must be a valid email.',
submit: 'Send Code',
cancel: 'Cancel',
},
resetPage: {
title: 'Reset your password',
code: 'code',
codeValidation: 'Code must be filled in with 4 digits.',
newPassword: 'New Password',
confirmedPassword: 'Confirm New Password',
newPasswordValidation: 'Password must meet all criteria.',
newPasswordLengthValidation: 'Must be at least 8 characters long.',
newPasswordCapitalValidation: 'Must contain at least one capital letter.',
newPasswordNumberValidation: 'Must contain at least one number.',
newPasswordSpecialCharacterValidation:
'Must contain at least one special character: !@#$%^&*()-_+=',
confirmNewPasswordValidation: 'Password must match new Password.',
submit: 'Send',
cancel: 'Cancel',
},
accountDialog: {
title: 'More',
item_1: 'Language',
item_2: 'Profil',
item_3: 'Log Out',
item_4: 'Time Sheet',
item_5: 'Annual calendar',
},
notificationDialog: {
notice: 'Notice',
markAllRead: 'Mark all read',
deleteAll: 'Delete all',
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',
},
indexAdminPage: {
card_1: 'Administrators',
card_2: 'Technicians',
card_3: 'Dealer',
card_4: 'Customers',
},
usersListPage: {
tableHeader: 'Users list',
search_input: 'Search',
tableCol_1: 'Status',
tableCol_2: 'First name',
tableCol_3: 'Last name',
tableCol_4: 'Email',
tableCol_5: 'Phone number',
tableCol_6: 'User type',
tableCol_7: 'Role',
tableCol_8: 'Created by',
tableCol_9: 'Supervisor',
activeStatus: 'Active',
unActiveStatus: 'Unactive',
addButton: 'Click here to add a new user',
customer: 'Customer',
dealer: 'Dealer',
employee: 'Employee',
technician: 'Technician',
admin: 'Administrator',
support: 'Support',
},
editUserPage: {
title: 'Edit Account',
passwordTitle: 'Reset Password',
firstName: 'First name',
lastName: 'Last name',
email: 'Email',
phoneNumber: 'Phone number',
type: 'Select a type',
role: 'Select a role',
job_title: 'Job title',
company: 'Company',
supervisor: 'Supervisor',
isSupervisor: 'Is supervisor',
hours_bank_max: 'Hours bank maximum',
address: 'Address',
verifiedAccountStatus: 'Verified Account',
unVerifiedAccountStatus: 'UnVerified Account',
password: 'New password',
confirmedPassword: 'Confirm your password',
submit: 'Update Account',
//Form Validation
firstNameValidation: 'First Name must be filled in.',
lastNameValidation: 'Last Name must be filled in.',
emailValidation: 'Email must be a valid email.',
phoneNumberValidation: 'Phone number must be filled in.',
typeValidation: 'Type must be filled in.',
roleValidation: 'Role must be filled in.',
job_titleValidation: 'Job title must be filled in.',
companyValidation: 'Company must be filled in.',
supervisorValidation: 'Supervisor must be filled in.',
hours_bank_maxValidation: 'Hours bank maximum must be filled in.',
addressValidation: 'Address must be filled in.',
passwordValidation: 'Password must meet all criteria.',
confirmPasswordValidation: 'Password must match new Password.',
},
addUserPage: {
title: 'Create User',
firstName: 'First name',
lastName: 'Last name',
email: 'Email',
phoneNumber: 'Phone number',
type: 'Select a type',
role: 'Select a role',
job_title: 'Job title',
company: 'Company',
supervisor: 'Supervisor',
isSupervisor: 'Is supervisor',
hours_bank_max: 'Hours bank maximum',
onboarding: 'Onboarding date',
offboarding: 'Offboarding date',
employee_number: 'Employee number (Employer D number)',
regular_hours_day: 'regular number of hours per day',
address: 'Address',
verifiedAccountStatus: 'Verified Account',
unVerifiedAccountStatus: 'UnVerified Account',
password: 'Password',
confirmedPassword: 'Confirm your password',
submit: 'Create',
//Form Validaiton
firstNameValidation: 'First Name must be filled in.',
lastNameValidation: 'Last Name must be filled in.',
emailValidation: 'Email must be a valid email.',
phoneNumberValidation: 'Phone number must be filled in.',
typeValidation: 'Type must be filled in.',
roleValidation: 'Role must be filled in.',
job_titleValidation: 'Job title must be filled in.',
companyValidation: 'Company must be filled in.',
supervisorValidation: 'Supervisor must be filled in.',
hours_bank_maxValidation: 'Hours bank maximum must be filled in.',
onboardingValidation: 'Onboarding date must be filled in.',
employee_numberValidation: 'Employee number must be filled in.',
regular_hours_dayValidation:
'regular number of hours per day must be filled in.',
addressValidation: 'Address must be filled in.',
passwordValidation: 'Password must meet all criteria.',
confirmPasswordValidation: 'Password must match new Password.',
},
pagesTitles: {
newUserPageTitle: 'New user',
updateUserPageTitle: 'Update user',
timeSheetPageTitle: 'Time sheet',
timeSheetValidationsIdPageTitle: 'Time sheet',
},
timeSheet: {
timeSheetTab_1: 'Shifts',
timeSheetTab_2: 'Expenses',
templateButton: 'Apply Templates',
shiftTemplateTitle: 'Set up your day schedule',
shiftType: 'Type',
remoteShift: 'Remote',
shiftStartTime: 'Start time',
shiftEndTime: 'End time',
shiftComment: 'Comment',
overTimeTitle: 'Overtime regular hours: ',
totalPayedHours: 'Total hours worked: ',
//shiftOptions
regularShift: 'Regular',
eveningShift: 'Evening',
emergencyShift: 'Emergency',
sickDay: 'Sick working day',
vacancyDay: 'vacation',
holiday: 'Holiday',
dateRangesWeek: 'Week from',
dateRangesTo: 'to',
shiftBankedHours: 'Total hours to bank',
bankedHoursHint_1: ' on',
bankedHoursHint_2: ' accumulated hours',
qTimeClose: 'Close',
saveButton: 'Save',
//shift validations
timeSheetValidated: 'Validated week',
timeSheetBlocked: 'Blocked week',
shiftTypeValidation: 'Type must be filled in.',
shiftStartTimeValidation: 'Start time must be filled in.',
shiftEndTimeValidation: 'End time must be filled in.',
endTimeValidation: 'The end time cannot be before or equal the start time',
expensesTile: 'daily expenses',
expensesType: 'Type',
expensesValue: 'amount',
expensesDescription: 'Description',
expensesEvidence: 'attachment',
//expenses validations
expensesTypeValidation: 'Type must be filled in.',
expensesValueValidation: 'Amount must be filled in.',
//expensesOptions
refund: 'Refund',
garde: 'Garde',
perdiem: 'Perdiem',
mileage: 'Mileage',
},
timeSheetValidations: {
tableHeader: 'List of employees',
tableCol_1: 'Full name',
tableCol_2: 'Regular hours',
tableCol_3: 'Evening hours',
tableCol_4: 'Emergency hours',
tableCol_5: 'Overtime hours',
tableCol_6: 'Expenses',
tableCol_7: 'Mileage',
tableCol_8: 'Status',
tableCol_9: 'Supervisor',
actionTitle: 'Please save the changes made.',
actionButton: 'Save',
timeSheetStatus_verified: 'Verified',
timeSheetStatus_unverified: 'Unverified',
timeSheetStatus_partial: 'Partial',
timeSheetStatus_complete: 'Complete',
timeSheetStatus_empty: 'Empty',
timeSheetStatus_blocked: 'Blocked',
showAllCheckbox: 'Show all',
accumulatedSicknessTotal: 'Accumulated illnesses',
consumedSicknessTotal: 'Consumed with illnesses',
accumulatedVacationTotal: 'Accumulated vacation',
consumedVacationTotal: 'Consumed with vacation',
maxVacationPerYear: 'Maximum vacation per year',
accumulatedSicknessTotalValidation:
'Accumulated illnesses must be positive.',
consumedSicknessTotalValidation:
'Consumed with illnesses must be positive.',
accumulatedVacationTotalValidation:
'Accumulated vacation must be positive.',
consumedVacationTotalValidation: 'Consumed with vacation must be positive.',
maxVacationPerYearValidation: 'Max Vacation Per Year must be positive.',
resteVacationTotal: 'Rest of vacation',
validateToolTip: 'Validate',
unvalidateToolTip: 'Unvalidate',
lockToolTip: 'Lock the week',
unlockToolTip: 'Unlock the week',
},
shiftColumns: {
title: 'Shifts',
column_1: 'Type',
column_2: 'Start time',
column_3: 'End time',
column_4: 'Comment',
column_5: 'Status',
column_6: 'Supervisors report',
},
expenseColumns: {
title: 'Expenses',
column_1: 'Type',
column_2: 'Amount',
column_3: 'Attachment',
column_4: 'Description',
column_5: 'Status',
column_6: 'Supervisors report',
},
table: {
recordsTitle: 'Records per page:',
noResultsLabel: 'The filter didnt uncover any results',
noDataLabel: 'I didnt find anything for you',
},
autoLogout: {
title: 'Alert',
message_start: 'Attention: You will be automatically logged out in',
message_end: 'seconds if you do not interact with the screen.',
},
daysOfWeek: {
Sunday: ' Sunday',
Monday: 'Monday',
Tuesday: 'Tuesday',
Wednesday: 'Wednesday',
Thursday: 'Thursday',
Friday: 'Friday',
Saturday: 'Saturday',
},
shiftsTemplate: {
tabTitle1: 'Shifts',
tabTitle2: 'Templates for shifts',
saveButton: 'Save',
emptyShiftsMessage: 'No shifts available.',
emptyTemplateMessage: 'No template available.',
selectTemplate: 'Select a template',
selectTemplateNoResult: 'No template available.',
selectDay: 'Day',
startTime: 'Start time',
endTime: 'End time',
templateTitle: 'Title',
templateDescription: 'Description',
createButton: 'Create',
updateButton: 'Update',
deleteButton: 'Delete',
resetButton: 'Reset',
dayValidation: 'Day must be filled in.',
startTimeValidation: 'Start time must be filled in.',
endTimeValidation: 'End time must be filled in.',
startTimeAfterEndTimeValidation:
'The end time cannot be before or equal the start time',
endTimeBeforeStartTimeValidation:
'The end time cannot be before or equal the start time',
existingTimeShift: 'This time is already in use',
},
}; };

401
src/i18n/fr-ca/index.ts Normal file
View File

@ -0,0 +1,401 @@
export default {
mainLayout: {
backButton: 'Retour à la page daccueil',
clearFilter: 'Effacer le filtre',
},
helpPage: {
title_1: 'Contactez-nous',
title_2:
'Veuillez remplir le formulaire ci-dessous et nous vous communiquerons dès que possible.',
fullName: 'Nom complet*',
email: 'Adresse e-mail*',
phoneNumber: 'Numéro de téléphone*',
message:
'Comment pouvons-nous vous aider? Sil vous plaît utiliser cette zone pour fournir un message détaillé, Merci!*',
//form validation
fullNameValidation: 'Le nom complet doit être rempli.',
emailValidation: 'Le-mail doit être un e-mail valide.',
phoneNumberValidation: 'Le numéro de téléphone doit être rempli.',
messageValidation: 'Message doit être rempli.',
submit: 'Envoyer',
},
navBar: {
navItem_1: 'Liste des utilisateurs',
navItem_2: 'Validations des quarts de travail',
menuItem_1: 'Profil',
menuItem_2: 'Aide',
menuItem_3: 'Déconnexion',
menuItem_4: 'Carte de temps',
menuItem_5: 'Calendrier annuel',
mobileIndexTitle: 'Bonjour',
},
notFoundPage: {
pageTitle: 'Oops. Rien ici...',
backButton: 'Aller à la page daccueil',
},
footerLayout: {
title: `Targo Canada, 2005 - 2025. Tous droits réservés.`,
},
loginPage: {
title: 'Se connecter à Targo',
forgotPassword: 'Mot de passe oublié?',
signUp: 'Vous navez pas encore de compte?',
email: 'Email',
password: 'Mot de passe',
submit: 'Se connecter',
authentik: 'Authentification Targo',
emailValidation: 'Email doit être un e-mail valide.',
passwordValidation: 'Mot de passe doit être rempli.',
},
signUpPage: {
title: 'Créer un nouveau compte',
firstName: 'Prénom',
lastName: 'Nom de famille',
email: 'Email',
phoneNumber: 'Numéro de téléphone',
password: 'Nouveau mot de passe',
confirmedPassword: 'Confirmez votre mot de passe',
signIn: 'Vous avez déjà un compte?',
submit: 'Sinscrire',
firstNameValidation: 'Le prénom doit être rempli.',
lastNameValidation: 'Le nom de famille doit être rempli.',
emailValidation: 'Email doit être un e-mail valide.',
phoneNumberValidation: 'Numéro de téléphone doit être rempli.',
passwordValidationTitle: 'Critères de mot de passe :',
passwordValidation: 'Le mot de passe doit répondre à tous les critères.',
passwordLengthValidation: 'Doit être dau moins 8 caractères de long.',
passwordCapitalValidation: 'Doit contenir au moins une lettre majuscule.',
passwordNumberValidation: 'Doit contenir au moins un numéro.',
passwordSpecialCharacterValidation:
'Doit contenir au moins un caractère spécial : !@#$%^&*()-_+=',
confirmPasswordValidation:
'Le mot de passe doit correspondre au nouveau mot de passe.',
},
forgotPage: {
title:
'Veuillez saisir votre e-mail pour rechercher votre compte et envoyer un code de vérification.',
email: 'Email',
emailValidation: 'Email doit être un e-mail valide.',
submit: 'Envoyer code',
cancel: 'Annuler',
},
resetPage: {
title: 'Réinitialiser votre mot de passe',
code: 'code',
codeValidation: 'Le code doit être rempli avec 4 chiffres.',
newPassword: 'Nouveau mot de passe',
confirmedPassword: 'Confirmez votre mot de passe',
newPasswordValidation: 'Le mot de passe doit répondre à tous les critères.',
newPasswordLengthValidation: 'Doit être dau moins 8 caractères de long.',
newPasswordCapitalValidation:
'Doit contenir au moins une lettre majuscule.',
newPasswordNumberValidation: 'Doit contenir au moins un numéro.',
newPasswordSpecialCharacterValidation:
'Doit contenir au moins un caractère spécial : !@#$%^&*()-_+=',
confirmNewPasswordValidation:
'Le mot de passe doit correspondre au nouveau mot de passe.',
submit: 'Envoyer',
cancel: 'Annuler',
},
accountDialog: {
title: 'Plus',
item_1: 'Langue',
item_2: 'Profile',
item_3: 'Déconnexion',
item_4: 'Carte de temps',
item_5: 'Calendrier annuel',
},
notificationDialog: {
notice: 'Notification',
markAllRead: 'Marquer tout comme lu',
deleteAll: 'Supprimer tout',
close: 'Fermer',
},
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 na 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',
},
indexAdminPage: {
card_1: 'Administrateurs',
card_2: 'Techniciens',
card_3: 'Marchand',
card_4: 'Clients',
},
usersListPage: {
tableHeader: 'Liste des utilisateurs',
search_input: 'Rechercher',
tableCol_1: 'État',
tableCol_2: 'Prénom',
tableCol_3: 'Nom de famille',
tableCol_4: 'Email',
tableCol_5: 'Numéro de téléphone',
tableCol_6: 'Type dutilisateur',
tableCol_7: 'Role',
tableCol_8: 'Créé par',
tableCol_9: 'Superviseur',
activeStatus: 'Actif',
unActiveStatus: 'Inactif',
addButton: 'Cliquez ici pour ajouter un nouvel utilisateur',
customer: 'Client',
dealer: 'Marchand',
employee: 'Employé',
technician: 'Technicien',
admin: 'Administrateur',
support: 'Support',
},
editUserPage: {
title: 'Modifier le compte',
passwordTitle: 'Réinitialiser le mot de passe',
firstName: 'Prénom',
lastName: 'Nom de famille',
email: 'Email',
phoneNumber: 'Numéro de téléphone',
type: 'Choisir un type',
role: 'Choisir un role',
job_title: 'Titre demploi',
company: 'Entreprise',
supervisor: 'Superviseur',
isSupervisor: 'Est un superviseur',
hours_bank_max: 'Maximum de banque dheures ',
address: 'Adresse',
verifiedAccountStatus: 'Compte vérifié',
unVerifiedAccountStatus: 'Compte non vérifié',
password: 'Nouveau mot de passe',
confirmedPassword: 'Confirmez votre mot de passe',
submit: 'Modifier le compte',
//Form Validaiton
firstNameValidation: 'Le prénom doit être rempli.',
lastNameValidation: 'Le nom de famille doit être rempli.',
emailValidation: 'Email doit être un e-mail valide.',
phoneNumberValidation: 'Numéro de téléphone doit être rempli.',
typeValidation: 'Type doit être rempli.',
roleValidation: 'Role doit être rempli.',
job_titleValidation: 'Le Titre demploi doit être rempli.',
companyValidation: 'Entreprise doit être rempli.',
supervisorValidation: 'Superviseur doit être rempli.',
hours_bank_maxValidation: 'Maximum de banque dheures doit être rempli.',
addressValidation: 'Adresse doit être rempli.',
passwordValidation: 'Le mot de passe doit répondre à tous les critères.',
confirmPasswordValidation:
'Le mot de passe doit correspondre au nouveau mot de passe.',
},
addUserPage: {
title: 'Créer un utilisateur',
firstName: 'Prénom',
lastName: 'Nom de famille',
email: 'Email',
phoneNumber: 'Numéro de téléphone',
type: 'Choisir un type',
role: 'Choisir un role',
job_title: 'Titre demploi',
company: 'Entreprise',
supervisor: 'Superviseur',
isSupervisor: 'Est un superviseur',
hours_bank_max: 'Maximum de banque dheures ',
onboarding: 'Date dembauche',
offboarding: 'date de départ',
employee_number: 'Numéro demployé (Matricule employeur D)',
regular_hours_day: 'nombre régulier dheures par jour',
address: 'Adresse',
verifiedAccountStatus: 'Compte vérifié',
unVerifiedAccountStatus: 'Compte non vérifié',
password: 'Nouveau mot de passe',
confirmedPassword: 'Confirmez votre mot de passe',
submit: 'Créer',
//Form Validaiton
firstNameValidation: 'Le prénom doit être rempli.',
lastNameValidation: 'Le nom de famille doit être rempli.',
emailValidation: 'Email doit être un e-mail valide.',
phoneNumberValidation: 'Numéro de téléphone doit être rempli.',
typeValidation: 'Type doit être rempli.',
roleValidation: 'Role doit être rempli.',
job_titleValidation: 'Le Titre demploi doit être rempli.',
companyValidation: 'Entreprise doit être rempli.',
supervisorValidation: 'Superviseur doit être rempli.',
hours_bank_maxValidation: 'Maximum de banque dheures doit être rempli.',
onboardingValidation: 'Date dembauche doit être rempli.',
employee_numberValidation: 'Numéro demployé doit être rempli.',
regular_hours_dayValidation:
'nombre régulier dheures par jour doit être rempli.',
addressValidation: 'Adresse doit être rempli.',
passwordValidation: 'Le mot de passe doit répondre à tous les critères.',
confirmPasswordValidation:
'Le mot de passe doit correspondre au nouveau mot de passe.',
},
pagesTitles: {
newUserPageTitle: 'Nouvel utilisateur',
updateUserPageTitle: 'Mettre à jour lutilisateur',
timeSheetPageTitle: 'Carte de temps',
timeSheetValidationsIdPageTitle: 'Carte de temps',
},
timeSheet: {
timeSheetTab_1: 'Quarts de travail',
timeSheetTab_2: 'Dépenses',
templateButton: 'Appliquer le modèle',
shiftTemplateTitle: 'Mettre en place votre horaire de jour',
shiftType: 'Type',
remoteShift: 'Télétravail',
shiftStartTime: 'Entrée',
shiftEndTime: 'Sortie',
shiftComment: 'Commentaire',
overTimeTitle: 'Heures régulières supplémentaires: ',
totalPayedHours: 'Total des heures travaillées: ',
//shiftOptions
regularShift: 'Régulier',
eveningShift: 'Soir',
emergencyShift: 'Urgence',
sickDay: 'Maladie',
vacancyDay: 'Vacances',
holiday: 'Férié',
dateRangesWeek: 'Semaine du',
dateRangesTo: 'au',
shiftBankedHours: 'Totale dheures à banquer',
bankedHoursHint_1: ' sur',
bankedHoursHint_2: ' heures daccumulé',
qTimeClose: 'Fermer',
saveButton: 'Enregistrer',
//shift validations
timeSheetValidated: 'Semaine validée',
timeSheetBlocked: 'Semaine bloquée',
shiftTypeValidation: 'Le type doit être rempli.',
shiftStartTimeValidation: 'Entrée doit être rempli.',
shiftEndTimeValidation: 'Sortie doit être rempli.',
endTimeValidation:
'Lheure de fin ne peut pas être antérieure ou égale à lheure de début',
expensesTile: 'Dépenses du jour',
expensesType: 'Type',
expensesValue: 'Montant',
expensesDescription: 'Description',
expensesEvidence: 'Attachement',
//expenses validations
expensesTypeValidation: 'Type doit être rempli.',
expensesValueValidation: 'Montant doit être rempli.',
//expensesOptions
refund: 'Remboursement ',
garde: 'Garde',
perdiem: 'Perdiem',
mileage: 'Kilometrage',
},
timeSheetValidations: {
tableHeader: 'Liste des employés',
tableCol_1: 'Nom et prénom',
tableCol_2: 'Heures régulières',
tableCol_3: 'Heures de soir',
tableCol_4: 'Heures durgence',
tableCol_5: 'Heures supplémentaires',
tableCol_6: 'Dépenses ',
tableCol_7: 'Kilométrage ',
tableCol_8: 'État',
tableCol_9: 'Superviseur',
actionTitle: 'Veuillez enregistrer les changements effectués.',
actionButton: 'Enregistrer',
timeSheetStatus_verified: 'Vérifié',
timeSheetStatus_unverified: 'Invérifié',
timeSheetStatus_partial: 'Partiel',
timeSheetStatus_complete: 'Complet',
timeSheetStatus_empty: 'Vide',
timeSheetStatus_blocked: 'Bloqué',
showAllCheckbox: 'Afficher tous',
accumulatedSicknessTotal: 'Accumulées de maladies',
consumedSicknessTotal: 'Consommées de maladies',
accumulatedVacationTotal: 'Accumulées de vacances',
consumedVacationTotal: 'Consommées de vacances',
maxVacationPerYear: 'Maximum de vacances par année',
accumulatedSicknessTotalValidation:
'Accumulées de maladies doit être positive.',
consumedSicknessTotalValidation:
'Consommées de maladies doit être positive.',
accumulatedVacationTotalValidation:
'Accumulées de vacances doit être positive.',
consumedVacationTotalValidation:
'Consommées de vacances doit être positive.',
maxVacationPerYearValidation:
'Le nombre maximum de vacances par an doit être positif.',
resteVacationTotal: 'Reste des vacances',
validateToolTip: 'Valider',
unvalidateToolTip: 'Invalider',
lockToolTip: 'Verrouiller la semaine',
unlockToolTip: 'Déverrouiller la semaine',
},
shiftColumns: {
title: 'Quarts de travail',
column_1: 'Type',
column_2: 'Entrée',
column_3: 'Sortie',
column_4: 'Commentaire',
column_5: 'État',
column_6: 'Rapport du superviseur',
},
expenseColumns: {
title: 'Dépenses',
column_1: 'Type',
column_2: 'Montant',
column_3: 'Attachement',
column_4: 'Description',
column_5: 'État',
column_6: 'Rapport du superviseur',
},
table: {
recordsTitle: 'Enregistrements par page:',
noResultsLabel: 'Le filtre na révélé aucun résultat',
noDataLabel: 'Je nai rien trouvé pour toi',
},
autoLogout: {
title: 'Alerte',
message_start: 'Attention : vous serez automatiquement déconnecté dans',
message_end: 'secondes si vous ninteragissez pas avec lécran.',
},
daysOfWeek: {
Sunday: 'dimanche',
Monday: 'lundi',
Tuesday: 'mardi',
Wednesday: 'mercredi',
Thursday: 'jeudi',
Friday: 'vendredi',
Saturday: 'samedi',
},
shiftsTemplate: {
tabTitle1: 'Quarts de travail',
tabTitle2: 'Modèles de quarts de travail',
saveButton: 'Enregistrer',
emptyShiftsMessage: 'Aucun modèle disponible.',
emptyTemplateMessage: 'Aucun quarts de travail disponible.',
selectTemplate: 'Sélectionnez un modèle',
selectTemplateNoResult: 'Aucun modele disponible.',
selectDay: 'Jour',
startTime: 'Heure de début',
endTime: 'Heure de fin',
templateTitle: 'Titre',
templateDescription: 'Description',
createButton: 'Créer',
updateButton: 'Mettre à jour',
deleteButton: 'Supprimer',
resetButton: 'Réinitialiser',
dayValidation: 'Jour doit être rempli.',
startTimeValidation: 'Heure de début doit être rempli.',
endTimeValidation: 'Heure de fin doit être rempli.',
startTimeAfterEndTimeValidation:
'Lheure de début ne peut pas être après lheure de fin',
endTimeBeforeStartTimeValidation:
'Lheure de fin ne peut pas être précédente à lheure de debut',
existingTimeShift: 'Ce temps est déjà utilisé',
},
};

View File

@ -1,5 +1,7 @@
import enCA from './en-ca'; import enCA from './en-ca';
import frCA from './fr-ca';
export default { export default {
'en-ca': enCA 'en-ca': enCA,
'fr-ca': frCA,
}; };

View File

@ -1,37 +0,0 @@
<template>
<q-layout view="lHh Lpr lFf" class="wrapper">
<NavBar />
<q-page-container :class="pageClass">
<router-view class="q-pa-sm" />
</q-page-container>
<FooterBar />
</q-layout>
</template>
<script lang="ts" setup>
import { RouterView } from 'vue-router';
import { useQuasar } from 'quasar';
import NavBar from 'src/modules/shared/components/navs/navBars/NavBar.vue';
import FooterBar from 'src/modules/shared/components/navs/footerBars/FooterBar.vue';
import { computed } from 'vue';
const $q = useQuasar();
const pageClass = computed(() => {
return !$q.screen.xs ? ' container' : 'full-width container';
});
</script>
<style lang="scss">
.wrapper {
display: flex;
flex-direction: column;
background-color: $grey-3;
}
.container {
flex-grow: 1;
width: 90%;
margin: 0 auto;
text-align: center;
}
</style>

View File

@ -0,0 +1,15 @@
<script lang="ts" setup>
import { RouterView } from 'vue-router';
import NavBar from 'src/pages/nav-bars/nav-bar.vue';
import FooterBar from 'src/pages/footer-bars/footer-bar.vue';
</script>
<template>
<q-layout view="hHh lpR fFf">
<NavBar />
<q-page-container>
<router-view class="q-pa-sm" />
</q-page-container>
<FooterBar />
</q-layout>
</template>

View File

@ -1,5 +1,6 @@
/* eslint-disable */
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import router from "src/modules/router"; import router from "src/router";
import { api } from "src/boot/axios"; import { api } from "src/boot/axios";
import { User } from "src/modules/users/types/user-interface"; import { User } from "src/modules/users/types/user-interface";
import { AuthState } from "./types/auth-interface"; import { AuthState } from "./types/auth-interface";

View File

@ -1,3 +1,4 @@
/* eslint-disable */
import { useAuthStore } from "src/modules/auth/auth-store"; import { useAuthStore } from "src/modules/auth/auth-store";
export const useAuthAccess = () => { export const useAuthAccess = () => {

View File

@ -1,3 +1,4 @@
/* eslint-disable */
import { useAuthStore } from "src/modules/auth/auth-store"; import { useAuthStore } from "src/modules/auth/auth-store";
export const useAuthSession = () => { export const useAuthSession = () => {

View File

@ -1,3 +1,4 @@
/* eslint-disable */
import { api } from 'src/boot/axios'; import { api } from 'src/boot/axios';
export const AuthService = { export const AuthService = {

View File

@ -1,4 +1,4 @@
import { User } from "src/modules/users/types/user-interface"; import type { User } from "src/modules/users/types/user-interface";
export interface AuthState { export interface AuthState {
token: string; token: string;

View File

@ -1,3 +1,7 @@
<script setup lang="ts">
/* eslint-disable */
</script>
<template> <template>
<div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center"> <div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center">
<div> <div>
@ -20,8 +24,4 @@
/> />
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts">
//
</script>

View File

@ -1,9 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
/* eslint-disable */
import { ref } from 'vue'; import { ref } from 'vue';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { useAuthStore } from 'src/modules/auth/auth-store'; import { useAuthStore } from 'src/modules/auth/auth-store';
// import { getInitials } from 'src/helpers/object';
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const authStore = useAuthStore(); const authStore = useAuthStore();
@ -40,9 +40,9 @@
<!-- <q-tab name="help" icon="help" @click="goToHelp" /> --> <!-- <q-tab name="help" icon="help" @click="goToHelp" /> -->
<q-tab name="menu" icon="menu" @click="toggleLeftDrawer" /> <q-tab name="menu" icon="menu" @click="toggleLeftDrawer" />
<q-drawer v-model="leftDrawerOpen" side="right"> <q-drawer v-model="leftDrawerOpen" side="right">
<q-scroll-area style="height: calc(100% - 150px); margin-top: 150px; border-right: 1px solid #ddd;"> <q-scroll-area style="border-right: 1px solid #ddd;">
<q-list padding> <q-list padding>
<q-item clickable v-ripple :active="route.path === '/users'" active-class="bg-primary text-white" @click="goToUsers" v-if="userRole === 'admin'"> <q-item clickable v-ripple :active="route.path === '/users'" active-class="bg-primary text-white" @click="goToUsers" >
<q-item-section avatar> <q-item-section avatar>
<q-icon name="list" /> <q-icon name="list" />
</q-item-section> </q-item-section>
@ -59,22 +59,7 @@
</q-list> </q-list>
</q-scroll-area> </q-scroll-area>
<q-img class="absolute-top" src="https://cdn.quasar.dev/img/material.png" style="height: 150px"> <q-img class="absolute-top" src="https://cdn.quasar.dev/img/material.png" height="150px" />
<div class="absolute-bottom bg-transparent">
<!-- <q-avatar color="primary" size="68px" class="q-mb-sm">
{{
getInitials(
`${userConnected.first_name} ${userConnected.last_name}`,
)
}}</q-avatar -->
>
<div class="text-weight-bold">
{{ userConnected.firstName }} {{ userConnected.lastName }}
</div>
<div>{{ userConnected.email }}</div>
</div>
</q-img>
</q-drawer> </q-drawer>
</q-tabs> </q-tabs>
</q-footer> </q-footer>

View File

@ -1,24 +1,5 @@
<template> <template>
<div class="gt-sm footer"> <q-toolbar>
<div class="container">© {{ $t('footerLayout.title') }}</div> <div class="text-right ">© 2025 Targo Communications inc.</div>
</div> </q-toolbar>
</template> </template>
<style scoped lang="scss">
.footer {
width: 100%;
height: 8em;
flex-shrink: 0;
margin: 3em auto 0;
justify-content: center;
}
.container {
padding: 1em;
width: 90%;
height: 100%;
border-top: 2px solid $primary;
display: flex;
align-items: center;
}
</style>

View File

@ -1,10 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import FooterBarMobile from './footer-bar-mobile.vue'; // import FooterBarMobile from './footer-bar-mobile.vue';
import FooterBarWeb from './footer-bar-web.vue'; import FooterBarWeb from './footer-bar-web.vue';
</script> </script>
<template> <template>
<FooterBarWeb class="gt-sm" /> <q-footer elevated class="bg-primary text-white">
<FooterBarMobile class="lt-md" /> <FooterBarWeb />
<!-- <FooterBarMobile class="lt-md" /> -->
</q-footer>
</template> </template>

View File

@ -1,11 +1,12 @@
<script lang="ts" setup> <script lang="ts" setup>
/* eslint-disable */
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { computed } from 'vue'; import { computed } from 'vue';
import { useAuthStore } from 'src/modules/auth/auth-store'; import { useAuthStore } from 'src/modules/auth/auth-store';
// import dialogs from 'src/components/dialogs'; // import dialogs from 'src/components/dialogs';
const authStore = useAuthStore(); // const authStore = useAuthStore();
const user = authStore.user; // const user = authStore.user;
// const { NotificationsDialog, AccountDialog } = dialogs; // const { NotificationsDialog, AccountDialog } = dialogs;
const route = useRoute(); const route = useRoute();
const backRoutes = [ const backRoutes = [

View File

@ -1,136 +1,109 @@
<script lang="ts" setup>
/* eslint-disable */
import { useRouter } from 'vue-router';
import { useQuasar } from 'quasar';
// import { getInitials } from 'src/helpers/object';
import { useAuthStore } from 'src/modules/auth/auth-store';
import LanguageSwitch from 'src/shared/components/language-switch.vue';
// import dialogs from 'src/components/dialogs';
// import authenticationApi from 'src/composables/useAuthentication';
// const { logout } = authenticationApi.useAuthUser();
// const { NotificationsDialog } = dialogs;
const authStore = useAuthStore();
const router = useRouter();
const $q = useQuasar();
const userConnected = authStore.user;
const userRole = userConnected.role;
// const userType = userConnected.type;
const goToProfile = () => {
router.replace('/profile');
};
const goToHelp = () => {
router.replace('/help');
};
const goToCalender = () => {
const pdfUrl = '/calendrier_annuel.pdf';
window.open(pdfUrl, '_blank');
};
const goToTimeSheet = () => {
router.replace('/time_sheet');
};
const handleLogout = async () => {
// const response = await logout();
// const { type, message } = response;
// $q.notify({ type, message });
};
</script>
<template> <template>
<q-toolbar> <q-toolbar>
<q-toolbar-title> <q-btn flat color="white" icon="img:src/assets/logo-targo-white.svg">
<RouterLink class="q-mr-sm navbar-brand" to="/"> </q-btn>
<q-img <q-space />
src="/public/icons/logo-targo-white.svg" <q-btn flat class="q-mr-xs" to="/users" color="white" :label="$t('navBar.navItem_1')" />
alt="logo" <q-btn flat class="q-mr-xs" to="/time_sheet_validations" color="white" :label="$t('navBar.navItem_2')" />
style="width: 50px" <LanguageSwitch class="q-mr-xs text-white"/>
to="/" <q-btn round color="white">
></q-img <q-avatar color="white" text-color="primary" />
></RouterLink> <q-menu fit transition-show="flip-right" transition-hide="flip-left">
</q-toolbar-title> <q-list>
<div> <q-item>
<q-btn <div class="text-subtitle1 q-mb-xs text-no-wrap text-center">
class="q-mr-xs" ND
to="/users" </div>
flat </q-item>
color="white" <q-separator />
:label="$t('navBar.navItem_1')" <q-item v-ripple clickable @click="goToProfile">
no-caps <q-item-section avatar
v-if="userRole === 'admin'" ><q-icon name="mdi-account" color="primary" size="2em"
/> /></q-item-section>
<q-btn <q-item-section>{{ $t('navBar.menuItem_1') }}</q-item-section>
class="q-mr-xs" </q-item>
to="/time_sheet_validations" <!-- <q-item
flat v-if="userType === 'employee'"
color="white" v-ripple
:label="$t('navBar.navItem_2')" clickable
no-caps @click="goToTimeSheet"
v-if="userRole === 'admin'" >
/> <q-item-section avatar>
<LangSwitch class="q-mr-xs text-white" /> <q-icon name="work_history" color="primary" size="2em" />
<NotificationsDialog /> </q-item-section>
<q-btn round color="white"> <q-item-section>{{ $t('navBar.menuItem_4') }}</q-item-section>
<q-avatar color="white" text-color="primary">{{ </q-item>
// getInitials(`${userConnected.first_name} ${userConnected.last_name}`) <q-item
}}</q-avatar> v-if="userType === 'employee'"
<q-menu fit transition-show="flip-right" transition-hide="flip-left"> v-ripple
<q-list> clickable
<q-item> @click="goToCalender"
<div class="text-subtitle1 q-mb-xs text-no-wrap text-center"> >
<!-- {{ userConnected.first_name }} {{ userConnected.last_name }} --> <q-item-section avatar>
</div> <q-icon name="calendar_month" color="primary" size="2em" />
</q-item> </q-item-section>
<q-separator /> <q-item-section>{{ $t('navBar.menuItem_5') }}</q-item-section>
<q-item v-ripple clickable @click="goToProfile"> </q-item> -->
<q-item-section avatar <q-item v-ripple clickable @click="goToHelp">
><q-icon name="mdi-account" color="primary" size="2em" <q-item-section avatar>
/></q-item-section> <q-icon name="help" color="primary" size="2em" />
<q-item-section>{{ $t('navBar.menuItem_1') }}</q-item-section> </q-item-section>
</q-item> <q-item-section>{{ $t('navBar.menuItem_2') }}</q-item-section>
<!-- <q-item </q-item>
v-if="userType === 'employee'" <q-separator />
v-ripple <q-item v-ripple clickable @click="handleLogout">
clickable <q-item-section avatar>
@click="goToTimeSheet" <q-icon name="logout" color="primary" size="2em" />
> </q-item-section>
<q-item-section avatar>
<q-icon name="work_history" color="primary" size="2em" />
</q-item-section>
<q-item-section>{{ $t('navBar.menuItem_4') }}</q-item-section>
</q-item>
<q-item
v-if="userType === 'employee'"
v-ripple
clickable
@click="goToCalender"
>
<q-item-section avatar>
<q-icon name="calendar_month" color="primary" size="2em" />
</q-item-section>
<q-item-section>{{ $t('navBar.menuItem_5') }}</q-item-section>
</q-item> -->
<q-item v-ripple clickable @click="goToHelp">
<q-item-section avatar>
<q-icon name="help" color="primary" size="2em" />
</q-item-section>
<q-item-section>{{ $t('navBar.menuItem_2') }}</q-item-section>
</q-item>
<q-separator />
<q-item v-ripple clickable @click="handleLogout">
<q-item-section avatar>
<q-icon name="logout" color="primary" size="2em" />
</q-item-section>
<q-item-section>{{ $t('navBar.menuItem_3') }}</q-item-section> <q-item-section>{{ $t('navBar.menuItem_3') }}</q-item-section>
</q-item> </q-item>
</q-list> </q-list>
</q-menu> </q-menu>
</q-btn> </q-btn>
</div>
</q-toolbar> </q-toolbar>
</template> </template>
<script lang="ts" setup>
import { useRouter } from 'vue-router';
import { useQuasar } from 'quasar';
// import { getInitials } from 'src/helpers/object';
import { useAuthStore } from 'src/modules/auth/auth-store';
import LangSwitch from 'src/components/LangSwitch.vue';
// import dialogs from 'src/components/dialogs';
// import authenticationApi from 'src/composables/useAuthentication';
// const { logout } = authenticationApi.useAuthUser();
// const { NotificationsDialog } = dialogs;
const authStore = useAuthStore();
const router = useRouter();
const $q = useQuasar();
const userConnected = authStore.user;
const userRole = userConnected.role;
// const userType = userConnected.type;
const goToProfile = () => {
router.replace('/profile');
};
const goToHelp = () => {
router.replace('/help');
};
const goToCalender = () => {
const pdfUrl = '/calendrier_annuel.pdf';
window.open(pdfUrl, '_blank');
};
const goToTimeSheet = () => {
router.replace('/time_sheet');
};
const handleLogout = async () => {
// const response = await logout();
// const { type, message } = response;
// $q.notify({ type, message });
};
</script>

View File

@ -1,12 +1,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import NavBarMobile from './nav-bar-mobile.vue'; // import NavBarMobile from './nav-bar-mobile.vue';
import NavBarWeb from './nav-bar-web.vue'; import NavBarWeb from './nav-bar-web.vue';
</script> </script>
<template> <template>
<q-header elevated> <q-header elevated>
<NavBarMobile class="lt-md" /> <!-- <NavBarMobile /> -->
<NavBarWeb class="gt-sm" /> <NavBarWeb />
</q-header> </q-header>
</template> </template>

56
src/pages/test-page.vue Normal file
View File

@ -0,0 +1,56 @@
<script setup lang="ts">
import { useQuasar } from 'quasar';
import type { QVueGlobals } from 'quasar';
const q: QVueGlobals = useQuasar();
const clickNotify = () => {
q.notify({
message: 'Nick pinged you.',
})
}
</script>
<template>
<q-page padding class="q-pa-md row items-center justify-center q-gutter-md">
<q-card class="shadow-2 col-9 dark-font">
<q-img src="src/assets/line-truck-1.jpg">
<div class="absolute-bottom text-h5">
Welcome to App Targo!
</div>
</q-img>
<q-card-section class="text-center">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,
totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta
sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia
consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui
dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora
incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum
exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem
vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui
dolorem eum fugiat quo voluptas nulla pariatur?
</q-card-section>
<q-card-section class="text-center">
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
</q-card-section>
<q-card-section class="text-center">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</q-card-section>
<q-separator />
<q-card-actions align="center">
<q-btn color="primary" label="Click Me" @click="clickNotify" />
</q-card-actions>
</q-card>
</q-page>
</template>
<style scoped>
.dark-font {
color: #676;
}
</style>

2
src/quasar.d.ts vendored
View File

@ -1,5 +1,3 @@
/* eslint-disable */
// Forces TS to apply `@quasar/app-vite` augmentations of `quasar` package // Forces TS to apply `@quasar/app-vite` augmentations of `quasar` package
// Removing this would break `quasar/wrappers` imports as those typings are declared // Removing this would break `quasar/wrappers` imports as those typings are declared
// into `@quasar/app-vite` // into `@quasar/app-vite`

View File

@ -3,15 +3,15 @@ import type { RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [ const routes: RouteRecordRaw[] = [
{ {
path: '/', path: '/',
component: () => import('layouts/MainLayout.vue'), component: () => import('src/layouts/main-layout.vue'),
children: [{ path: '', component: () => import('pages/IndexPage.vue') }], children: [{ path: '', component: () => import('src/pages/test-page.vue') }],
}, },
// Always leave this as last one, // Always leave this as last one,
// but you can also remove it // but you can also remove it
{ {
path: '/:catchAll(.*)*', path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue'), component: () => import('src/pages/error-page.vue'),
}, },
]; ];

View File

@ -0,0 +1,20 @@
<script lang="ts" setup>
import { useI18n } from 'vue-i18n';
const { locale } = useI18n();
const setLocale = (newLocale: string) => { locale.value = newLocale; };
const localeOptions = [
{ value: 'en', label: 'English' },
{ value: 'fr', label: 'Francais' },
];
</script>
<template>
<q-btn-dropdown flat :label=locale class="rounded-borders" icon="language">
<q-list>
<q-item clickable v-close-popup v-for="option in localeOptions" :key="option.value" @click="setLocale(option.value)">
<q-item-section>{{ option.label }}</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</template>

View File

@ -1,4 +1,3 @@
/* eslint-disable */
// THIS FEATURE-FLAG FILE IS AUTOGENERATED, // THIS FEATURE-FLAG FILE IS AUTOGENERATED,
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
import 'quasar/dist/types/feature-flag'; import 'quasar/dist/types/feature-flag';

View File

@ -1,29 +1,28 @@
export const deepEqual = (o1: any, o2: any) => { export const deepEqual = (a: unknown, b: unknown): boolean => {
if (o1 === o2) { if (a === b) {
return true; return true;
} }
if ( if (
o1 == null || a == null || // handles null and undefined
o2 == null || b == null ||
typeof o1 !== 'object' || typeof a !== 'object' ||
typeof o2 !== 'object' typeof b !== 'object'
) { ) {
return false; return false;
} }
const keys1 = Object.keys(o1); const aKeys = Object.keys(a as Record<string, unknown>);
const keys2 = Object.keys(o2); const bKeys = Object.keys(b as Record<string, unknown>);
if (keys1.length !== keys2.length) { if (aKeys.length !== bKeys.length) {
return false; return false;
} }
for (const key of keys1) { return aKeys.every((key) =>
if (!deepEqual(o1[key], o2[key])) { deepEqual(
return false; (a as Record<string, unknown>)[key],
} (b as Record<string, unknown>)[key]
} )
);
return true; };
};