Merge remote-tracking branch 'origin/dev/guerby' into dev/cedric

This commit is contained in:
cdricms
2025-02-10 09:56:16 +01:00
6 changed files with 422 additions and 316 deletions

View File

@@ -0,0 +1,61 @@
package migrations
import (
"context"
"fmt"
"fr.latosa-escrima/core/models"
"github.com/uptrace/bun"
)
func init() {
Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
fmt.Print(" [up migration] ")
_, err := db.NewAddColumn().
Model((*models.Event)(nil)).
ColumnExpr("full_day BOOLEAN NOT NULL DEFAULT FALSE").
Exec(ctx)
if err != nil {
return err
}
// Add "is_visible" column
_, err = db.NewAddColumn().
Model((*models.Event)(nil)).
ColumnExpr("is_visible BOOLEAN NOT NULL DEFAULT TRUE").
Exec(ctx)
if err != nil {
return err
}
// Add "rrule" column
_, err = db.NewAddColumn().
Model((*models.Event)(nil)).
ColumnExpr("rrule TEXT").
Exec(ctx)
return err
}, func(ctx context.Context, db *bun.DB) error {
fmt.Print(" [down migration] ")
_, err := db.NewDropColumn().
Model((*models.Event)(nil)).
Column("full_day").
Exec(ctx)
if err != nil {
return err
}
_, err = db.NewDropColumn().
Model((*models.Event)(nil)).
Column("is_visible").
Exec(ctx)
if err != nil {
return err
}
_, err = db.NewDropColumn().
Model((*models.Event)(nil)).
Column("rrule").
Exec(ctx)
return err
})
}

View File

