add basic schedule page

This commit is contained in:
vchikalkin 2025-01-30 20:12:45 +03:00
parent 628fb30ce9
commit 7821e39345
8 changed files with 122 additions and 1 deletions

View File

@ -1,3 +1,12 @@
import { PageHeader } from '@/components/navigation';
import { SlotsCalendar, TimeSlots } from '@/components/schedule';
export default function SchedulePage() {
return 'Schedule';
return (
<>
<PageHeader title="График работы" />
<SlotsCalendar />
<TimeSlots />
</>
);
}

View File

@ -0,0 +1,29 @@
'use client';
import { useLocale } from 'next-intl';
import { useEffect, useRef, useState } from 'react';
import 'vanilla-calendar-pro/styles/index.css';
import { Calendar, type Options } from 'vanilla-calendar-pro';
type CalendarProps = React.HTMLAttributes<HTMLDivElement> & {
readonly config?: Options;
};
function VanillaCalendar({ config, ...attributes }: CalendarProps) {
const ref = useRef(null);
const [calendar, setCalendar] = useState<Calendar | null>(null);
const locale = useLocale();
useEffect(() => {
if (!ref.current) return;
setCalendar(new Calendar(ref.current, { ...config, locale }));
}, [config, locale, ref]);
useEffect(() => {
if (!calendar) return;
calendar.init();
}, [calendar]);
return <div {...attributes} ref={ref} />;
}
export default VanillaCalendar;

View File

@ -0,0 +1,14 @@
import VanillaCalendar from '@/components/common/vanilla-calendar';
export function SlotsCalendar() {
return (
<div className="p-4">
<VanillaCalendar
config={{
dateMin: new Date(),
selectionYearsMode: false,
}}
/>
</div>
);
}

View File

@ -0,0 +1,2 @@
export * from './calendar';
export * from './time-slots';

View File

@ -0,0 +1,48 @@
'use client';
import { Button } from '@repo/ui/components/ui/button';
import { Input } from '@repo/ui/components/ui/input';
import { type FormEvent, useState } from 'react';
type Props = {
readonly onAddSlot: (startTime: string, endTime: string) => void;
};
export function AddSlotForm({ onAddSlot }: Props) {
const [startTime, setStartTime] = useState('');
const [endTime, setEndTime] = useState('');
const handleSubmit = (event: FormEvent) => {
event.preventDefault();
if (startTime && endTime) {
onAddSlot(startTime, endTime);
setStartTime('');
setEndTime('');
}
};
return (
<form className="flex items-center space-x-2" onSubmit={handleSubmit}>
<div className="flex flex-1 space-x-2">
<div className="flex-1">
<Input
id="start-time"
onChange={(event) => setStartTime(event.target.value)}
required
type="time"
value={startTime}
/>
</div>
<div className="flex-1">
<Input
id="end-time"
onChange={(event) => setEndTime(event.target.value)}
required
type="time"
value={endTime}
/>
</div>
</div>
<Button type="submit">Добавить</Button>
</form>
);
}

View File

@ -0,0 +1,10 @@
import { AddSlotForm } from './add-slot-form';
export function TimeSlots() {
return (
<div className="p-4">
<h3 className="text-md mb-2 font-semibold">Добавить новый интервал</h3>
<AddSlotForm onAddSlot={undefined} />
</div>
);
}

View File

@ -27,6 +27,7 @@
"react": "catalog:",
"react-dom": "catalog:",
"use-debounce": "^10.0.4",
"vanilla-calendar-pro": "^3.0.3",
"zod": "catalog:"
},
"devDependencies": {

8
pnpm-lock.yaml generated
View File

@ -177,6 +177,9 @@ importers:
use-debounce:
specifier: ^10.0.4
version: 10.0.4(react@19.0.0)
vanilla-calendar-pro:
specifier: ^3.0.3
version: 3.0.3
zod:
specifier: 'catalog:'
version: 3.24.1
@ -6121,6 +6124,9 @@ packages:
resolution: {integrity: sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==}
engines: {node: '>=12'}
vanilla-calendar-pro@3.0.3:
resolution: {integrity: sha512-bfmeGFaDeakk/OrwgM+22qDiRvIx1Zu+GG3+E/sCPjaKwbJR7AsDyRBfJQzVHRw3eeavU8jQQTRSFt8EPIPOGw==}
vite-node@2.1.8:
resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==}
engines: {node: ^18.0.0 || >=20.0.0}
@ -12945,6 +12951,8 @@ snapshots:
value-or-promise@1.0.12: {}
vanilla-calendar-pro@3.0.3: {}
vite-node@2.1.8(@types/node@20.17.8):
dependencies:
cac: 6.7.14