Journal für abholungen

This commit is contained in:
2026-01-04 01:39:51 +01:00
parent 8b0326bac9
commit 3b68701263

View File

@@ -95,6 +95,60 @@ const JournalPage = ({ authorizedFetch, stores }) => {
return parsed.getTime();
}, []);
const getIntervalMonths = useCallback((interval) => {
if (interval === 'monthly') {
return 1;
}
if (interval === 'quarterly') {
return 3;
}
return 12;
}, []);
const addMonths = useCallback((date, months) => {
const copy = new Date(date.getTime());
copy.setMonth(copy.getMonth() + months);
return copy;
}, []);
const startOfDay = useCallback((date) => {
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}, []);
const getNextReminderTimestamp = useCallback(
(entry) => {
if (!entry?.reminder?.enabled || !entry.pickupDate) {
return null;
}
const baseDate = new Date(`${entry.pickupDate}T00:00:00`);
if (Number.isNaN(baseDate.getTime())) {
return null;
}
const intervalMonths = getIntervalMonths(entry.reminder.interval);
const daysBefore = Number.isFinite(entry.reminder.daysBefore)
? Math.max(0, entry.reminder.daysBefore)
: 42;
const todayStart = startOfDay(new Date());
let occurrence = startOfDay(baseDate);
const guardYear = todayStart.getFullYear() + 200;
while (occurrence < todayStart && occurrence.getFullYear() < guardYear) {
occurrence = startOfDay(addMonths(occurrence, intervalMonths));
}
if (occurrence.getFullYear() >= guardYear) {
return null;
}
let reminderDate = new Date(occurrence.getTime());
reminderDate.setDate(reminderDate.getDate() - daysBefore);
if (reminderDate < todayStart) {
occurrence = startOfDay(addMonths(occurrence, intervalMonths));
reminderDate = new Date(occurrence.getTime());
reminderDate.setDate(reminderDate.getDate() - daysBefore);
}
return reminderDate.getTime();
},
[addMonths, getIntervalMonths, startOfDay]
);
const filteredEntries = useMemo(() => {
const query = filters.query.trim().toLowerCase();
const fromValue = parseDateValue(filters.dateFrom);
@@ -142,11 +196,25 @@ const JournalPage = ({ authorizedFetch, stores }) => {
const aLabel = a.storeName || storeLabelMap.get(String(a.storeId)) || '';
const bLabel = b.storeName || storeLabelMap.get(String(b.storeId)) || '';
return bLabel.localeCompare(aLabel);
},
nextReminderAsc: (a, b) => {
const aNext = getNextReminderTimestamp(a);
const bNext = getNextReminderTimestamp(b);
if (aNext === null && bNext === null) {
return 0;
}
if (aNext === null) {
return 1;
}
if (bNext === null) {
return -1;
}
return aNext - bNext;
}
};
const sorter = sorters[sortBy] || sorters.pickupDateDesc;
return [...results].sort(sorter);
}, [entries, filters, parseDateValue, sortBy, storeLabelMap]);
}, [entries, filters, getNextReminderTimestamp, parseDateValue, sortBy, storeLabelMap]);
const releaseEntryImageUrls = useCallback((entryList) => {
if (!Array.isArray(entryList)) {
@@ -538,6 +606,7 @@ const JournalPage = ({ authorizedFetch, stores }) => {
<option value="createdAtAsc">Erstellt </option>
<option value="storeNameAsc">Betrieb AZ</option>
<option value="storeNameDesc">Betrieb ZA</option>
<option value="nextReminderAsc">Nächste Erinnerung</option>
</select>
</div>
<div className="space-y-4">