Merge pull request 'fix(payperiodpicker, expensedialog): change date picker display from dialog to menu, add transition animations for expense dialog form, move update dialog form into expense item.' (#24) from dev/nicolas/timesheet-gui-refactor into main
Reviewed-on: Targo/targo_frontend#24
This commit is contained in:
commit
ce2fd3e024
|
|
@ -39,7 +39,7 @@ body.body--dark {
|
||||||
}
|
}
|
||||||
|
|
||||||
.frosted-glass {
|
.frosted-glass {
|
||||||
background-color: #FFFA !important;
|
background-color: #0008 !important;
|
||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(5px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@ $primary : #30303A;
|
||||||
$secondary : #DAE0E7;
|
$secondary : #DAE0E7;
|
||||||
$accent : #0c9a3b;
|
$accent : #0c9a3b;
|
||||||
|
|
||||||
$dark-shadow-color : #00220f;
|
$dark-shadow-color : #173625;
|
||||||
|
|
||||||
$elevation-dark-umbra : rgba($dark-shadow-color, 1);
|
$elevation-dark-umbra : rgba($dark-shadow-color, 1);
|
||||||
$elevation-dark-penumbra : rgba($dark-shadow-color, 0.2);
|
$elevation-dark-penumbra : rgba($dark-shadow-color, 0.5);
|
||||||
$elevation-dark-ambient : rgba($dark-shadow-color, 0.2);
|
$elevation-dark-ambient : rgba($dark-shadow-color, 0.3);
|
||||||
|
|
||||||
$dark-shadow-2 : 0 3px 5px -1px $elevation-dark-umbra, 0 5px 8px $elevation-dark-penumbra, 0 1px 14px $elevation-dark-ambient;
|
$dark-shadow-2 : 2px 3px $elevation-dark-umbra, 2px 3px 6px $elevation-dark-penumbra, 2px 3px 14px $elevation-dark-ambient;
|
||||||
$layout-shadow-dark : 0 0 10px 5px rgba($dark-shadow-color, 0.5);
|
$layout-shadow-dark : 0 0 10px 5px rgba($dark-shadow-color, 0.5);
|
||||||
|
|
||||||
$input-text-color : #455A64;
|
$input-text-color : #455A64;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script
|
||||||
|
setup
|
||||||
|
lang="ts"
|
||||||
|
>
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { date} from 'quasar';
|
import { date } from 'quasar';
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
|
|
||||||
const NEXT = 1;
|
const NEXT = 1;
|
||||||
|
|
@ -10,18 +13,18 @@
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
|
|
||||||
const is_showing_calendar_picker = ref(false);
|
const is_showing_calendar_picker = ref(false);
|
||||||
const calendar_date = ref(date.formatDate( Date.now(), 'YYYY-MM-DD' ));
|
const calendar_date = ref(date.formatDate(Date.now(), 'YYYY-MM-DD'));
|
||||||
const is_disabled = computed(() => timesheet_store.pay_period === undefined);
|
const is_disabled = computed(() => timesheet_store.pay_period === undefined);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
'date-selected': [ value: string ]
|
'date-selected': [value: string]
|
||||||
'pressed-previous-button': []
|
'pressed-previous-button': []
|
||||||
'pressed-next-button': []
|
'pressed-next-button': []
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const is_previous_pay_period_limit = computed( ()=>
|
const is_previous_pay_period_limit = computed(() =>
|
||||||
( timesheet_store.pay_period?.pay_year === 2024 &&
|
(timesheet_store.pay_period?.pay_year === 2024 &&
|
||||||
timesheet_store.pay_period?.pay_period_no <= 1 ) ?? false
|
timesheet_store.pay_period?.pay_period_no <= 1) ?? false
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDateSelected = (value: string) => {
|
const onDateSelected = (value: string) => {
|
||||||
|
|
@ -59,10 +62,11 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="row" >
|
<div class="row">
|
||||||
<!-- navigation to previous week -->
|
<!-- navigation to previous week -->
|
||||||
<q-btn
|
<q-btn
|
||||||
push rounded
|
push
|
||||||
|
rounded
|
||||||
icon="keyboard_arrow_left"
|
icon="keyboard_arrow_left"
|
||||||
color="accent"
|
color="accent"
|
||||||
@click="getPreviousPayPeriod"
|
@click="getPreviousPayPeriod"
|
||||||
|
|
@ -74,13 +78,14 @@
|
||||||
self="center middle"
|
self="center middle"
|
||||||
class="bg-primary text-uppercase text-weight-bold"
|
class="bg-primary text-uppercase text-weight-bold"
|
||||||
>
|
>
|
||||||
{{ $t( 'timesheet.nav_button.previous_week' )}}
|
{{ $t('timesheet.nav_button.previous_week') }}
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
|
||||||
<!-- navigation through calendar date picker -->
|
<!-- navigation through calendar date picker -->
|
||||||
<q-btn
|
<q-btn
|
||||||
push rounded
|
push
|
||||||
|
rounded
|
||||||
icon="calendar_month"
|
icon="calendar_month"
|
||||||
color="accent"
|
color="accent"
|
||||||
@click="is_showing_calendar_picker = true"
|
@click="is_showing_calendar_picker = true"
|
||||||
|
|
@ -94,11 +99,29 @@
|
||||||
>
|
>
|
||||||
{{ $t('timesheet.nav_button.calendar_date_picker') }}
|
{{ $t('timesheet.nav_button.calendar_date_picker') }}
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
|
|
||||||
|
<!-- date picker calendar -->
|
||||||
|
<q-menu
|
||||||
|
anchor="bottom middle"
|
||||||
|
self="top middle"
|
||||||
|
:offset="[0, 10]"
|
||||||
|
class="shadow-24"
|
||||||
|
>
|
||||||
|
<q-date
|
||||||
|
v-model="calendar_date"
|
||||||
|
color="primary"
|
||||||
|
today-btn
|
||||||
|
mask="YYYY-MM-DD"
|
||||||
|
:options="date => date >= PAY_PERIOD_DATE_LIMIT"
|
||||||
|
@update:model-value="onDateSelected"
|
||||||
|
/>
|
||||||
|
</q-menu>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
|
||||||
<!-- navigation to next week -->
|
<!-- navigation to next week -->
|
||||||
<q-btn
|
<q-btn
|
||||||
push rounded
|
push
|
||||||
|
rounded
|
||||||
icon="keyboard_arrow_right"
|
icon="keyboard_arrow_right"
|
||||||
color="accent"
|
color="accent"
|
||||||
@click="getNextPayPeriod"
|
@click="getNextPayPeriod"
|
||||||
|
|
@ -113,21 +136,4 @@
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- date picker calendar -->
|
|
||||||
<q-dialog
|
|
||||||
v-model="is_showing_calendar_picker"
|
|
||||||
transition-show="jump-down"
|
|
||||||
transition-hide="jump-up"
|
|
||||||
position="top">
|
|
||||||
<q-date
|
|
||||||
v-model="calendar_date"
|
|
||||||
color="primary"
|
|
||||||
class="q-mt-xl"
|
|
||||||
today-btn
|
|
||||||
mask="YYYY-MM-DD"
|
|
||||||
:options="date => date >= PAY_PERIOD_DATE_LIMIT"
|
|
||||||
@update:model-value="onDateSelected"
|
|
||||||
/>
|
|
||||||
</q-dialog>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -2,17 +2,19 @@
|
||||||
setup
|
setup
|
||||||
lang="ts"
|
lang="ts"
|
||||||
>
|
>
|
||||||
import { inject, ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { useExpensesStore } from 'src/stores/expense-store';
|
|
||||||
import { Expense, EXPENSE_TYPE, TYPES_WITH_AMOUNT_ONLY } from 'src/modules/timesheets/models/expense.models';
|
|
||||||
import { useExpenseRules } from 'src/modules/timesheets/utils/expense.util';
|
|
||||||
import { useExpensesApi } from 'src/modules/timesheets/composables/use-expense-api';
|
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
|
||||||
import { date } from 'quasar';
|
import { date } from 'quasar';
|
||||||
|
import { computed, inject, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useUiStore } from 'src/stores/ui-store';
|
||||||
|
import { useExpensesStore } from 'src/stores/expense-store';
|
||||||
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
|
import { useExpensesApi } from 'src/modules/timesheets/composables/use-expense-api';
|
||||||
|
import { useExpenseRules } from 'src/modules/timesheets/utils/expense.util';
|
||||||
|
import { Expense, EXPENSE_TYPE, TYPES_WITH_AMOUNT_ONLY } from 'src/modules/timesheets/models/expense.models';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const ui_store = useUiStore();
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
const expenses_store = useExpensesStore();
|
const expenses_store = useExpensesStore();
|
||||||
const expenses_api = useExpensesApi();
|
const expenses_api = useExpensesApi();
|
||||||
|
|
@ -23,11 +25,16 @@
|
||||||
const employee_email = inject<string>('employeeEmail');
|
const employee_email = inject<string>('employeeEmail');
|
||||||
const rules = useExpenseRules(t);
|
const rules = useExpenseRules(t);
|
||||||
|
|
||||||
|
const period_start_date = computed(() => timesheet_store.pay_period?.period_start.replaceAll('-', '/') ?? '');
|
||||||
|
const period_end_date = computed(() => timesheet_store.pay_period?.period_end.replaceAll('-', '/') ?? '');
|
||||||
|
|
||||||
const openDatePicker = () => {
|
const openDatePicker = () => {
|
||||||
is_navigator_open.value = true;
|
is_navigator_open.value = true;
|
||||||
if (expenses_store.current_expense.date === '') {
|
if (timesheet_store.pay_period !== undefined) {
|
||||||
expenses_store.current_expense.date = date.formatDate(new Date(), 'YYYY-MM-DD');
|
expenses_store.current_expense.date = timesheet_store.pay_period.period_start;
|
||||||
}
|
}
|
||||||
|
console.log('current pay period start date: ', period_start_date.value);
|
||||||
|
console.log('current pay period end date: ', period_end_date.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelUpdateMode = () => {
|
const cancelUpdateMode = () => {
|
||||||
|
|
@ -40,12 +47,6 @@
|
||||||
if (expenses_store.mode === 'create') await expenses_api.createExpenseByEmployeeEmail(employee_email ?? '', expenses_store.current_expense?.date ?? '');
|
if (expenses_store.mode === 'create') await expenses_api.createExpenseByEmployeeEmail(employee_email ?? '', expenses_store.current_expense?.date ?? '');
|
||||||
else await expenses_api.updateExpenseByEmployeeEmail(employee_email ?? '', expenses_store.current_expense?.date ?? '');
|
else await expenses_api.updateExpenseByEmployeeEmail(employee_email ?? '', expenses_store.current_expense?.date ?? '');
|
||||||
};
|
};
|
||||||
|
|
||||||
const getExpenseCalendarRange = (current_date: string) => {
|
|
||||||
const period = timesheet_store.pay_period;
|
|
||||||
if (period !== undefined) return current_date >= period.period_start && current_date <= period.period_end;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -55,7 +56,10 @@
|
||||||
flat
|
flat
|
||||||
@submit.prevent="requestExpenseCreationOrUpdate"
|
@submit.prevent="requestExpenseCreationOrUpdate"
|
||||||
>
|
>
|
||||||
<div class="text-uppercase text-weight-medium q-pt-sm q-px-lg">
|
<div
|
||||||
|
class="text-uppercase text-weight-medium q-pt-sm q-px-lg q-ma-sm"
|
||||||
|
:class="expenses_store.mode === 'create' ? '' : 'invisible'"
|
||||||
|
>
|
||||||
{{ $t('timesheet.expense.add_expense') }}
|
{{ $t('timesheet.expense.add_expense') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-between items-start rounded-5 q-px-lg q-pb-sm">
|
<div class="row justify-between items-start rounded-5 q-px-lg q-pb-sm">
|
||||||
|
|
@ -66,8 +70,10 @@
|
||||||
outlined
|
outlined
|
||||||
readonly
|
readonly
|
||||||
stack-label
|
stack-label
|
||||||
class="col q-px-xs"
|
|
||||||
color="primary"
|
color="primary"
|
||||||
|
class="col q-px-xs"
|
||||||
|
input-class="text-weight-medium"
|
||||||
|
input-style="font-size: 1.2em;"
|
||||||
:label="$t('timesheet.expense.date')"
|
:label="$t('timesheet.expense.date')"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
|
|
@ -89,11 +95,17 @@
|
||||||
v-model="expenses_store.current_expense.date"
|
v-model="expenses_store.current_expense.date"
|
||||||
mask="YYYY-MM-DD"
|
mask="YYYY-MM-DD"
|
||||||
event-color="accent"
|
event-color="accent"
|
||||||
:options="getExpenseCalendarRange"
|
:options="date => date >= period_start_date && date <= period_end_date"
|
||||||
@update:model-value="is_navigator_open = false"
|
@update:model-value="is_navigator_open = false"
|
||||||
/>
|
/>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #label>
|
||||||
|
<span class="text-weight-bold text-accent text-uppercase text-caption">
|
||||||
|
{{ $t('timesheet.expense.date') }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
<!-- expenses type selection -->
|
<!-- expenses type selection -->
|
||||||
|
|
@ -103,8 +115,8 @@
|
||||||
standout="bg-blue-grey-9"
|
standout="bg-blue-grey-9"
|
||||||
dense
|
dense
|
||||||
emit-value
|
emit-value
|
||||||
map-options
|
|
||||||
hide-dropdown-icon
|
hide-dropdown-icon
|
||||||
|
label-slot
|
||||||
class="col q-px-xs"
|
class="col q-px-xs"
|
||||||
color="primary"
|
color="primary"
|
||||||
:label="$t('timesheet.expense.type')"
|
:label="$t('timesheet.expense.type')"
|
||||||
|
|
@ -115,7 +127,26 @@
|
||||||
popup-content-style="border: 2px solid var(--q-accent)"
|
popup-content-style="border: 2px solid var(--q-accent)"
|
||||||
:rules="[rules.typeRequired]"
|
:rules="[rules.typeRequired]"
|
||||||
:option-label="label => $t(`timesheet.expense.types.${label}`)"
|
:option-label="label => $t(`timesheet.expense.types.${label}`)"
|
||||||
/>
|
>
|
||||||
|
<template #label>
|
||||||
|
<span class="text-weight-bold text-accent text-uppercase text-caption">
|
||||||
|
{{ $t('timesheet.expense.type') }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #selected-item="scope">
|
||||||
|
<div
|
||||||
|
class="row flex-center text-weight-bold q-ma-none q-pa-none no-wrap ellipsis full-width"
|
||||||
|
:class="ui_store.is_mobile_mode ? 'items-center full-height' : 'flex-center'"
|
||||||
|
:tabindex="scope.tabindex"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style="line-height: 0.9em;"
|
||||||
|
class="col-auto ellipsis"
|
||||||
|
>{{ scope.opt.label }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
|
||||||
<!-- amount input -->
|
<!-- amount input -->
|
||||||
<div v-if="TYPES_WITH_AMOUNT_ONLY.includes(expenses_store.current_expense?.type ?? 'EXPENSES')">
|
<div v-if="TYPES_WITH_AMOUNT_ONLY.includes(expenses_store.current_expense?.type ?? 'EXPENSES')">
|
||||||
|
|
@ -207,6 +238,12 @@
|
||||||
color="primary"
|
color="primary"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #label>
|
||||||
|
<span class="text-weight-bold text-accent text-uppercase text-caption">
|
||||||
|
{{ $t('timesheet.expense.hints.attach_file') }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
</q-file>
|
</q-file>
|
||||||
</div>
|
</div>
|
||||||
<div class="col row full-width items-center">
|
<div class="col row full-width items-center">
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
import { useAuthStore } from 'src/stores/auth-store';
|
import { useAuthStore } from 'src/stores/auth-store';
|
||||||
import { CAN_APPROVE_PAY_PERIODS } from 'src/modules/shared/models/user.models';
|
import { CAN_APPROVE_PAY_PERIODS } from 'src/modules/shared/models/user.models';
|
||||||
import { Expense } from 'src/modules/timesheets/models/expense.models';
|
import { Expense } from 'src/modules/timesheets/models/expense.models';
|
||||||
|
import ExpenseDialogForm from 'src/modules/timesheets/components/expense-dialog-form.vue';
|
||||||
|
|
||||||
const { expense, horizontal = false } = defineProps<{
|
const { expense, horizontal = false } = defineProps<{
|
||||||
expense: Expense;
|
expense: Expense;
|
||||||
|
|
@ -29,6 +30,7 @@
|
||||||
const background_style = computed(() => deepEqual(expense, expenses_store.current_expense) ? 'border: 3px solid var(--q-accent);' : '');
|
const background_style = computed(() => deepEqual(expense, expenses_store.current_expense) ? 'border: 3px solid var(--q-accent);' : '');
|
||||||
const approved_class = computed(() => expense.is_approved ? ' bg-accent text-white' : '')
|
const approved_class = computed(() => expense.is_approved ? ' bg-accent text-white' : '')
|
||||||
const is_authorized_to_approve = computed(() => CAN_APPROVE_PAY_PERIODS.includes(auth_store.user?.role ?? 'GUEST'))
|
const is_authorized_to_approve = computed(() => CAN_APPROVE_PAY_PERIODS.includes(auth_store.user?.role ?? 'GUEST'))
|
||||||
|
const is_showing_update_form = ref(false);
|
||||||
|
|
||||||
const requestExpenseDeletion = async () => {
|
const requestExpenseDeletion = async () => {
|
||||||
await expenses_api.deleteExpenseById(expense.id);
|
await expenses_api.deleteExpenseById(expense.id);
|
||||||
|
|
@ -45,28 +47,27 @@
|
||||||
if (deepEqual(expense, expenses_store.current_expense)) {
|
if (deepEqual(expense, expenses_store.current_expense)) {
|
||||||
expenses_store.mode = 'create';
|
expenses_store.mode = 'create';
|
||||||
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'));
|
||||||
|
is_showing_update_form.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
expenses_store.mode = 'update';
|
expenses_store.mode = 'update';
|
||||||
expenses_store.current_expense = expense;
|
expenses_store.current_expense = expense;
|
||||||
expenses_store.initial_expense = unwrapAndClone(expense);
|
expenses_store.initial_expense = unwrapAndClone(expense);
|
||||||
|
is_showing_update_form.value = true;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<transition
|
<q-item
|
||||||
enter-active-class="animated pulse"
|
:key="refresh_key"
|
||||||
mode="out-in"
|
:clickable="horizontal"
|
||||||
|
class="column col-4 items-center q-my-sm q-py-none shadow-3 rounded-5 bg-dark"
|
||||||
|
:class="background_class + approved_class"
|
||||||
|
:style="background_style"
|
||||||
|
@click="onExpenseClicked"
|
||||||
>
|
>
|
||||||
<q-item
|
<div class="row full-width items-center">
|
||||||
:key="refresh_key"
|
|
||||||
:clickable="horizontal"
|
|
||||||
class="row col-4 items-center q-my-sm q-py-none shadow-3 rounded-5 bg-dark"
|
|
||||||
:class="background_class + approved_class"
|
|
||||||
:style="background_style"
|
|
||||||
@click="onExpenseClicked"
|
|
||||||
>
|
|
||||||
<!-- avatar type icon section -->
|
<!-- avatar type icon section -->
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon
|
<q-icon
|
||||||
|
|
@ -194,6 +195,13 @@
|
||||||
@click.stop="requestExpenseDeletion"
|
@click.stop="requestExpenseDeletion"
|
||||||
/>
|
/>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</div>
|
||||||
</transition>
|
|
||||||
|
<q-slide-transition
|
||||||
|
@hide="expenses_store.is_hiding_create_form = false"
|
||||||
|
:duration="200"
|
||||||
|
>
|
||||||
|
<ExpenseDialogForm v-if="is_showing_update_form && expenses_store.is_hiding_create_form" />
|
||||||
|
</q-slide-transition>
|
||||||
|
</q-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -14,9 +14,10 @@
|
||||||
|
|
||||||
const expenses_list = computed(() => {
|
const expenses_list = computed(() => {
|
||||||
if (timesheet_store.timesheets !== undefined) {
|
if (timesheet_store.timesheets !== undefined) {
|
||||||
return timesheet_store.timesheets.flatMap(week => week.days).flatMap(day => day.expenses);
|
const current_expenses = timesheet_store.timesheets.flatMap(week => week.days).flatMap(day => day.expenses);
|
||||||
|
console.log('current expenses: ', current_expenses);
|
||||||
|
return current_expenses;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -29,10 +30,12 @@
|
||||||
:class="horizontal ? 'row flex-center' : ''"
|
:class="horizontal ? 'row flex-center' : ''"
|
||||||
>
|
>
|
||||||
<q-item-label
|
<q-item-label
|
||||||
v-if="expenses_list.length > 0"
|
v-if="expenses_list.length < 1"
|
||||||
class="text-italic q-px-sm"
|
class="text-italic text-center q-pa-sm rounded-4"
|
||||||
>
|
>
|
||||||
|
<q-separator spaced />
|
||||||
{{ $t('timesheet.expense.empty_list') }}
|
{{ $t('timesheet.expense.empty_list') }}
|
||||||
|
<q-separator spaced />
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
|
|
||||||
<ExpenseDialogListItem
|
<ExpenseDialogListItem
|
||||||
|
|
|
||||||
|
|
@ -38,20 +38,9 @@
|
||||||
|
|
||||||
<ExpenseDialogList />
|
<ExpenseDialogList />
|
||||||
|
|
||||||
<transition
|
<q-slide-transition @hide="expense_store.is_hiding_create_form = true" :duration="200">
|
||||||
appear
|
<ExpenseDialogForm v-if="!expense_store.current_expense.is_approved && expense_store.mode !== 'update' && expense_store.is_hiding_create_form === false" />
|
||||||
enter-active-class="animated fadeInDown faster"
|
</q-slide-transition>
|
||||||
leave-active-class="animated fadeOutDown faster"
|
|
||||||
mode="out-in"
|
|
||||||
>
|
|
||||||
<ExpenseDialogForm v-if="!expense_store.current_expense.is_approved" />
|
|
||||||
<q-icon
|
|
||||||
v-else
|
|
||||||
name="block"
|
|
||||||
color="negative"
|
|
||||||
size="lg"
|
|
||||||
/>
|
|
||||||
</transition>
|
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
|
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
<script
|
|
||||||
setup
|
|
||||||
lang="ts"
|
|
||||||
>
|
|
||||||
import { type Shift, SHIFT_TYPES } from 'src/modules/timesheets/models/shift.models';
|
|
||||||
|
|
||||||
const shift = defineModel<Shift>({ required: true });
|
|
||||||
|
|
||||||
defineEmits<{
|
|
||||||
'onCommentBlur': [void];
|
|
||||||
}>();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="row full-width justify-center">
|
|
||||||
<div class="col-sm-6 col-md-3 row q-mx-xs q-my-none">
|
|
||||||
<div class="col-auto column items-center">
|
|
||||||
<span
|
|
||||||
class="text-caption q-pa-none q-ma-none"
|
|
||||||
style="line-height: 0.7em; font-size: 0.7em;"
|
|
||||||
>{{ $t('timesheet.shift.types.REMOTE') }}</span>
|
|
||||||
<q-toggle
|
|
||||||
v-model="shift.is_remote"
|
|
||||||
class="q-pa-none q-ma-none"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<q-select
|
|
||||||
v-model="shift.type"
|
|
||||||
options-dense
|
|
||||||
:options="SHIFT_TYPES"
|
|
||||||
:label="$t('timesheet.shift.types.label')"
|
|
||||||
class="col q-pa-none"
|
|
||||||
color="primary"
|
|
||||||
outlined
|
|
||||||
dense
|
|
||||||
square
|
|
||||||
hide-dropdown-icon
|
|
||||||
emit-value
|
|
||||||
map-options
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-auto row q-mx-xs">
|
|
||||||
<q-input
|
|
||||||
v-model="shift.start_time"
|
|
||||||
:label="$t('timesheet.shift.fields.start')"
|
|
||||||
outlined
|
|
||||||
dense
|
|
||||||
square
|
|
||||||
inputmode="numeric"
|
|
||||||
mask="##:##"
|
|
||||||
class="col-auto q-mx-xs"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<q-input
|
|
||||||
v-model="shift.end_time"
|
|
||||||
:label="$t('timesheet.shift.fields.end')"
|
|
||||||
outlined
|
|
||||||
dense
|
|
||||||
square
|
|
||||||
inputmode="numeric"
|
|
||||||
mask="##:##"
|
|
||||||
class="col-auto q-mx-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<q-input
|
|
||||||
v-model="shift.comment"
|
|
||||||
type="textarea"
|
|
||||||
autogrow
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
square
|
|
||||||
:label="$t('timesheet.shift.fields.header_comment')"
|
|
||||||
:counter="true"
|
|
||||||
:maxlength="512"
|
|
||||||
class="col-grow"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
@ -85,7 +85,8 @@
|
||||||
<template>
|
<template>
|
||||||
<q-slide-item
|
<q-slide-item
|
||||||
right-color="negative"
|
right-color="negative"
|
||||||
class="q-my-xs rounded-5 bg-transparent"
|
class="rounded-5 bg-transparent"
|
||||||
|
:class="ui_store.is_mobile_mode ? 'q-my-md' : ''"
|
||||||
@right="details => slideDeleteShift(details.reset)"
|
@right="details => slideDeleteShift(details.reset)"
|
||||||
>
|
>
|
||||||
<template
|
<template
|
||||||
|
|
@ -94,172 +95,226 @@
|
||||||
>
|
>
|
||||||
<q-icon name="delete" />
|
<q-icon name="delete" />
|
||||||
</template>
|
</template>
|
||||||
|
<div :class="ui_store.is_mobile_mode ? 'column' : 'row'">
|
||||||
|
<div class="row items-center text-uppercase rounded-5 bg-transparent q-mb-xs" :class="ui_store.is_mobile_mode ? 'col' : 'col-4'">
|
||||||
|
<!-- mobile comment button -->
|
||||||
|
<q-btn
|
||||||
|
v-if="ui_store.is_mobile_mode && !dense"
|
||||||
|
:icon="shift.comment ? 'chat' : 'chat_bubble_outline'"
|
||||||
|
:text-color="shift.comment ? 'accent' : 'grey-5'"
|
||||||
|
class="col-auto full-height q-mx-xs rounded-5 shadow-1"
|
||||||
|
>
|
||||||
|
<q-popup-edit
|
||||||
|
v-model="shift.comment"
|
||||||
|
:title="$t('timesheet.shift.fields.header_comment')"
|
||||||
|
auto-save
|
||||||
|
v-slot="scope"
|
||||||
|
class="bg-dark"
|
||||||
|
>
|
||||||
|
<q-input
|
||||||
|
color="white"
|
||||||
|
v-model="scope.value"
|
||||||
|
dense
|
||||||
|
:readonly="shift.is_approved"
|
||||||
|
autofocus
|
||||||
|
counter
|
||||||
|
bottom-slots
|
||||||
|
:maxlength="COMMENT_LENGTH_MAX"
|
||||||
|
class="q-pb-lg"
|
||||||
|
:class="shift.is_approved ? 'cursor-not-allowed' : ''"
|
||||||
|
@keyup.enter="scope.set"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<q-icon name="edit" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<div
|
<template #counter>
|
||||||
class="row flex-center text-uppercase rounded-5 bg-transparent"
|
<div class="row flex-center">
|
||||||
>
|
<q-space />
|
||||||
<!-- shift type -->
|
<q-knob
|
||||||
<q-select
|
:model-value="scope.value?.length"
|
||||||
ref="select"
|
readonly
|
||||||
v-model="shift_type_selected"
|
:max="COMMENT_LENGTH_MAX"
|
||||||
standout="bg-blue-grey-9"
|
size="1.6em"
|
||||||
dense
|
:thickness="0.4"
|
||||||
:readonly="shift.is_approved"
|
:color="getCommentCounterColor(scope.value?.length ?? 0)"
|
||||||
:options-dense="!ui_store.is_mobile_mode"
|
track-color="grey-4"
|
||||||
hide-dropdown-icon
|
class="col-auto q-mr-xs"
|
||||||
:menu-offset="[0, 10]"
|
/>
|
||||||
menu-anchor="bottom middle"
|
<span
|
||||||
menu-self="top middle"
|
:class="'col-auto text-weight-bolder text-' + getCommentCounterColor(scope.value?.length ?? 0)"
|
||||||
:options="SHIFT_OPTIONS"
|
>{{ 280 - (scope.value?.length ?? 0) }}</span>
|
||||||
class="rounded-5 q-mx-xs bg-dark"
|
</div>
|
||||||
:class="(ui_store.is_mobile_mode ? 'col-12 q-mb-xs ' : 'col ')"
|
</template>
|
||||||
popup-content-class="text-uppercase text-weight-bold text-center rounded-5"
|
</q-input>
|
||||||
popup-content-style="border: 2px solid var(--q-accent)"
|
</q-popup-edit>
|
||||||
@blur="onBlurShiftTypeSelect"
|
</q-btn>
|
||||||
@update:model-value="option => shift.type = option.value"
|
|
||||||
>
|
|
||||||
<template #selected-item="scope">
|
|
||||||
<div
|
|
||||||
class="row flex-center text-weight-bold q-ma-none q-pa-none no-wrap ellipsis full-width"
|
|
||||||
:class="ui_store.is_mobile_mode ? 'items-center full-height' : 'flex-center'"
|
|
||||||
:tabindex="scope.tabindex"
|
|
||||||
>
|
|
||||||
<q-icon
|
|
||||||
:name="scope.opt.icon"
|
|
||||||
:color="scope.opt.icon_color"
|
|
||||||
size="sm"
|
|
||||||
class="col-auto q-mx-xs"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
style="line-height: 0.9em;"
|
|
||||||
class="col-auto ellipsis"
|
|
||||||
>{{ scope.opt.label }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</q-select>
|
|
||||||
|
|
||||||
<!-- punch in field -->
|
<!-- shift type -->
|
||||||
<q-input
|
<q-select
|
||||||
v-model="shift.start_time"
|
ref="select"
|
||||||
dense
|
v-model="shift_type_selected"
|
||||||
:readonly="shift.is_approved"
|
standout="bg-blue-grey-9"
|
||||||
type="time"
|
dense
|
||||||
:standout="$q.dark.isActive ? 'bg-blue-grey-9' : 'bg-blue-grey-1 text-white'"
|
:readonly="shift.is_approved"
|
||||||
label-slot
|
:options-dense="!ui_store.is_mobile_mode"
|
||||||
label-color="accent"
|
hide-dropdown-icon
|
||||||
:input-class="'text-weight-medium ' + (shift.id === -2 ? 'text-white ' : ' ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
:menu-offset="[0, 10]"
|
||||||
input-style="font-size: 1.2em;"
|
menu-anchor="bottom middle"
|
||||||
class="col rounded-5 bg-dark"
|
menu-self="top middle"
|
||||||
:class="(shift.id === -2 ? 'bg-negative ' : ' ') + (ui_store.is_mobile_mode ? 'q-mr-xs ' : 'q-mx-xs ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
:options="SHIFT_OPTIONS"
|
||||||
>
|
class="col rounded-5 q-mx-xs bg-dark"
|
||||||
<template #label>
|
popup-content-class="text-uppercase text-weight-bold text-center rounded-5"
|
||||||
<span
|
popup-content-style="border: 2px solid var(--q-accent)"
|
||||||
class="text-weight-bolder"
|
@blur="onBlurShiftTypeSelect"
|
||||||
style="font-size: 0.95em;"
|
@update:model-value="option => shift.type = option.value"
|
||||||
>{{ $t('shared.misc.in') }}</span>
|
>
|
||||||
</template>
|
<template #selected-item="scope">
|
||||||
</q-input>
|
<div
|
||||||
|
class="row flex-center text-weight-bold q-ma-none q-pa-none no-wrap ellipsis full-width"
|
||||||
|
:class="ui_store.is_mobile_mode ? 'items-center full-height' : 'flex-center'"
|
||||||
|
:tabindex="scope.tabindex"
|
||||||
|
>
|
||||||
|
<q-icon
|
||||||
|
:name="scope.opt.icon"
|
||||||
|
:color="scope.opt.icon_color"
|
||||||
|
size="sm"
|
||||||
|
class="col-auto q-mx-xs"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
style="line-height: 0.9em;"
|
||||||
|
class="col-auto ellipsis"
|
||||||
|
>{{ scope.opt.label }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- punch out field -->
|
<div class="col row flex-center text-uppercase rounded-5 bg-transparent q-pa-xs">
|
||||||
<q-input
|
<!-- punch in field -->
|
||||||
v-model="shift.end_time"
|
<q-input
|
||||||
dense
|
v-model="shift.start_time"
|
||||||
:readonly="shift.is_approved"
|
dense
|
||||||
type="time"
|
:readonly="shift.is_approved"
|
||||||
standout="bg-blue-grey-9"
|
type="time"
|
||||||
label-slot
|
:standout="$q.dark.isActive ? 'bg-blue-grey-9' : 'bg-blue-grey-1 text-white'"
|
||||||
label-color="accent"
|
label-slot
|
||||||
:input-class="'text-weight-medium ' + (shift.id === -2 ? 'text-white ' : ' ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
label-color="accent"
|
||||||
input-style="font-size: 1.2em;"
|
:input-class="'text-weight-medium ' + (shift.id === -2 ? 'text-white ' : ' ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
||||||
class="col rounded-5 bg-dark"
|
input-style="font-size: 1.2em;"
|
||||||
:class="(shift.id === -2 ? 'bg-negative ' : ' ') + (ui_store.is_mobile_mode ? 'q-ml-xs ' : 'q-mx-xs ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
class="col rounded-5 bg-dark"
|
||||||
>
|
:class="(shift.id === -2 ? 'bg-negative ' : ' ') + (ui_store.is_mobile_mode ? 'q-mr-xs ' : 'q-mx-xs ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
||||||
<template #label>
|
>
|
||||||
<span
|
<template #label>
|
||||||
class="text-weight-bolder"
|
<span
|
||||||
style="font-size: 0.95em;"
|
class="text-weight-bolder"
|
||||||
>{{ $t('shared.misc.out') }}</span>
|
style="font-size: 0.95em;"
|
||||||
</template>
|
>{{ $t('shared.misc.in') }}</span>
|
||||||
</q-input>
|
</template>
|
||||||
|
</q-input>
|
||||||
|
|
||||||
<!-- comment and delete buttons -->
|
<!-- punch out field -->
|
||||||
<div :class="ui_store.is_mobile_mode ? 'col-12 row' : 'col-auto'">
|
<q-input
|
||||||
<q-icon
|
v-model="shift.end_time"
|
||||||
v-if="shift.type && dense"
|
dense
|
||||||
:name="shift.comment ? 'comment' : ''"
|
:readonly="shift.is_approved"
|
||||||
color="primary"
|
type="time"
|
||||||
:size="dense ? 'xs' : 'sm'"
|
standout="bg-blue-grey-9"
|
||||||
class="col"
|
label-slot
|
||||||
/>
|
label-color="accent"
|
||||||
|
:input-class="'text-weight-medium ' + (shift.id === -2 ? 'text-white ' : ' ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
||||||
|
input-style="font-size: 1.2em;"
|
||||||
|
class="col rounded-5 bg-dark"
|
||||||
|
:class="(shift.id === -2 ? 'bg-negative ' : ' ') + (ui_store.is_mobile_mode ? 'q-ml-xs ' : 'q-mx-xs ') + (shift.is_approved ? 'cursor-not-allowed' : '')"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<span
|
||||||
|
class="text-weight-bolder"
|
||||||
|
style="font-size: 0.95em;"
|
||||||
|
>{{ $t('shared.misc.out') }}</span>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
|
||||||
<q-btn
|
<!-- comment and delete buttons -->
|
||||||
v-else
|
<div :class="ui_store.is_mobile_mode ? 'col-12 row' : 'col-auto'">
|
||||||
flat
|
<q-icon
|
||||||
dense
|
v-if="shift.type && dense"
|
||||||
:icon="shift.comment ? 'chat' : 'chat_bubble_outline'"
|
:name="shift.comment ? 'comment' : ''"
|
||||||
:text-color="shift.comment ? 'accent' : 'grey-5'"
|
color="primary"
|
||||||
class="col"
|
:size="dense ? 'xs' : 'sm'"
|
||||||
:class="ui_store.is_mobile_mode ? 'q-mt-xs bg-dark' : ''"
|
class="col"
|
||||||
>
|
/>
|
||||||
<q-popup-edit
|
|
||||||
v-model="shift.comment"
|
|
||||||
:title="$t('timesheet.shift.fields.header_comment')"
|
|
||||||
auto-save
|
|
||||||
v-slot="scope"
|
|
||||||
class="bg-dark"
|
|
||||||
>
|
|
||||||
<q-input
|
|
||||||
color="white"
|
|
||||||
v-model="scope.value"
|
|
||||||
dense
|
|
||||||
:readonly="shift.is_approved"
|
|
||||||
autofocus
|
|
||||||
counter
|
|
||||||
bottom-slots
|
|
||||||
:maxlength="COMMENT_LENGTH_MAX"
|
|
||||||
class="q-pb-lg"
|
|
||||||
:class="shift.is_approved ? 'cursor-not-allowed' : ''"
|
|
||||||
@keyup.enter="scope.set"
|
|
||||||
>
|
|
||||||
<template #append>
|
|
||||||
<q-icon name="edit" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #counter>
|
<!-- desktop comment button -->
|
||||||
<div class="row flex-center">
|
<q-btn
|
||||||
<q-space />
|
v-else-if="!ui_store.is_mobile_mode"
|
||||||
<q-knob
|
flat
|
||||||
:model-value="scope.value?.length"
|
dense
|
||||||
readonly
|
:icon="shift.comment ? 'chat' : 'chat_bubble_outline'"
|
||||||
:max="COMMENT_LENGTH_MAX"
|
:text-color="shift.comment ? 'accent' : 'grey-5'"
|
||||||
size="1.6em"
|
class="col"
|
||||||
:thickness="0.4"
|
:class="ui_store.is_mobile_mode ? 'q-mt-xs bg-dark' : ''"
|
||||||
:color="getCommentCounterColor(scope.value?.length ?? 0)"
|
>
|
||||||
track-color="grey-4"
|
<q-popup-edit
|
||||||
class="col-auto q-mr-xs"
|
v-model="shift.comment"
|
||||||
/>
|
:title="$t('timesheet.shift.fields.header_comment')"
|
||||||
<span
|
auto-save
|
||||||
:class="'col-auto text-weight-bolder text-' + getCommentCounterColor(scope.value?.length ?? 0)"
|
v-slot="scope"
|
||||||
>{{ 280 - (scope.value?.length ?? 0) }}</span>
|
class="bg-dark"
|
||||||
</div>
|
>
|
||||||
</template>
|
<q-input
|
||||||
</q-input>
|
color="white"
|
||||||
</q-popup-edit>
|
v-model="scope.value"
|
||||||
</q-btn>
|
dense
|
||||||
|
:readonly="shift.is_approved"
|
||||||
|
autofocus
|
||||||
|
counter
|
||||||
|
bottom-slots
|
||||||
|
:maxlength="COMMENT_LENGTH_MAX"
|
||||||
|
class="q-pb-lg"
|
||||||
|
:class="shift.is_approved ? 'cursor-not-allowed' : ''"
|
||||||
|
@keyup.enter="scope.set"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<q-icon name="edit" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<q-btn
|
<template #counter>
|
||||||
v-if="!ui_store.is_mobile_mode"
|
<div class="row flex-center">
|
||||||
flat
|
<q-space />
|
||||||
dense
|
<q-knob
|
||||||
:disable="shift.is_approved"
|
:model-value="scope.value?.length"
|
||||||
tabindex="-1"
|
readonly
|
||||||
icon="cancel"
|
:max="COMMENT_LENGTH_MAX"
|
||||||
text-color="negative"
|
size="1.6em"
|
||||||
class="col"
|
:thickness="0.4"
|
||||||
:class="shift.is_approved ? 'invisible' : ''"
|
:color="getCommentCounterColor(scope.value?.length ?? 0)"
|
||||||
@click="$emit('requestDelete')"
|
track-color="grey-4"
|
||||||
/>
|
class="col-auto q-mr-xs"
|
||||||
</div>
|
/>
|
||||||
</div>
|
<span
|
||||||
|
:class="'col-auto text-weight-bolder text-' + getCommentCounterColor(scope.value?.length ?? 0)"
|
||||||
|
>{{ 280 - (scope.value?.length ?? 0) }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</q-popup-edit>
|
||||||
|
</q-btn>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
v-if="!ui_store.is_mobile_mode"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
:disable="shift.is_approved"
|
||||||
|
tabindex="-1"
|
||||||
|
icon="cancel"
|
||||||
|
text-color="negative"
|
||||||
|
class="col"
|
||||||
|
:class="shift.is_approved ? 'invisible' : ''"
|
||||||
|
@click="$emit('requestDelete')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</q-slide-item>
|
</q-slide-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="column justify-center q-py-xs" :class="approved ? 'bg-dark' : ''">
|
<div class="column justify-center q-py-xs" :class="approved ? '' : ''">
|
||||||
<ShiftListDayRow
|
<ShiftListDayRow
|
||||||
v-for="shift, shift_index in day.shifts"
|
v-for="shift, shift_index in day.shifts"
|
||||||
:key="shift_index"
|
:key="shift_index"
|
||||||
|
|
|
||||||
|
|
@ -57,17 +57,20 @@
|
||||||
v-if="ui_store.is_mobile_mode"
|
v-if="ui_store.is_mobile_mode"
|
||||||
class="col column full-width"
|
class="col column full-width"
|
||||||
>
|
>
|
||||||
<q-card class="rounded-5 q-my-md" :class="getDayApproval(day) ? 'bg-accent' : 'bg-dark'">
|
<q-card
|
||||||
|
class="rounded-10 bg-dark"
|
||||||
|
:style="ui_store.is_mobile_mode ? (getDayApproval(day) ? 'border: 3px solid var(--q-accent)' : 'border: 1px solid var(--q-accent);') : ''"
|
||||||
|
>
|
||||||
|
|
||||||
<q-card-section
|
<q-card-section
|
||||||
class="text-white text-weight-bolder text-uppercase text-h6 q-py-xs"
|
class="text-weight-bolder text-uppercase text-h6 q-py-xs"
|
||||||
:class="getDayApproval(day) ? 'bg-dark' : 'bg-accent'"
|
:class="getDayApproval(day) ? 'bg-dark text-accent' : 'bg-primary text-white'"
|
||||||
style="line-height: 1em;"
|
style="line-height: 1em;"
|
||||||
>
|
>
|
||||||
<span> {{ $d(extractDate(day.date, 'YYYY-MM-DD'), {
|
<span> {{ $d(extractDate(day.date, 'YYYY-MM-DD'), {
|
||||||
weekday: 'long', day: 'numeric', month:
|
weekday: 'long', day: 'numeric', month:
|
||||||
'long'
|
'long'
|
||||||
}) }}</span>
|
}) }}</span>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
<q-card-section
|
<q-card-section
|
||||||
|
|
@ -85,7 +88,6 @@
|
||||||
<q-card-actions class="q-pa-none">
|
<q-card-actions class="q-pa-none">
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="!getDayApproval(day)"
|
v-if="!getDayApproval(day)"
|
||||||
push
|
|
||||||
square
|
square
|
||||||
color="accent"
|
color="accent"
|
||||||
icon="more_time"
|
icon="more_time"
|
||||||
|
|
@ -98,7 +100,7 @@
|
||||||
<q-badge
|
<q-badge
|
||||||
v-if="getDayApproval(day)"
|
v-if="getDayApproval(day)"
|
||||||
floating
|
floating
|
||||||
class="bg-secondary q-pa-none rounded-50"
|
class="transparent q-pa-none rounded-50"
|
||||||
style="transform: translate(15px, -5px);"
|
style="transform: translate(15px, -5px);"
|
||||||
>
|
>
|
||||||
<q-icon
|
<q-icon
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@
|
||||||
v-if="$q.screen.lt.md"
|
v-if="$q.screen.lt.md"
|
||||||
push
|
push
|
||||||
rounded
|
rounded
|
||||||
color="primary"
|
color="accent"
|
||||||
icon="receipt_long"
|
icon="receipt_long"
|
||||||
:label="$t('timesheet.expense.open_btn')"
|
:label="$t('timesheet.expense.open_btn')"
|
||||||
class="q-mt-sm"
|
class="q-mt-sm"
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ export const ShiftService = {
|
||||||
updateShifts: async (existing_shifts: Shift[]) => {
|
updateShifts: async (existing_shifts: Shift[]) => {
|
||||||
console.log('sent shifts: ', existing_shifts)
|
console.log('sent shifts: ', existing_shifts)
|
||||||
const response = await api.patch(`/shift/update`, existing_shifts);
|
const response = await api.patch(`/shift/update`, existing_shifts);
|
||||||
console.log('API response to existing shifts: ', response.data);
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -20,7 +20,7 @@ export const timesheetService = {
|
||||||
},
|
},
|
||||||
|
|
||||||
getTimesheetsByPayPeriod: async (year: number, period_number: number): Promise<TimesheetResponse> => {
|
getTimesheetsByPayPeriod: async (year: number, period_number: number): Promise<TimesheetResponse> => {
|
||||||
const response = await api.get('timesheets', { params: { year, period_number } });
|
const response = await api.get(`timesheets/${year}/${period_number}`);
|
||||||
return response.data;
|
return response.data.data;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
import { useTimesheetStore } from "src/stores/timesheet-store";
|
||||||
import { Expense } from "src/modules/timesheets/models/expense.models";
|
import { Expense } from "src/modules/timesheets/models/expense.models";
|
||||||
import { ExpenseService } from "src/modules/timesheets/services/expense-service";
|
import { ExpenseService } from "src/modules/timesheets/services/expense-service";
|
||||||
import { date } from "quasar";
|
import { date } from "quasar";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const useExpensesStore = defineStore('expenses', () => {
|
export const useExpensesStore = defineStore('expenses', () => {
|
||||||
|
const timesheet_store = useTimesheetStore();
|
||||||
const is_open = ref(false);
|
const is_open = ref(false);
|
||||||
const is_loading = ref(false);
|
const is_loading = ref(false);
|
||||||
|
const is_hiding_create_form = ref(false);
|
||||||
const mode = ref<'create' | 'update' | 'delete'>('create');
|
const mode = ref<'create' | 'update' | 'delete'>('create');
|
||||||
const current_expense = ref<Expense>(new Expense(date.formatDate(new Date(), 'YYYY-MM-DD')));
|
const current_expense = ref<Expense>(new Expense(date.formatDate(new Date(), 'YYYY-MM-DD')));
|
||||||
const initial_expense = ref<Expense>(new Expense(date.formatDate(new Date(), 'YYYY-MM-DD')));
|
const initial_expense = ref<Expense>(new Expense(date.formatDate(new Date(), 'YYYY-MM-DD')));
|
||||||
|
|
||||||
const open = (): void => {
|
const open = (): void => {
|
||||||
is_open.value = true;
|
is_open.value = true;
|
||||||
current_expense.value = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
if (timesheet_store.pay_period !== undefined) {
|
||||||
initial_expense.value = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
current_expense.value = new Expense(timesheet_store.pay_period.period_start);
|
||||||
|
initial_expense.value = new Expense(timesheet_store.pay_period.period_start);
|
||||||
|
}
|
||||||
mode.value = 'create';
|
mode.value = 'create';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,6 +48,7 @@ export const useExpensesStore = defineStore('expenses', () => {
|
||||||
return {
|
return {
|
||||||
is_open,
|
is_open,
|
||||||
is_loading,
|
is_loading,
|
||||||
|
is_hiding_create_form,
|
||||||
mode,
|
mode,
|
||||||
current_expense,
|
current_expense,
|
||||||
initial_expense,
|
initial_expense,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user