import { Fragment, useCallback, useMemo, useRef, useState } from 'react' import Content from '/src/components/Content/Content' import { usePalette } from '/src/hooks/usePalette' import { useTranslation } from '/src/i18n/client' import { useStore } from '/src/stores' import useSettingsStore from '/src/stores/settingsStore' import { calculateTable, makeClass } from '/src/utils' import styles from '../AvailabilityViewer/AvailabilityViewer.module.scss' interface AvailabilityEditorProps { times: string[] timezone: string value: string[] onChange: (value: string[]) => void } const AvailabilityEditor = ({ times, timezone, value = [], onChange, }: AvailabilityEditorProps) => { const { t, i18n } = useTranslation('event') const timeFormat = useStore(useSettingsStore, state => state.timeFormat) ?? '12h' // Calculate table const { rows, columns } = useMemo(() => calculateTable(times, i18n.language, timeFormat, timezone), [times, i18n.language, timeFormat, timezone]) // Ref and state required to rerender but also access static version in callbacks const selectingRef = useRef([]) const [selecting, _setSelecting] = useState([]) const setSelecting = useCallback((v: string[]) => { selectingRef.current = v _setSelecting(v) }, []) const startPos = useRef({ x: 0, y: 0 }) const mode = useRef<'add' | 'remove'>() // Create the colour palette const palette = usePalette(2) return <> {t('you.info')} {/* {isSpecificDates && (
}> onChange( times.filter(time => !busyArray.some(busy => dayjs(time, 'HHmm-DDMMYYYY').isBetween(busy.start, busy.end, null, '[)') )) )} /> onChange( times.filter(time => !busyArray.some(busy => dayjs(time, 'HHmm-DDMMYYYY').isBetween(dayjs.tz(busy.start.dateTime, busy.start.timeZone), dayjs.tz(busy.end.dateTime, busy.end.timeZone), null, '[)') )) )} />
)} */}
{rows.map((row, i) =>
{row && }
)}
{columns.map((column, x) => {column ?
{column.header.dateLabel && }
{column.cells.map((cell, y) => { if (y === column.cells.length - 1) return null if (!cell) return
('greyed_times')} /> return
{ e.preventDefault() startPos.current = { x, y } mode.current = value.includes(cell.serialized) ? 'remove' : 'add' setSelecting([cell.serialized]) e.currentTarget.releasePointerCapture(e.pointerId) document.addEventListener('pointerup', () => { if (mode.current === 'add') { onChange([...value, ...selectingRef.current]) } else if (mode.current === 'remove') { onChange(value.filter(t => !selectingRef.current.includes(t))) } mode.current = undefined }, { once: true }) }} onPointerEnter={() => { if (mode.current) { const found = [] for (let cy = Math.min(startPos.current.y, y); cy < Math.max(startPos.current.y, y) + 1; cy++) { for (let cx = Math.min(startPos.current.x, x); cx < Math.max(startPos.current.x, x) + 1; cx++) { found.push({ y: cy, x: cx }) } } setSelecting(found.flatMap(d => { const serialized = columns[d.x]?.cells[d.y]?.serialized if (serialized && times.includes(serialized)) { return [serialized] } return [] })) } }} /> })}
:
} )}
} export default AvailabilityEditor