diff --git a/src/assets/google_thumbnail.png b/src/assets/google_thumbnail.png new file mode 100644 index 0000000..7ca64d8 Binary files /dev/null and b/src/assets/google_thumbnail.png differ diff --git a/src/assets/info-pannes.png b/src/assets/info-pannes.png new file mode 100644 index 0000000..fcfe362 Binary files /dev/null and b/src/assets/info-pannes.png differ diff --git a/src/assets/login-background.png b/src/assets/login-background.png index f234c90..82d0429 100644 Binary files a/src/assets/login-background.png and b/src/assets/login-background.png differ diff --git a/src/assets/targo_help_banner.png b/src/assets/targo_help_banner.png index a55cf4d..be0c2b5 100644 Binary files a/src/assets/targo_help_banner.png and b/src/assets/targo_help_banner.png differ diff --git a/src/i18n/en-ca/index.ts b/src/i18n/en-ca/index.ts index acb390b..6f9234d 100644 --- a/src/i18n/en-ca/index.ts +++ b/src/i18n/en-ca/index.ts @@ -4,8 +4,9 @@ export default { welcome_title: "Welcome to the new Targo Application!", welcome_message: "Development is complete and the application is live! Things have remained mostly the same, but with a new coat of paint, a more streamlined user experience, and most importantly, drastically improved security and optimization!", help_title: "We have a help page!", - help_message: "We did our best to keep the app intuitive with as few clicks and changes as possible, but it's not always perfect! We made this page to explain every part of the app if you any of it ever feels confusing.", + help_message: "We've modernized the app while trying to make as few functional changes as possible, but if there's ever any part of the site that leaves you scratching your head, feel free to check out the help page.", }, + useful_links: "useful links", }, help: { label: "Centre d'aide", @@ -207,6 +208,7 @@ export default { modify: "modify", close: "close", download: "download", + open: "open", }, misc: { or: "or", @@ -243,6 +245,9 @@ export default { page_header: "Timesheet", week: "week", total_hours: "total hours: ", + total_expenses: "total expenses: ", + vacation_available: "vacation time available: ", + sick_available: "sick time available: ", current_shifts: "shifts worked", apply_preset: "auto-fill", apply_preset_day: "Apply schedule to day", @@ -329,6 +334,7 @@ export default { }, print_report: { title: "Download options", + description: "Choose what to include in the report", company: "companies", type: "type", shifts: "shifts", @@ -345,7 +351,7 @@ export default { unverified: "pending", inactive: "inactive", filter_active: "show only active employees", - filter_team: "", + filter_team: "show my team only", }, tooltip: { button_detailed_view: "detailed view", diff --git a/src/i18n/fr-ca/index.ts b/src/i18n/fr-ca/index.ts index db605e0..0ef60ca 100644 --- a/src/i18n/fr-ca/index.ts +++ b/src/i18n/fr-ca/index.ts @@ -2,10 +2,11 @@ export default { dashboard: { carousel: { welcome_title: "Bienvenue dans la nouvelle application Targo!", - welcome_message: "Le développement est terminé et l'application est officiellement en ligne! Les fonctionnalités demeurent grandement intactes comparé à l'ancienne version, mise à part une nouvelle couche de peinture, une expérience utilisateur plus intuitive et surtout une sécurité et optimization drastiquement amélioriés!", + welcome_message: "La nouvelle application est officiellement en ligne ! Plus performante et plus sécuritaire, elle conserve l’essentiel avec un design rafraîchie.", help_title: "Nous avons une page d'aide!", - help_message: "Nous avons fait notre possible pour rendre l'application plus intuitive et facile d'accès en suivant les tendances modernes, mais il y a toujours place à l'amélioration! La page d'aide est là pour vous si jamais nous avons raté la cible et qu'une partie du site semble nébuleux.", + help_message: "L’application a été pensée pour être plus intuitive et moderne. En cas de doute, la page d’aide est à votre disposition.", }, + useful_links: "liens utiles", }, help: { label: "Centre d'aide", @@ -207,7 +208,8 @@ export default { update: "mettre à jour", modify: "modifier", close: "fermer", - download: "téléchargement", + download: "télécharger", + open: "ouvrir", }, misc: { or: "ou", @@ -244,6 +246,9 @@ export default { page_header: "Carte de temps", week: "semaine", total_hours: "heures totales: ", + total_expenses: "dépenses totales: ", + vacation_available: "vacances disponibles: ", + sick_available: "congés maladie disponible: ", current_shifts: "quarts entrées", apply_preset: "auto-remplir", apply_preset_day: "Appliquer horaire pour la journée", @@ -330,6 +335,7 @@ export default { }, print_report: { title: "options de téléchargement", + description: "Choisissez ce qui sera inclu dans le rapport", company: "compagnies", type: "types de données", shifts: "quarts de travail", @@ -345,8 +351,8 @@ export default { verified: "approuvé", unverified: "à vérifier", inactive: "inactif", - filter_active: "", - filter_team: "", + filter_active: "montrer les employés inactifs", + filter_team: "montrer mon équipe seulement", }, tooltip: { button_detailed_view: "vue détaillée", diff --git a/src/layouts/components/main-layout-left-drawer.vue b/src/layouts/components/main-layout-left-drawer.vue index 01472c3..498d4cf 100644 --- a/src/layouts/components/main-layout-left-drawer.vue +++ b/src/layouts/components/main-layout-left-drawer.vue @@ -2,21 +2,34 @@ setup lang="ts" > + import { onMounted, ref } from 'vue'; + import { useQuasar } from 'quasar'; import { useRouter } from 'vue-router'; import { useAuthStore } from 'src/stores/auth-store'; import { useUiStore } from 'src/stores/ui-store'; - import { ref } from 'vue'; import { RouteNames } from 'src/router/router-constants'; - import { ModuleNames } from 'src/modules/shared/models/user.models'; + import { ModuleNames, type UserModuleAccess } from 'src/modules/shared/models/user.models'; + const DRAWER_BUTTONS: { i18n_key: string, icon: string, route: RouteNames, required_module?: UserModuleAccess }[] = [ + { i18n_key: 'nav_bar.home', icon: "home", route: RouteNames.DASHBOARD, required_module: ModuleNames.DASHBOARD }, + { i18n_key: 'nav_bar.timesheet_approvals', icon: "event_available", route: RouteNames.TIMESHEET_APPROVALS, required_module: ModuleNames.TIMESHEETS_APPROVAL }, + { i18n_key: 'nav_bar.employee_list', icon: "groups", route: RouteNames.EMPLOYEE_LIST, required_module: ModuleNames.EMPLOYEE_LIST }, + { i18n_key: 'nav_bar.timesheet', icon: "punch_clock", route: RouteNames.TIMESHEET, required_module: ModuleNames.TIMESHEETS }, + { i18n_key: 'nav_bar.profile', icon: "account_box", route: RouteNames.PROFILE, required_module: ModuleNames.PERSONAL_PROFILE }, + { i18n_key: 'nav_bar.help', icon: "contact_support", route: RouteNames.HELP }, + ] + + const q = useQuasar(); const auth_store = useAuthStore(); const ui_store = useUiStore(); const router = useRouter(); const is_mini = ref(true); - const goToPageName = (page_name: string) => { - router.push({ name: page_name }).catch(err => { - console.error('Error with Vue Router: ', err); + const onClickDrawerPage = (page_name: RouteNames) => { + is_mini.value = true; + + router.push({ name: page_name }).catch(error => { + console.error('failed to reach page: ', error); }); }; @@ -26,7 +39,13 @@ router.push({ name: 'login' }).catch(err => { console.error('could not log you out: ', err); }) - } + }; + + onMounted(() => { + if (q.platform.is.mobile) { + ui_store.is_left_drawer_open = false; + } + }) \ No newline at end of file diff --git a/src/layouts/main-layout.vue b/src/layouts/main-layout.vue index 6c730c9..0e42eb5 100644 --- a/src/layouts/main-layout.vue +++ b/src/layouts/main-layout.vue @@ -32,10 +32,13 @@ \ No newline at end of file diff --git a/src/modules/auth/components/login-connection-panel.vue b/src/modules/auth/components/login-connection-panel.vue index 1b68a96..f5b1513 100644 --- a/src/modules/auth/components/login-connection-panel.vue +++ b/src/modules/auth/components/login-connection-panel.vue @@ -1,25 +1,31 @@ - + + \ No newline at end of file diff --git a/src/modules/employee-list/components/employee-list-table.vue b/src/modules/employee-list/components/employee-list-table.vue index 03852c3..5af2c2a 100644 --- a/src/modules/employee-list/components/employee-list-table.vue +++ b/src/modules/employee-list/components/employee-list-table.vue @@ -7,13 +7,18 @@ import { onMounted, ref } from 'vue'; import { date, type QTableColumn } from 'quasar'; import { useUiStore } from 'src/stores/ui-store'; + import { useAuthStore } from 'src/stores/auth-store'; import { useEmployeeStore } from 'src/stores/employee-store'; import { useTimesheetStore } from 'src/stores/timesheet-store'; import { employee_list_columns, type EmployeeProfile, type EmployeeListFilters } from 'src/modules/employee-list/models/employee-profile.models'; + const ui_store = useUiStore(); + const auth_store = useAuthStore(); const employee_store = useEmployeeStore(); const timesheet_store = useTimesheetStore(); - const ui_store = useUiStore(); + + const is_management = auth_store.user?.user_module_access.includes('employee_management') ?? false; + const visible_columns = ref<(keyof EmployeeProfile)[]>(['first_name', 'email', 'job_title', 'last_work_day']); const table_grid_container = ref(null); @@ -86,16 +91,33 @@ :visible-columns="visible_columns" > @@ -178,7 +192,7 @@ + + diff --git a/src/modules/help/components/help-module.vue b/src/modules/help/components/help-module.vue index a2b33f5..f947c35 100644 --- a/src/modules/help/components/help-module.vue +++ b/src/modules/help/components/help-module.vue @@ -1,40 +1,43 @@ - @@ -45,14 +48,15 @@ const switchSide = (index: number) => { >
{{ ($t(`help.tutorial.${help_module}.title`)).toUpperCase() }}
- + +
- +
{ leave-active-class="animated fade-out" >
-
+ +
{
- + +
{ leave-active-class="animated fade-out" > diff --git a/src/modules/profile/components/shared/menu-panel-preferences.vue b/src/modules/profile/components/shared/menu-panel-preferences.vue index 2bb437b..135678c 100644 --- a/src/modules/profile/components/shared/menu-panel-preferences.vue +++ b/src/modules/profile/components/shared/menu-panel-preferences.vue @@ -23,36 +23,40 @@ :class="ui_store.is_mobile_mode ? 'column' : 'row'" style="border: 1px solid var(--q-accent);" > - - - - + + + + - - {{ $t(mode.label) }} - + + {{ $t(mode.label) }} + - - - - + + + + +
{{ $t(title) }} + class="col q-pt-lg" + > + {{ $t(title) }} +
@@ -50,8 +50,8 @@
-
- +
+
diff --git a/src/modules/timesheet-approval/components/overview-list-filters.vue b/src/modules/timesheet-approval/components/overview-list-filters.vue index d51c3d0..f56b583 100644 --- a/src/modules/timesheet-approval/components/overview-list-filters.vue +++ b/src/modules/timesheet-approval/components/overview-list-filters.vue @@ -15,17 +15,18 @@ keep-color size="lg" color="accent" - label="show inactive" + :label="$t('timesheet_approvals.table.filter_active')" class="col" :class="filters.is_showing_inactive ? 'text-accent text-weight-bolder' : 'text-white text-weight-medium'" /> + diff --git a/src/modules/timesheet-approval/components/overview-list-item.vue b/src/modules/timesheet-approval/components/overview-list-item.vue index 5e9201b..40eb0e3 100644 --- a/src/modules/timesheet-approval/components/overview-list-item.vue +++ b/src/modules/timesheet-approval/components/overview-list-item.vue @@ -154,7 +154,6 @@ import { getHoursMinutesStringFromHoursFloat, getMinutes } from 'src/utils/date- >
{{ 'Total : ' + Math.floor(row.total_hours) }} diff --git a/src/modules/timesheet-approval/components/overview-list.vue b/src/modules/timesheet-approval/components/overview-list.vue index 864e7ae..2f2d955 100644 --- a/src/modules/timesheet-approval/components/overview-list.vue +++ b/src/modules/timesheet-approval/components/overview-list.vue @@ -35,15 +35,18 @@ 'is_approved', ]); + const { maxHeight } = defineProps<{ + maxHeight: number; + }>(); + const is_showing_filters = ref(false); - const search_string = ref(''); const overview_rows = computed(() => timesheet_store.pay_period_overviews.filter(overview => overview)); const overview_filters = ref({ is_showing_inactive: false, is_showing_team_only: false, supervisors: [], - name_search_string: search_string.value, + name_search_string: '', }); const onClickedDetails = async (row: TimesheetApprovalOverview) => { @@ -80,211 +83,213 @@ @@ -305,4 +310,7 @@ tbody scroll-margin-top: 48px + +.q-table__grid-content + overflow: auto \ No newline at end of file diff --git a/src/modules/timesheet-approval/components/overview-report.vue b/src/modules/timesheet-approval/components/overview-report.vue index 32fda13..eda4698 100644 --- a/src/modules/timesheet-approval/components/overview-report.vue +++ b/src/modules/timesheet-approval/components/overview-report.vue @@ -1,143 +1,163 @@ - diff --git a/src/modules/timesheets/components/mobile/shift-list-day-row-mobile.vue b/src/modules/timesheets/components/mobile/shift-list-day-row-mobile.vue index cc1101e..77f9206 100644 --- a/src/modules/timesheets/components/mobile/shift-list-day-row-mobile.vue +++ b/src/modules/timesheets/components/mobile/shift-list-day-row-mobile.vue @@ -209,6 +209,18 @@ + +
diff --git a/src/modules/timesheets/components/mobile/shift-list-weekly-overview.vue b/src/modules/timesheets/components/mobile/shift-list-weekly-overview-mobile.vue similarity index 95% rename from src/modules/timesheets/components/mobile/shift-list-weekly-overview.vue rename to src/modules/timesheets/components/mobile/shift-list-weekly-overview-mobile.vue index 1b4b183..5c26db2 100644 --- a/src/modules/timesheets/components/mobile/shift-list-weekly-overview.vue +++ b/src/modules/timesheets/components/mobile/shift-list-weekly-overview-mobile.vue @@ -12,7 +12,7 @@ + +
diff --git a/src/modules/timesheets/components/shift-list-day.vue b/src/modules/timesheets/components/shift-list-day.vue index 64bd392..8ab3523 100644 --- a/src/modules/timesheets/components/shift-list-day.vue +++ b/src/modules/timesheets/components/shift-list-day.vue @@ -6,14 +6,16 @@ import ShiftListDayRowMobile from 'src/modules/timesheets/components/mobile/shift-list-day-row-mobile.vue'; import { ref } from 'vue'; + import { useTimesheetStore } from 'src/stores/timesheet-store'; import { useShiftApi } from 'src/modules/timesheets/composables/use-shift-api'; import { useTimesheetApi } from 'src/modules/timesheets/composables/use-timesheet-api'; import type { Shift } from 'src/modules/timesheets/models/shift.models'; import type { TimesheetDay } from 'src/modules/timesheets/models/timesheet.models'; -import { isShiftOverlap } from 'src/modules/timesheets/utils/shift.util'; + import { isShiftOverlap } from 'src/modules/timesheets/utils/shift.util'; const shift_api = useShiftApi(); const timesheet_api = useTimesheetApi(); + const timesheet_store = useTimesheetStore(); const shift_error_message = ref(); const { day, dense = false, approved = false } = defineProps<{ @@ -63,7 +65,7 @@ import { isShiftOverlap } from 'src/modules/timesheets/utils/shift.util'; leave-active-class="animated zoomOut fast" > - + import { useAuthStore } from 'src/stores/auth-store'; +import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-utils'; + + const { mode = 'totals', totalHours = 0, vacationHours = 0, sickHours = 0, totalExpenses = 0 } = defineProps<{ + mode: 'total-hours' | 'off-hours'; + totalHours?: number; + vacationHours?: number; + sickHours?: number; + totalExpenses?: number; + }>(); + + const auth_store = useAuthStore(); + const is_management = auth_store.user?.user_module_access.includes('timesheets_approval'); + + + \ No newline at end of file diff --git a/src/modules/timesheets/components/shift-list.vue b/src/modules/timesheets/components/shift-list.vue index ca95b19..637662f 100644 --- a/src/modules/timesheets/components/shift-list.vue +++ b/src/modules/timesheets/components/shift-list.vue @@ -5,22 +5,25 @@ import ShiftListDay from 'src/modules/timesheets/components/shift-list-day.vue'; import ShiftListDateWidget from 'src/modules/timesheets/components/shift-list-date-widget.vue'; - import { date } from 'quasar'; - import { computed, ref } from 'vue'; + import { date, useQuasar } from 'quasar'; + import { computed, ref, watch } from 'vue'; import { useUiStore } from 'src/stores/ui-store'; import { useTimesheetStore } from 'src/stores/timesheet-store'; import { Shift } from 'src/modules/timesheets/models/shift.models'; import { useTimesheetApi } from 'src/modules/timesheets/composables/use-timesheet-api'; - import type { QScrollArea } from 'quasar'; + import type { QScrollArea, TouchSwipeValue } from 'quasar'; import type { TimesheetDay } from 'src/modules/timesheets/models/timesheet.models'; + const CURRENT_DATE_STRING = new Date().toISOString().slice(0, 10); + const { extractDate } = date; + const q = useQuasar(); const ui_store = useUiStore(); const timesheet_store = useTimesheetStore(); const timesheet_api = useTimesheetApi(); - const { mode = 'normal'} = defineProps<{ + const { mode = 'normal' } = defineProps<{ mode: 'normal' | 'approval'; }>(); @@ -28,7 +31,12 @@ const animation_style = computed(() => ui_store.is_mobile_mode ? mobile_animation_direction.value : 'fadeInDown'); const timesheet_page = ref(null); - const scroll_y = computed(() => timesheet_page.value?.getScrollPosition().top ?? 0) + const currentDayComponent = ref(null); + const currentDayComponentWatcher = ref(currentDayComponent); + + const scroll_y = computed(() => timesheet_page.value?.getScrollPosition().top ?? 0); + const timesheet_container = ref(null); + const scroll_area_height = ref(0); const addNewShift = (day_shifts: Shift[], date: string, timesheet_id: number) => { ui_store.focus_next_component = true; @@ -44,37 +52,54 @@ const shifts_without_deleted_shift = day.shifts.filter(shift => shift.id !== 0); day.shifts = shifts_without_deleted_shift; } - } + }; const getDayApproval = (day: TimesheetDay) => { if (day.shifts.length < 1) return false; return day.shifts.every(shift => shift.is_approved === true); - } + }; - const handleSwipe = async (direction: 'left' | 'up' | 'down' | 'right' | undefined, distance: { x?: number, y?: number }) => { - mobile_animation_direction.value = direction === 'left' ? 'fadeInRight' : 'fadeInLeft'; - if (distance.x && Math.abs(distance.x) > 10) { - await timesheet_api.getTimesheetsBySwiping(direction === 'left' ? 1 : -1) + const handleSwipe: TouchSwipeValue = (details) => { + mobile_animation_direction.value = details.direction === 'left' ? 'fadeInRight' : 'fadeInLeft'; + if (details.distance && details.distance.x && Math.abs(details.distance.x) > 10) { + timesheet_api.getTimesheetsBySwiping(details.direction === 'left' ? 1 : -1).catch(error => console.error(error)); } - } + }; + + const getMobileDayRef = (iso_date_string: string): string => { + return iso_date_string === CURRENT_DATE_STRING ? 'currentDayComponent' : ''; + }; + + watch(currentDayComponentWatcher, () => { + if (currentDayComponent.value && timesheet_page.value && q.platform.is.mobile) { + console.log('setting scroll position to offsetTop of currentDayComponent: ', currentDayComponent.value[0]!.offsetTop); + timesheet_page.value.setScrollPosition('vertical', currentDayComponent.value[0]!.offsetTop, 800); + return; + } + + if (timesheet_container.value !== null && mode === 'approval') { + scroll_area_height.value = timesheet_container.value.offsetHeight + } + })