- 일정 색상 로직 수정: 커스텀 컬러 삭제 - 일정 시작/종료일 설정 구현 - 일정 타입 구현 - 일정 시작/종료 시간 구현 중
This commit is contained in:
303
src/ui/component/popover/schedule/SchedulePopover.tsx
Normal file
303
src/ui/component/popover/schedule/SchedulePopover.tsx
Normal file
@@ -0,0 +1,303 @@
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { usePalette } from '@/hooks/use-palette';
|
||||
import { ColorPalette, type ColorPaletteType } from '@/const/ColorPalette';
|
||||
import { ColorPickPopover } from './ColorPickPopover';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import * as z from 'zod';
|
||||
import { CreateScheduleSchema } from '@/data/form/createSchedule.schema';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Field, FieldError } from '@/components/ui/field';
|
||||
import { PenSquare, X } from 'lucide-react';
|
||||
import { ScheduleTypeLabel, type ScheduleType } from '@/const/schedule/ScheduleType';
|
||||
import { useRecord } from '@/hooks/use-record';
|
||||
import { TypePickPopover } from './TypePickPopover';
|
||||
import { ScheduleDay } from '@/const/schedule/ScheduleDay';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||
import { DatePickPopover } from './DatePickPopover';
|
||||
import { format } from 'date-fns';
|
||||
import { TimePickPopover } from './TimePickPopover';
|
||||
|
||||
interface ScheduleSheetProps {
|
||||
date: Date | undefined;
|
||||
open: boolean;
|
||||
popoverSide: 'left' | 'right';
|
||||
popoverAlign: 'start' | 'end';
|
||||
}
|
||||
|
||||
export const SchedulePopover = ({ date, open, popoverSide, popoverAlign }: ScheduleSheetProps) => {
|
||||
const {
|
||||
getPaletteByKey
|
||||
} = usePalette();
|
||||
const [mode, setMode] = useState<'list' | 'create' | 'detail' | 'update'>('list');
|
||||
const [colorPopoverOpen, setColorPopoverOpen] = useState(false);
|
||||
const dayLabelList = useRecord(ScheduleDay).keys.map((key) => {
|
||||
return {
|
||||
day: Number(key),
|
||||
label: ScheduleDay[Number(key)]
|
||||
} as { day: number, label: string };
|
||||
})
|
||||
const createScheduleForm = useForm<z.infer<typeof CreateScheduleSchema>>({
|
||||
resolver: zodResolver(CreateScheduleSchema),
|
||||
defaultValues: {
|
||||
name: "",
|
||||
startDate: date || new Date(),
|
||||
endDate: date || new Date(),
|
||||
content: "",
|
||||
startTime: "",
|
||||
endTime: "",
|
||||
type: "once",
|
||||
status: "yet",
|
||||
style: getPaletteByKey('Black').style,
|
||||
dayList: ""
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
console.log(date);
|
||||
if (open && date) {
|
||||
createScheduleForm.setValue('startDate', date);
|
||||
createScheduleForm.setValue('endDate', date);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
setMode('list');
|
||||
createScheduleForm.clearErrors();
|
||||
createScheduleForm.reset();
|
||||
}, 150);
|
||||
}, [open]);
|
||||
|
||||
const {
|
||||
name,
|
||||
startDate,
|
||||
endDate,
|
||||
content,
|
||||
startTime,
|
||||
endTime,
|
||||
type,
|
||||
status,
|
||||
style,
|
||||
dayList
|
||||
} = createScheduleForm.watch();
|
||||
|
||||
const selectColor = (color: ColorPaletteType) => {
|
||||
createScheduleForm.setValue('style', color.style);
|
||||
setColorPopoverOpen(false);
|
||||
}
|
||||
|
||||
const selectType = (type: ScheduleType) => {
|
||||
createScheduleForm.setValue('type', type);
|
||||
}
|
||||
|
||||
const selectDayList = (newValues: string[]) => {
|
||||
const sortedValues = newValues.sort();
|
||||
const newDayList = sortedValues.join('');
|
||||
createScheduleForm.setValue('dayList', newDayList);
|
||||
}
|
||||
|
||||
const selectDate = (type: 'startDate' | 'endDate', date: Date | undefined) => {
|
||||
if (!date) return;
|
||||
createScheduleForm.setValue(type, date);
|
||||
}
|
||||
|
||||
const selectTime = (type: 'startTime' | 'endTime', time: string) => {
|
||||
createScheduleForm.setValue(type, time);
|
||||
}
|
||||
|
||||
const ListContent = () => {
|
||||
return (
|
||||
<div>
|
||||
<PenSquare onClick={() => setMode('create')}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const CreateContent = () => {
|
||||
|
||||
const OnceContent = () => {
|
||||
return (
|
||||
<div
|
||||
className="w-full h-10"
|
||||
>
|
||||
<DatePickPopover
|
||||
disabled={false}
|
||||
mode={'range'}
|
||||
popoverAlign={popoverAlign}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
setStartDate={(date: Date | undefined) => selectDate('startDate', date)}
|
||||
setEndDate={(date: Date | undefined) => selectDate('endDate', date)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const DailyContent = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const DefaultContent = () => {
|
||||
return (
|
||||
(
|
||||
<ToggleGroup
|
||||
type="multiple"
|
||||
className="w-full h-10 flex flex-row justify-center items-center"
|
||||
onValueChange={selectDayList}
|
||||
>
|
||||
{
|
||||
dayLabelList.map((day) => (
|
||||
<ToggleGroupItem
|
||||
value={`${day.day}`}
|
||||
className="border rounded-none not-last:border-r-0"
|
||||
>
|
||||
{day.label}
|
||||
</ToggleGroupItem>
|
||||
))
|
||||
}
|
||||
</ToggleGroup>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
const renderContent = () => {
|
||||
switch (type) {
|
||||
case 'Once':
|
||||
return <OnceContent />;
|
||||
case 'Daily':
|
||||
return <DailyContent />;
|
||||
default:
|
||||
return <DefaultContent />;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full h-full flex flex-col justify-start items-start gap-4">
|
||||
<div className="w-full flex flex-row justify-center items-center gap-5">
|
||||
<Popover open={colorPopoverOpen} onOpenChange={setColorPopoverOpen}>
|
||||
<div className="w-6 h-6 flex justify-center items-center">
|
||||
<PopoverTrigger asChild>
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-full w-5 h-5 border-2 border-gray-300',
|
||||
)}
|
||||
style={{
|
||||
backgroundColor: `${style}`,
|
||||
}}
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
</div>
|
||||
<ColorPickPopover
|
||||
setColor={selectColor}
|
||||
/>
|
||||
</Popover>
|
||||
<Controller
|
||||
name="name"
|
||||
control={createScheduleForm.control}
|
||||
render={({ field, fieldState }) => (
|
||||
<Field data-invalid={fieldState.invalid}>
|
||||
<Input
|
||||
{...field}
|
||||
id="form-create-schedule-name"
|
||||
placeholder="제목"
|
||||
className="font-bold border-t-0 border-r-0 border-l-0 p-0 border-b-2 rounded-none shadow-none border-indigo-300 focus-visible:ring-0 focus-visible:border-b-indigo-500"
|
||||
style={{
|
||||
fontSize: '20px'
|
||||
}}
|
||||
tabIndex={1}
|
||||
arai-invalid={fieldState.invalid}
|
||||
/>
|
||||
<FieldError errors={[fieldState.error]} />
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<div className="hover:bg-gray-100 cursor-default w-full h-10 border flex justify-center items-center rounded-sm">
|
||||
{ScheduleTypeLabel[type as keyof typeof ScheduleTypeLabel]}
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<TypePickPopover
|
||||
setType={selectType}
|
||||
popoverSide={popoverSide}
|
||||
/>
|
||||
</Popover>
|
||||
<div
|
||||
className="w-full h-10"
|
||||
>
|
||||
{renderContent()}
|
||||
</div>
|
||||
<div className="w-full h-10">
|
||||
<TimePickPopover
|
||||
mode='range'
|
||||
popoverAlign={popoverAlign}
|
||||
disabled={false}
|
||||
startTime=''
|
||||
setStartTime={(time: string | undefined) => {}}
|
||||
endTime=''
|
||||
setEndTime={(time: string | undefined) => {}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="flex flex-row self-end justify-self-end items-center justify-center cursor-default"
|
||||
onClick={() => setMode('list')}
|
||||
>
|
||||
<X />
|
||||
<span>취소</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const DetailContent = () => {
|
||||
return (
|
||||
<div>
|
||||
Detail
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const UpdateContent = () => {
|
||||
return (
|
||||
<div>
|
||||
Update
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const SchedulePopoverContent = () => {
|
||||
switch(mode) {
|
||||
case 'list':
|
||||
return <ListContent />
|
||||
case 'create':
|
||||
return <CreateContent />
|
||||
case 'detail':
|
||||
return <DetailContent />
|
||||
case 'update':
|
||||
return <UpdateContent />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<PopoverContent
|
||||
className="rounded-xl xl:w-[calc(100vw/4)] xl:max-w-[480px] min-w-[384px]"
|
||||
align={popoverAlign} side={popoverSide}
|
||||
>
|
||||
<div>{date && format(date, "yyyy년 MM월 dd일")}</div>
|
||||
<ScrollArea
|
||||
className={
|
||||
cn(
|
||||
"min-h-[125px] h-[calc(100vh/2.5)] p-2.5 w-full flex flex-col",
|
||||
)
|
||||
}
|
||||
>
|
||||
{<SchedulePopoverContent />}
|
||||
</ScrollArea>
|
||||
</PopoverContent>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user