+import { ref } from 'vue';
+/* eslint-disable */
+const props = defineProps<{
+ commentString: string;
+}>();
+
+const emit = defineEmits<{
+ clickClose: [];
+ clickSave: [comment: string];
+}>();
+
+const text = ref(props.commentString);
+
+const close = ()=> {
+ emit('clickClose');
+ text.value = '';
+}
+
+const save = ()=> {
+ emit('clickSave',text.value);
+ close();
+}
+
+
+
+
+
+ {{ $t('timesheet.fields.header_comment') }}
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/timesheets/components/timesheet/time-sheet-shift-list-row.vue b/src/modules/timesheets/components/timesheet/time-sheet-shift-list-row.vue
deleted file mode 100644
index e69de29..0000000
diff --git a/src/modules/timesheets/components/timesheet/time-sheet-shift-list.vue b/src/modules/timesheets/components/timesheet/time-sheet-shift-list.vue
deleted file mode 100644
index e69de29..0000000
diff --git a/src/modules/timesheets/components/timesheet/time-sheet.vue b/src/modules/timesheets/components/timesheet/time-sheet.vue
deleted file mode 100644
index e69de29..0000000
diff --git a/src/modules/timesheets/components/timesheet/timesheet-navigation.vue b/src/modules/timesheets/components/timesheet/timesheet-navigation.vue
new file mode 100644
index 0000000..1a1136b
--- /dev/null
+++ b/src/modules/timesheets/components/timesheet/timesheet-navigation.vue
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+ {{ $t( 'timesheet.nav_button.previous_week' )}}
+
+
+
+
+ {{ $t('timesheet.nav_button.current_week') }}
+
+
+
+
+ {{ $t('timesheet.nav_button.calendar_date_picker') }}
+
+
+
+
+ {{ $t('timesheet.nav_button.next_week') }}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/timesheets/components/timesheet/timesheet-save-payload.vue b/src/modules/timesheets/components/timesheet/timesheet-save-payload.vue
new file mode 100644
index 0000000..c71840b
--- /dev/null
+++ b/src/modules/timesheets/components/timesheet/timesheet-save-payload.vue
@@ -0,0 +1,64 @@
+
+
+
+
+
+ {{ $t('timesheet.save_button') }}
+
+
+
\ No newline at end of file
diff --git a/src/modules/timesheets/components/timesheet/timesheet-shift-form.vue b/src/modules/timesheets/components/timesheet/timesheet-shift-form.vue
new file mode 100644
index 0000000..e9e3afc
--- /dev/null
+++ b/src/modules/timesheets/components/timesheet/timesheet-shift-form.vue
@@ -0,0 +1,266 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ days[index] }}
+
+
+ {{ $t('timesheet.remote_button') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('timesheet.add_shift') }}
+
+
+
+ emit('save', payload)"
+ />
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/timesheets/composables/use-timesheet-api.ts b/src/modules/timesheets/composables/use-timesheet-api.ts
index e69de29..8b5eefb 100644
--- a/src/modules/timesheets/composables/use-timesheet-api.ts
+++ b/src/modules/timesheets/composables/use-timesheet-api.ts
@@ -0,0 +1,60 @@
+import { useAuthStore } from "src/stores/auth-store";
+import { useTimesheetStore } from "src/stores/timesheet-store"
+import { ref } from "vue";
+import { timesheetTempService } from "../services/timesheet-services";
+import type { CreateShiftPayload } from "../types/timesheet-shift-interface";
+
+
+export const useTimesheetApi = () => {
+ const timesheet_store = useTimesheetStore();
+ const auth_store = useAuthStore();
+ const week_offset = ref(0);
+
+ const fetchWeek = async (offset = week_offset.value) => {
+ const email = auth_store.user?.email;
+ if(!email) return;
+ try{
+ timesheet_store.is_loading = true;
+ const timesheet = await timesheetTempService.getTimesheetsByEmail(email, offset);
+ timesheet_store.current_timesheet = timesheet;
+ week_offset.value = offset;
+ }catch (err) {
+ console.error('fetch week error', err);
+ timesheet_store.current_timesheet = { ...timesheet_store.current_timesheet, shifts: [], expenses: [] };
+ } finally {
+ timesheet_store.is_loading = false;
+ }
+ };
+
+ const this_week = async () => fetchWeek(0);
+ const next_week = async () => fetchWeek(week_offset.value + 1);
+ const previous_week = async () => fetchWeek(week_offset.value - 1);
+
+ const saveTimesheetShifts = async (shifts: CreateShiftPayload[]) => {
+ const email = auth_store.user?.email;
+ if(!email || shifts.length === 0) return;
+ await timesheet_store.createTimesheetShifts(email, shifts, week_offset.value);
+ };
+
+ const weekStart = (date: Date) => {
+ const x = new Date(date);
+ x.setHours(0, 0, 0, 0);
+ x.setDate(x.getDate() - x.getDay());
+ return x;
+ };
+
+ const getCurrentWeekTimesheetOverview = async (when: Date = new Date()) => {
+ const off = Math.trunc((weekStart(when).getTime() - weekStart(new Date()).getTime()) / 604800000);
+ await fetchWeek(off);
+ }
+
+ return {
+ week_offset,
+ fetchWeek,
+ this_week,
+ next_week,
+ previous_week,
+ saveTimesheetShifts,
+ getCurrentWeekTimesheetOverview,
+ };
+};
\ No newline at end of file
diff --git a/src/modules/timesheets/pages/timesheet-temp-page.vue b/src/modules/timesheets/pages/timesheet-temp-page.vue
index e69de29..dd2c731 100644
--- a/src/modules/timesheets/pages/timesheet-temp-page.vue
+++ b/src/modules/timesheets/pages/timesheet-temp-page.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+ {{ $t('pageTitles.timeSheets') }}
+
+
+
+ {{ timesheet_label.start_date }}
+
+
+ {{ $t('timesheet.dateRangesTo') }}
+
+
+ {{ timesheet_label.end_date }}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/timesheets/services/timesheet-services.ts b/src/modules/timesheets/services/timesheet-services.ts
index e69de29..d96bef5 100644
--- a/src/modules/timesheets/services/timesheet-services.ts
+++ b/src/modules/timesheets/services/timesheet-services.ts
@@ -0,0 +1,18 @@
+import { api } from "src/boot/axios";
+import type {Timesheet} from "src/modules/timesheets/types/timesheet-interface";
+import type { CreateShiftPayload, CreateWeekShiftPayload } from "../types/timesheet-shift-interface";
+
+export const timesheetTempService = {
+ //GET
+ getTimesheetsByEmail: async ( email: string, offset = 0): Promise
=> {
+ const response = await api.get(`/timesheets/${encodeURIComponent(email)}`, {params: offset ? { offset } : undefined});
+ return response.data as Timesheet;
+ },
+
+ //POST
+ createTimesheetShifts: async ( email: string, shifts: CreateShiftPayload[], offset = 0): Promise => {
+ const payload: CreateWeekShiftPayload = { shifts };
+ const response = await api.post(`/timesheets/shifts/${encodeURIComponent(email)}`, payload, { params: offset ? { offset }: undefined });
+ return response.data as Timesheet;
+ }
+};
\ No newline at end of file
diff --git a/src/modules/timesheets/timesheet-constants.ts b/src/modules/timesheets/timesheet-constants.ts
index e69de29..7ca8ae2 100644
--- a/src/modules/timesheets/timesheet-constants.ts
+++ b/src/modules/timesheets/timesheet-constants.ts
@@ -0,0 +1 @@
+//mock data
\ No newline at end of file
diff --git a/src/modules/timesheets/types/timesheet-details-interface.ts b/src/modules/timesheets/types/timesheet-details-interface.ts
index daf3874..21b42ee 100644
--- a/src/modules/timesheets/types/timesheet-details-interface.ts
+++ b/src/modules/timesheets/types/timesheet-details-interface.ts
@@ -38,7 +38,12 @@ interface TimesheetDetailsDailyExpenses {
[otherType: string]: Expense[]; //for possible future types of expenses
}
-
+//employee timesheet template
+export interface EmployeeTimesheetDetailsWeek {
+ is_approved: boolean;
+ shifts: WeekDay;
+ expenses: WeekDay;
+}
// empty default builder
const makeWeek = (factory: () => T): WeekDay => ({
sun: factory(),
diff --git a/src/modules/timesheets/types/timesheet-interface.ts b/src/modules/timesheets/types/timesheet-interface.ts
new file mode 100644
index 0000000..927cfd0
--- /dev/null
+++ b/src/modules/timesheets/types/timesheet-interface.ts
@@ -0,0 +1,28 @@
+export interface Timesheet {
+ is_approved: boolean;
+ start_day: string;
+ end_day: string;
+ label: string;
+ shifts: Shifts[];
+ expenses: Expenses[];
+}
+
+type Shifts = {
+ bank_type: string;
+ date: string;
+ start_time: string;
+ end_time: string;
+ description: string;
+ is_approved: boolean;
+ is_remote: boolean;
+}
+
+type Expenses = {
+ bank_type: string;
+ date: string;
+ amount: number;
+ km: number;
+ description: string;
+ supervisor_comment: string;
+ is_approved: boolean;
+}
\ No newline at end of file
diff --git a/src/modules/timesheets/types/timesheet-shift-interface.ts b/src/modules/timesheets/types/timesheet-shift-interface.ts
index 8438cfc..b57aecf 100644
--- a/src/modules/timesheets/types/timesheet-shift-interface.ts
+++ b/src/modules/timesheets/types/timesheet-shift-interface.ts
@@ -1,9 +1,24 @@
+export interface CreateShiftPayload {
+ date: string;
+ type: string;
+ start_time: string;
+ end_time: string;
+ description?: string;
+ is_remote?: boolean;
+};
+
+export interface CreateWeekShiftPayload {
+ shifts: CreateShiftPayload[];
+}
+
export interface Shift {
- date : string;
- start_time : string;
- end_time : string;
- type : string;
- is_approved : boolean;
+ date : string;
+ type : string;
+ start_time : string;
+ end_time : string;
+ comment : string;
+ is_approved: boolean;
+ is_remote : boolean;
}
export const default_shift: Shift = {
@@ -11,5 +26,7 @@ export const default_shift: Shift = {
start_time: '--:--',
end_time: '--:--',
type: '',
+ comment: '',
is_approved: false,
-}
\ No newline at end of file
+ is_remote: false,
+}
diff --git a/src/router/router-constants.ts b/src/router/router-constants.ts
index b264bf2..b24aa80 100644
--- a/src/router/router-constants.ts
+++ b/src/router/router-constants.ts
@@ -6,4 +6,5 @@ export enum RouteNames {
TIMESHEET_APPROVALS = 'timesheet-approvals',
EMPLOYEE_LIST = 'employee-list',
PROFILE = 'user/profile',
+ TIMESHEET_TEMP = 'timesheet-temp'
}
\ No newline at end of file
diff --git a/src/router/routes.ts b/src/router/routes.ts
index 564f357..33cb2a6 100644
--- a/src/router/routes.ts
+++ b/src/router/routes.ts
@@ -22,6 +22,11 @@ const routes: RouteRecordRaw[] = [
name: RouteNames.EMPLOYEE_LIST,
component: () => import('src/modules/employee-list/pages/supervisor-crew-page.vue'),
},
+ {
+ path: 'timesheet-temp',
+ name: RouteNames.TIMESHEET_TEMP,
+ component: () => import('src/modules/timesheets/pages/timesheet-temp-page.vue')
+ }
],
},
diff --git a/src/stores/timesheet-store.ts b/src/stores/timesheet-store.ts
index ad97173..72b48d8 100644
--- a/src/stores/timesheet-store.ts
+++ b/src/stores/timesheet-store.ts
@@ -1,10 +1,13 @@
import { defineStore } from 'pinia';
import { ref } from 'vue';
import { timesheetApprovalService } from 'src/modules/timesheet-approval/services/services-timesheet-approval';
+import { timesheetTempService } from 'src/modules/timesheets/services/timesheet-services';
import type { PayPeriod } from 'src/modules/shared/types/pay-period-interface';
import type { PayPeriodOverviewEmployee } from "src/modules/timesheet-approval/types/timesheet-approval-pay-period-overview-employee-interface";
import { default_pay_period_employee_details, type PayPeriodEmployeeDetails } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-details-interface';
import type { PayPeriodReportFilters } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-report-interface';
+import type { Timesheet } from 'src/modules/timesheets/types/timesheet-interface';
+import type { CreateShiftPayload } from 'src/modules/timesheets/types/timesheet-shift-interface';
const default_pay_period: PayPeriod = {
pay_period_no: -1,
@@ -15,6 +18,16 @@ const default_pay_period: PayPeriod = {
label: ''
};
+ //employee timesheet
+ const default_timesheet: Timesheet = {
+ start_day: '',
+ end_day: '',
+ label: '',
+ is_approved: false,
+ shifts: [],
+ expenses: [],
+ };
+
export const useTimesheetStore = defineStore('timesheet', () => {
const is_loading = ref(false);
const current_pay_period = ref(default_pay_period);
@@ -23,6 +36,9 @@ export const useTimesheetStore = defineStore('timesheet', () => {
const pay_period_employee_details = ref(default_pay_period_employee_details);
const pay_period_report = ref();
+ //employee timesheet
+ const current_timesheet = ref(default_timesheet);
+
const getPayPeriodByDate = async (date_string: string): Promise => {
is_loading.value = true;
@@ -85,6 +101,32 @@ export const useTimesheetStore = defineStore('timesheet', () => {
is_loading.value = false;
};
+ //employee timesheet
+ const getTimesheetByEmail = async (employee_email: string) => {
+ is_loading.value = true;
+ try{
+ const response = await timesheetTempService.getTimesheetsByEmail(employee_email);
+ current_timesheet.value = response;
+ }catch (error) {
+ console.error('There was an error retrieving timesheet details for this employee: ', error);
+ current_timesheet.value = { ...default_timesheet }
+ } finally {
+ is_loading.value = false;
+ }
+ }
+ //employee timesheet
+ const createTimesheetShifts = async (employee_email: string, shifts: CreateShiftPayload[], offset = 0) => {
+ is_loading.value = true;
+ try{
+ const timesheet = await timesheetTempService.createTimesheetShifts(employee_email, shifts, offset);
+ current_timesheet.value = timesheet;
+ } catch (err) {
+ console.error('createTimesheetShifts error: ', err);
+ } finally {
+ is_loading.value = false;
+ }
+ };
+
const getTimesheetsByPayPeriodAndEmail = async (employee_email: string) => {
is_loading.value = true;
@@ -126,8 +168,11 @@ export const useTimesheetStore = defineStore('timesheet', () => {
pay_period_overview_employees,
pay_period_overview_employee_approval_statuses,
pay_period_employee_details,
+ current_timesheet,
is_loading,
getPayPeriodByDate,
+ getTimesheetByEmail,
+ createTimesheetShifts,
getPayPeriodByYearAndPeriodNumber,
getTimesheetApprovalPayPeriodEmployeeOverviews,
getTimesheetsByPayPeriodAndEmail,