fix(dashboard): restore event visibility and fix lint errors in App.tsx

Appointments: no longer hide existing events on holiday dates
Resources: load all overlapping events per group, include inactive/past events, and reload on date/view navigation
App.tsx: replace any types in password input handlers with typed event shapes
This commit is contained in:
2026-03-30 09:51:22 +00:00
parent 24cdf07279
commit 90ccbdf920
3 changed files with 33 additions and 65 deletions

View File

@@ -439,7 +439,7 @@ const Layout: React.FC = () => {
type="password"
placeholder="Aktuelles Passwort"
value={pwdCurrent}
input={(e: any) => setPwdCurrent(e.value)}
input={(e: { value?: string }) => setPwdCurrent(e.value ?? '')}
disabled={pwdBusy}
/>
</div>
@@ -449,7 +449,7 @@ const Layout: React.FC = () => {
type="password"
placeholder="Mindestens 6 Zeichen"
value={pwdNew}
input={(e: any) => setPwdNew(e.value)}
input={(e: { value?: string }) => setPwdNew(e.value ?? '')}
disabled={pwdBusy}
/>
</div>
@@ -459,7 +459,7 @@ const Layout: React.FC = () => {
type="password"
placeholder="Wiederholen"
value={pwdConfirm}
input={(e: any) => setPwdConfirm(e.value)}
input={(e: { value?: string }) => setPwdConfirm(e.value ?? '')}
disabled={pwdBusy}
/>
</div>

View File

@@ -523,28 +523,10 @@ const Appointments: React.FC = () => {
}, [holidays, allowScheduleOnHolidays]);
const dataSource = useMemo(() => {
// Filter: Events with SkipHolidays=true (from internal Event type) are never shown on holidays
const filteredEvents = events.filter(ev => {
if (ev.SkipHolidays) {
// If event falls within a holiday, hide it
const s = ev.StartTime instanceof Date ? ev.StartTime : new Date(ev.StartTime);
const e = ev.EndTime instanceof Date ? ev.EndTime : new Date(ev.EndTime);
for (const h of holidays) {
const hs = new Date(h.start_date + 'T00:00:00');
const he = new Date(h.end_date + 'T23:59:59');
if (
(s >= hs && s <= he) ||
(e >= hs && e <= he) ||
(s <= hs && e >= he)
) {
return false;
}
}
}
return true;
});
return [...filteredEvents, ...holidayDisplayEvents, ...holidayBlockEvents];
}, [events, holidayDisplayEvents, holidayBlockEvents, holidays]);
// Existing events should always be visible; holiday skipping for recurring events
// is handled via RecurrenceException from the backend.
return [...events, ...holidayDisplayEvents, ...holidayBlockEvents];
}, [events, holidayDisplayEvents, holidayBlockEvents]);
// Removed dataSource logging
@@ -1227,37 +1209,6 @@ const Appointments: React.FC = () => {
}
}}
eventRendered={(args: EventRenderedArgs) => {
// Always hide events that skip holidays when they fall on holidays, regardless of toggle
if (args.data) {
const ev = args.data as unknown as Partial<Event>;
if (ev.SkipHolidays && !args.data.isHoliday) {
const s =
args.data.StartTime instanceof Date
? args.data.StartTime
: new Date(args.data.StartTime);
const e =
args.data.EndTime instanceof Date ? args.data.EndTime : new Date(args.data.EndTime);
if (isWithinHolidayRange(s, e)) {
args.cancel = true;
return;
}
}
}
// Blende Nicht-Ferien-Events aus, falls sie in Ferien fallen und Terminieren nicht erlaubt ist
// Hide events on holidays if not allowed
if (!allowScheduleOnHolidays && args.data && !args.data.isHoliday) {
const s =
args.data.StartTime instanceof Date
? args.data.StartTime
: new Date(args.data.StartTime);
const e =
args.data.EndTime instanceof Date ? args.data.EndTime : new Date(args.data.EndTime);
if (isWithinHolidayRange(s, e)) {
args.cancel = true;
return;
}
}
if (selectedGroupId && args.data && args.data.Id) {
const groupColor = getGroupColor(selectedGroupId, groups);

View File

@@ -33,7 +33,7 @@ const Ressourcen: React.FC = () => {
const [groupOrder, setGroupOrder] = useState<number[]>([]);
const [showOrderPanel, setShowOrderPanel] = useState<boolean>(false);
const [timelineView] = useState<TimelineView>('day');
const [viewDate] = useState<Date>(() => {
const [viewDate, setViewDate] = useState<Date>(() => {
const now = new Date();
now.setHours(0, 0, 0, 0);
return now;
@@ -110,23 +110,31 @@ const Ressourcen: React.FC = () => {
for (const group of groups) {
try {
console.log(`[Ressourcen] Fetching events for group "${group.name}" (ID: ${group.id})`);
const apiEvents = await fetchEvents(group.id.toString(), false, {
const apiEvents = await fetchEvents(group.id.toString(), true, {
start,
end,
});
console.log(`[Ressourcen] Got ${apiEvents?.length || 0} events for group "${group.name}"`);
if (Array.isArray(apiEvents) && apiEvents.length > 0) {
const event = apiEvents[0];
const eventTitle = event.subject || event.title || 'Unnamed Event';
const eventType = event.type || event.event_type || 'other';
const eventStart = event.startTime || event.start;
const eventEnd = event.endTime || event.end;
for (const event of apiEvents) {
const eventTitle = event.subject || event.title || 'Unnamed Event';
const eventType = event.type || event.event_type || 'other';
const eventStart = event.startTime || event.start;
const eventEnd = event.endTime || event.end;
if (!eventStart || !eventEnd) {
continue;
}
if (eventStart && eventEnd) {
const parsedStart = parseUTCDate(eventStart);
const parsedEnd = parseUTCDate(eventEnd);
// Keep only events that overlap the visible range.
if (parsedEnd < start || parsedStart > end) {
continue;
}
// Capitalize first letter of event type
const formattedType = eventType.charAt(0).toUpperCase() + eventType.slice(1);
@@ -138,7 +146,6 @@ const Ressourcen: React.FC = () => {
ResourceId: group.id,
EventType: eventType,
});
console.log(`[Ressourcen] Group "${group.name}" has event: ${eventTitle}`);
}
}
} catch (error) {
@@ -324,6 +331,16 @@ const Ressourcen: React.FC = () => {
group={{ resources: ['Groups'], allowGroupEdit: false }}
timeScale={{ interval: 60, slotCount: 1 }}
rowAutoHeight={false}
actionComplete={(args) => {
if (args.requestType === 'dateNavigate' || args.requestType === 'viewNavigate') {
const selected = scheduleRef.current?.selectedDate;
if (selected) {
const normalized = new Date(selected);
normalized.setHours(0, 0, 0, 0);
setViewDate(normalized);
}
}
}}
>
<ViewsDirective>
<ViewDirective option="TimelineDay" displayName="Tag"></ViewDirective>