Skip to content

Commit 7235562

Browse files
Merge pull request #55 from linked-planet/dev
Dev
2 parents cb96457 + d98fab7 commit 7235562

File tree

10 files changed

+602
-392
lines changed

10 files changed

+602
-392
lines changed

library/src/components/form/DynamicForm.tsx

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
type UseFormWatch,
1010
} from "react-hook-form"
1111
import { twMerge } from "tailwind-merge"
12-
import { Button } from "../Button"
12+
import { Button, ButtonGroup } from "../Button"
1313

1414
export interface FormProps<T extends FieldValues> {
1515
control: Control<T>
@@ -44,6 +44,9 @@ export interface DynamicFormProps<T extends FieldValues>
4444
horizontal?: boolean
4545
hideReset?: boolean
4646
hideSave?: boolean
47+
48+
customSubmitButton?: (props: { disabled: boolean }) => React.ReactNode
49+
customResetButton?: (props: { disabled: boolean }) => React.ReactNode
4750
}
4851

4952
export function DynamicForm<T extends FieldValues>({
@@ -55,6 +58,8 @@ export function DynamicForm<T extends FieldValues>({
5558
className,
5659
hideSave,
5760
hideReset,
61+
customResetButton,
62+
customSubmitButton,
5863
...props
5964
}: DynamicFormProps<T>) {
6065
const {
@@ -95,26 +100,32 @@ export function DynamicForm<T extends FieldValues>({
95100

96101
<hr className="border border-border" />
97102

98-
<div className="flex flex-row items-end w-full justify-end mt-4">
99-
{!hideReset && (
100-
<Button
101-
type="reset"
102-
appearance="subtle"
103-
disabled={!isDirty}
104-
>
105-
Reset
106-
</Button>
107-
)}
108-
{!hideSave && (
109-
<Button
110-
appearance="primary"
111-
type="submit"
112-
disabled={!isValid}
113-
>
114-
Save
115-
</Button>
116-
)}
117-
</div>
103+
<ButtonGroup className="justify-end">
104+
{!hideReset &&
105+
(customResetButton ? (
106+
customResetButton({ disabled: !isDirty })
107+
) : (
108+
<Button
109+
type="reset"
110+
appearance="subtle"
111+
disabled={!isDirty}
112+
>
113+
Reset
114+
</Button>
115+
))}
116+
{!hideSave &&
117+
(customSubmitButton ? (
118+
customSubmitButton({ disabled: !isValid })
119+
) : (
120+
<Button
121+
appearance="primary"
122+
type="submit"
123+
disabled={!isValid}
124+
>
125+
Save
126+
</Button>
127+
))}
128+
</ButtonGroup>
118129
</form>
119130
)
120131
}

library/src/components/timetable/TimeTable.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ import {
3737
initAndUpdateTimeTableSelectionStore,
3838
type onTimeRangeSelectedType,
3939
} from "./TimeTableSelectionStore"
40-
import { getStartAndEndSlot, useGroupRows } from "./useGoupRows"
40+
import { useGroupRows } from "./useGoupRows"
4141
import { twMerge } from "tailwind-merge"
42+
import { getStartAndEndSlot } from "./timeTableUtils"
4243

4344
export interface TimeSlotBooking {
4445
title: string
@@ -189,8 +190,8 @@ export interface LPTimeTableProps<
189190

190191
/** custom header row */
191192
customHeaderRow?: {
192-
timeSlot: (props: CustomHeaderRowTimeSlotProps) => JSX.Element
193-
header: (props: CustomHeaderRowHeaderProps) => JSX.Element
193+
timeSlot: (props: CustomHeaderRowTimeSlotProps<G, I>) => JSX.Element
194+
header: (props: CustomHeaderRowHeaderProps<G, I>) => JSX.Element
194195
}
195196
}
196197

@@ -257,6 +258,7 @@ const LPTimeTableImpl = <G extends TimeTableGroup, I extends TimeSlotBooking>({
257258
)
258259

259260
// change on viewType
261+
// biome-ignore lint/correctness/useExhaustiveDependencies: just remove the message is props change
260262
useEffect(() => {
261263
setMessage?.(undefined) // clear the message on time frame change
262264
}, [viewType, startDate, endDate, setMessage, timeStepsMinutes])
@@ -490,8 +492,9 @@ const LPTimeTableImpl = <G extends TimeTableGroup, I extends TimeSlotBooking>({
490492
}
491493
ref={tableRef}
492494
>
493-
<LPTimeTableHeader
495+
<LPTimeTableHeader<G, I>
494496
slotsArray={slotsArray}
497+
timeSlotMinutes={timeSlotMinutes}
495498
columnWidth={columnWidth}
496499
groupHeaderColumnWidth={groupHeaderColumnWidth}
497500
startDate={startDate}
@@ -508,7 +511,8 @@ const LPTimeTableImpl = <G extends TimeTableGroup, I extends TimeSlotBooking>({
508511
weekStartsOnSunday={weekStartsOnSunday}
509512
locale={locale}
510513
customHeaderRow={customHeaderRow}
511-
ref={tableHeaderRef}
514+
entries={entries}
515+
tableHeaderRef={tableHeaderRef}
512516
/>
513517
<tbody ref={tableBodyRef} className="table-fixed">
514518
<TimeTableRows<G, I>

library/src/components/timetable/TimeTableHeader.tsx

Lines changed: 118 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ dayjs.extend(weekOfYear)
66
dayjs.extend(weekYear)
77
dayjs.extend(localeData)
88
import type React from "react"
9-
import { Fragment, forwardRef } from "react"
9+
import { Fragment, type RefObject, useRef } from "react"
1010

1111
// if more locales then english and germans are needed, we need to enable them first here
1212
import "dayjs/locale/de"
@@ -15,7 +15,12 @@ import "dayjs/locale/de"
1515
//import "dayjs/locale/it"
1616
//import "dayjs/locale/nl"
1717

18-
import type { TimeTableViewType } from "./TimeTable"
18+
import type {
19+
TimeSlotBooking,
20+
TimeTableEntry,
21+
TimeTableGroup,
22+
TimeTableViewType,
23+
} from "./TimeTable"
1924
import type { TimeFrameDay } from "./TimeTableConfigStore"
2025

2126
const headerTimeSlotFormat: { [viewType in TimeTableViewType]: string } = {
@@ -52,22 +57,36 @@ export function headerText(
5257
}
5358
}
5459

55-
export type CustomHeaderRowTimeSlotProps = {
60+
export type CustomHeaderRowTimeSlotProps<
61+
G extends TimeTableGroup,
62+
I extends TimeSlotBooking,
63+
> = {
5664
timeSlot: Dayjs
5765
timeSlotMinutes: number
5866
isLastOfDay: boolean
5967
viewType: TimeTableViewType
6068
timeFrameOfDay: TimeFrameDay
69+
entries: TimeTableEntry<G, I>[]
70+
slotsArray: readonly Dayjs[]
71+
tableCellRef: RefObject<HTMLTableCellElement>
6172
}
6273

63-
export type CustomHeaderRowHeaderProps = {
74+
export type CustomHeaderRowHeaderProps<
75+
G extends TimeTableGroup,
76+
I extends TimeSlotBooking,
77+
> = {
6478
slotsArray: readonly Dayjs[]
6579
viewType: TimeTableViewType
6680
timeFrameOfDay: TimeFrameDay
81+
entries: TimeTableEntry<G, I>[]
6782
}
6883

69-
type TimeTableHeaderProps = {
84+
type TimeTableHeaderProps<
85+
G extends TimeTableGroup,
86+
I extends TimeSlotBooking,
87+
> = {
7088
slotsArray: readonly Dayjs[]
89+
timeSlotMinutes: number
7190
groupHeaderColumnWidth: number | string
7291
columnWidth: number | string
7392
startDate: Dayjs
@@ -80,29 +99,38 @@ type TimeTableHeaderProps = {
8099
weekStartsOnSunday: boolean
81100
locale?: "en" | "de"
82101

102+
entries: TimeTableEntry<G, I>[]
83103
customHeaderRow?: {
84-
timeSlot: (props: CustomHeaderRowTimeSlotProps) => JSX.Element
85-
header: (props: CustomHeaderRowHeaderProps) => JSX.Element
104+
timeSlot: (props: CustomHeaderRowTimeSlotProps<G, I>) => JSX.Element
105+
header: (props: CustomHeaderRowHeaderProps<G, I>) => JSX.Element
86106
}
107+
108+
tableHeaderRef: React.Ref<HTMLTableSectionElement>
87109
}
88110

89-
export const LPTimeTableHeader = forwardRef(function TimeTableHeader(
90-
{
91-
slotsArray,
92-
groupHeaderColumnWidth,
93-
columnWidth,
94-
startDate,
95-
endDate,
96-
viewType,
97-
showTimeSlotHeader,
98-
timeFrameDay,
99-
dateHeaderTextFormat,
100-
weekStartsOnSunday,
101-
locale,
102-
customHeaderRow,
103-
}: TimeTableHeaderProps,
104-
tableHeaderRef: React.Ref<HTMLTableSectionElement>,
105-
) {
111+
const headerCellBaseClassname =
112+
"bg-surface border-transparent border-b-border after:border-border relative select-none border-0 border-b-2 border-solid p-0 pl-1 font-bold after:absolute after:bottom-[1px] after:right-0 after:top-0 after:h-full after:border-solid"
113+
114+
export const LPTimeTableHeader = function TimeTableHeader<
115+
G extends TimeTableGroup,
116+
I extends TimeSlotBooking,
117+
>({
118+
slotsArray,
119+
timeSlotMinutes,
120+
groupHeaderColumnWidth,
121+
columnWidth,
122+
startDate,
123+
endDate,
124+
viewType,
125+
showTimeSlotHeader,
126+
timeFrameDay,
127+
dateHeaderTextFormat,
128+
weekStartsOnSunday,
129+
locale,
130+
customHeaderRow,
131+
entries,
132+
tableHeaderRef,
133+
}: TimeTableHeaderProps<G, I>) {
106134
const currentLocale = dayjs.locale()
107135
if (locale && locale !== currentLocale) {
108136
dayjs.locale(locale)
@@ -254,7 +282,7 @@ export const LPTimeTableHeader = forwardRef(function TimeTableHeader(
254282
<th
255283
key={`timeheader${slot.unix()}`}
256284
colSpan={2}
257-
className={`bg-surface border-transparent border-b-border after:border-border relative select-none border-0 border-b-2 border-solid p-0 pl-1 font-bold after:absolute after:bottom-[1px] after:right-0 after:top-0 after:h-full after:border-solid ${
285+
className={`${headerCellBaseClassname} ${
258286
isLastOfDay ? "after:border-l-2" : ""
259287
} ${showTimeSlotHeader ? "pt-1" : ""}`}
260288
>
@@ -278,33 +306,83 @@ export const LPTimeTableHeader = forwardRef(function TimeTableHeader(
278306
slotsArray,
279307
timeFrameOfDay: timeFrameDay,
280308
viewType,
309+
entries,
281310
})}
282311
</th>
283312
{slotsArray.map((slot, i) => {
284313
const isLastOfDay =
285314
i === slotsArray.length - 1 ||
286315
!slotsArray[i + 1].isSame(slot, "day")
287316
return (
288-
<th
317+
<CustomHeaderRowCell
318+
customHeaderRow={customHeaderRow}
319+
timeSlot={slot}
320+
timeSlotMinutes={timeSlotMinutes}
321+
timeFrameOfDay={timeFrameDay}
322+
slotsArray={slotsArray}
323+
entries={entries}
324+
showTimeSlotHeader={showTimeSlotHeader}
325+
viewType={viewType}
326+
isLastOfDay={isLastOfDay}
289327
key={`timeheader${slot.unix()}`}
290-
colSpan={2}
291-
className={`bg-surface border-transparent border-b-border after:border-border relative select-none border-0 border-b-2 border-solid p-0 pl-1 font-bold after:absolute after:bottom-[1px] after:right-0 after:top-0 after:h-full after:border-solid ${
292-
isLastOfDay ? "after:border-l-2" : ""
293-
} ${showTimeSlotHeader ? "pt-1" : ""}`}
294-
>
295-
{customHeaderRow.timeSlot({
296-
timeSlot: slot,
297-
timeSlotMinutes: 60,
298-
isLastOfDay,
299-
timeFrameOfDay: timeFrameDay,
300-
viewType,
301-
})}
302-
</th>
328+
/>
303329
)
304330
})}
305331
</tr>
306332
)}
307333
</thead>
308334
</>
309335
)
310-
})
336+
}
337+
338+
function CustomHeaderRowCell<
339+
G extends TimeTableGroup,
340+
I extends TimeSlotBooking,
341+
>({
342+
timeSlot,
343+
timeSlotMinutes,
344+
isLastOfDay,
345+
viewType,
346+
timeFrameOfDay,
347+
entries,
348+
slotsArray,
349+
showTimeSlotHeader,
350+
customHeaderRow,
351+
}: {
352+
timeSlot: Dayjs
353+
timeSlotMinutes: number
354+
isLastOfDay: boolean
355+
viewType: TimeTableViewType
356+
timeFrameOfDay: TimeFrameDay
357+
entries: TimeTableEntry<G, I>[]
358+
slotsArray: readonly Dayjs[]
359+
showTimeSlotHeader: boolean
360+
customHeaderRow: {
361+
timeSlot: (props: CustomHeaderRowTimeSlotProps<G, I>) => JSX.Element
362+
header: (props: CustomHeaderRowHeaderProps<G, I>) => JSX.Element
363+
}
364+
}) {
365+
const ref = useRef<HTMLTableCellElement>(null)
366+
367+
return (
368+
<th
369+
key={`timeheader${timeSlot.unix()}`}
370+
colSpan={2}
371+
className={`${headerCellBaseClassname} ${
372+
isLastOfDay ? "after:border-l-2" : ""
373+
} ${showTimeSlotHeader ? "pt-1" : ""}`}
374+
ref={ref}
375+
>
376+
{customHeaderRow.timeSlot({
377+
timeSlot,
378+
timeSlotMinutes,
379+
isLastOfDay,
380+
timeFrameOfDay,
381+
viewType,
382+
entries,
383+
slotsArray,
384+
tableCellRef: ref,
385+
})}
386+
</th>
387+
)
388+
}

library/src/components/timetable/index.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ export type { TimeTableItemProps } from "./ItemWrapper"
1818
export type { TimeTablePlaceholderItemProps } from "./PlaceholderItem"
1919
import type { TimeFrameDay as _TimeFrameDay } from "./TimeTableConfigStore"
2020

21+
import {
22+
getLeftAndWidth,
23+
getStartAndEndSlot,
24+
itemsOutsideOfDayRangeORSameStartAndEnd,
25+
} from "./timeTableUtils"
26+
export const timeTableUtils = {
27+
getLeftAndWidth,
28+
getStartAndEndSlot,
29+
itemsOutsideOfDayRangeORSameStartAndEnd,
30+
}
31+
2132
//const memoized = React.memo(TimeTable) as typeof TimeTable
2233

2334
//export { memoized as TimeTable }
@@ -27,8 +38,14 @@ export namespace TimeTableTypes {
2738
export type TimeSlotBooking = _TimeSlotBooking
2839
export type TimeFrameDay = _TimeFrameDay
2940
export type TimeTableGroup = _TimeTableGroup
30-
export type CustomHeaderRowHeaderProps = _CustomHeaderRowHeaderProps
31-
export type CustomHeadeRowTimeSlotProps = _CustomHeaderRowTimeSlotProps
41+
export type CustomHeaderRowHeaderProps<
42+
G extends TimeTableGroup,
43+
I extends TimeSlotBooking,
44+
> = _CustomHeaderRowHeaderProps<G, I>
45+
export type CustomHeadeRowTimeSlotProps<
46+
G extends TimeTableGroup,
47+
I extends TimeSlotBooking,
48+
> = _CustomHeaderRowTimeSlotProps<G, I>
3249

3350
export type TimeTableEntry<
3451
G extends TimeTableGroup,

0 commit comments

Comments
 (0)