Files
L-Ami-Fiduciaire/resources/js/components/clients/DeclarationCalendar.vue
Saad Ibn-Ezzoubayr 4807376c49 feat: implement Story 2.2 — Priority Alerts Panel with UI fixes
Add PriorityAlertsPanel component to the dashboard, update DashboardController
with alert logic, and apply misc UI fixes across sidebar, forms, and pages.
Includes epic-1 retrospective and sprint status update.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:33:27 +00:00

135 lines
3.7 KiB
Vue

<script setup lang="ts">
import { ChevronLeft, ChevronRight } from 'lucide-vue-next';
import { computed, ref } from 'vue';
import { Button } from '@/components/ui/button';
type Declaration = {
id: number;
due_date: string | null;
};
type Props = {
declarations: Declaration[];
};
const props = defineProps<Props>();
const monthNames = [
'Janvier',
'Février',
'Mars',
'Avril',
'Mai',
'Juin',
'Juillet',
'Août',
'Septembre',
'Octobre',
'Novembre',
'Décembre',
];
const dayNames = ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'];
const current = ref(new Date());
const monthLabel = computed(
() =>
`${monthNames[current.value.getMonth()]} ${current.value.getFullYear()}`,
);
const declarationsByDate = computed(() => {
const map = new Map<string, number>();
props.declarations.forEach((f) => {
if (f.due_date) {
map.set(f.due_date, (map.get(f.due_date) ?? 0) + 1);
}
});
return map;
});
const calendarDays = computed(() => {
const year = current.value.getFullYear();
const month = current.value.getMonth();
const first = new Date(year, month, 1);
const last = new Date(year, month + 1, 0);
const startDay = (first.getDay() + 6) % 7;
const daysInMonth = last.getDate();
const days: Array<{
date: Date | null;
dateStr: string | null;
count: number;
}> = [];
for (let i = 0; i < startDay; i++) {
days.push({ date: null, dateStr: null, count: 0 });
}
for (let d = 1; d <= daysInMonth; d++) {
const date = new Date(year, month, d);
const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
days.push({
date,
dateStr,
count: declarationsByDate.value.get(dateStr) ?? 0,
});
}
return days;
});
function prevMonth() {
current.value = new Date(
current.value.getFullYear(),
current.value.getMonth() - 1,
);
}
function nextMonth() {
current.value = new Date(
current.value.getFullYear(),
current.value.getMonth() + 1,
);
}
</script>
<template>
<div class="rounded-xl border border-sidebar-border/70 bg-card p-4">
<div class="mb-4 flex items-center justify-between">
<Button variant="ghost" size="icon" @click="prevMonth">
<ChevronLeft class="size-4" />
</Button>
<span class="text-sm font-medium">{{ monthLabel }}</span>
<Button variant="ghost" size="icon" @click="nextMonth">
<ChevronRight class="size-4" />
</Button>
</div>
<div class="grid grid-cols-7 gap-1 text-center text-xs">
<div
v-for="day in dayNames"
:key="day"
class="py-1 font-medium text-muted-foreground"
>
{{ day }}
</div>
<div
v-for="(cell, i) in calendarDays"
:key="i"
class="flex min-h-8 flex-col items-center justify-center rounded-md py-1"
:class="[
!cell.date
? 'invisible'
: cell.count > 0
? 'bg-primary/15 font-medium'
: 'text-muted-foreground hover:bg-muted/50',
]"
>
<template v-if="cell.date">
{{ cell.date.getDate() }}
<span v-if="cell.count > 0" class="mt-0.5 text-[10px]">
{{ cell.count }} décl.
</span>
</template>
</div>
</div>
</div>
</template>