Merge branch 'dev/nicolas/staging-prep' of https://git.targo.ca/Targo/targo_frontend into dev/nicolas/staging-prep
This commit is contained in:
commit
e7b154e041
|
|
@ -224,6 +224,7 @@ export default {
|
||||||
error: {
|
error: {
|
||||||
no_data_found: "no data found",
|
no_data_found: "no data found",
|
||||||
no_search_results: "no results matching search",
|
no_search_results: "no results matching search",
|
||||||
|
generic_error: "An error occured",
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
search: "search",
|
search: "search",
|
||||||
|
|
@ -284,6 +285,7 @@ export default {
|
||||||
apply_preset: "auto-fill",
|
apply_preset: "auto-fill",
|
||||||
apply_preset_day: "Apply schedule to day",
|
apply_preset_day: "Apply schedule to day",
|
||||||
apply_preset_week: "Apply schedule to week",
|
apply_preset_week: "Apply schedule to week",
|
||||||
|
save_successful: "timesheets saved",
|
||||||
nav_button: {
|
nav_button: {
|
||||||
calendar_date_picker: "Calendar",
|
calendar_date_picker: "Calendar",
|
||||||
current_week: "This week",
|
current_week: "This week",
|
||||||
|
|
@ -359,6 +361,7 @@ export default {
|
||||||
SHIFT_TYPE_REQUIRED: "Shift type required",
|
SHIFT_TYPE_REQUIRED: "Shift type required",
|
||||||
TIMESHEET_NOT_FOUND: "No timesheet found with provided data",
|
TIMESHEET_NOT_FOUND: "No timesheet found with provided data",
|
||||||
UPDATE_ERROR: "Error while updating data",
|
UPDATE_ERROR: "Error while updating data",
|
||||||
|
ERROR_SAVING_SHIFTS: "Timesheet changes were not saved",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,7 @@ export default {
|
||||||
error: {
|
error: {
|
||||||
no_data_found: 'aucune donnée à afficher',
|
no_data_found: 'aucune donnée à afficher',
|
||||||
no_search_results: 'aucun résultat ne correspond à la recherche',
|
no_search_results: 'aucun résultat ne correspond à la recherche',
|
||||||
|
generic_error: "Une erreur est survenue",
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
search: 'recherche',
|
search: 'recherche',
|
||||||
|
|
@ -284,6 +285,7 @@ export default {
|
||||||
apply_preset: "auto-remplir",
|
apply_preset: "auto-remplir",
|
||||||
apply_preset_day: "Appliquer horaire pour la journée",
|
apply_preset_day: "Appliquer horaire pour la journée",
|
||||||
apply_preset_week: "Appliquer horaire pour la semaine",
|
apply_preset_week: "Appliquer horaire pour la semaine",
|
||||||
|
save_successful: "feuilles de temps enregistrées",
|
||||||
nav_button: {
|
nav_button: {
|
||||||
calendar_date_picker: "Calendrier",
|
calendar_date_picker: "Calendrier",
|
||||||
current_week: "Semaine actuelle",
|
current_week: "Semaine actuelle",
|
||||||
|
|
@ -359,6 +361,7 @@ export default {
|
||||||
SHIFT_TYPE_REQUIRED: "Type requis",
|
SHIFT_TYPE_REQUIRED: "Type requis",
|
||||||
TIMESHEET_NOT_FOUND: "Aucune feuille de temps ne correspond au détails fournis",
|
TIMESHEET_NOT_FOUND: "Aucune feuille de temps ne correspond au détails fournis",
|
||||||
UPDATE_ERROR: "Une erreur est survenu lors de la mise à jour",
|
UPDATE_ERROR: "Une erreur est survenu lors de la mise à jour",
|
||||||
|
ERROR_SAVING_SHIFTS: "les changements aux feuilles de temps n'ont pas été enregistrés",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
setup
|
setup
|
||||||
lang="ts"
|
lang="ts"
|
||||||
>
|
>
|
||||||
import { onMounted, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { Bar } from 'vue-chartjs';
|
import { Bar } from 'vue-chartjs';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar, colors } from 'quasar';
|
import { useQuasar, colors } from 'quasar';
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, TimeScale, type ChartDataset } from 'chart.js';
|
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, TimeScale } from 'chart.js';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
|
|
@ -19,27 +19,21 @@
|
||||||
|
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
|
|
||||||
const all_days = timesheet_store.timesheets.flatMap(week => week.days.flatMap(day => day.daily_expenses));
|
const all_days = computed(() => timesheet_store.timesheets.flatMap(week => week.days.flatMap(day => day.daily_expenses)));
|
||||||
|
|
||||||
const expenses_labels = ref<string[]>(timesheet_store.timesheets.flatMap(week => week.days.map(day => day.date.slice(-5,))));
|
const expenses_labels = ref<string[]>(timesheet_store.timesheets.flatMap(week => week.days.map(day => day.date.slice(-5,))));
|
||||||
const expenses_dataset = ref<ChartDataset<'bar'>[]>([]);
|
const expenses_dataset = computed(() => [
|
||||||
|
{
|
||||||
onMounted(() => {
|
label: t('timesheet_approvals.table.expenses'),
|
||||||
setTimeout(() => {
|
data: all_days.value.map(day => (day.expenses + day.on_call + day.per_diem)),
|
||||||
expenses_dataset.value = [
|
backgroundColor: colors.getPaletteColor('accent'),
|
||||||
{
|
},
|
||||||
label: t('timesheet_approvals.table.expenses'),
|
{
|
||||||
data: all_days.map(day => (day.expenses + day.on_call + day.per_diem)),
|
label: t('timesheet_approvals.table.mileage'),
|
||||||
backgroundColor: colors.getPaletteColor('accent'),
|
data: all_days.value.map(day => day.mileage),
|
||||||
},
|
backgroundColor: colors.getPaletteColor('info'),
|
||||||
{
|
}
|
||||||
label: t('timesheet_approvals.table.mileage'),
|
]);
|
||||||
data: all_days.map(day => day.mileage),
|
|
||||||
backgroundColor: colors.getPaletteColor('info'),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}, 100)
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,17 @@
|
||||||
setup
|
setup
|
||||||
lang="ts"
|
lang="ts"
|
||||||
>
|
>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { colors, date, useQuasar } from 'quasar';
|
import { colors, date, useQuasar } from 'quasar';
|
||||||
import { Bar } from 'vue-chartjs';
|
import { Bar } from 'vue-chartjs';
|
||||||
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, TimeScale, type ChartDataset } from 'chart.js';
|
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, TimeScale } from 'chart.js';
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import type { TotalHours } from 'src/modules/timesheets/models/timesheet.models';
|
import type { TotalHours } from 'src/modules/timesheets/models/timesheet.models';
|
||||||
import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-utils';
|
import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-utils';
|
||||||
|
|
||||||
interface ChartConfigHoursWorked {
|
interface ChartConfigHoursWorked {
|
||||||
key: keyof Pick<TotalHours, 'regular' | 'evening' | 'emergency' | 'overtime'| 'vacation' | 'holiday'>;
|
key: keyof Pick<TotalHours, 'regular' | 'evening' | 'emergency' | 'overtime' | 'vacation' | 'holiday'>;
|
||||||
label: string;
|
label: string;
|
||||||
color: string;
|
color: string;
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +27,7 @@ import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-uti
|
||||||
|
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
|
|
||||||
const all_days = timesheet_store.timesheets.flatMap(week => week.days);
|
const all_days = computed(() => timesheet_store.timesheets.flatMap(week => week.days));
|
||||||
|
|
||||||
const datasetConfig: ChartConfigHoursWorked[] = [
|
const datasetConfig: ChartConfigHoursWorked[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -62,18 +62,12 @@ import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-uti
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const hours_worked_labels = ref<string[]>(all_days.map(day => day.date.slice(-5,)));
|
const hours_worked_labels = ref<string[]>(all_days.value.map(day => day.date.slice(-5,)));
|
||||||
const hours_worked_dataset = ref<ChartDataset<'bar'>[]>([]);
|
const hours_worked_datasets = computed(() => datasetConfig.map(cfg => ({
|
||||||
|
label: cfg.label,
|
||||||
onMounted(() => {
|
data: all_days.value.map(day => day.daily_hours[cfg.key]),
|
||||||
setTimeout(() => {
|
backgroundColor: cfg.color,
|
||||||
hours_worked_dataset.value = datasetConfig.map(cfg => ({
|
})))
|
||||||
label: cfg.label,
|
|
||||||
data: all_days.map(day => day.daily_hours[cfg.key]),
|
|
||||||
backgroundColor: cfg.color,
|
|
||||||
}));
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -83,7 +77,7 @@ import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-uti
|
||||||
>
|
>
|
||||||
<Bar
|
<Bar
|
||||||
:data="{
|
:data="{
|
||||||
datasets: hours_worked_dataset,
|
datasets: hours_worked_datasets,
|
||||||
labels: hours_worked_labels,
|
labels: hours_worked_labels,
|
||||||
}"
|
}"
|
||||||
:options="({
|
:options="({
|
||||||
|
|
@ -92,7 +86,7 @@ import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-uti
|
||||||
tooltip: {
|
tooltip: {
|
||||||
callbacks: {
|
callbacks: {
|
||||||
title: function (context) {
|
title: function (context) {
|
||||||
return $d(date.extractDate(`2025-${context[0]!.label}`, 'YYYY-MM-DD'), {month: 'long', day: 'numeric'});
|
return $d(date.extractDate(`2025-${context[0]!.label}`, 'YYYY-MM-DD'), { month: 'long', day: 'numeric' });
|
||||||
},
|
},
|
||||||
label: function (context) {
|
label: function (context) {
|
||||||
return getHoursMinutesStringFromHoursFloat(context.parsed.y);
|
return getHoursMinutesStringFromHoursFloat(context.parsed.y);
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@
|
||||||
setup
|
setup
|
||||||
lang="ts"
|
lang="ts"
|
||||||
>
|
>
|
||||||
/* eslint-disable */
|
import { computed } from 'vue';
|
||||||
import { onMounted, ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { colors } from 'quasar';
|
import { colors } from 'quasar';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import { Doughnut } from 'vue-chartjs';
|
import { Doughnut } from 'vue-chartjs';
|
||||||
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement, CategoryScale, LinearScale, type ChartDataset } from 'chart.js';
|
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement, CategoryScale, LinearScale } from 'chart.js';
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-utils';
|
import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-utils';
|
||||||
|
import type { Timesheet, TotalHours } from 'src/modules/timesheets/models/timesheet.models';
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
@ -22,33 +22,27 @@
|
||||||
|
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
|
|
||||||
const shift_type_labels = ref<string[]>([
|
const TRACKABLE_SHIFT_TYPES: (keyof TotalHours)[] = ['regular', 'evening', 'emergency', 'overtime', 'holiday', 'vacation']
|
||||||
|
|
||||||
|
const SHIFT_TYPE_LABELS = [
|
||||||
t('shared.shift_type.regular'),
|
t('shared.shift_type.regular'),
|
||||||
t('shared.shift_type.evening'),
|
t('shared.shift_type.evening'),
|
||||||
t('shared.shift_type.emergency'),
|
t('shared.shift_type.emergency'),
|
||||||
t('shared.shift_type.overtime'),
|
t('shared.shift_type.overtime'),
|
||||||
]);
|
t('shared.shift_type.holiday'),
|
||||||
|
t('shared.shift_type.vacation'),
|
||||||
|
];
|
||||||
|
|
||||||
const shift_type_totals = ref<ChartDataset<'doughnut'>[]>([]);
|
const shift_type_data = computed(() => {
|
||||||
|
const initial_totals = new Array(TRACKABLE_SHIFT_TYPES.length).fill(0);
|
||||||
|
|
||||||
onMounted(() => {
|
return timesheet_store.timesheets.reduce((accumulator: number[], timesheet: Timesheet) => {
|
||||||
setTimeout(() => {
|
TRACKABLE_SHIFT_TYPES.forEach( (trackable_shift_type, index) => {
|
||||||
shift_type_totals.value = [{
|
accumulator[index]! += timesheet.weekly_hours[trackable_shift_type] ?? 0;
|
||||||
data: [
|
});
|
||||||
timesheet_store.current_pay_period_overview!.regular_hours,
|
|
||||||
timesheet_store.current_pay_period_overview!.other_hours.evening_hours,
|
|
||||||
timesheet_store.current_pay_period_overview!.other_hours.emergency_hours,
|
|
||||||
timesheet_store.current_pay_period_overview!.other_hours.overtime_hours,
|
|
||||||
],
|
|
||||||
backgroundColor: [
|
|
||||||
colors.getPaletteColor('accent'), // Regular
|
|
||||||
colors.getPaletteColor('green-10'), // Evening
|
|
||||||
colors.getPaletteColor('warning'), // Emergency
|
|
||||||
colors.getPaletteColor('negative'), // Overtime
|
|
||||||
]
|
|
||||||
}]
|
|
||||||
|
|
||||||
}, 100);
|
return accumulator;
|
||||||
|
}, initial_totals);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -59,8 +53,16 @@
|
||||||
>
|
>
|
||||||
<Doughnut
|
<Doughnut
|
||||||
:data="{
|
:data="{
|
||||||
labels: shift_type_labels,
|
labels: SHIFT_TYPE_LABELS,
|
||||||
datasets: shift_type_totals,
|
datasets: [{
|
||||||
|
data: shift_type_data,
|
||||||
|
backgroundColor: [
|
||||||
|
colors.getPaletteColor('accent'), // Regular
|
||||||
|
colors.getPaletteColor('green-10'), // Evening
|
||||||
|
colors.getPaletteColor('warning'), // Emergency
|
||||||
|
colors.getPaletteColor('negative'), // Overtime
|
||||||
|
]
|
||||||
|
}],
|
||||||
}"
|
}"
|
||||||
:options="({
|
:options="({
|
||||||
plugins: {
|
plugins: {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
backdrop-filter="blur(6px)"
|
backdrop-filter="blur(6px)"
|
||||||
@show="is_dialog_open = true"
|
@show="is_dialog_open = true"
|
||||||
@hide="is_dialog_open = false"
|
@hide="is_dialog_open = false"
|
||||||
|
@before-hide="timesheet_store.getTimesheetOverviews"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="column bg-secondary hide-scrollbar shadow-12 rounded-15 q-pa-sm no-wrap"
|
class="column bg-secondary hide-scrollbar shadow-12 rounded-15 q-pa-sm no-wrap"
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
value: ExpenseType;
|
value: ExpenseType;
|
||||||
icon: string;
|
icon: string;
|
||||||
}
|
}
|
||||||
|
const expense = defineModel<Expense>({ default: new Expense(new Date().toISOString().slice(0, 10)) })
|
||||||
|
|
||||||
const COMMENT_MAX_LENGTH = 280;
|
const COMMENT_MAX_LENGTH = 280;
|
||||||
|
|
||||||
|
|
@ -30,6 +31,8 @@
|
||||||
const files = defineModel<File[] | null>('files');
|
const files = defineModel<File[] | null>('files');
|
||||||
const is_navigator_open = ref(false);
|
const is_navigator_open = ref(false);
|
||||||
const rules = useExpenseRules(t);
|
const rules = useExpenseRules(t);
|
||||||
|
|
||||||
|
|
||||||
const expense_options: ExpenseOption[] = [
|
const expense_options: ExpenseOption[] = [
|
||||||
{ label: t('timesheet.expense.types.PER_DIEM'), value: 'PER_DIEM', icon: getExpenseIcon('PER_DIEM') },
|
{ label: t('timesheet.expense.types.PER_DIEM'), value: 'PER_DIEM', icon: getExpenseIcon('PER_DIEM') },
|
||||||
{ label: t('timesheet.expense.types.EXPENSES'), value: 'EXPENSES', icon: getExpenseIcon('EXPENSES') },
|
{ label: t('timesheet.expense.types.EXPENSES'), value: 'EXPENSES', icon: getExpenseIcon('EXPENSES') },
|
||||||
|
|
@ -67,13 +70,16 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
expense_selected.value = expense_options.find(expense => expense.value === expenses_store.current_expense.type);
|
if (expense.value)
|
||||||
|
expense_selected.value = expense_options.find(expense_option => expense_option.value === expense.value.type);
|
||||||
|
else
|
||||||
|
expense_selected.value = expense_options[1];
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-form
|
<q-form
|
||||||
v-if="!timesheet_store.timesheets?.every(timesheet => timesheet.is_approved)"
|
v-if="!expenses_store.current_expense.is_approved"
|
||||||
flat
|
flat
|
||||||
@submit.prevent="requestExpenseCreationOrUpdate"
|
@submit.prevent="requestExpenseCreationOrUpdate"
|
||||||
class="full-width q-mt-md q-px-md"
|
class="full-width q-mt-md q-px-md"
|
||||||
|
|
@ -292,7 +298,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
:deep(.q-field--standout.q-field--readonly .q-field__control::before) {
|
:deep(.q-field--standout.q-field--readonly .q-field__control::before) {
|
||||||
border: transparent;
|
border: transparent;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -212,6 +212,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<ExpenseDialogForm />
|
<ExpenseDialogForm v-model="expense" />
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
setup
|
setup
|
||||||
lang="ts"
|
lang="ts"
|
||||||
>
|
>
|
||||||
/* eslint-disable */
|
|
||||||
import ShiftList from 'src/modules/timesheets/components/shift-list.vue';
|
import ShiftList from 'src/modules/timesheets/components/shift-list.vue';
|
||||||
import ShiftListScrollable from 'src/modules/timesheets/components/shift-list-scrollable.vue';
|
import ShiftListScrollable from 'src/modules/timesheets/components/shift-list-scrollable.vue';
|
||||||
import LoadingOverlay from 'src/modules/shared/components/loading-overlay.vue';
|
import LoadingOverlay from 'src/modules/shared/components/loading-overlay.vue';
|
||||||
|
|
@ -13,7 +12,8 @@
|
||||||
import ShiftListWeeklyOverview from 'src/modules/timesheets/components/shift-list-weekly-overview.vue';
|
import ShiftListWeeklyOverview from 'src/modules/timesheets/components/shift-list-weekly-overview.vue';
|
||||||
import ShiftListWeeklyOverviewMobile from 'src/modules/timesheets/components/mobile/shift-list-weekly-overview-mobile.vue';
|
import ShiftListWeeklyOverviewMobile from 'src/modules/timesheets/components/mobile/shift-list-weekly-overview-mobile.vue';
|
||||||
|
|
||||||
import { date } from 'quasar';
|
import { date, Notify } from 'quasar';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
import { computed, onMounted, provide } from 'vue';
|
import { computed, onMounted, provide } from 'vue';
|
||||||
import { useShiftApi } from 'src/modules/timesheets/composables/use-shift-api';
|
import { useShiftApi } from 'src/modules/timesheets/composables/use-shift-api';
|
||||||
import { useTimesheetApi } from 'src/modules/timesheets/composables/use-timesheet-api';
|
import { useTimesheetApi } from 'src/modules/timesheets/composables/use-timesheet-api';
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
employeeEmail?: string | undefined;
|
employeeEmail?: string | undefined;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
const expenses_store = useExpensesStore();
|
const expenses_store = useExpensesStore();
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
const timesheet_api = useTimesheetApi();
|
const timesheet_api = useTimesheetApi();
|
||||||
|
|
@ -50,13 +51,25 @@
|
||||||
sum + timesheet.weekly_expenses.expenses
|
sum + timesheet.weekly_expenses.expenses
|
||||||
+ timesheet.weekly_expenses.on_call
|
+ timesheet.weekly_expenses.on_call
|
||||||
+ timesheet.weekly_expenses.per_diem,
|
+ timesheet.weekly_expenses.per_diem,
|
||||||
0) //initial value
|
0 //initial value
|
||||||
);
|
));
|
||||||
|
|
||||||
// =================== methods ==========================
|
// =================== methods ==========================
|
||||||
|
|
||||||
provide('employeeEmail', employeeEmail);
|
provide('employeeEmail', employeeEmail);
|
||||||
|
|
||||||
|
const onClickSaveTimesheets = async () => {
|
||||||
|
if (mode === 'normal') {
|
||||||
|
await shift_api.saveShiftChanges();
|
||||||
|
Notify.create({
|
||||||
|
message: t('timesheet.save_successful'),
|
||||||
|
color: 'accent',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await shift_api.saveShiftChanges(timesheet_store.current_pay_period_overview?.email);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (mode === 'normal')
|
if (mode === 'normal')
|
||||||
await timesheet_api.getTimesheetsByDate(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
await timesheet_api.getTimesheetsByDate(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
||||||
|
|
@ -106,7 +119,10 @@
|
||||||
v-if="!$q.platform.is.mobile"
|
v-if="!$q.platform.is.mobile"
|
||||||
class="col-xs-6 col-md-4 col-xl-3 q-pa-md"
|
class="col-xs-6 col-md-4 col-xl-3 q-pa-md"
|
||||||
>
|
>
|
||||||
<ShiftListWeeklyOverview mode="off-hours" :timesheet-mode="mode" />
|
<ShiftListWeeklyOverview
|
||||||
|
mode="off-hours"
|
||||||
|
:timesheet-mode="mode"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -125,7 +141,10 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- mobile expenses button -->
|
<!-- mobile expenses button -->
|
||||||
<div v-if="($q.platform.is.mobile && ($q.screen.width < $q.screen.height))" class="col q-pl-lg">
|
<div
|
||||||
|
v-if="($q.platform.is.mobile && ($q.screen.width < $q.screen.height))"
|
||||||
|
class="col q-pl-lg"
|
||||||
|
>
|
||||||
<q-btn
|
<q-btn
|
||||||
push
|
push
|
||||||
rounded
|
rounded
|
||||||
|
|
@ -159,7 +178,7 @@
|
||||||
icon="upload"
|
icon="upload"
|
||||||
:label="$t('shared.label.save')"
|
:label="$t('shared.label.save')"
|
||||||
:class="$q.platform.is.mobile && ($q.screen.width < $q.screen.height) ? 'full-width' : 'q-ml-md'"
|
:class="$q.platform.is.mobile && ($q.screen.width < $q.screen.height) ? 'full-width' : 'q-ml-md'"
|
||||||
@click="shift_api.saveShiftChanges"
|
@click="onClickSaveTimesheets"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -213,7 +232,7 @@
|
||||||
:label="$t('shared.label.save')"
|
:label="$t('shared.label.save')"
|
||||||
class="col-auto absolute-bottom shadow-up-10"
|
class="col-auto absolute-bottom shadow-up-10"
|
||||||
style="height: 50px;"
|
style="height: 50px;"
|
||||||
@click="shift_api.saveShiftChanges"
|
@click="onClickSaveTimesheets"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ExpenseDialog
|
<ExpenseDialog
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,17 @@ export const useExpensesApi = () => {
|
||||||
|
|
||||||
const upsertExpense = async (expense: Expense, employee_email?: string): Promise<void> => {
|
const upsertExpense = async (expense: Expense, employee_email?: string): Promise<void> => {
|
||||||
const success = await expenses_store.upsertExpense(expense, employee_email);
|
const success = await expenses_store.upsertExpense(expense, employee_email);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
expenses_store.current_expense = new Expense(date.formatDate( new Date(), 'YYYY-MM-DD'));
|
expenses_store.current_expense = new Expense(date.formatDate( new Date(), 'YYYY-MM-DD'));
|
||||||
timesheet_store.getTimesheetsByOptionalEmployeeEmail();
|
timesheet_store.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteExpenseById = async (expense_id: number): Promise<void> => {
|
const deleteExpenseById = async (expense_id: number, employee_email?: string): Promise<void> => {
|
||||||
const success = await expenses_store.deleteExpenseById(expense_id);
|
const success = await expenses_store.deleteExpenseById(expense_id);
|
||||||
if (success) {
|
if (success) {
|
||||||
timesheet_store.getTimesheetsByOptionalEmployeeEmail();
|
timesheet_store.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,29 @@
|
||||||
import { useAuthStore } from "src/stores/auth-store";
|
|
||||||
import { useShiftStore } from "src/stores/shift-store";
|
import { useShiftStore } from "src/stores/shift-store";
|
||||||
import { useTimesheetStore } from "src/stores/timesheet-store";
|
import { useTimesheetStore } from "src/stores/timesheet-store";
|
||||||
|
|
||||||
export const useShiftApi = () => {
|
export const useShiftApi = () => {
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
const shift_store = useShiftStore();
|
const shift_store = useShiftStore();
|
||||||
const auth_store = useAuthStore();
|
|
||||||
|
|
||||||
const deleteShiftById = async (shift_id: number, employee_email?: string) => {
|
const deleteShiftById = async (shift_id: number, employee_email?: string) => {
|
||||||
timesheet_store.is_loading = true;
|
timesheet_store.is_loading = true;
|
||||||
const success = await shift_store.deleteShiftById(shift_id, employee_email);
|
const success = await shift_store.deleteShiftById(shift_id, employee_email);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
await timesheet_store.getTimesheetsByOptionalEmployeeEmail(auth_store.user?.email ?? '');
|
await timesheet_store.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
||||||
}
|
}
|
||||||
|
|
||||||
timesheet_store.is_loading = false;
|
timesheet_store.is_loading = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveShiftChanges = async () => {
|
const saveShiftChanges = async (employee_email?: string) => {
|
||||||
timesheet_store.is_loading = true;
|
timesheet_store.is_loading = true;
|
||||||
|
|
||||||
const update_success = await shift_store.updateShifts();
|
const update_success = await shift_store.updateShifts(employee_email);
|
||||||
const create_success = await shift_store.createNewShifts();
|
const create_success = await shift_store.createNewShifts(employee_email);
|
||||||
|
|
||||||
if (create_success || update_success){
|
if (create_success || update_success){
|
||||||
await timesheet_store.getTimesheetsByOptionalEmployeeEmail(auth_store.user?.email ?? '');
|
await timesheet_store.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
||||||
}
|
}
|
||||||
|
|
||||||
timesheet_store.is_loading = false;
|
timesheet_store.is_loading = false;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export const ShiftService = {
|
||||||
|
|
||||||
createNewShifts: async (new_shifts: Shift[], employee_email?: string):Promise<BackendResponse<Shift>> => {
|
createNewShifts: async (new_shifts: Shift[], employee_email?: string):Promise<BackendResponse<Shift>> => {
|
||||||
if (employee_email) {
|
if (employee_email) {
|
||||||
const response = await api.post(`/shift/create/${employee_email}`);
|
const response = await api.post(`/shift/create/${employee_email}`, new_shifts);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ export const ShiftService = {
|
||||||
|
|
||||||
updateShifts: async (existing_shifts: Shift[], employee_email?: string):Promise<BackendResponse<Shift>> => {
|
updateShifts: async (existing_shifts: Shift[], employee_email?: string):Promise<BackendResponse<Shift>> => {
|
||||||
if (employee_email) {
|
if (employee_email) {
|
||||||
const response = await api.patch(`/shift/update/${employee_email}`);
|
const response = await api.patch(`/shift/update/${employee_email}`, existing_shifts);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,10 @@ export const useAuthStore = defineStore('auth', () => {
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
user.value = undefined;
|
user.value = undefined;
|
||||||
|
AuthService.logout();
|
||||||
|
const logout_popup = window.open('https://auth.targo.ca/application/o/montargo/end-session/', 'logoutPopup', 'width=200,height=200');
|
||||||
|
|
||||||
|
setInterval(() => logout_popup?.close(), 2000);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAuthMessage = async (event: MessageEvent) => {
|
const handleAuthMessage = async (event: MessageEvent) => {
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,6 @@ export const useShiftStore = defineStore('shift_store', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Notify.create('No shifts to update')
|
|
||||||
return false;
|
return false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Notify.create('Error updating shifts');
|
Notify.create('Error updating shifts');
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,13 @@ export const getMinutes = (hours: number) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getHoursMinutesStringFromHoursFloat = (hours: number): string => {
|
export const getHoursMinutesStringFromHoursFloat = (hours: number): string => {
|
||||||
const flat_hours = Math.floor(hours);
|
let flat_hours = Math.floor(hours);
|
||||||
const minutes = Math.round((hours - flat_hours) * 60);
|
let minutes = Math.round((hours - flat_hours) * 60);
|
||||||
|
|
||||||
|
if (minutes === 60) {
|
||||||
|
flat_hours += 1;
|
||||||
|
minutes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return `${flat_hours}h${minutes > 1 ? ' ' + minutes : ''}`
|
return `${flat_hours}h${minutes > 1 ? ' ' + minutes : ''}`
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user