fix: update loading state handling in CalendarPage and DutyList components

- Set isLoading to false in CalendarPage to prevent unnecessary loading indicators.
- Removed the loading spinner from CalendarHeader and adjusted rendering logic in DutyList to show a placeholder when data is not yet loaded for the month.
- Enhanced tests in DutyList to verify behavior when data is empty and when data is loading, ensuring accurate user feedback during data fetching.
This commit is contained in:
2026-03-03 16:21:27 +03:00
parent 3b68e29d7b
commit 95f65141e1
4 changed files with 38 additions and 34 deletions

View File

@@ -64,9 +64,15 @@ export interface DutyListProps {
export function DutyList({ scrollMarginTop = 268, className }: DutyListProps) {
const { t } = useTranslation();
const listRef = useRef<HTMLDivElement>(null);
const { currentMonth, duties, loading } = useAppStore(
useShallow((s) => ({ currentMonth: s.currentMonth, duties: s.duties, loading: s.loading }))
const { currentMonth, duties, dataForMonthKey } = useAppStore(
useShallow((s) => ({
currentMonth: s.currentMonth,
duties: s.duties,
dataForMonthKey: s.dataForMonthKey,
}))
);
const monthKey = `${currentMonth.getFullYear()}-${String(currentMonth.getMonth() + 1).padStart(2, "0")}`;
const hasDataForMonth = dataForMonthKey === monthKey;
const { filtered, dates, dutiesByDateKey } = useMemo(() => {
const filteredList = duties.filter((d) => d.event_type === "duty");
@@ -105,7 +111,6 @@ export function DutyList({ scrollMarginTop = 268, className }: DutyListProps) {
const id = setInterval(() => setNow(new Date()), 60_000);
return () => clearInterval(id);
}, []);
const monthKey = `${currentMonth.getFullYear()}-${currentMonth.getMonth()}`;
const scrolledForMonthRef = useRef<string | null>(null);
const prevScrollMarginTopRef = useRef<number>(scrollMarginTop);
const prevMonthKeyRef = useRef<string>(monthKey);
@@ -139,17 +144,25 @@ export function DutyList({ scrollMarginTop = 268, className }: DutyListProps) {
});
}, [filtered, dates.length, scrollMarginTop, monthKey]);
if (!hasDataForMonth) {
return (
<div
className={cn("min-h-[120px]", className)}
role="status"
aria-busy="true"
aria-live="polite"
aria-label={t("loading")}
>
<span className="sr-only">{t("loading")}</span>
</div>
);
}
if (filtered.length === 0) {
return (
<div className={cn("flex flex-col gap-1", className)}>
{loading ? (
<p className="text-sm text-muted m-0">{t("loading")}</p>
) : (
<>
<p className="text-sm text-muted m-0">{t("duty.none_this_month")}</p>
<p className="text-xs text-muted m-0">{t("duty.none_this_month_hint")}</p>
</>
)}
<p className="text-sm text-muted m-0">{t("duty.none_this_month")}</p>
<p className="text-xs text-muted m-0">{t("duty.none_this_month_hint")}</p>
</div>
);
}