cal.pub0.org/packages/features/calendars/weeklyview/components/Calendar.tsx

134 lines
5.5 KiB
TypeScript
Raw Normal View History

Calendar Weekly Scheduler (#5653) * storybook v2 init * Merge config into storybook vite build * Remove path * Storybook config tweaks * Added styles and settings for storybook v2, and started working on button documentation and examples. * Badges + flex wrap on mobile * Breadcrumbs+button+avatar * Checkbox * Input + moving files around * WIP table * WIP table grid * Replaced imports for new components. * Added first steps for varianttable. * Small alignment fix. * Custom Args Table - With scrollbar * Adding table to components that need it + darkmode * Add intro * Fix types * Remove V1 storybook and replace with V2 * Fix badge type error * Fixed storybook dependencies * Added cover image to storybook * Remove vita from ts config, we dont use vite. * Fixed button import. * Explained postcss pseudo plugin. * Fixed badge import. * Add Avatar Stories * ButtonGroup Stories * Fixed imports * Add checkbox stories * Inital state plannning * Inital state combined with passed in props * Start of UI work * Able to change dates? * Add dynamic hour props * Get grid system setup correctly * Show events on grid * Weird sizing issue but events placed correctly gridstart * CAL styled calendar event component * availability WIP ish * Blocking days! + Block days < today * Kinda working time line * Rename grid stop + formatting * Handle sorting events if required. * Add util for getting startDate bassed on weekday * Remove event stories for now * Implement gridstops per hour to be dyamic * New CSS Grid + offsetbased positoning * Fix weird Z-Index issues on hover * Implement blocklist again with new format * Side by side events working - styling needs work * New design of overlap * Overlapping? Working :O * Cleanup * WIP hover state * Werid border issue * fix translate issue * Kinda working with overflow * Fix overflow * Progressive date blocking * Cleanup * Fix double render of blocked list * WIP mobile implementaiton * Trying to fix CSS * Extract CSS to styles.css to allow media queries * Improve documentation - allow args to be changed in storybook * Fix hover showing even if disabled * WIP cols auto approach * Merge blocking dates * Fix zindex * Fix hover position * Fix Z-Index issues on hover and blocking events * Re add onclick handler * Fix overlapping blocking dates * Fix scaling for datevalues columns * Date values closer to DS * Blocked List Tidy up * Storybook + file tidy up * Little tidy up * Fix offsets * Remove event hover * Fix random bg-red-500 * Fix import * FIx blocking cells appearing above start Date * Fix truncation * Fix border overlap * Overlap a little nicer * Condtional 80% sizing * Nitpicks * Fix today height and top breaking * Add text left to time stamp * Support string dates * Add shalow to reduce re-renders * Rename to Calendar instead of scheduler * Fix 3 overlapping events * Fix merge type error * Fix destructuring * NITS * Move to features package Co-authored-by: Jeroen Reumkens <hello@jeroenreumkens.nl> Co-authored-by: zomars <zomars@me.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-12-14 13:36:10 +00:00
import React, { useEffect, useMemo, useRef } from "react";
import { useCalendarStore } from "../state/store";
import "../styles/styles.css";
import { CalendarComponentProps } from "../types/state";
import { getDaysBetweenDates, getHoursToDisplay } from "../utils";
import { DateValues } from "./DateValues";
import { BlockedList } from "./blocking/BlockedList";
import { EmptyCell } from "./event/Empty";
import { EventList } from "./event/EventList";
import { SchedulerColumns } from "./grid";
import { SchedulerHeading } from "./heading/SchedulerHeading";
import { HorizontalLines } from "./horizontalLines";
import { VeritcalLines } from "./verticalLines";
export function Calendar(props: CalendarComponentProps) {
const container = useRef<HTMLDivElement | null>(null);
const containerNav = useRef<HTMLDivElement | null>(null);
const containerOffset = useRef<HTMLDivElement | null>(null);
const initalState = useCalendarStore((state) => state.initState);
const startDate = useCalendarStore((state) => state.startDate);
const endDate = useCalendarStore((state) => state.endDate);
const startHour = useCalendarStore((state) => state.startHour || 0);
const endHour = useCalendarStore((state) => state.endHour || 23);
const usersCellsStopsPerHour = useCalendarStore((state) => state.gridCellsPerHour || 4);
const days = useMemo(() => getDaysBetweenDates(startDate, endDate), [startDate, endDate]);
const hours = useMemo(() => getHoursToDisplay(startHour || 0, endHour || 23), [startHour, endHour]);
const numberOfGridStopsPerDay = hours.length * usersCellsStopsPerHour;
// Initalise State on inital mount
useEffect(() => {
initalState(props);
}, [props, initalState]);
return (
<MobileNotSupported>
<div
className="scheduler-wrapper flex h-full w-full flex-col overflow-y-scroll"
style={
{ "--one-minute-height": `calc(1.75rem/(60/${usersCellsStopsPerHour}))` } as React.CSSProperties // This can't live in the css file because it's a dynamic value and css variable gets super
}>
<SchedulerHeading />
<div ref={container} className="relative isolate flex flex-auto flex-col bg-white">
<div
style={{ width: "165%" }}
className="flex max-w-full flex-none flex-col sm:max-w-none md:max-w-full">
<DateValues containerNavRef={containerNav} days={days} />
{/* TODO: Implement this at a later date. */}
{/* <CurrentTime
containerNavRef={containerNav}
containerOffsetRef={containerOffset}
containerRef={container}
/> */}
<div className="flex flex-auto">
<div className="sticky left-0 z-10 w-14 flex-none bg-white ring-1 ring-gray-100" />
<div className="grid flex-auto grid-cols-1 grid-rows-1 ">
<HorizontalLines
hours={hours}
numberOfGridStopsPerCell={usersCellsStopsPerHour}
containerOffsetRef={containerOffset}
/>
<VeritcalLines days={days} />
{/* Empty Cells */}
<SchedulerColumns
zIndex={50}
offsetHeight={containerOffset.current?.offsetHeight}
gridStopsPerDay={numberOfGridStopsPerDay}>
<>
{[...Array(days.length)].map((_, i) => (
<li
key={i}
style={{
gridRow: `2 / span ${numberOfGridStopsPerDay}`,
position: "relative",
}}>
{/* While startDate < endDate: */}
{[...Array(numberOfGridStopsPerDay)].map((_, j) => {
const key = `${i}-${j}`;
return (
<EmptyCell
key={key}
day={days[i].toDate()}
gridCellIdx={j}
totalGridCells={numberOfGridStopsPerDay}
selectionLength={endHour - startHour}
startHour={startHour}
/>
);
})}
</li>
))}
</>
</SchedulerColumns>
<SchedulerColumns
offsetHeight={containerOffset.current?.offsetHeight}
gridStopsPerDay={numberOfGridStopsPerDay}>
{/*Loop over events per day */}
{days.map((day, i) => {
return (
<li key={day.toISOString()} className="relative" style={{ gridColumnStart: i + 1 }}>
<EventList day={day} />
<BlockedList day={day} containerRef={container} />
</li>
);
})}
</SchedulerColumns>
</div>
</div>
</div>
</div>
</div>
</MobileNotSupported>
);
}
/** @todo Will be removed once we have mobile support */
const MobileNotSupported = ({ children }: { children: React.ReactNode }) => {
return (
<>
<div className="flex h-full flex-col items-center justify-center sm:hidden">
<h1 className="text-2xl font-bold">Mobile not supported yet </h1>
<p className="text-gray-500">Please use a desktop browser to view this page</p>
</div>
<div className="hidden sm:block">{children}</div>
</>
);
};