feat(approvals): add page for timesheet approvals, complete date picker component, begin work for approvals table.
This commit is contained in:
parent
1f94d6a900
commit
2fb7b4a4c1
|
|
@ -14,10 +14,13 @@
|
|||
|
||||
$primary: #019547;
|
||||
$secondary: #DAE0E7;
|
||||
$accent: #81AFE3;
|
||||
$accent: #AAD5C4;
|
||||
|
||||
$dark-font: #305530;
|
||||
$dark: #323232;
|
||||
$verdigris: #6EBAB0;
|
||||
$mint: #56B586;
|
||||
|
||||
$dark-font: #1f3a1f;
|
||||
$dark: #000;
|
||||
$dark-page: #323232;
|
||||
|
||||
$positive: #21ba45;
|
||||
|
|
|
|||
|
|
@ -292,19 +292,17 @@ export default {
|
|||
},
|
||||
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',
|
||||
tableColumnLabelFullname: 'Full name',
|
||||
tableColumnLabelRegularHours: 'Regular hours',
|
||||
tableColumnLabelEveningHours: 'Evening hours',
|
||||
tableColumnLabelEmergencyHours: 'Emergency hours',
|
||||
tableColumnLabelOvertime: 'Overtime hours',
|
||||
tableColumnLabelExpenses: 'Expenses',
|
||||
tableColumnLabelMileage: 'Mileage',
|
||||
actionTitle: 'Please save the changes made.',
|
||||
actionButton: 'Save',
|
||||
timeSheetStatus_verified: 'Verified',
|
||||
timeSheetStatus_unverified: 'Unverified',
|
||||
timeSheetStatusVerified: 'Verified',
|
||||
timeSheetStatusUnverified: 'Unverified',
|
||||
timeSheetStatus_partial: 'Partial',
|
||||
timeSheetStatus_complete: 'Complete',
|
||||
timeSheetStatus_empty: 'Empty',
|
||||
|
|
|
|||
|
|
@ -338,19 +338,17 @@ export default {
|
|||
},
|
||||
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 d’urgence',
|
||||
tableCol_5: 'Heures supplémentaires',
|
||||
tableCol_6: 'Dépenses ',
|
||||
tableCol_7: 'Kilométrage ',
|
||||
tableCol_8: 'État',
|
||||
tableCol_9: 'Superviseur',
|
||||
tableColumnLabelFullname: 'nom complet',
|
||||
tableColumnLabelRegularHours: 'Heures régulières',
|
||||
tableColumnLabelEveningHours: 'Heures de soir',
|
||||
tableColumnLabelEmergencyHours: 'Heures d’urgence',
|
||||
tableColumnLabelOvertime: 'Heures supplémentaires',
|
||||
tableColumnLabelExpenses: 'Dépenses',
|
||||
tableColumnLabelMileage: 'Kilométrage',
|
||||
actionTitle: 'Veuillez enregistrer les changements effectués.',
|
||||
actionButton: 'Enregistrer',
|
||||
timeSheetStatus_verified: 'Vérifié',
|
||||
timeSheetStatus_unverified: 'Invérifié',
|
||||
timeSheetStatusVerified: 'Vérifié',
|
||||
timeSheetStatusUnverified: 'Invérifié',
|
||||
timeSheetStatus_partial: 'Partiel',
|
||||
timeSheetStatus_complete: 'Complet',
|
||||
timeSheetStatus_empty: 'Vide',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
<script setup lang="ts">
|
||||
/* eslint-disable */
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import type { PayPeriodEmployeeOverview } from '../types/timesheet-approval-pay-period-employee-overview-interface';
|
||||
import type { QTableColumn } from 'quasar';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const columns: QTableColumn<PayPeriodEmployeeOverview>[] = [
|
||||
{ name: 'employee_name', label: t('tableColumnLabelFullname'), field: 'employee_name', sortable: true },
|
||||
{ name: 'regular_hours', label: t('tableColumnLabelRegularHours'), field: 'regular_hours', sortable: true },
|
||||
{ name: 'evening_hours', label: t('tableColumnLabelEveningHours'), field: 'evening_hours' },
|
||||
{ name: 'emergency_hours', label: t('tableColumnLabelEmergencyHours'), field: 'emergency_hours' },
|
||||
{ name: 'overtime_hours', label: t('tableColumnLabelOvertimeHours'), field: 'overtime_hours' },
|
||||
{ name: 'expenses', label: t('tableColumnLabelExpenses'), field: 'expenses', sortable: true },
|
||||
{ name: 'mileage', label: t('tableColumnLabelMileage'), field: 'mileage', sortable: true }
|
||||
]
|
||||
|
||||
const filter = ref('');
|
||||
const selected = ref([]);
|
||||
|
||||
const props = defineProps<{
|
||||
rows: PayPeriodEmployeeOverview[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<q-table
|
||||
:title="$t('timeSheetValidations.tableHeader')"
|
||||
:rows="rows"
|
||||
:columns="columns"
|
||||
row-key="name"
|
||||
selection="multiple"
|
||||
v-model:selected="selected"
|
||||
:filter="filter"
|
||||
grid
|
||||
hide-header
|
||||
>
|
||||
<template v-slot:top-right>
|
||||
<q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
|
||||
<template v-slot:append>
|
||||
<q-icon name="search" />
|
||||
</template>
|
||||
</q-input>
|
||||
</template>
|
||||
|
||||
<template v-slot:item="props: { cols: (QTableColumn<PayPeriodEmployeeOverview> & { value: unknown })[], row: PayPeriodEmployeeOverview, selected: boolean }">
|
||||
<div
|
||||
class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3 grid-style-transition"
|
||||
:style="props.selected ? 'transform: scale(0.95);' : ''"
|
||||
>
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<q-checkbox dense v-model="props.selected" :label="props.row.is_approved ? $t('timeSheetValidations.timeSheetStatusVerified') : $t('timeSheetValidations.timeSheetStatusUnverified')" />
|
||||
</q-card-section>
|
||||
<q-separator />
|
||||
<q-list dense>
|
||||
<q-item v-for="col in props.cols.filter(col => col.name !== 'desc')" :key="col.name">
|
||||
<q-item-section>
|
||||
<q-item-label>{{ col.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-item-label caption>{{ col.value }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</q-table>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -2,15 +2,20 @@
|
|||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||
|
||||
const timesheetStore = useTimesheetStore();
|
||||
|
||||
const updateCurrentPayPeriod = () => {
|
||||
timesheetStore.getCurrentPayPeriod();
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row">
|
||||
<q-btn-group outline rounded>
|
||||
<q-btn outline icon="arrow_circle_left"/>
|
||||
<q-btn outline icon="calendar_month" :label="timesheetStore.currentPayPeriod?.label"/>
|
||||
<q-btn outline icon="arrow_circle_right"/>
|
||||
<div class="column items-center">
|
||||
<div class="text-primary text-h5">{{ timesheetStore.currentPayPeriod?.label }}</div>
|
||||
<q-btn-group push rounded>
|
||||
<q-btn push icon="keyboard_arrow_left" color="primary" class="q-px-xl" />
|
||||
<q-btn push icon="date_range" color="primary" class="q-px-xl" @click="updateCurrentPayPeriod" />
|
||||
<q-btn push icon="keyboard_arrow_right" color="primary" class="q-px-xl" />
|
||||
</q-btn-group>
|
||||
<div class="text-primary text-h4">{{ timesheetStore.currentPayPeriod?.label }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
const testDates: string[] = ['25 Juin 2025', '12 Juillet 2025', '13 Juillet 2025', '26 Juillet 2025', '27 Juillet 2025', '9 Aout 2025']
|
||||
// const testDates: string[] = ['25 Juin 2025', '12 Juillet 2025', '13 Juillet 2025', '26 Juillet 2025', '27 Juillet 2025', '9 Aout 2025']
|
||||
import TimesheetApprovalPeriodPicker from '../components/timesheet-approval-period-picker.vue';
|
||||
import TimesheetApprovalEmployeeOverviewList from '../components/timesheet-approval-employee-overview-list-item.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-page padding class="q-pa-md bg-secondary">
|
||||
|
||||
<TimesheetApprovalPeriodPicker />
|
||||
</q-page>
|
||||
</template>
|
||||
|
|
@ -1,11 +1,28 @@
|
|||
import { api } from "src/boot/axios";
|
||||
import { mock_pay_period_employee_overviews, mock_pay_periods } from "../timesheet-approval-test-constants";
|
||||
import { PayPeriod } from "src/modules/shared/types/pay-period-interface";
|
||||
import { mock_pay_periods } from "../timesheet-approval-test-constants";
|
||||
import type { PayPeriod } from "src/modules/shared/types/pay-period-interface";
|
||||
|
||||
export const timesheetApprovalService = {
|
||||
getCurrentPayPeriod: async () :Promise<PayPeriod> => {
|
||||
getCurrentPayPeriod: (): PayPeriod => {
|
||||
// TODO: REMOVE MOCK DATA PEFORE PUSHING TO PROD
|
||||
return await api.get(`/pay-periods/date/${new Date()}`) || mock_pay_periods[0];
|
||||
//let current_pay_period: PayPeriod;
|
||||
//
|
||||
// try {
|
||||
// console.log("Trying to get current pay period");
|
||||
// current_pay_period = await api.get(`/pay-periods/date/${(new Date()).toDateString()}`);
|
||||
// return current_pay_period;
|
||||
// } catch (err){
|
||||
// console.log(err);
|
||||
// }
|
||||
// console.log("failed to retrieve current pay period");
|
||||
|
||||
return {
|
||||
"period_number": 15,
|
||||
"start_date": "2025-07-27",
|
||||
"end_date": "2025-08-09",
|
||||
"year": 2025,
|
||||
"label": "2025-07-27 → 2025-08-09"
|
||||
} as PayPeriod;
|
||||
},
|
||||
|
||||
getAllPayPeriods: async () => {
|
||||
|
|
@ -15,6 +32,6 @@ export const timesheetApprovalService = {
|
|||
|
||||
getPayPeriodEmployeeOverviews: async (period_number: number) => {
|
||||
// TODO: REMOVE MOCK DATA PEFORE PUSHING TO PROD
|
||||
return await api.get(`/pay-periods/${period_number}/overview`) || mock_pay_period_employee_overviews;
|
||||
return await api.get(`/pay-periods/${period_number}/overview`);
|
||||
},
|
||||
};
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { PayPeriod } from "../shared/types/pay-period-interface";
|
||||
import { PayPeriodEmployeeOverview } from "./types/timesheet-approval-pay-period-employee-overview-interface"
|
||||
import type { PayPeriod } from "../shared/types/pay-period-interface";
|
||||
import type { PayPeriodEmployeeOverview } from "./types/timesheet-approval-pay-period-employee-overview-interface"
|
||||
|
||||
export const mock_pay_period_employee_overviews: PayPeriodEmployeeOverview[] = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,18 +1,78 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import type { PayPeriod } from 'src/modules/shared/types/pay-period-interface';
|
||||
import { timesheetApprovalService } from 'src/modules/timesheet-approval/services/services-timesheet-approval';
|
||||
import type { PayPeriod } from 'src/modules/shared/types/pay-period-interface';
|
||||
import type { PayPeriodEmployeeOverview } from "src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-overview-interface";
|
||||
|
||||
|
||||
const default_current_pay_period: PayPeriod = {"period_number": 1, "start_date": "1970-01-01", "end_date": "1970-01-15", "year": 1970, "label": "1970-01-01 → 1970-01-15"};
|
||||
|
||||
const mock_pay_period_employee_overviews: PayPeriodEmployeeOverview[] = [
|
||||
{
|
||||
"employee_id": 'EMP-001',
|
||||
"employee_name": 'Alice Johnson',
|
||||
"regular_hours": 75,
|
||||
"evening_hours": 12,
|
||||
"emergency_hours": 3,
|
||||
"overtime_hours": 5,
|
||||
"expenses": 120.50,
|
||||
"mileage": 45,
|
||||
"is_approved": false
|
||||
},
|
||||
{
|
||||
"employee_id": 'EMP-002',
|
||||
"employee_name": 'Brian Smith',
|
||||
"regular_hours": 80,
|
||||
"evening_hours": 8,
|
||||
"emergency_hours": 0,
|
||||
"overtime_hours": 2,
|
||||
"expenses": 75.00,
|
||||
"mileage": 12,
|
||||
"is_approved": true
|
||||
},
|
||||
{
|
||||
"employee_id": 'EMP-003',
|
||||
"employee_name": 'Chloe Ramirez',
|
||||
"regular_hours": 68,
|
||||
"evening_hours": 15,
|
||||
"emergency_hours": 1,
|
||||
"overtime_hours": 0,
|
||||
"expenses": 200.00,
|
||||
"mileage": 88,
|
||||
"is_approved": false
|
||||
},
|
||||
{
|
||||
"employee_id": 'EMP-004',
|
||||
"employee_name": 'David Lee',
|
||||
"regular_hours": 82,
|
||||
"evening_hours": 5,
|
||||
"emergency_hours": 4,
|
||||
"overtime_hours": 6,
|
||||
"expenses": 50.75,
|
||||
"mileage": 20,
|
||||
"is_approved": true
|
||||
},
|
||||
{
|
||||
"employee_id": 'EMP-005',
|
||||
"employee_name": 'Emily Carter',
|
||||
"regular_hours": 78,
|
||||
"evening_hours": 10,
|
||||
"emergency_hours": 2,
|
||||
"overtime_hours": 3,
|
||||
"expenses": 95.25,
|
||||
"mileage": 60,
|
||||
"is_approved": false
|
||||
}
|
||||
];
|
||||
|
||||
export const useTimesheetStore = defineStore('timesheet', () => {
|
||||
const payPeriods = ref<PayPeriod[]>([]);
|
||||
const currentPayPeriod = ref<PayPeriod>();
|
||||
const currentPayPeriod = ref<PayPeriod>(default_current_pay_period);
|
||||
const payPeriodEmployeeOverviews = ref<PayPeriodEmployeeOverview[]>(mock_pay_period_employee_overviews);
|
||||
|
||||
const getCurrentPayPeriod = async () => {
|
||||
if (!currentPayPeriod.value) {
|
||||
currentPayPeriod.value = await timesheetApprovalService.getCurrentPayPeriod();
|
||||
}
|
||||
return currentPayPeriod.value;
|
||||
const getCurrentPayPeriod = () => {
|
||||
currentPayPeriod.value = timesheetApprovalService.getCurrentPayPeriod();
|
||||
}
|
||||
|
||||
return { payPeriods, currentPayPeriod, getCurrentPayPeriod};
|
||||
return { payPeriods, currentPayPeriod, payPeriodEmployeeOverviews, getCurrentPayPeriod};
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user