diff --git a/package.json b/package.json
index e18c3c4..fb4a2c1 100644
--- a/package.json
+++ b/package.json
@@ -56,20 +56,25 @@
"next-auth": "^5.0.0-beta.25",
"next-swagger-doc": "^0.4.1",
"next-themes": "^0.4.6",
- "react": "^19.0.0",
+ "react": "^19.1.0",
+ "react-big-calendar": "^1.18.0",
+ "react-datepicker": "^8.4.0",
"react-day-picker": "^9.7.0",
"react-dom": "^19.0.0",
+ "react-error-boundary": "^6.0.0",
"react-hook-form": "^7.56.4",
"sonner": "^2.0.5",
"swagger-ui-react": "^5.24.1",
"tailwind-merge": "^3.2.0",
- "zod": "^3.25.60"
+ "zod": "^3.25.60",
+ "zod-validation-error": "^3.5.2"
},
"devDependencies": {
"@eslint/eslintrc": "3.3.1",
"@tailwindcss/postcss": "4.1.10",
"@types/node": "22.15.33",
"@types/react": "19.1.8",
+ "@types/react-big-calendar": "^1",
"@types/react-dom": "19.1.6",
"@types/swagger-ui-react": "5",
"@types/webpack-env": "1.18.8",
diff --git a/src/app/(main)/home/page.tsx b/src/app/(main)/home/page.tsx
index 66a97d8..1cf8a90 100644
--- a/src/app/(main)/home/page.tsx
+++ b/src/app/(main)/home/page.tsx
@@ -1,22 +1,17 @@
'use client';
-import { RedirectButton } from '@/components/buttons/redirect-button';
+import Calendar from '@/components/calendar';
import { useGetApiUserMe } from '@/generated/api/user/user';
export default function Home() {
- const { data, isLoading } = useGetApiUserMe();
+ const { data } = useGetApiUserMe();
return (
-
-
-
- Hello{' '}
- {isLoading ? 'Loading...' : data?.data.user?.name || 'Unknown User'}
-
-
-
-
-
+
+
);
}
diff --git a/src/app/api/user/[user]/calendar/route.ts b/src/app/api/user/[user]/calendar/route.ts
index f6b6098..62142e9 100644
--- a/src/app/api/user/[user]/calendar/route.ts
+++ b/src/app/api/user/[user]/calendar/route.ts
@@ -136,15 +136,15 @@ export const GET = auth(async function GET(req, { params }) {
start_time: 'asc',
},
select: {
- id: requestUserId === requestedUserId ? true : false,
- reason: requestUserId === requestedUserId ? true : false,
+ id: true,
+ reason: true,
start_time: true,
end_time: true,
- is_recurring: requestUserId === requestedUserId ? true : false,
- recurrence_end_date: requestUserId === requestedUserId ? true : false,
- rrule: requestUserId === requestedUserId ? true : false,
- created_at: requestUserId === requestedUserId ? true : false,
- updated_at: requestUserId === requestedUserId ? true : false,
+ is_recurring: true,
+ recurrence_end_date: true,
+ rrule: true,
+ created_at: true,
+ updated_at: true,
},
},
},
@@ -167,6 +167,7 @@ export const GET = auth(async function GET(req, { params }) {
calendar.push({ ...event.meeting, type: 'event' });
} else {
calendar.push({
+ id: event.meeting.id,
start_time: event.meeting.start_time,
end_time: event.meeting.end_time,
type: 'blocked_private',
@@ -182,6 +183,7 @@ export const GET = auth(async function GET(req, { params }) {
calendar.push({ ...event, type: 'event' });
} else {
calendar.push({
+ id: event.id,
start_time: event.start_time,
end_time: event.end_time,
type: 'blocked_private',
@@ -190,23 +192,35 @@ export const GET = auth(async function GET(req, { params }) {
}
for (const slot of requestedUser.blockedSlots) {
- calendar.push({
- start_time: slot.start_time,
- end_time: slot.end_time,
- id: slot.id,
- reason: slot.reason,
- is_recurring: slot.is_recurring,
- recurrence_end_date: slot.recurrence_end_date,
- rrule: slot.rrule,
- created_at: slot.created_at,
- updated_at: slot.updated_at,
- type:
- requestUserId === requestedUserId ? 'blocked_owned' : 'blocked_private',
- });
+ if (requestUserId === requestedUserId) {
+ calendar.push({
+ start_time: slot.start_time,
+ end_time: slot.end_time,
+ id: slot.id,
+ reason: slot.reason,
+ is_recurring: slot.is_recurring,
+ recurrence_end_date: slot.recurrence_end_date,
+ rrule: slot.rrule,
+ created_at: slot.created_at,
+ updated_at: slot.updated_at,
+ type: 'blocked_owned',
+ });
+ } else {
+ calendar.push({
+ start_time: slot.start_time,
+ end_time: slot.end_time,
+ id: slot.id,
+ type: 'blocked_private',
+ });
+ }
}
return returnZodTypeCheckedResponse(UserCalendarResponseSchema, {
success: true,
- calendar,
+ calendar: calendar.filter(
+ (event, index, self) =>
+ self.findIndex((e) => e.id === event.id && e.type === event.type) ===
+ index,
+ ),
});
});
diff --git a/src/app/api/user/[user]/calendar/validation.ts b/src/app/api/user/[user]/calendar/validation.ts
index a0d179f..1572793 100644
--- a/src/app/api/user/[user]/calendar/validation.ts
+++ b/src/app/api/user/[user]/calendar/validation.ts
@@ -13,23 +13,28 @@ export const BlockedSlotSchema = zod
start_time: eventStartTimeSchema,
end_time: eventEndTimeSchema,
type: zod.literal('blocked_private'),
+ id: zod.string(),
})
.openapi('BlockedSlotSchema', {
description: 'Blocked time slot in the user calendar',
});
-export const OwnedBlockedSlotSchema = BlockedSlotSchema.extend({
- id: zod.string(),
- reason: zod.string().nullish(),
- is_recurring: zod.boolean().default(false),
- recurrence_end_date: zod.date().nullish(),
- rrule: zod.string().nullish(),
- created_at: zod.date().nullish(),
- updated_at: zod.date().nullish(),
- type: zod.literal('blocked_owned'),
-}).openapi('OwnedBlockedSlotSchema', {
- description: 'Blocked slot owned by the user',
-});
+export const OwnedBlockedSlotSchema = zod
+ .object({
+ start_time: eventStartTimeSchema,
+ end_time: eventEndTimeSchema,
+ id: zod.string(),
+ reason: zod.string().nullish(),
+ is_recurring: zod.boolean().default(false),
+ recurrence_end_date: zod.date().nullish(),
+ rrule: zod.string().nullish(),
+ created_at: zod.date().nullish(),
+ updated_at: zod.date().nullish(),
+ type: zod.literal('blocked_owned'),
+ })
+ .openapi('OwnedBlockedSlotSchema', {
+ description: 'Blocked slot owned by the user',
+ });
export const VisibleSlotSchema = EventSchema.omit({
organizer: true,
diff --git a/src/components/calendar.tsx b/src/components/calendar.tsx
new file mode 100644
index 0000000..a8d6005
--- /dev/null
+++ b/src/components/calendar.tsx
@@ -0,0 +1,256 @@
+'use client';
+
+import { Calendar as RBCalendar, momentLocalizer } from 'react-big-calendar';
+import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop';
+import moment from 'moment';
+import '@/components/react-big-calendar.css';
+import 'react-big-calendar/lib/addons/dragAndDrop/styles.css';
+import CustomToolbar from '@/components/custom-toolbar';
+import React from 'react';
+import { useGetApiUserUserCalendar } from '@/generated/api/user/user';
+import { useRouter } from 'next/navigation';
+import { usePatchApiEventEventID } from '@/generated/api/event/event';
+import { useSession } from 'next-auth/react';
+import { UserCalendarSchemaItem } from '@/generated/api/meetup.schemas';
+import { QueryErrorResetBoundary } from '@tanstack/react-query';
+import { ErrorBoundary } from 'react-error-boundary';
+import { Button } from '@/components/ui/button';
+import { fromZodIssue } from 'zod-validation-error/v4';
+import type { $ZodIssue } from 'zod/v4/core';
+
+moment.updateLocale('en', {
+ week: {
+ dow: 1,
+ doy: 4,
+ },
+});
+
+const DaDRBCalendar = withDragAndDrop<
+ {
+ id: string;
+ start: Date;
+ end: Date;
+ type: UserCalendarSchemaItem['type'];
+ },
+ {
+ id: string;
+ title: string;
+ type: UserCalendarSchemaItem['type'];
+ }
+>(RBCalendar);
+
+const localizer = momentLocalizer(moment);
+
+export default function Calendar({
+ userId,
+ height,
+}: {
+ userId?: string;
+ height: string;
+}) {
+ return (
+
+ {({ reset }) => (
+ (
+
+ There was an error!
+
+ {typeof error === 'string'
+ ? error
+ : error.errors
+ .map((e: $ZodIssue) => fromZodIssue(e).toString())
+ .join(', ')}
+
+
+
+ )}
+ >
+ {userId ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+ );
+}
+
+function CalendarWithUserEvents({
+ userId,
+ height,
+}: {
+ userId: string;
+ height: string;
+}) {
+ const sesstion = useSession();
+ const [currentView, setCurrentView] = React.useState<
+ 'month' | 'week' | 'day' | 'agenda' | 'work_week'
+ >('week');
+ const [currentDate, setCurrentDate] = React.useState
(new Date());
+ const router = useRouter();
+
+ const { data, refetch, error, isError } = useGetApiUserUserCalendar(
+ userId,
+ {
+ start: moment(currentDate)
+ .startOf(
+ currentView === 'agenda'
+ ? 'month'
+ : currentView === 'work_week'
+ ? 'week'
+ : currentView,
+ )
+ .toISOString(),
+ end: moment(currentDate)
+ .endOf(
+ currentView === 'agenda'
+ ? 'month'
+ : currentView === 'work_week'
+ ? 'week'
+ : currentView,
+ )
+ .toISOString(),
+ },
+ {
+ query: {
+ refetchOnWindowFocus: true,
+ refetchOnReconnect: true,
+ refetchOnMount: true,
+ },
+ },
+ );
+
+ if (isError) {
+ throw error.response?.data || 'Failed to fetch calendar data';
+ }
+
+ const { mutate: patchEvent } = usePatchApiEventEventID({
+ mutation: {
+ throwOnError(error) {
+ throw error.response?.data || 'Failed to update event';
+ },
+ },
+ });
+
+ return (
+ {
+ setCurrentDate(date);
+ }}
+ events={
+ data?.data.calendar.map((event) => ({
+ id: event.id,
+ title: event.type === 'event' ? event.title : 'Blocker',
+ start: new Date(event.start_time),
+ end: new Date(event.end_time),
+ type: event.type,
+ })) ?? []
+ }
+ onSelectEvent={(event) => {
+ router.push(`/events/${event.id}`);
+ }}
+ onSelectSlot={(slotInfo) => {
+ router.push(
+ `/events/new?start=${slotInfo.start.toISOString()}&end=${slotInfo.end.toISOString()}`,
+ );
+ }}
+ resourceIdAccessor={(event) => event.id}
+ resourceTitleAccessor={(event) => event.title}
+ startAccessor={(event) => event.start}
+ endAccessor={(event) => event.end}
+ selectable={sesstion.data?.user?.id === userId}
+ onEventDrop={(event) => {
+ const { start, end, event: droppedEvent } = event;
+ if (droppedEvent.type === 'blocked_private') return;
+ const startISO = new Date(start).toISOString();
+ const endISO = new Date(end).toISOString();
+ patchEvent(
+ {
+ eventID: droppedEvent.id,
+ data: {
+ start_time: startISO,
+ end_time: endISO,
+ },
+ },
+ {
+ onSuccess: () => {
+ refetch();
+ },
+ onError: (error) => {
+ console.error('Error updating event:', error);
+ },
+ },
+ );
+ }}
+ onEventResize={(event) => {
+ const { start, end, event: resizedEvent } = event;
+ if (resizedEvent.type === 'blocked_private') return;
+ const startISO = new Date(start).toISOString();
+ const endISO = new Date(end).toISOString();
+ if (startISO === endISO) {
+ console.warn('Start and end times are the same, skipping resize.');
+ return;
+ }
+ patchEvent(
+ {
+ eventID: resizedEvent.id,
+ data: {
+ start_time: startISO,
+ end_time: endISO,
+ },
+ },
+ {
+ onSuccess: () => {
+ refetch();
+ },
+ onError: (error) => {
+ console.error('Error resizing event:', error);
+ },
+ },
+ );
+ }}
+ />
+ );
+}
+
+function CalendarWithoutUserEvents({ height }: { height: string }) {
+ const [currentView, setCurrentView] = React.useState<
+ 'month' | 'week' | 'day' | 'agenda' | 'work_week'
+ >('week');
+ const [currentDate, setCurrentDate] = React.useState(new Date());
+
+ return (
+ {
+ setCurrentDate(date);
+ }}
+ />
+ );
+}
diff --git a/src/components/custom-toolbar.css b/src/components/custom-toolbar.css
new file mode 100644
index 0000000..3fba69f
--- /dev/null
+++ b/src/components/custom-toolbar.css
@@ -0,0 +1,114 @@
+/* Container der Toolbar */
+.custom-toolbar {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ padding: calc(var(--spacing) * 2);
+ padding-left: calc(50px + var(--spacing));
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+}
+
+/* Anzeige des aktuellen Datums (Monat und Jahr) */
+.custom-toolbar .current-date {
+ font-weight: bold;
+ font-size: 12px;
+ text-align: center;
+ color: #ffffff;
+ background-color: #717171;
+ height: 37px;
+ border-radius: 11px;
+}
+
+/* Navigationsbereich (Today, Prev, Next) */
+.custom-toolbar .navigation-controls {
+ display: flex;
+ gap: 8px;
+ justify-content: center;
+}
+
+.custom-toolbar .navigation-controls button {
+ padding: 8px 12px;
+ color: #ffffff;
+ border: none;
+ border-radius: 11px;
+ font-size: 12px;
+ cursor: pointer;
+ transition: background-color 0.2s;
+}
+
+.custom-toolbar .navigation-controls button:hover {
+ background-color: #1976d2;
+}
+
+.custom-toolbar .navigation-controls button:active {
+ background-color: #1565c0;
+}
+
+/* Dropdown-Bereich für Woche und Jahr */
+.custom-toolbar .dropdowns {
+ display: flex;
+ gap: 8px;
+ justify-content: center;
+ height: 30px;
+ font-size: 10px;
+ margin-top: 3.5px;
+ border-radius: 11px;
+}
+
+.custom-toolbar .dropdowns select {
+ padding: 8px 12px;
+ border-radius: 11px;
+ font-size: 10px;
+ background-color: #555555;
+ color: #ffffff;
+ cursor: pointer;
+ transition: border-color 0.2s;
+}
+
+.custom-toolbar .dropdowns select:hover {
+ border-color: #999;
+}
+
+.right-section,
+.view-switcher {
+ background-color: #717171;
+ height: 48px;
+ border-radius: 11px;
+ justify-items: center;
+ align-items: center;
+}
+
+.custom-toolbar .navigation-controls .handleWeek button {
+ background-color: #717171;
+ height: 30px;
+ width: 30px;
+ margin-bottom: 3.5px;
+}
+
+.view-change,
+.right-section {
+ background-color: #717171;
+ height: 48px;
+ padding: 0 8px;
+ border-radius: 11px;
+ justify-items: center;
+}
+
+.right-section .datepicker-box {
+ color: #000000;
+ background-color: #c6c6c6;
+ height: 36px;
+ border-radius: 11px;
+ font-size: 12px;
+ align-self: center;
+}
+
+.datepicker {
+ text-align: center;
+ height: 30px;
+}
+
+.datepicker-box {
+ z-index: 5;
+}
diff --git a/src/components/custom-toolbar.tsx b/src/components/custom-toolbar.tsx
new file mode 100644
index 0000000..36c8fff
--- /dev/null
+++ b/src/components/custom-toolbar.tsx
@@ -0,0 +1,260 @@
+import React, { useState, useEffect } from 'react';
+import './custom-toolbar.css';
+import { Button } from '@/components/ui/button';
+import DatePicker from 'react-datepicker';
+import 'react-datepicker/dist/react-datepicker.css';
+import { NavigateAction } from 'react-big-calendar';
+
+interface CustomToolbarProps {
+ //Aktuell angezeigtes Datum
+ date: Date;
+ //Aktuelle Ansicht
+ view: 'month' | 'week' | 'day' | 'agenda' | 'work_week';
+
+ onNavigate: (action: NavigateAction, newDate?: Date) => void;
+ //Ansichtwechsel
+ onView: (newView: 'month' | 'week' | 'day' | 'agenda' | 'work_week') => void;
+}
+
+const CustomToolbar: React.FC = ({
+ date,
+ view,
+ onNavigate,
+ onView,
+}) => {
+ //ISO-Wochennummer eines Datums ermitteln
+ const getISOWeek = (date: Date): number => {
+ const tmp = new Date(date.getTime());
+ //Datum so verschieben, dass der nächste Donnerstag erreicht wird (ISO: Woche beginnt am Montag)
+ tmp.setDate(tmp.getDate() + 4 - (tmp.getDay() || 7));
+ const yearStart = new Date(tmp.getFullYear(), 0, 1);
+ const weekNo = Math.ceil(
+ ((tmp.getTime() - yearStart.getTime()) / 86400000 + 1) / 7,
+ );
+ return weekNo;
+ };
+
+ //ISO-Wochenjahr eines Datums ermitteln
+ const getISOWeekYear = (date: Date): number => {
+ const tmp = new Date(date.getTime());
+ tmp.setDate(tmp.getDate() + 4 - (tmp.getDay() || 7));
+ return tmp.getFullYear();
+ };
+
+ //Ermittlung der Anzahl der Wochen im Jahr
+ const getISOWeeksInYear = (year: number): number => {
+ const d = new Date(year, 11, 31);
+ const week = getISOWeek(d);
+ return week === 1 ? getISOWeek(new Date(year, 11, 24)) : week;
+ };
+
+ const getDateOfISOWeek = (week: number, year: number): Date => {
+ const jan1 = new Date(year, 0, 1);
+ const dayOfWeek = jan1.getDay();
+ const isoDayOfWeek = dayOfWeek === 0 ? 7 : dayOfWeek;
+ let firstMonday: Date;
+ if (isoDayOfWeek <= 4) {
+ //1. Januar gehört zur ersten ISO-Woche (Montag dieser Woche bestimmen)
+ firstMonday = new Date(year, 0, 1 - isoDayOfWeek + 1);
+ } else {
+ //Ansonsten liegt der erste Montag in der darauffolgenden Woche
+ firstMonday = new Date(year, 0, 1 + (8 - isoDayOfWeek));
+ }
+ firstMonday.setDate(firstMonday.getDate() + (week - 1) * 7);
+ return firstMonday;
+ };
+
+ //Lokaler State für Woche und ISO-Wochenjahr (statt des reinen Kalenderjahrs)
+ const [selectedWeek, setSelectedWeek] = useState(getISOWeek(date));
+ const [selectedYear, setSelectedYear] = useState(
+ getISOWeekYear(date),
+ );
+
+ //Auswahl aktualisieren, wenn sich die Prop "date" ändert
+ useEffect(() => {
+ setSelectedWeek(getISOWeek(date));
+ setSelectedYear(getISOWeekYear(date));
+ }, [date]);
+
+ //Start (Montag) und Ende (Sonntag) der aktuell angezeigten Woche berechnen
+ const weekStartDate = getDateOfISOWeek(selectedWeek, selectedYear);
+ const weekEndDate = new Date(weekStartDate);
+ weekEndDate.setDate(weekStartDate.getDate() + 6);
+
+ //Ansichtwechsel
+ const handleViewChange = (newView: 'month' | 'week' | 'day' | 'agenda') => {
+ onView(newView);
+ };
+
+ //Today-Button aktualisiert das Datum im DatePicker auf das heutige
+ const handleToday = () => {
+ const today = new Date();
+ setSelectedDate(today);
+ setSelectedWeek(getISOWeek(today));
+ setSelectedYear(getISOWeekYear(today));
+ onNavigate('TODAY', today);
+ };
+
+ //Pfeiltaste nach Vorne
+ const handleNext = () => {
+ let newDate: Date;
+ if (view === 'day' || view === 'agenda') {
+ newDate = new Date(date);
+ newDate.setDate(newDate.getDate() + 1);
+ } else if (view === 'week') {
+ let newWeek = selectedWeek + 1;
+ let newYear = selectedYear;
+ if (newWeek > getISOWeeksInYear(selectedYear)) {
+ newYear = selectedYear + 1;
+ newWeek = 1;
+ }
+ setSelectedWeek(newWeek);
+ setSelectedYear(newYear);
+ newDate = getDateOfISOWeek(newWeek, newYear);
+ } else if (view === 'month') {
+ newDate = new Date(date.getFullYear(), date.getMonth() + 1, 1);
+ } else {
+ newDate = new Date(date);
+ }
+ //Datum im DatePicker aktualisieren
+ setSelectedDate(newDate);
+ onNavigate('DATE', newDate);
+ };
+
+ //Pfeiltaste nach Hinten
+ const handlePrev = () => {
+ let newDate: Date;
+ if (view === 'day' || view === 'agenda') {
+ newDate = new Date(date);
+ newDate.setDate(newDate.getDate() - 1);
+ } else if (view === 'week') {
+ let newWeek = selectedWeek - 1;
+ let newYear = selectedYear;
+ if (newWeek < 1) {
+ newYear = selectedYear - 1;
+ newWeek = getISOWeeksInYear(newYear);
+ }
+ setSelectedWeek(newWeek);
+ setSelectedYear(newYear);
+ newDate = getDateOfISOWeek(newWeek, newYear);
+ } else if (view === 'month') {
+ newDate = new Date(date.getFullYear(), date.getMonth() - 1, 1);
+ } else {
+ newDate = new Date(date);
+ }
+ //Datum im DatePicker aktualisieren
+ setSelectedDate(newDate);
+ onNavigate('DATE', newDate);
+ };
+
+ const [selectedDate, setSelectedDate] = useState(new Date());
+
+ const handleDateChange = (date: Date | null) => {
+ setSelectedDate(date);
+ if (date) {
+ if (view === 'week') {
+ const newWeek = getISOWeek(date);
+ const newYear = getISOWeekYear(date);
+ setSelectedWeek(newWeek);
+ setSelectedYear(newYear);
+ const newDate = getDateOfISOWeek(newWeek, newYear);
+ onNavigate('DATE', newDate);
+ } else if (view === 'day') {
+ onNavigate('DATE', date);
+ } else if (view === 'month') {
+ const newDate = new Date(date.getFullYear(), date.getMonth(), 1);
+ onNavigate('DATE', newDate);
+ } else if (view === 'agenda') {
+ onNavigate('DATE', date);
+ }
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default CustomToolbar;
diff --git a/src/components/misc/header.tsx b/src/components/misc/header.tsx
index ed53953..dd9e36d 100644
--- a/src/components/misc/header.tsx
+++ b/src/components/misc/header.tsx
@@ -45,7 +45,7 @@ export default function Header({
- {children}
+ {children}
);
}
diff --git a/src/components/react-big-calendar.css b/src/components/react-big-calendar.css
new file mode 100644
index 0000000..675898c
--- /dev/null
+++ b/src/components/react-big-calendar.css
@@ -0,0 +1,930 @@
+@charset "UTF-8";
+.rbc-btn {
+ color: inherit;
+ font: inherit;
+ margin: 0;
+}
+
+button.rbc-btn {
+ overflow: visible;
+ text-transform: none;
+ -webkit-appearance: button;
+ -moz-appearance: button;
+ appearance: button;
+ cursor: pointer;
+}
+
+button[disabled].rbc-btn {
+ cursor: not-allowed;
+}
+
+button.rbc-input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+.rbc-calendar {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ height: 100%;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-box-align: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+}
+
+.rbc-m-b-negative-3 {
+ margin-bottom: -3px;
+}
+
+.rbc-h-full {
+ height: 100%;
+}
+
+.rbc-calendar *,
+.rbc-calendar *:before,
+.rbc-calendar *:after {
+ -webkit-box-sizing: inherit;
+ box-sizing: inherit;
+}
+
+.rbc-abs-full,
+.rbc-row-bg {
+ overflow: hidden;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+
+.rbc-ellipsis,
+.rbc-show-more,
+.rbc-row-segment .rbc-event-content,
+.rbc-event-label {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.rbc-rtl {
+ direction: rtl;
+}
+
+.rbc-off-range {
+ color: #999999;
+}
+
+.rbc-off-range-bg {
+ background: #e6e6e6;
+}
+
+.rbc-header {
+ overflow: hidden;
+ -webkit-box-flex: 1;
+ -ms-flex: 1 0 0%;
+ flex: 1 0 0%;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ padding: 0 3px;
+ text-align: center;
+ vertical-align: middle;
+ font-weight: bold;
+ font-size: 90%;
+ min-height: 0;
+ border-bottom: 1px solid #ddd;
+}
+.rbc-header + .rbc-header {
+ border-left: 1px solid #c6c6c6; /*#ddd*/
+}
+.rbc-rtl .rbc-header + .rbc-header {
+ border-left-width: 0;
+ border-right: 1px solid #ddd;
+}
+.rbc-header > a,
+.rbc-header > a:active,
+.rbc-header > a:visited {
+ color: inherit;
+ text-decoration: none;
+}
+
+.rbc-button-link {
+ color: inherit;
+ background: none;
+ margin: 0;
+ padding: 0;
+ border: none;
+ cursor: pointer;
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ -ms-user-select: text;
+ user-select: text;
+}
+
+.rbc-row-content {
+ position: relative;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-user-select: none;
+ z-index: 4;
+}
+
+.rbc-row-content-scrollable {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ height: 100%;
+}
+.rbc-row-content-scrollable .rbc-row-content-scroll-container {
+ height: 100%;
+ overflow-y: scroll;
+ -ms-overflow-style: none; /* IE and Edge */
+ scrollbar-width: none; /* Firefox */
+ -ms-overflow-style: none; /* IE and Edge */
+ scrollbar-width: none; /* Firefox */
+ /* Hide scrollbar for Chrome, Safari and Opera */
+}
+.rbc-row-content-scrollable
+ .rbc-row-content-scroll-container::-webkit-scrollbar {
+ display: none;
+}
+
+.rbc-today {
+ background-color: #5770ff; /*#eaf6ff*/
+}
+/*Own changes 10*/
+.rbc-allday-cell .rbc-row-bg .rbc-day-bg.rbc-today {
+ background-color: transparent !important;
+ /*border: none !important;*/
+}
+/*Own changes 10*/
+
+/*Own changes 11*/
+.rbc-time-header-cell .rbc-header:first-child.rbc-today {
+ border-top-left-radius: 11px !important;
+}
+
+.rbc-time-header-cell .rbc-header:last-child.rbc-today {
+ border-top-right-radius: 11px !important;
+}
+/*Own changes 11*/
+
+.rbc-toolbar {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ margin-bottom: 10px;
+ font-size: 16px;
+}
+.rbc-toolbar .rbc-toolbar-label {
+ -webkit-box-flex: 1;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ padding: 0 10px;
+ text-align: center;
+
+ /*Own changes 01*/
+ background-color: #717171;
+ color: #ffffff;
+ /*Own changes 01*/
+}
+.rbc-toolbar button {
+ color: #373a3c;
+ display: inline-block;
+ margin: 0;
+ text-align: center;
+ vertical-align: middle;
+ background: none;
+ background-image: none;
+ border: 1px solid #ccc;
+ padding: 0.375rem 1rem;
+ border-radius: 4px;
+ line-height: normal;
+ white-space: nowrap;
+}
+.rbc-toolbar button:active,
+.rbc-toolbar button.rbc-active {
+ background-image: none;
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.rbc-toolbar button:active:hover,
+.rbc-toolbar button:active:focus,
+.rbc-toolbar button.rbc-active:hover,
+.rbc-toolbar button.rbc-active:focus {
+ color: #373a3c;
+ background-color: #d4d4d4;
+ border-color: #8c8c8c;
+}
+.rbc-toolbar button:focus {
+ color: #373a3c;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.rbc-toolbar button:hover {
+ color: #373a3c;
+ cursor: pointer;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+
+.rbc-btn-group {
+ display: inline-block;
+ white-space: nowrap;
+}
+.rbc-btn-group > button:first-child:not(:last-child) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+
+ /*Own changes 02*/
+ background-color: #c6c6c6;
+ color: #000000;
+ /*Own changes 02*/
+}
+.rbc-btn-group > button:last-child:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+
+ /*Own changes 03*/
+ background-color: #c6c6c6;
+ color: #000000;
+ /*Own changes 03*/
+}
+.rbc-rtl .rbc-btn-group > button:first-child:not(:last-child) {
+ border-radius: 4px;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+.rbc-rtl .rbc-btn-group > button:last-child:not(:first-child) {
+ border-radius: 4px;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.rbc-btn-group > button:not(:first-child):not(:last-child) {
+ border-radius: 0;
+
+ /*Own changes 04*/
+ background-color: #c6c6c6;
+ color: #000000;
+ /*Own changes 04*/
+}
+.rbc-btn-group button + button {
+ margin-left: -1px;
+}
+.rbc-rtl .rbc-btn-group button + button {
+ margin-left: 0;
+ margin-right: -1px;
+}
+.rbc-btn-group + .rbc-btn-group,
+.rbc-btn-group + button {
+ margin-left: 10px;
+}
+
+@media (max-width: 767px) {
+ .rbc-toolbar {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ }
+}
+.rbc-event,
+.rbc-day-slot .rbc-background-event {
+ border: none;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ margin: 0;
+ padding: 2px 5px;
+ background-color: #3174ad;
+ border-radius: 5px;
+ color: #fff;
+ cursor: pointer;
+ width: 100%;
+ text-align: left;
+}
+.rbc-slot-selecting .rbc-event,
+.rbc-slot-selecting .rbc-day-slot .rbc-background-event,
+.rbc-day-slot .rbc-slot-selecting .rbc-background-event {
+ cursor: inherit;
+ pointer-events: none;
+}
+.rbc-event.rbc-selected,
+.rbc-day-slot .rbc-selected.rbc-background-event {
+ background-color: #265985;
+}
+.rbc-event:focus,
+.rbc-day-slot .rbc-background-event:focus {
+ outline: 5px auto #3b99fc;
+}
+
+.rbc-event-label {
+ font-size: 80%;
+}
+
+.rbc-event-overlaps {
+ -webkit-box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5);
+ box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5);
+}
+
+.rbc-event-continues-prior {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.rbc-event-continues-after {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.rbc-event-continues-earlier {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.rbc-event-continues-later {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.rbc-row {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: row;
+ flex-direction: row;
+}
+
+.rbc-row-segment {
+ padding: 0 1px 1px 1px;
+}
+.rbc-selected-cell {
+ background-color: rgba(0, 0, 0, 0.1);
+}
+
+.rbc-show-more {
+ background-color: rgba(255, 255, 255, 0.3);
+ z-index: 4;
+ font-weight: bold;
+ font-size: 85%;
+ height: auto;
+ line-height: normal;
+ color: #3174ad;
+}
+.rbc-show-more:hover,
+.rbc-show-more:focus {
+ color: #265985;
+}
+
+.rbc-month-view {
+ position: relative;
+ border: 1px solid #ddd;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-box-flex: 1;
+ -ms-flex: 1 0 0px;
+ flex: 1 0 0;
+ width: 100%;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-user-select: none;
+ height: 100%;
+}
+
+.rbc-month-header {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: row;
+ flex-direction: row;
+}
+
+.rbc-month-row {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ position: relative;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-box-flex: 1;
+ -ms-flex: 1 0 0px;
+ flex: 1 0 0;
+ -ms-flex-preferred-size: 0px;
+ flex-basis: 0px;
+ overflow: hidden;
+ height: 100%;
+}
+.rbc-month-row + .rbc-month-row {
+ border-top: 1px solid #ddd;
+}
+
+.rbc-date-cell {
+ -webkit-box-flex: 1;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0;
+ min-width: 0;
+ padding-right: 5px;
+ text-align: right;
+}
+.rbc-date-cell.rbc-now {
+ font-weight: bold;
+}
+.rbc-date-cell > a,
+.rbc-date-cell > a:active,
+.rbc-date-cell > a:visited {
+ color: inherit;
+ text-decoration: none;
+}
+
+.rbc-row-bg {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: row;
+ flex-direction: row;
+ -webkit-box-flex: 1;
+ -ms-flex: 1 0 0px;
+ flex: 1 0 0;
+ overflow: hidden;
+ right: 1px;
+}
+
+.rbc-day-bg {
+ -webkit-box-flex: 1;
+ -ms-flex: 1 0 0%;
+ flex: 1 0 0%;
+}
+.rbc-day-bg + .rbc-day-bg {
+ border-left: 1px solid #ddd;
+}
+.rbc-rtl .rbc-day-bg + .rbc-day-bg {
+ border-left-width: 0;
+ border-right: 1px solid #ddd;
+}
+
+.rbc-overlay {
+ position: absolute;
+ z-index: 5;
+ border: 1px solid #e5e5e5;
+ background-color: #fff;
+ -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.25);
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.25);
+ padding: 10px;
+}
+.rbc-overlay > * + * {
+ margin-top: 1px;
+}
+
+.rbc-overlay-header {
+ border-bottom: 1px solid #e5e5e5;
+ margin: -10px -10px 5px -10px;
+ padding: 2px 10px;
+}
+
+.rbc-agenda-view {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-box-flex: 1;
+ -ms-flex: 1 0 0px;
+ flex: 1 0 0;
+ overflow: auto;
+}
+.rbc-agenda-view table.rbc-agenda-table {
+ width: 100%;
+ border: 1px solid #ddd;
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+.rbc-agenda-view table.rbc-agenda-table tbody > tr > td {
+ padding: 5px 10px;
+ vertical-align: top;
+}
+.rbc-agenda-view table.rbc-agenda-table .rbc-agenda-time-cell {
+ padding-left: 15px;
+ padding-right: 15px;
+ text-transform: lowercase;
+}
+.rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td,
+.rbc-agenda-view table.rbc-agenda-table tbody > tr > td.rbc-agenda-time-cell {
+ border-left: 1px solid #ddd;
+}
+.rbc-rtl .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
+ border-left-width: 0;
+ border-right: 1px solid #ddd;
+}
+.rbc-agenda-view table.rbc-agenda-table tbody > tr + tr {
+ border-top: 1px solid #ddd;
+}
+.rbc-agenda-view table.rbc-agenda-table thead > tr > th {
+ padding: 3px 5px;
+ text-align: left;
+ border-bottom: 1px solid #ddd;
+}
+.rbc-rtl .rbc-agenda-view table.rbc-agenda-table thead > tr > th {
+ text-align: right;
+}
+
+.rbc-agenda-time-cell {
+ text-transform: lowercase;
+}
+.rbc-agenda-time-cell .rbc-continues-after:after {
+ content: ' »';
+}
+.rbc-agenda-time-cell .rbc-continues-prior:before {
+ content: '« ';
+}
+
+.rbc-agenda-date-cell,
+.rbc-agenda-time-cell {
+ white-space: nowrap;
+}
+
+.rbc-agenda-event-cell {
+ width: 100%;
+}
+
+.rbc-time-column {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ min-height: 100%;
+
+ /*Own changes 06*/
+ background-color: #383838;
+ /*Own changes 06*/
+}
+.rbc-time-column .rbc-timeslot-group {
+ -webkit-box-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+}
+
+.rbc-timeslot-group {
+ border-bottom: 1px solid #8d8d8d; /*#ddd*/
+ min-height: 40px;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-flow: column nowrap;
+ flex-flow: column nowrap;
+}
+
+.rbc-time-gutter,
+.rbc-header-gutter {
+ -webkit-box-flex: 0;
+ -ms-flex: none;
+ flex: none;
+
+ /*Own changes 07*/
+ background-color: #8d8d8d;
+ /*Own changes 07*/
+}
+
+.rbc-label {
+ padding: 0 5px;
+}
+
+.rbc-day-slot {
+ position: relative;
+}
+.rbc-day-slot .rbc-events-container {
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ right: 0;
+ margin-right: 10px;
+ top: 0;
+}
+.rbc-day-slot .rbc-events-container.rbc-rtl {
+ left: 10px;
+ right: 0;
+}
+.rbc-day-slot .rbc-event,
+.rbc-day-slot .rbc-background-event {
+ border: 1px solid #265985;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ max-height: 100%;
+ min-height: 20px;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-flow: column wrap;
+ flex-flow: column wrap;
+ -webkit-box-align: start;
+ -ms-flex-align: start;
+ align-items: flex-start;
+ overflow: hidden;
+ position: absolute;
+}
+.rbc-day-slot .rbc-background-event {
+ opacity: 0.75;
+}
+.rbc-day-slot .rbc-event-label {
+ -webkit-box-flex: 0;
+ -ms-flex: none;
+ flex: none;
+ padding-right: 5px;
+ width: auto;
+}
+.rbc-day-slot .rbc-event-content {
+ width: 100%;
+ -webkit-box-flex: 1;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0;
+ word-wrap: break-word;
+ line-height: 1;
+ height: 100%;
+ min-height: 1em;
+}
+.rbc-day-slot .rbc-time-slot {
+ border-top: 1px solid #383838; /*#f7f7f7*/
+}
+
+.rbc-time-view-resources .rbc-time-gutter,
+.rbc-time-view-resources .rbc-time-header-gutter {
+ position: sticky;
+ left: 0;
+ background-color: white;
+ border-right: 1px solid #ddd;
+ z-index: 10;
+ margin-right: -1px;
+}
+.rbc-time-view-resources .rbc-time-header {
+ overflow: hidden;
+}
+.rbc-time-view-resources .rbc-time-header-content {
+ min-width: auto;
+ -webkit-box-flex: 1;
+ -ms-flex: 1 0 0px;
+ flex: 1 0 0;
+ -ms-flex-preferred-size: 0px;
+ flex-basis: 0px;
+}
+.rbc-time-view-resources .rbc-time-header-cell-single-day {
+ display: none;
+}
+.rbc-time-view-resources .rbc-day-slot {
+ min-width: 140px;
+}
+.rbc-time-view-resources .rbc-header,
+.rbc-time-view-resources .rbc-day-bg {
+ width: 140px;
+ -webkit-box-flex: 1;
+ -ms-flex: 1 1 0px;
+ flex: 1 1 0;
+ -ms-flex-preferred-size: 0 px;
+ flex-basis: 0 px;
+}
+
+.rbc-time-header-content + .rbc-time-header-content {
+ margin-left: -1px;
+}
+
+.rbc-time-slot {
+ -webkit-box-flex: 1;
+ -ms-flex: 1 0 0px;
+ flex: 1 0 0;
+}
+.rbc-time-slot.rbc-now {
+ font-weight: bold;
+}
+
+.rbc-day-header {
+ text-align: center;
+}
+
+.rbc-slot-selection {
+ z-index: 10;
+ position: absolute;
+ background-color: rgba(0, 0, 0, 0.5);
+ color: white;
+ font-size: 75%;
+ width: 100%;
+ padding: 3px;
+}
+
+.rbc-slot-selecting {
+ cursor: move;
+}
+
+.rbc-time-view {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-box-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ width: 100%;
+ min-height: 0;
+}
+.rbc-time-view .rbc-time-gutter {
+ white-space: nowrap;
+ text-align: right;
+}
+.rbc-time-view .rbc-allday-cell {
+ -webkit-box-sizing: content-box;
+ box-sizing: content-box;
+ width: 100%;
+ height: 100%;
+ position: relative;
+
+ /*Own changes 05*/
+ background-color: #555555;
+ /*Own changes 05*/
+}
+.rbc-time-view .rbc-allday-cell + .rbc-allday-cell {
+ border-left: 1px solid #ddd;
+}
+.rbc-time-view .rbc-allday-events {
+ position: relative;
+ z-index: 4;
+}
+.rbc-time-view .rbc-row {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ min-height: 20px;
+}
+
+.rbc-time-header {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex: 0;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: row;
+ flex-direction: row;
+}
+.rbc-rtl .rbc-time-header.rbc-overflowing {
+ border-right-width: 0;
+ border-left: 1px solid #ddd;
+}
+.rbc-time-header > .rbc-row:first-child {
+ border-bottom: 1px solid #ddd;
+}
+.rbc-time-header > .rbc-row.rbc-row-resource {
+ border-bottom: 1px solid #ddd;
+}
+
+.rbc-time-header-cell-single-day {
+ display: none;
+}
+
+.rbc-time-header-content {
+ -webkit-box-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ min-width: 0;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ border-left: 1px solid #ddd;
+
+ /*Own changes 08*/
+ background-color: #c6c6c6;
+ color: #000000;
+ border-top-left-radius: 11px;
+ border-top-right-radius: 11px;
+ /*Own changes 08*/
+}
+.rbc-rtl .rbc-time-header-content {
+ border-left-width: 0;
+ border-right: 1px solid #ddd;
+}
+.rbc-time-header-content > .rbc-row.rbc-row-resource {
+ border-bottom: 1px solid #ddd;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.rbc-time-content {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex: 1;
+ -ms-flex: 1 0 0%;
+ flex: 1 0 0%;
+ -webkit-box-align: start;
+ -ms-flex-align: start;
+ align-items: flex-start;
+ width: 100%;
+ overflow-y: auto;
+ position: relative;
+}
+
+.rbc-time-header-content {
+ border-bottom: 2px solid #717171; /*#ddd*/
+}
+
+.rbc-time-column :last-child {
+ border-bottom: 0;
+}
+
+.rbc-time-content > .rbc-time-gutter {
+ -webkit-box-flex: 0;
+ -ms-flex: none;
+ flex: none;
+
+ /*Own changes 09*/
+ border-top-left-radius: 11px;
+ border-bottom-left-radius: 11px;
+ /*Own changes 09*/
+}
+.rbc-time-content > * + * > * {
+ border-left: 1px solid #c6c6c6; /*#ddd*/
+}
+.rbc-rtl .rbc-time-content > * + * > * {
+ border-left-width: 0;
+ border-right: 1px solid #ddd;
+}
+.rbc-time-content > .rbc-day-slot {
+ width: 100%;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-user-select: none;
+}
+
+.rbc-current-time-indicator {
+ position: absolute;
+ z-index: 3;
+ left: 0;
+ right: 0;
+ height: 1px;
+ background-color: #74ad31;
+ pointer-events: none;
+}
+
+.rbc-resource-grouping.rbc-time-header-content {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+}
+.rbc-resource-grouping .rbc-row .rbc-header {
+ width: 141px;
+}
+
+/*# sourceMappingURL=react-big-calendar.css.map */
diff --git a/yarn.lock b/yarn.lock
index 5ef4d93..74ff1df 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -156,7 +156,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.3.1":
+"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.7":
version: 7.27.6
resolution: "@babel/runtime@npm:7.27.6"
checksum: 10c0/89726be83f356f511dcdb74d3ea4d873a5f0cf0017d4530cb53aa27380c01ca102d573eff8b8b77815e624b1f8c24e7f0311834ad4fb632c90a770fda00bd4c8
@@ -539,7 +539,7 @@ __metadata:
languageName: node
linkType: hard
-"@floating-ui/react-dom@npm:^2.0.0":
+"@floating-ui/react-dom@npm:^2.0.0, @floating-ui/react-dom@npm:^2.1.3":
version: 2.1.3
resolution: "@floating-ui/react-dom@npm:2.1.3"
dependencies:
@@ -551,6 +551,20 @@ __metadata:
languageName: node
linkType: hard
+"@floating-ui/react@npm:^0.27.3":
+ version: 0.27.12
+ resolution: "@floating-ui/react@npm:0.27.12"
+ dependencies:
+ "@floating-ui/react-dom": "npm:^2.1.3"
+ "@floating-ui/utils": "npm:^0.2.9"
+ tabbable: "npm:^6.0.0"
+ peerDependencies:
+ react: ">=17.0.0"
+ react-dom: ">=17.0.0"
+ checksum: 10c0/da453965074bd4ded8e3de97ceb2c0833df8df2ecd9eff5ae4d336413443ea5abde5c9e37b092956901b97e7b47f9138d51d4896fa82da68e77eb0090289bf64
+ languageName: node
+ linkType: hard
+
"@floating-ui/utils@npm:^0.2.9":
version: 0.2.9
resolution: "@floating-ui/utils@npm:0.2.9"
@@ -1267,6 +1281,13 @@ __metadata:
languageName: node
linkType: hard
+"@popperjs/core@npm:^2.11.6":
+ version: 2.11.8
+ resolution: "@popperjs/core@npm:2.11.8"
+ checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63
+ languageName: node
+ linkType: hard
+
"@prisma/client@npm:^6.9.0":
version: 6.10.1
resolution: "@prisma/client@npm:6.10.1"
@@ -2175,6 +2196,17 @@ __metadata:
languageName: node
linkType: hard
+"@restart/hooks@npm:^0.4.7":
+ version: 0.4.16
+ resolution: "@restart/hooks@npm:0.4.16"
+ dependencies:
+ dequal: "npm:^2.0.3"
+ peerDependencies:
+ react: ">=16.8.0"
+ checksum: 10c0/b6a0f1db046cdec28737092ab5defdfb25fad498d37d218646f7f123aed02a5078b1c89ae631bda14d9ee35f7bb8c9e0f15379b1a45003144dc30cd15e8ba668
+ languageName: node
+ linkType: hard
+
"@rtsao/scc@npm:^1.1.0":
version: 1.1.0
resolution: "@rtsao/scc@npm:1.1.0"
@@ -3282,6 +3314,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/date-arithmetic@npm:*":
+ version: 4.1.4
+ resolution: "@types/date-arithmetic@npm:4.1.4"
+ checksum: 10c0/4ee68b5a422bd5f1cf08923d18a08db558e653bbdc597677e0465a330f1e807da0e79b06b72651b62b19b4b922a779470f84657cbd765805f84f33af518b408f
+ languageName: node
+ linkType: hard
+
"@types/es-aggregate-error@npm:^1.0.2":
version: 1.0.6
resolution: "@types/es-aggregate-error@npm:1.0.6"
@@ -3348,6 +3387,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/prop-types@npm:*":
+ version: 15.7.15
+ resolution: "@types/prop-types@npm:15.7.15"
+ checksum: 10c0/b59aad1ad19bf1733cf524fd4e618196c6c7690f48ee70a327eb450a42aab8e8a063fbe59ca0a5701aebe2d92d582292c0fb845ea57474f6a15f6994b0e260b2
+ languageName: node
+ linkType: hard
+
"@types/ramda@npm:~0.30.0":
version: 0.30.2
resolution: "@types/ramda@npm:0.30.2"
@@ -3357,6 +3403,17 @@ __metadata:
languageName: node
linkType: hard
+"@types/react-big-calendar@npm:^1":
+ version: 1.16.2
+ resolution: "@types/react-big-calendar@npm:1.16.2"
+ dependencies:
+ "@types/date-arithmetic": "npm:*"
+ "@types/prop-types": "npm:*"
+ "@types/react": "npm:*"
+ checksum: 10c0/a2ea4116b999cf8dac014fdc4a9f0c10fb2fd9d9886857e93649c0a601057e93e73e3d9096a756b76e227e08f68e4c979f91bf4cfd96692aea3ab7f3df0745d0
+ languageName: node
+ linkType: hard
+
"@types/react-dom@npm:19.1.6":
version: 19.1.6
resolution: "@types/react-dom@npm:19.1.6"
@@ -3366,7 +3423,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/react@npm:*, @types/react@npm:19.1.8":
+"@types/react@npm:*, @types/react@npm:19.1.8, @types/react@npm:>=16.9.11":
version: 19.1.8
resolution: "@types/react@npm:19.1.8"
dependencies:
@@ -3440,6 +3497,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/warning@npm:^3.0.0":
+ version: 3.0.3
+ resolution: "@types/warning@npm:3.0.3"
+ checksum: 10c0/82c1235bd05d7f6940f80012404844e225d589ad338aa4585b231a2c8deacc695b683f4168757c82c10047b81854cbeaaeefd60536dd67bb48f8a65e20410652
+ languageName: node
+ linkType: hard
+
"@types/webpack-env@npm:1.18.8":
version: 1.18.8
resolution: "@types/webpack-env@npm:1.18.8"
@@ -4521,6 +4585,13 @@ __metadata:
languageName: node
linkType: hard
+"clsx@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "clsx@npm:1.2.1"
+ checksum: 10c0/34dead8bee24f5e96f6e7937d711978380647e936a22e76380290e35486afd8634966ce300fc4b74a32f3762c7d4c0303f442c3e259f4ce02374eb0c82834f27
+ languageName: node
+ linkType: hard
+
"clsx@npm:^2.1.1":
version: 2.1.1
resolution: "clsx@npm:2.1.1"
@@ -4809,6 +4880,13 @@ __metadata:
languageName: node
linkType: hard
+"date-arithmetic@npm:^4.1.0":
+ version: 4.1.0
+ resolution: "date-arithmetic@npm:4.1.0"
+ checksum: 10c0/697774a1a6a1b226004b5527326599c01a095bf715a0d43089e0493a565a91e7f4342b1b73b855c0e7b0caaf4bc947a61bc35ec60d162d52ef3c3c08eab26b6e
+ languageName: node
+ linkType: hard
+
"date-fns-jalali@npm:4.1.0-0":
version: 4.1.0-0
resolution: "date-fns-jalali@npm:4.1.0-0"
@@ -4823,7 +4901,7 @@ __metadata:
languageName: node
linkType: hard
-"dayjs@npm:^1.10.4":
+"dayjs@npm:^1.10.4, dayjs@npm:^1.11.7":
version: 1.11.13
resolution: "dayjs@npm:1.11.13"
checksum: 10c0/a3caf6ac8363c7dade9d1ee797848ddcf25c1ace68d9fe8678ecf8ba0675825430de5d793672ec87b24a69bf04a1544b176547b2539982275d5542a7955f35b7
@@ -4908,6 +4986,13 @@ __metadata:
languageName: node
linkType: hard
+"dequal@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "dequal@npm:2.0.3"
+ checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888
+ languageName: node
+ linkType: hard
+
"detect-libc@npm:^2.0.3, detect-libc@npm:^2.0.4":
version: 2.0.4
resolution: "detect-libc@npm:2.0.4"
@@ -4956,6 +5041,16 @@ __metadata:
languageName: node
linkType: hard
+"dom-helpers@npm:^5.2.0, dom-helpers@npm:^5.2.1":
+ version: 5.2.1
+ resolution: "dom-helpers@npm:5.2.1"
+ dependencies:
+ "@babel/runtime": "npm:^7.8.7"
+ csstype: "npm:^3.0.2"
+ checksum: 10c0/f735074d66dd759b36b158fa26e9d00c9388ee0e8c9b16af941c38f014a37fc80782de83afefd621681b19ac0501034b4f1c4a3bff5caa1b8667f0212b5e124c
+ languageName: node
+ linkType: hard
+
"dompurify@npm:=3.2.4":
version: 3.2.4
resolution: "dompurify@npm:3.2.4"
@@ -6211,6 +6306,13 @@ __metadata:
languageName: node
linkType: hard
+"globalize@npm:^0.1.1":
+ version: 0.1.1
+ resolution: "globalize@npm:0.1.1"
+ checksum: 10c0/6d4687e7c52a38e7f16f77339aef9b3364c34ce8cc1c8b8495b76418013252eaf5b2453fbc2d8bb9e6e56c739262665484dc7ac51b729501ff0a3b822730116b
+ languageName: node
+ linkType: hard
+
"globals@npm:^14.0.0":
version: 14.0.0
resolution: "globals@npm:14.0.0"
@@ -6526,7 +6628,7 @@ __metadata:
languageName: node
linkType: hard
-"invariant@npm:^2.2.2":
+"invariant@npm:^2.2.2, invariant@npm:^2.2.4":
version: 2.2.4
resolution: "invariant@npm:2.2.4"
dependencies:
@@ -7318,6 +7420,13 @@ __metadata:
languageName: node
linkType: hard
+"lodash-es@npm:^4.17.21":
+ version: 4.17.21
+ resolution: "lodash-es@npm:4.17.21"
+ checksum: 10c0/fb407355f7e6cd523a9383e76e6b455321f0f153a6c9625e21a8827d10c54c2a2341bd2ae8d034358b60e07325e1330c14c224ff582d04612a46a4f0479ff2f2
+ languageName: node
+ linkType: hard
+
"lodash.debounce@npm:^4":
version: 4.0.8
resolution: "lodash.debounce@npm:4.0.8"
@@ -7489,6 +7598,13 @@ __metadata:
languageName: node
linkType: hard
+"luxon@npm:^3.2.1":
+ version: 3.6.1
+ resolution: "luxon@npm:3.6.1"
+ checksum: 10c0/906d57a9dc4d1de9383f2e9223e378c298607c1b4d17b6657b836a3cd120feb1c1de3b5d06d846a3417e1ca764de8476e8c23b3cd4083b5cdb870adcb06a99d5
+ languageName: node
+ linkType: hard
+
"magic-string@npm:^0.30.17":
version: 0.30.17
resolution: "magic-string@npm:0.30.17"
@@ -7586,6 +7702,7 @@ __metadata:
"@tanstack/react-query": "npm:^5.80.7"
"@types/node": "npm:22.15.33"
"@types/react": "npm:19.1.8"
+ "@types/react-big-calendar": "npm:^1"
"@types/react-dom": "npm:19.1.6"
"@types/swagger-ui-react": "npm:5"
"@types/webpack-env": "npm:1.18.8"
@@ -7608,9 +7725,12 @@ __metadata:
postcss: "npm:8.5.6"
prettier: "npm:3.5.3"
prisma: "npm:6.10.1"
- react: "npm:^19.0.0"
+ react: "npm:^19.1.0"
+ react-big-calendar: "npm:^1.18.0"
+ react-datepicker: "npm:^8.4.0"
react-day-picker: "npm:^9.7.0"
react-dom: "npm:^19.0.0"
+ react-error-boundary: "npm:^6.0.0"
react-hook-form: "npm:^7.56.4"
sonner: "npm:^2.0.5"
swagger-ui-react: "npm:^5.24.1"
@@ -7621,9 +7741,17 @@ __metadata:
tw-animate-css: "npm:1.3.4"
typescript: "npm:^5.8.3"
zod: "npm:^3.25.60"
+ zod-validation-error: "npm:^3.5.2"
languageName: unknown
linkType: soft
+"memoize-one@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "memoize-one@npm:6.0.0"
+ checksum: 10c0/45c88e064fd715166619af72e8cf8a7a17224d6edf61f7a8633d740ed8c8c0558a4373876c9b8ffc5518c2b65a960266adf403cc215cb1e90f7e262b58991f54
+ languageName: node
+ linkType: hard
+
"merge-stream@npm:^2.0.0":
version: 2.0.0
resolution: "merge-stream@npm:2.0.0"
@@ -7808,6 +7936,22 @@ __metadata:
languageName: node
linkType: hard
+"moment-timezone@npm:^0.5.40":
+ version: 0.5.48
+ resolution: "moment-timezone@npm:0.5.48"
+ dependencies:
+ moment: "npm:^2.29.4"
+ checksum: 10c0/ab14ec9d94bc33f29ac18e5417b7f8aca0b17130b952c5cc9697b8fea839e5ece9313af5fd3c9703a05db472b1560ddbfc7ad2aa24aac9afd047d6da6c3c6033
+ languageName: node
+ linkType: hard
+
+"moment@npm:^2.29.4":
+ version: 2.30.1
+ resolution: "moment@npm:2.30.1"
+ checksum: 10c0/865e4279418c6de666fca7786607705fd0189d8a7b7624e2e56be99290ac846f90878a6f602e34b4e0455c549b85385b1baf9966845962b313699e7cb847543a
+ languageName: node
+ linkType: hard
+
"ms@npm:^2.1.1, ms@npm:^2.1.3":
version: 2.1.3
resolution: "ms@npm:2.1.3"
@@ -8657,7 +8801,7 @@ __metadata:
languageName: node
linkType: hard
-"prop-types@npm:^15.8.1":
+"prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@@ -8773,6 +8917,33 @@ __metadata:
languageName: node
linkType: hard
+"react-big-calendar@npm:^1.18.0":
+ version: 1.19.4
+ resolution: "react-big-calendar@npm:1.19.4"
+ dependencies:
+ "@babel/runtime": "npm:^7.20.7"
+ clsx: "npm:^1.2.1"
+ date-arithmetic: "npm:^4.1.0"
+ dayjs: "npm:^1.11.7"
+ dom-helpers: "npm:^5.2.1"
+ globalize: "npm:^0.1.1"
+ invariant: "npm:^2.2.4"
+ lodash: "npm:^4.17.21"
+ lodash-es: "npm:^4.17.21"
+ luxon: "npm:^3.2.1"
+ memoize-one: "npm:^6.0.0"
+ moment: "npm:^2.29.4"
+ moment-timezone: "npm:^0.5.40"
+ prop-types: "npm:^15.8.1"
+ react-overlays: "npm:^5.2.1"
+ uncontrollable: "npm:^7.2.1"
+ peerDependencies:
+ react: ^16.14.0 || ^17 || ^18 || ^19
+ react-dom: ^16.14.0 || ^17 || ^18 || ^19
+ checksum: 10c0/78730e6396c06a27b24af860fa64d063f6407ccd12546116eb8cb2f274d827891c68a701b9c83f9903f63e5dea03fb6a3dd46d6a0a9186b3ab2f7e1d994fe86b
+ languageName: node
+ linkType: hard
+
"react-copy-to-clipboard@npm:5.1.0":
version: 5.1.0
resolution: "react-copy-to-clipboard@npm:5.1.0"
@@ -8785,6 +8956,20 @@ __metadata:
languageName: node
linkType: hard
+"react-datepicker@npm:^8.4.0":
+ version: 8.4.0
+ resolution: "react-datepicker@npm:8.4.0"
+ dependencies:
+ "@floating-ui/react": "npm:^0.27.3"
+ clsx: "npm:^2.1.1"
+ date-fns: "npm:^4.1.0"
+ peerDependencies:
+ react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc
+ react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc
+ checksum: 10c0/e96ba4f2b54476f66bfa33aa0c21729095c83d293671b07a9ddd96ab48dad85b6530acc5ca016e83ef8907feeebfefb7133bf7a02dc550175c48c5d9f66d70ac
+ languageName: node
+ linkType: hard
+
"react-day-picker@npm:^9.7.0":
version: 9.7.0
resolution: "react-day-picker@npm:9.7.0"
@@ -8821,6 +9006,17 @@ __metadata:
languageName: node
linkType: hard
+"react-error-boundary@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "react-error-boundary@npm:6.0.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.12.5"
+ peerDependencies:
+ react: ">=16.13.1"
+ checksum: 10c0/1914d600dee95a14f14af4afe9867b0d35c26c4f7826d23208800ba2a99728659029aad60a6ef95e13430b4d79c2c4c9b3585f50bf508450478760d2e4e732d8
+ languageName: node
+ linkType: hard
+
"react-hook-form@npm:^7.56.4":
version: 7.58.1
resolution: "react-hook-form@npm:7.58.1"
@@ -8868,6 +9064,32 @@ __metadata:
languageName: node
linkType: hard
+"react-lifecycles-compat@npm:^3.0.4":
+ version: 3.0.4
+ resolution: "react-lifecycles-compat@npm:3.0.4"
+ checksum: 10c0/1d0df3c85af79df720524780f00c064d53a9dd1899d785eddb7264b378026979acbddb58a4b7e06e7d0d12aa1494fd5754562ee55d32907b15601068dae82c27
+ languageName: node
+ linkType: hard
+
+"react-overlays@npm:^5.2.1":
+ version: 5.2.1
+ resolution: "react-overlays@npm:5.2.1"
+ dependencies:
+ "@babel/runtime": "npm:^7.13.8"
+ "@popperjs/core": "npm:^2.11.6"
+ "@restart/hooks": "npm:^0.4.7"
+ "@types/warning": "npm:^3.0.0"
+ dom-helpers: "npm:^5.2.0"
+ prop-types: "npm:^15.7.2"
+ uncontrollable: "npm:^7.2.1"
+ warning: "npm:^4.0.3"
+ peerDependencies:
+ react: ">=16.3.0"
+ react-dom: ">=16.3.0"
+ checksum: 10c0/61836490040cfcdebc792b6eddcfac47b7b7e159f99304165371e9eb389a6875f20ddba3433421413ccfb918e8da6042ab2829f9b1f6f5dd9f8476aa16ddcfbe
+ languageName: node
+ linkType: hard
+
"react-redux@npm:^9.2.0":
version: 9.2.0
resolution: "react-redux@npm:9.2.0"
@@ -8954,7 +9176,7 @@ __metadata:
languageName: node
linkType: hard
-"react@npm:^19.0.0":
+"react@npm:^19.1.0":
version: 19.1.0
resolution: "react@npm:19.1.0"
checksum: 10c0/530fb9a62237d54137a13d2cfb67a7db6a2156faed43eecc423f4713d9b20c6f2728b026b45e28fcd72e8eadb9e9ed4b089e99f5e295d2f0ad3134251bdd3698
@@ -10041,6 +10263,13 @@ __metadata:
languageName: node
linkType: hard
+"tabbable@npm:^6.0.0":
+ version: 6.2.0
+ resolution: "tabbable@npm:6.2.0"
+ checksum: 10c0/ced8b38f05f2de62cd46836d77c2646c42b8c9713f5bd265daf0e78ff5ac73d3ba48a7ca45f348bafeef29b23da7187c72250742d37627883ef89cbd7fa76898
+ languageName: node
+ linkType: hard
+
"tailwind-merge@npm:^3.2.0":
version: 3.3.1
resolution: "tailwind-merge@npm:3.3.1"
@@ -10510,6 +10739,20 @@ __metadata:
languageName: node
linkType: hard
+"uncontrollable@npm:^7.2.1":
+ version: 7.2.1
+ resolution: "uncontrollable@npm:7.2.1"
+ dependencies:
+ "@babel/runtime": "npm:^7.6.3"
+ "@types/react": "npm:>=16.9.11"
+ invariant: "npm:^2.2.4"
+ react-lifecycles-compat: "npm:^3.0.4"
+ peerDependencies:
+ react: ">=15.0.0"
+ checksum: 10c0/81473e892027a99f1ead6b9afd16db65097651cd36c4b6db710728f206f1fc4b82ba9170ecb4a1127a23857e01ba51c0194d0a7cfeecfea61ba9418e0276cb56
+ languageName: node
+ linkType: hard
+
"undici-types@npm:~6.21.0":
version: 6.21.0
resolution: "undici-types@npm:6.21.0"
@@ -10737,6 +10980,15 @@ __metadata:
languageName: node
linkType: hard
+"warning@npm:^4.0.3":
+ version: 4.0.3
+ resolution: "warning@npm:4.0.3"
+ dependencies:
+ loose-envify: "npm:^1.0.0"
+ checksum: 10c0/aebab445129f3e104c271f1637fa38e55eb25f968593e3825bd2f7a12bd58dc3738bb70dc8ec85826621d80b4acfed5a29ebc9da17397c6125864d72301b937e
+ languageName: node
+ linkType: hard
+
"web-streams-polyfill@npm:^3.0.3":
version: 3.3.3
resolution: "web-streams-polyfill@npm:3.3.3"
@@ -11035,6 +11287,15 @@ __metadata:
languageName: node
linkType: hard
+"zod-validation-error@npm:^3.5.2":
+ version: 3.5.2
+ resolution: "zod-validation-error@npm:3.5.2"
+ peerDependencies:
+ zod: ^3.25.0
+ checksum: 10c0/da50926ec91c7ad2880bacc5010a53c42de58f73f7c4629baad8132695c4daf74dd68620787198da81aca85134471182ed4c566b5fc9bc5349aefd8540946d57
+ languageName: node
+ linkType: hard
+
"zod@npm:^3.25.60":
version: 3.25.67
resolution: "zod@npm:3.25.67"