mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-05 08:16:22 +00:00
fix: open the event editor as a sheet over the calendar so the week keeps its width
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import type { Calendar, CalendarEvent } from '@/lib/jmap/types';
|
||||
import { useCalendarStore } from '@/stores/calendar-store';
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
import { useSettingsStore } from '@/stores/settings-store';
|
||||
import { useTaskStore } from '@/stores/task-store';
|
||||
|
||||
// pim-25: the event editor sat beside the week grid and squeezed its seven
|
||||
// columns to ~85 px at 1366x768. It now opens as a sheet over the grid from
|
||||
// the right, and the grid keeps its width.
|
||||
|
||||
vi.mock('@/hooks/use-media-query', () => ({
|
||||
useIsMobile: () => false,
|
||||
useIsDesktop: () => true,
|
||||
useIsTablet: () => false,
|
||||
useMediaQuery: () => false,
|
||||
}));
|
||||
vi.mock('@/components/layout/navigation-rail', () => ({ NavigationRail: () => null }));
|
||||
vi.mock('@/components/layout/sidebar-apps-modal', () => ({ SidebarAppsModal: () => null }));
|
||||
vi.mock('@/components/layout/inline-app-view', () => ({ InlineAppView: () => null }));
|
||||
vi.mock('@/components/layout/mv-top-bar', () => ({ MvTopBar: () => null }));
|
||||
vi.mock('@/components/plugins/app-top-banner-slot', () => ({ AppTopBannerSlot: () => null }));
|
||||
vi.mock('@/hooks/use-refresh-gesture', () => ({ useRefreshGesture: () => ({ indicator: null }) }));
|
||||
vi.mock('@/hooks/use-calendar-push-refresh', () => ({ useCalendarPushRefresh: () => {} }));
|
||||
vi.mock('@/hooks/use-account-principal-emails', () => ({ useAccountPrincipalEmails: () => [] }));
|
||||
vi.mock('../participant-availability', () => ({ ParticipantAvailability: () => null }));
|
||||
vi.mock('@/hooks/use-config', () => ({ useConfig: () => ({ demoMode: false }) }));
|
||||
|
||||
import { CalendarApp } from '../calendar-app';
|
||||
|
||||
vi.setConfig({ testTimeout: 30000 });
|
||||
|
||||
const RIGHTS = {
|
||||
mayReadFreeBusy: true, mayReadItems: true, mayWriteAll: true, mayWriteOwn: true,
|
||||
mayUpdatePrivate: true, mayRSVP: true, mayShare: true, mayDelete: true,
|
||||
};
|
||||
const calendars = [{
|
||||
id: 'cal', name: 'Personal', color: '#123456', isDefault: true, sortOrder: 0, description: null,
|
||||
isSubscribed: true, isVisible: true, includeInAvailability: 'all', defaultAlertsWithTime: null,
|
||||
defaultAlertsWithoutTime: null, timeZone: null, shareWith: null, myRights: RIGHTS,
|
||||
}] as unknown as Calendar[];
|
||||
const event = {
|
||||
id: 'e1', uid: 'u1', '@type': 'Event', title: 'Standup', description: '', start: '2026-10-12T10:00:00',
|
||||
duration: 'PT1H', timeZone: null, showWithoutTime: false, calendarIds: { cal: true },
|
||||
participants: null, alerts: null, recurrenceRules: null, isOrigin: true, status: 'confirmed',
|
||||
} as unknown as CalendarEvent;
|
||||
const client = {
|
||||
getAccountId: () => 'acc',
|
||||
getMaxParticipantsPerEvent: () => null,
|
||||
supportsCalendars: () => true,
|
||||
queryCalendarEvents: vi.fn().mockResolvedValue([]),
|
||||
getCalendarEvent: vi.fn().mockResolvedValue(null),
|
||||
getCalendarTasks: vi.fn().mockResolvedValue([]),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
useAuthStore.setState({ isAuthenticated: true, client: client as never, isLoading: false, activeAccountId: 'acc' });
|
||||
useCalendarStore.setState({
|
||||
calendars, events: [event], supportsCalendar: true, selectedCalendarIds: ['cal'], viewMode: 'week',
|
||||
selectedDate: new Date(2026, 9, 12), isLoading: false, isLoadingEvents: false, error: null,
|
||||
fetchCalendars: vi.fn(), fetchEvents: vi.fn(), refreshAllSubscriptions: vi.fn(),
|
||||
createEvent: vi.fn(), updateEvent: vi.fn(), deleteEvent: vi.fn(), rsvpEvent: vi.fn(),
|
||||
} as never);
|
||||
useSettingsStore.setState({ calendarHoverPreview: 'instant', enableCalendarTasks: true, proInterface: false } as never);
|
||||
useTaskStore.setState({ tasks: [] } as never);
|
||||
});
|
||||
|
||||
describe('CalendarApp event editor (pim-25)', () => {
|
||||
it('opens over the grid instead of beside it', async () => {
|
||||
render(<CalendarApp />);
|
||||
fireEvent.keyDown(document.body, { key: 'n', code: 'KeyN' });
|
||||
const editor = await screen.findByRole('dialog', { name: 'events.create' });
|
||||
const sheet = editor.parentElement!;
|
||||
// Out of the row's flow, pinned to its end edge, above the grid.
|
||||
expect(sheet.className).toMatch(/\babsolute\b/);
|
||||
expect(sheet.className).toMatch(/\binset-y-0\b/);
|
||||
expect(sheet.className).toMatch(/\bend-0\b/);
|
||||
expect(sheet.className).not.toMatch(/\bflex-shrink-0\b/);
|
||||
expect(sheet.parentElement!.className).toMatch(/\brelative\b/);
|
||||
});
|
||||
});
|
||||
@@ -2362,9 +2362,11 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps =
|
||||
{renderView()}
|
||||
</div>
|
||||
|
||||
{/* Desktop event panel */}
|
||||
{/* Desktop event panel: a sheet over the grid from the right, as
|
||||
on small screens, so the week keeps its width (pim-25). Above
|
||||
the views' sticky headers (z-50) inside this isolated row. */}
|
||||
{!isMobile && showEventModal && (
|
||||
<div className="w-[400px] border-s border-border flex-shrink-0 overflow-hidden">
|
||||
<div data-testid="event-panel" className="absolute inset-y-0 end-0 z-[55] w-[400px] max-w-full border-s border-border bg-background shadow-xl overflow-hidden">
|
||||
<EventModal
|
||||
key={`${editEvent?.id ?? 'new'}${modalStartsInEdit ? ':edit' : ''}`}
|
||||
event={editEvent}
|
||||
|
||||
Reference in New Issue
Block a user