201 lines
7.5 KiB
Vue
201 lines
7.5 KiB
Vue
<template>
|
||
<div class="py-6 flex flex-col gap-3">
|
||
<SiteFilterSelector v-if="sites.length > 0 && isAdmin" v-model="selectedSiteIds" :sites="sites" />
|
||
|
||
<div class="flex justify-between items-center gap-4">
|
||
<div class="flex gap-4 flex-wrap">
|
||
<div
|
||
v-if="viewMode === 'day'"
|
||
class="inline-flex h-10 w-[320px] overflow-hidden rounded-md border border-primary-500 bg-white"
|
||
>
|
||
<button
|
||
type="button"
|
||
class="flex-1 px-4 py-2 text-sm font-semibold active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
:class="shortcutButtonClass('yesterday')"
|
||
@click="emit('set-yesterday')"
|
||
>
|
||
Hier
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="flex-1 border-x border-primary-500 px-4 py-2 text-sm font-semibold active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
:class="shortcutButtonClass('today')"
|
||
@click="emit('set-today')"
|
||
>
|
||
Aujourd'hui
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="flex-1 px-4 py-2 text-sm font-semibold active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
:class="shortcutButtonClass('tomorrow')"
|
||
@click="emit('set-tomorrow')"
|
||
>
|
||
Demain
|
||
</button>
|
||
</div>
|
||
|
||
<div
|
||
v-else
|
||
class="inline-flex h-10 w-[320px] overflow-hidden rounded-md border border-primary-500 bg-white"
|
||
>
|
||
<button
|
||
type="button"
|
||
class="flex-1 px-4 py-2 text-sm font-semibold active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
:class="weekShortcutButtonClass('previousWeek')"
|
||
@click="emit('set-previous-week')"
|
||
>
|
||
{{ getWeekShortcutLabel('previousWeek') }}
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="flex-1 border-x border-primary-500 px-4 py-2 text-sm font-semibold active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
:class="weekShortcutButtonClass('thisWeek')"
|
||
@click="emit('set-this-week')"
|
||
>
|
||
{{ getWeekShortcutLabel('thisWeek') }}
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="flex-1 px-4 py-2 text-sm font-semibold active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
:class="weekShortcutButtonClass('nextWeek')"
|
||
@click="emit('set-next-week')"
|
||
>
|
||
{{ getWeekShortcutLabel('nextWeek') }}
|
||
</button>
|
||
</div>
|
||
|
||
<div class="relative inline-flex h-10 w-[320px] items-center overflow-hidden rounded-md border border-primary-500 bg-white">
|
||
<input
|
||
ref="nativeDateInput"
|
||
:value="pickerValue"
|
||
:type="viewMode === 'week' ? 'week' : 'date'"
|
||
class="pointer-events-none absolute inset-0 h-full w-full opacity-0"
|
||
tabindex="-1"
|
||
aria-hidden="true"
|
||
@input="onPickerInput"
|
||
@change="onPickerInput"
|
||
/>
|
||
<button
|
||
type="button"
|
||
class="h-10 px-3 text-lg font-semibold text-primary-500 hover:bg-tertiary-500 active:bg-tertiary-500 active:scale-[0.96] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
aria-label="Période précédente"
|
||
@click="emit('shift-date', -1)"
|
||
>
|
||
‹
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="h-10 flex-1 border-x border-primary-500 px-4 text-sm font-semibold text-primary-500 text-center hover:bg-tertiary-500 active:bg-tertiary-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
@click="openDatePicker"
|
||
>
|
||
{{ formattedSelectedDate }}
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="h-10 px-3 text-lg font-semibold text-primary-500 hover:bg-tertiary-500 active:bg-tertiary-500 active:scale-[0.96] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
aria-label="Période suivante"
|
||
@click="emit('shift-date', 1)"
|
||
>
|
||
›
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="isAdmin" class="inline-flex h-10 overflow-hidden rounded-md border border-primary-500 bg-white">
|
||
<button
|
||
type="button"
|
||
class="inline-flex items-center gap-2 px-4 py-2 text-sm font-semibold active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
:class="viewModeButtonClass('day')"
|
||
@click="viewMode = 'day'"
|
||
>
|
||
<Icon name="mdi:calendar-clock" />
|
||
Jour
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="inline-flex items-center gap-2 border-l border-primary-500 px-4 py-2 text-sm font-semibold active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40"
|
||
:class="viewModeButtonClass('week')"
|
||
@click="viewMode = 'week'"
|
||
>
|
||
<Icon name="mdi:calendar-week" />
|
||
Semaine
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="isAdmin" class="w-80 max-w-full">
|
||
<EmployeeNameFilterInput v-model="employeeFilter" />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import type { Site } from '~/services/dto/site'
|
||
import EmployeeNameFilterInput from '~/components/EmployeeNameFilterInput.vue'
|
||
import SiteFilterSelector from '~/components/SiteFilterSelector.vue'
|
||
import { weekInputValueToYmd, ymdToWeekInputValue } from '~/utils/date'
|
||
|
||
const selectedDate = defineModel<string>('selectedDate', { required: true })
|
||
const viewMode = defineModel<'day' | 'week'>('viewMode', { required: true })
|
||
const selectedSiteIds = defineModel<number[]>('selectedSiteIds', { required: true })
|
||
const employeeFilter = defineModel<string>('employeeFilter', { required: true })
|
||
|
||
defineProps<{
|
||
isAdmin: boolean
|
||
sites: Site[]
|
||
formattedSelectedDate: string
|
||
shortcutButtonClass: (target: 'yesterday' | 'today' | 'tomorrow') => string
|
||
weekShortcutButtonClass: (target: 'previousWeek' | 'thisWeek' | 'nextWeek') => string
|
||
getWeekShortcutLabel: (target: 'previousWeek' | 'thisWeek' | 'nextWeek') => string
|
||
}>()
|
||
|
||
const emit = defineEmits<{
|
||
(e: 'set-yesterday'): void
|
||
(e: 'set-today'): void
|
||
(e: 'set-tomorrow'): void
|
||
(e: 'set-previous-week'): void
|
||
(e: 'set-this-week'): void
|
||
(e: 'set-next-week'): void
|
||
(e: 'shift-date', value: number): void
|
||
}>()
|
||
|
||
const nativeDateInput = ref<HTMLInputElement | null>(null)
|
||
const pickerValue = computed(() => {
|
||
if (viewMode.value === 'week') return ymdToWeekInputValue(selectedDate.value)
|
||
return selectedDate.value
|
||
})
|
||
|
||
const viewModeButtonClass = (mode: 'day' | 'week') => {
|
||
if (viewMode.value === mode) {
|
||
return 'bg-primary-500 text-white'
|
||
}
|
||
|
||
return 'bg-white text-primary-500 hover:bg-tertiary-500'
|
||
}
|
||
|
||
const openDatePicker = () => {
|
||
const input = nativeDateInput.value
|
||
if (!input) return
|
||
if (typeof input.showPicker === 'function') {
|
||
input.showPicker()
|
||
return
|
||
}
|
||
input.focus()
|
||
input.click()
|
||
}
|
||
|
||
const onPickerInput = (event: Event) => {
|
||
const value = (event.target as HTMLInputElement).value
|
||
if (!value) return
|
||
|
||
if (viewMode.value === 'week') {
|
||
const ymd = weekInputValueToYmd(value)
|
||
if (!ymd) return
|
||
selectedDate.value = ymd
|
||
return
|
||
}
|
||
|
||
selectedDate.value = value
|
||
}
|
||
</script>
|