@@ -7,13 +7,6 @@ import (
"github.com/uptrace/bun" "github.com/uptrace/bun"
) )
type Status string
const (
Active Status = "Active"
Inactive Status = "Inactive"
)
type Event struct { type Event struct {
bun.BaseModel `bun:"table:events"` bun.BaseModel `bun:"table:events"`
@@ -22,5 +15,7 @@ type Event struct {
CreationDate time.Time `bun:"creation_date,notnull,default:current_timestamp" json:"creationDate"` CreationDate time.Time `bun:"creation_date,notnull,default:current_timestamp" json:"creationDate"`
ScheduleStart time.Time `bun:"schedule_start,notnull" json:"start"` ScheduleStart time.Time `bun:"schedule_start,notnull" json:"start"`
ScheduleEnd time.Time `bun:"schedule_end,notnull" json:"end"` ScheduleEnd time.Time `bun:"schedule_end,notnull" json:"end"`
Status Status `bun:"status,notnull,default:'Inactive'" json:"status"` FullDay bool `bun:"full_day,notnull,default:false" json:"fullDay"`
IsVisible bool `bun:"is_visible,notnull,default:true" json:"isVisible"`
Rrule string `bun:"rrule" json:"rrule"`
} }

View File

@@ -1,114 +0,0 @@
"use client"
import * as React from "react";
import { format } from "date-fns";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
interface DateTimePickerProps {
onDateSelectChange: (selectedDate: Date | undefined) => void;
}
export function DateTimePicker({
onDateSelectChange
}: DateTimePickerProps) {
const [date, setDate] = React.useState<Date>();
const [isOpen, setIsOpen] = React.useState(false);
// TODO : this is buggy as hell
const hours = Array.from({ length: 24 }, (_, i) => i);
const handleDateSelect = (selectedDate: Date | undefined) => {
if (selectedDate) {
setDate(selectedDate);
onDateSelectChange(selectedDate)
}
};
const handleTimeChange = (
type: "hour" | "minute",
value: string
) => {
if (date) {
const newDate = new Date(date);
if (type === "hour") {
newDate.setHours(parseInt(value));
} else if (type === "minute") {
newDate.setMinutes(parseInt(value));
}
setDate(newDate);
}
};
return (
<Popover open={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
className={cn(
"w-fit justify-start text-left font-normal",
!date && "text-muted-foreground"
)}
>
{/*<CalendarIcon className="mr-2 h-4 w-4" />*/}
<p className="w-full"> {date ? (
format(date, "MM/dd/yyyy hh:mm")
) : (
<span>MM/DD/YYYY hh:mm</span>
)} </p>
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<div className="sm:flex">
<Calendar
mode="single"
selected={date}
onSelect={handleDateSelect}
initialFocus
/>
<div className="flex flex-col sm:flex-row sm:h-[300px] divide-y sm:divide-y-0 sm:divide-x">
<ScrollArea className="w-64 sm:w-auto">
<div className="flex sm:flex-col p-2">
{hours.reverse().map((hour) => (
<Button
key={hour}
size="icon"
variant={date && date.getHours() === hour ? "default" : "ghost"}
className="sm:w-full shrink-0 aspect-square"
onClick={() => handleTimeChange("hour", hour.toString())}
>
{hour}
</Button>
))}
</div>
<ScrollBar orientation="horizontal" className="sm:hidden" />
</ScrollArea>
<ScrollArea className="w-64 sm:w-auto">
<div className="flex sm:flex-col p-2">
{Array.from({ length: 12 }, (_, i) => i * 5).map((minute) => (
<Button
key={minute}
size="icon"
variant={date && date.getMinutes() === minute ? "default" : "ghost"}
className="sm:w-full shrink-0 aspect-square"
onClick={() => handleTimeChange("minute", minute.toString())}
>
{minute.toString().padStart(2, '0')}
</Button>
))}
</div>
<ScrollBar orientation="horizontal" className="sm:hidden" />
</ScrollArea>
</div>
</div>
</PopoverContent>
</Popover>
);
}

View File

@@ -0,0 +1,286 @@
"use client"
import * as React from "react"
import { CalendarIcon } from "lucide-react"
import { format } from "date-fns"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { Checkbox } from "@/components/ui/checkbox"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { useForm } from "react-hook-form"
import {
CalendarEventExternal,
} from "@schedule-x/calendar";
import ICalendarEvent from "@/interfaces/ICalendarEvent"
export const eventFormSchema = z.object({
title: z.string().min(1, "Titre requis"),
startDate: z.date({
required_error: "Date de début requise",
}),
startTime: z.string(),
endDate: z.date({
required_error: "Date finale requise",
}),
endTime: z.string(),
fullDay: z.boolean().default(false),
frequency: z.enum(["unique", "quotidien", "hebdomadaire", "mensuel"]),
frequencyEndDate: z.date().optional(),
isVisible: z.boolean().default(true),
})
export type EventFormValues = z.infer<typeof eventFormSchema>
const frequencies = [
{ label: "Unique", value: "unique" },
{ label: "Quotidien", value: "quotidien" },
{ label: "Hebdomadaire", value: "hebdomadaire" },
{ label: "Mensuel", value: "mensuel" },
]
const isCalendarEventExternal = (event: CalendarEventExternal | Omit<CalendarEventExternal, "id">): event is CalendarEventExternal => {
return (event as CalendarEventExternal).id !== undefined;
};
export const EventForm: React.FC<
{
event: ICalendarEvent | Omit<ICalendarEvent, "id">;
onSubmitEvent: (eventFormValues: EventFormValues) => void;
}
> = ({
event,
onSubmitEvent,
}) => {
const form = useForm<EventFormValues>({
resolver: zodResolver(eventFormSchema),
defaultValues: {
title: isCalendarEventExternal(event) ? event.title : "",
startDate: isCalendarEventExternal(event) ? new Date(event.start) : new Date(),
startTime: isCalendarEventExternal(event) ? `${new Date(event.start).getHours()}:${new Date(event.start).getMinutes()}` : "10:00",
endDate: isCalendarEventExternal(event) ? new Date(event.end) : new Date(),
endTime: isCalendarEventExternal(event) ? `${new Date(event.end).getHours()}:${new Date(event.end).getMinutes()}` : "11:00",
fullDay: isCalendarEventExternal(event) ? event.fullday : false,
frequency: isCalendarEventExternal(event) ? event.rrule : "unique",
isVisible: isCalendarEventExternal(event) ? event.visibility : true,
},
})
const frequency = form.watch("frequency")
async function onSubmit(data: EventFormValues) {
try {
const validatedData = eventFormSchema.parse(data)
onSubmitEvent(validatedData)
} catch (error) {
console.error("On submit error : ", error)
}
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="w-full max-w-md space-y-4">
<FormField
control={form.control}
name="title"
render={({ field }) => (
<FormItem>
<FormLabel>Titre</FormLabel>
<FormControl>
<Input placeholder="Ajouter un titre" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="grid grid-cols-[1fr,auto,1fr] items-end gap-2">
<FormField
control={form.control}
name="startDate"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Début</FormLabel>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant="outline"
className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
>
{field.value ? format(field.value, "dd/MM/yyyy") : <span>Choisis une date</span>}
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar mode="single" selected={field.value} onSelect={field.onChange} initialFocus />
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="startTime"
render={({ field }) => (
<FormItem>
<FormControl>
<Input type="time" {...field} className="w-[120px]" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<span className="invisible">Until</span>
<FormField
control={form.control}
name="endDate"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Fin</FormLabel>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant="outline"
className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
>
{field.value ? format(field.value, "MM/dd/yyyy") : <span>Choisis une date</span>}
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar mode="single" selected={field.value} onSelect={field.onChange} initialFocus />
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="endTime"
render={({ field }) => (
<FormItem>
<FormControl>
<Input type="time" {...field} className="w-[120px]" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<FormField
control={form.control}
name="fullDay"
render={({ field }) => (
<FormItem className="flex flex-row items-start space-x-3 space-y-0">
<FormControl>
<Checkbox checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
<FormLabel>Journée complète</FormLabel>
<FormMessage />
</FormItem>
)}
/>
<div className="flex gap-4 items-end">
<FormField
control={form.control}
name="frequency"
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>Fréquence</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Selectionner Fréquence" />
</SelectTrigger>
</FormControl>
<SelectContent>
{frequencies.map((frequency) => (
<SelectItem key={frequency.value} value={frequency.value}>
{frequency.label}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
{frequency !== "unique" && (
<FormField
control={form.control}
name="frequencyEndDate"
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>Jusqu'au</FormLabel>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant="outline"
className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
>
{field.value ? format(field.value, "MM/dd/yyyy") : <span>Choisis une date</span>}
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar mode="single" selected={field.value} onSelect={field.onChange} initialFocus />
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
)}
/>
)}
</div>
<FormField
control={form.control}
name="isVisible"
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel className="align-sub">Evènement visible ?</FormLabel>
<FormControl>
<Checkbox className="m-3 align-top justify-center"
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-end space-x-2">
<Button variant="outline" type="button">
Abandonner
</Button>
<Button type="submit" className="bg-[#6B4EFF] hover:bg-[#5B3FEF]">
Sauvegarder
</Button>
</div>
</form>
</Form>
)
}

View File

@@ -8,11 +8,7 @@ import { createEventsServicePlugin } from "@schedule-x/events-service";
import { createDragAndDropPlugin } from "@schedule-x/drag-and-drop"; import { createDragAndDropPlugin } from "@schedule-x/drag-and-drop";
import { createResizePlugin } from "@schedule-x/resize"; import { createResizePlugin } from "@schedule-x/resize";
import { createEventRecurrencePlugin } from "@schedule-x/event-recurrence"; import { createEventRecurrencePlugin } from "@schedule-x/event-recurrence";
import { import { createViewDay, createViewWeek } from "@schedule-x/calendar";
CalendarEventExternal,
createViewDay,
createViewWeek,
} from "@schedule-x/calendar";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { format } from "date-fns"; import { format } from "date-fns";
import { Dialog, DialogProps } from "@radix-ui/react-dialog"; import { Dialog, DialogProps } from "@radix-ui/react-dialog";
@@ -23,25 +19,49 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { KeyedMutator } from "swr"; import { KeyedMutator } from "swr";
import { getCookie } from "cookies-next"; import { getCookie } from "cookies-next";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { Checkbox } from "@/components/ui/checkbox"; import { EventForm, EventFormValues } from "./event-dialog";
import { eventNames } from "process"; import ICalendarEvent from "@/interfaces/ICalendarEvent";
import { useSearchParams } from "next/navigation";
import { CheckedState } from "@radix-ui/react-checkbox";
import { DateTimePicker } from "./date-time-picker";
interface CalendarEventExternalDB extends CalendarEventExternal { const mapFrequencyToRrule = (
status: "Active" | "Inactive"; frequency: "unique" | "quotidien" | "hebdomadaire" | "mensuel",
} frequencyEndDate?: Date,
): string => {
let rrule = "";
switch (frequency) {
case "quotidien":
rrule = "FREQ=DAILY";
break;
case "hebdomadaire":
rrule = "FREQ=WEEKLY";
break;
case "mensuel":
rrule = "FREQ=MONTHLY";
break;
default:
return "";
}
if (frequencyEndDate) {
const until = frequencyEndDate.getTime();
const untilDate = new Date(until);
const epochDateString = untilDate
.toISOString()
.replace(/[-:]/g, "")
.split(".")[0]; // Format as YYYYMMDDTHHmmss
rrule += `;UNTIL=${epochDateString}`;
}
return rrule;
};
const Planning: React.FC<{ const Planning: React.FC<{
events: CalendarEventExternal[]; events: ICalendarEvent[];
mutate?: KeyedMutator<ApiResponse<CalendarEventExternal[]>>; mutate?: KeyedMutator<ApiResponse<ICalendarEvent[]>>;
}> = ({ events, mutate }) => { }> = ({ events, mutate }) => {
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();
console.log(resolvedTheme); console.log(resolvedTheme);
@@ -54,18 +74,15 @@ const Planning: React.FC<{
createEventRecurrencePlugin(), createEventRecurrencePlugin(),
] ]
: []; : [];
const [eventSelected, setEventSelected] = const [eventSelected, setEventSelected] = useState<ICalendarEvent | null>(
useState<CalendarEventExternal | null>(null); null,
const [eventStatus, setEventStatus] = useState<"Active" | "Inactive">( );
"Active", const [newEvent, setNewEvent] = useState<Omit<ICalendarEvent, "id"> | null>(
null,
); );
const [newEvent, setNewEvent] = useState<Omit<
CalendarEventExternal,
"id"
> | null>(null);
const handleEventUpdate = async (eventSelected: CalendarEventExternal) => { const handleEventUpdate = async (eventSelected: ICalendarEvent) => {
const event: CalendarEventExternal = { const event: ICalendarEvent = {
...eventSelected, ...eventSelected,
start: `${new Date(eventSelected.start).toISOString()}`, start: `${new Date(eventSelected.start).toISOString()}`,
end: `${new Date(eventSelected.end).toISOString()}`, end: `${new Date(eventSelected.end).toISOString()}`,
@@ -104,14 +121,10 @@ const Planning: React.FC<{
})), })),
callbacks: { callbacks: {
onEventClick(event, e) { onEventClick(event, e) {
setEventSelected(event); setEventSelected(event as ICalendarEvent);
}, },
// async onBeforeEventUpdate(oldEvent, newEvent) {
// await request("/api/me/has-permissions")
// },
async onEventUpdate(newEvent) { async onEventUpdate(newEvent) {
// console.log(event); await handleEventUpdate(newEvent as ICalendarEvent);
await handleEventUpdate(newEvent);
}, },
}, },
}, },
@@ -145,72 +158,20 @@ const Planning: React.FC<{
setNewEvent((e) => (open ? e : null)); setNewEvent((e) => (open ? e : null));
}} }}
event={newEvent} event={newEvent}
//onStartChange={(e) => { onSubmitEvent={async (eventFormValues) => {
// const val = e.currentTarget.value; const rrule = mapFrequencyToRrule(
// setNewEvent((ev) => { eventFormValues.frequency,
// if (ev) eventFormValues.frequencyEndDate,
// return { );
// ...ev,
// start: val,
// };
// return ev;
// });
//}}
onStartDateChange={(date) => {
setNewEvent((ev) => {
if (ev)
return {
...ev,
start: date,
};
return ev;
});
}}
onEndDateChange={(date) => {
setNewEvent((ev) => {
if (ev)
return {
...ev,
end: date,
};
return ev;
});
}}
onTitleChange={(e) => {
const val = e.currentTarget.value;
setNewEvent((ev) => {
if (ev)
return {
...ev,
title: val,
};
return ev;
});
}}
onActiveStateChange={(e) => {
e
? setEventStatus("Active")
: setEventStatus("Inactive");
}}
//onEndChange={(e) => {
// const val = e.currentTarget.value;
// setNewEvent((ev) => {
// if (ev)
// return {
// ...ev,
// end: val,
// };
// return ev;
// });
//}}
onAdd={async () => {
try { try {
const event: Omit<CalendarEventExternal, "id"> = { const event: Omit<ICalendarEvent, "id"> = {
...newEvent, ...newEvent,
start: `${new Date(newEvent.start).toISOString()}`, start: `${eventFormValues.startDate} ${eventFormValues.startTime}`,
end: `${new Date(newEvent.end).toISOString()}`, end: `${eventFormValues.endDate} ${eventFormValues.endTime}`,
title: newEvent.title, title: `${eventFormValues.title}`,
status: eventStatus, fullDay: eventFormValues.fullDay,
rrule: rrule,
isVisible: eventFormValues.isVisible,
}; };
const res = await request<undefined>( const res = await request<undefined>(
`/events/new`, `/events/new`,
@@ -241,25 +202,8 @@ const Planning: React.FC<{
setEventSelected((e) => (open ? e : null)); setEventSelected((e) => (open ? e : null));
}} }}
event={eventSelected} event={eventSelected}
onStartDateChange={(date) => { onSubmitEvent={(eventForm) => {
setEventSelected((ev) => { console.log("Event form: " + eventForm);
if (ev && date)
return {
...ev,
start: format(date, "YYYY-MM-DD HH:MM"),
};
return ev;
});
}}
onEndDateChange={(date) => {
setEventSelected((ev) => {
if (ev && date)
return {
...ev,
end: format(date, "YYYY-MM-DD HH:MM"),
};
return ev;
});
}} }}
onDelete={async () => { onDelete={async () => {
calendar?.events?.remove(eventSelected.id); calendar?.events?.remove(eventSelected.id);
@@ -296,35 +240,21 @@ const Planning: React.FC<{
const EventDialog: React.FC< const EventDialog: React.FC<
{ {
// onEndChange: React.ChangeEventHandler<HTMLInputElement>; onSubmitEvent: (eventFormValues: EventFormValues) => void;
// onStartChange: React.ChangeEventHandler<HTMLInputElement>;
onStartDateChange: (selectedDate: Date | undefined) => void;
onEndDateChange: (selectedDate: Date | undefined) => void;
onDelete?: () => void; onDelete?: () => void;
onUpdate?: () => void; onUpdate?: () => void;
onAdd?: () => void; onAdd?: () => void;
onTitleChange?: React.ChangeEventHandler<HTMLInputElement>; event: ICalendarEvent | Omit<ICalendarEvent, "id">;
onActiveStateChange?: (status: boolean) => void;
event: CalendarEventExternal | Omit<CalendarEventExternal, "id">;
} & DialogProps } & DialogProps
> = ({ > = ({
open, open,
onOpenChange, onOpenChange,
// onEndChange, onSubmitEvent,
// onStartChange,
onStartDateChange,
onEndDateChange,
onDelete, onDelete,
onUpdate, onUpdate,
onAdd, onAdd,
onTitleChange,
onActiveStateChange,
event, event,
}) => { }) => {
const [checked, setChecked] = useState<CheckedState>(
event.status === "Active",
);
return ( return (
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-md"> <DialogContent className="sm:max-w-md">
@@ -332,67 +262,7 @@ const EventDialog: React.FC<
<DialogTitle>{event.title}</DialogTitle> <DialogTitle>{event.title}</DialogTitle>
<DialogDescription>{event.description}</DialogDescription> <DialogDescription>{event.description}</DialogDescription>
</DialogHeader> </DialogHeader>
<EventForm event={event} onSubmitEvent={onSubmitEvent} />
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="title" className="text-right">
Titre
</Label>
<Input
id="title"
value={event.title || ""}
onChange={onTitleChange}
className="col-span-3"
type="text"
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="start" className="text-right">
Début
</Label>
<DateTimePicker
onDateSelectChange={(date) =>
onStartDateChange(date)
}
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="end" className="text-right">
Fin
</Label>
{/*<Input
id="end"
value={event.end || ""}
onChange={onEndChange}
className="col-span-3"
/> */}
<DateTimePicker
onDateSelectChange={(date) => onEndDateChange(date)}
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label
htmlFor="status"
className="col-span-3 text-right"
>
Rendre cette évènement actif ?
</Label>
<Checkbox
id="status"
checked={checked}
onCheckedChange={(e) => {
const booleanCheck = !!e;
setChecked((prev) => {
return !prev;
});
if (onActiveStateChange) {
onActiveStateChange(booleanCheck);
}
}}
/>
</div>
</div>
<DialogFooter className="flex flex-row justify-end"> <DialogFooter className="flex flex-row justify-end">
{onUpdate && ( {onUpdate && (
<Button <Button

View File

@@ -0,0 +1,8 @@
import {
CalendarEventExternal,
} from "@schedule-x/calendar";
export default interface ICalendarEvent extends CalendarEventExternal {
isVisible: boolean,
fullday: boolean,
rrule: string
}