diff --git a/backend/api/core/schemas.go b/backend/api/core/schemas.go
index 5660a58..a2b6e35 100644
--- a/backend/api/core/schemas.go
+++ b/backend/api/core/schemas.go
@@ -97,11 +97,11 @@ func Verify(ctx context.Context, email, password string) (*User, error) {
type Event struct {
bun.BaseModel `bun:"table:events"`
- EventID uuid.UUID `bun:"type:uuid,pk,default:gen_random_uuid()" json:"eventID"`
+ EventID uuid.UUID `bun:"event_id,type:uuid,pk,default:gen_random_uuid()" json:"id"`
CreationDate time.Time `bun:"creation_date,notnull,default:current_timestamp" json:"creationDate"`
- ScheduleStart time.Time `bun:"schedule_start,notnull" json:"scheduleStart"`
- ScheduleEnd time.Time `bun:"schedule_end,notnull" json:"scheduleEnd"`
- Status Status `bun:"status,notnull,default:Inactive" json:"status"`
+ ScheduleStart time.Time `bun:"schedule_start,notnull" json:"start"`
+ ScheduleEnd time.Time `bun:"schedule_end,notnull" json:"end"`
+ Status Status `bun:"status,notnull,default:'Inactive'" json:"status"`
}
type EventToUser struct {
diff --git a/backend/api/delete_event.go b/backend/api/delete_event.go
index 586eac4..578229d 100644
--- a/backend/api/delete_event.go
+++ b/backend/api/delete_event.go
@@ -13,7 +13,7 @@ func HandleDeleteEvent(w http.ResponseWriter, r *http.Request) {
var event core.Event
res, err := core.DB.NewDelete().
Model(&event).
- Where("id = ?", uuid).
+ Where("event_id = ?", uuid).
Returning("*").
Exec(context.Background())
if err != nil {
@@ -24,10 +24,9 @@ func HandleDeleteEvent(w http.ResponseWriter, r *http.Request) {
return
}
log.Println(res)
-
+
core.JSONSuccess{
Status: core.Success,
Message: "Event deleted.",
}.Respond(w, http.StatusOK)
}
-
diff --git a/backend/api/new_blog.go b/backend/api/new_blog.go
index 29419f2..de12e4d 100644
--- a/backend/api/new_blog.go
+++ b/backend/api/new_blog.go
@@ -10,14 +10,6 @@ import (
)
func HandleCreateBlog(w http.ResponseWriter, r *http.Request) {
- if r.Method != http.MethodPost {
- core.JSONError{
- Status: core.Error,
- Message: "Method is not allowed",
- }.Respond(w, http.StatusMethodNotAllowed)
- return
- }
-
body, err := io.ReadAll(r.Body)
if err != nil {
core.JSONError{
diff --git a/backend/api/new_event.go b/backend/api/new_event.go
index 6abba18..cade7c5 100644
--- a/backend/api/new_event.go
+++ b/backend/api/new_event.go
@@ -18,18 +18,19 @@ func HandleCreateEvent(w http.ResponseWriter, r *http.Request) {
}.Respond(w, http.StatusBadRequest)
return
}
-
- _, err = core.DB.NewInsert().Model(&event).Exec(context.Background())
+
+ _, err = core.DB.NewInsert().Model(&event).Exec(context.Background())
if err != nil {
core.JSONError{
Status: core.Error,
Message: err.Error(),
}.Respond(w, http.StatusNotAcceptable)
- }
+ return
+ }
core.JSONSuccess{
Status: core.Success,
Message: "Event created",
- Data: event,
+ Data: event,
}.Respond(w, http.StatusCreated)
}
diff --git a/backend/api/update_event.go b/backend/api/update_event.go
index ed143ae..753f40a 100644
--- a/backend/api/update_event.go
+++ b/backend/api/update_event.go
@@ -22,7 +22,7 @@ func HandleUpdateEvent(w http.ResponseWriter, r *http.Request) {
}
event_uuid := r.PathValue("event_uuid")
- event.EventID, err = uuid.FromBytes([]byte(event_uuid))
+ event.EventID, err = uuid.Parse(event_uuid)
if err != nil {
core.JSONError{
Status: core.Error,
@@ -44,7 +44,7 @@ func HandleUpdateEvent(w http.ResponseWriter, r *http.Request) {
// }
_, err = core.DB.NewUpdate().
- Model(event).
+ Model(&event).
OmitZero().
WherePK().
Exec(context.Background())
@@ -62,4 +62,3 @@ func HandleUpdateEvent(w http.ResponseWriter, r *http.Request) {
Data: event,
}.Respond(w, http.StatusOK)
}
-
diff --git a/backend/api/update_shortcode.go b/backend/api/update_shortcode.go
index ab699a3..17c98f9 100644
--- a/backend/api/update_shortcode.go
+++ b/backend/api/update_shortcode.go
@@ -13,10 +13,11 @@ import (
)
type UpdateShortcodeArgs struct {
- Code *string `json:"code"` // The shortcode value
- Type *core.ShortcodeType `json:"type"`
- Value *string `json:"value"`
- MediaID *uuid.UUID `json:"media_id"` // Nullable reference to another table's ID
+ ID *int64 `json:"id,omitempty"`
+ Code *string `json:"code,omitempty"` // The shortcode value
+ Type *core.ShortcodeType `bun:"shortcode_type" json:"type,omitempty"`
+ Value *string `json:"value,omitempty"`
+ MediaID *uuid.UUID `json:"media_id,omitempty"` // Nullable reference to another table's ID
}
func HandleUpdateShortcode(w http.ResponseWriter, r *http.Request) {
@@ -51,7 +52,7 @@ func HandleUpdateShortcode(w http.ResponseWriter, r *http.Request) {
code := r.PathValue("shortcode")
_, err = updateQuery.
- Where("code = ?", code).
+ Where("id = ? OR code = ?", updateArgs.ID, code).
Returning("*").
Exec(context.Background())
diff --git a/frontend/app/(auth)/dashboard/settings/shortcodes/page.tsx b/frontend/app/(auth)/dashboard/settings/shortcodes/page.tsx
index 03fe4cd..cd508f9 100644
--- a/frontend/app/(auth)/dashboard/settings/shortcodes/page.tsx
+++ b/frontend/app/(auth)/dashboard/settings/shortcodes/page.tsx
@@ -48,7 +48,7 @@ export default function ShortcodesPage() {
};
return (
-
+
Shortcodes
{isLoading && (
diff --git a/frontend/app/(main)/planning/page.tsx b/frontend/app/(main)/planning/page.tsx
index 3584f6a..b7fbcb9 100644
--- a/frontend/app/(main)/planning/page.tsx
+++ b/frontend/app/(main)/planning/page.tsx
@@ -1,276 +1,20 @@
"use client";
+import Planning from "@/components/planning.tsx";
+import { useApi } from "@/hooks/use-api";
+import { type CalendarEventExternal } from "@schedule-x/calendar";
+import { Loader2 } from "lucide-react";
-import { request, useApi } from "@/hooks/use-api";
-import "@schedule-x/theme-shadcn/dist/index.css";
-import { useNextCalendarApp, ScheduleXCalendar } from "@schedule-x/react";
-import { createEventsServicePlugin } from "@schedule-x/events-service";
-import {
- CalendarEventExternal,
- createViewDay,
- createViewWeek,
-} from "@schedule-x/calendar";
-import { useEffect, useState } from "react";
-import { format } from "date-fns";
-import { Dialog } from "@radix-ui/react-dialog";
-import {
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
-} from "@/components/ui/dialog";
-import { Label } from "@/components/ui/label";
-import { Input } from "@/components/ui/input";
-import { Button } from "@/components/ui/button";
-import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@/components/ui/popover";
-import { CalendarIcon } from "lucide-react";
-import { Calendar } from "@/components/ui/calendar";
-import { cn } from "@/lib/utils";
-import { requestFormReset } from "react-dom";
+const Page = () => {
+ const {
+ data: requestedEvents,
+ isLoading,
+ success,
+ mutate,
+ } = useApi
("/events", undefined, false, false);
-const Planning = () => {
- const plugins = [createEventsServicePlugin()];
- const [eventSelected, setEventSelected] =
- useState(null);
- const [events, setEvents] = useState([
- {
- id: "1", // TODO put an uuid there
- title: "Event 1",
- start: format(new Date(Date.now()), "yyyy-MM-dd HH:mm"),
- end: format(
- new Date(Date.now() + 1 * 3600 * 1000),
- "yyyy-MM-dd HH:mm",
- ),
- },
- ]);
-
- const [requestCreateEvent, setRequestCreateEvent] = useState(false)
-
- const calendar = useNextCalendarApp(
- {
- theme: "shadcn",
- views: [createViewDay(), createViewWeek()],
- defaultView: "week",
- isDark: true,
- isResponsive: true,
- locale: "fr-FR",
- dayBoundaries: {
- start: "06:00",
- end: "00:00",
- },
- events,
- callbacks: {
- onEventClick(event, e) {
- setEventSelected(event);
- },
- async onClickDateTime(dateTime) {
- setRequestCreateEvent(true)
- const newEvent: CalendarEventExternal = {
- id: "5",
- title: "Event 1",
- start: dateTime,
- end: format(
- new Date(dateTime).getTime() + (1000 * 60 * 60),
- "yyyy-MM-dd HH:mm",
- ),
- }
- try {
- const res = await request(
- `/events/new`,
- {
- method: "POST",
- body: JSON.stringify(newEvent),
- requiresAuth: true,
- csrfToken: false
- },)
- if (res.status === "Error") {
- console.log("Error")
- }
- if (res.status === "Success") {
- console.log("Success")
- }
- } catch (e) {
- console.log(e)
- }
- },
- },
- },
- plugins,
- );
-
- const {data: requestedEvents, isLoading, success} = useApi("/events", {
- onSuccess: (data) => {
- calendar?.events.set(data)
- }
- }, false, false)
-
- useEffect(() => {
- // get all events
- calendar?.events.getAll();
- }, []);
-
- return (
-
-
-
-
-
-
- );
+ if (isLoading) return ;
+ if (success)
+ return ;
};
-export default Planning;
+export default Page;
diff --git a/frontend/components/members-table.tsx b/frontend/components/members-table.tsx
new file mode 100644
index 0000000..399ec59
--- /dev/null
+++ b/frontend/components/members-table.tsx
@@ -0,0 +1,238 @@
+"use client";
+
+import { useState } from "react";
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table";
+import { Button } from "@/components/ui/button";
+import { Checkbox } from "@/components/ui/checkbox";
+import { ScrollArea } from "@/components/ui/scroll-area";
+import { UpdateMemberDialog } from "./UpdateMemberDialog";
+import { AddMemberDialog } from "./AddMemberDialog";
+
+interface Member {
+ user_id: string;
+ firstname: string;
+ lastname: string;
+ email: string;
+ password: string;
+ phone: string;
+ role: string;
+}
+
+const initialMembers: Member[] = [
+ // Add some sample data here
+ {
+ user_id: "1",
+ firstname: "John",
+ lastname: "Doe",
+ email: "john@example.com",
+ password: "********",
+ phone: "1234567890",
+ role: "User",
+ },
+ {
+ user_id: "1",
+ firstname: "John",
+ lastname: "Doe",
+ email: "john@example.com",
+ password: "********",
+ phone: "1234567890",
+ role: "User",
+ },
+ {
+ user_id: "1",
+ firstname: "John",
+ lastname: "Doe",
+ email: "john@example.com",
+ password: "********",
+ phone: "1234567890",
+ role: "User",
+ },
+ {
+ user_id: "1",
+ firstname: "John",
+ lastname: "Doe",
+ email: "john@example.com",
+ password: "********",
+ phone: "1234567890",
+ role: "User",
+ },
+ {
+ user_id: "1",
+ firstname: "John",
+ lastname: "Doe",
+ email: "john@example.com",
+ password: "********",
+ phone: "1234567890",
+ role: "User",
+ },
+ {
+ user_id: "1",
+ firstname: "John",
+ lastname: "Doe",
+ email: "john@example.com",
+ password: "********",
+ phone: "1234567890",
+ role: "User",
+ },
+ {
+ user_id: "1",
+ firstname: "John",
+ lastname: "Doe",
+ email: "john@example.com",
+ password: "********",
+ phone: "1234567890",
+ role: "User",
+ },
+ // Add more sample members...
+];
+
+export function MembersTable() {
+ const [members, setMembers] = useState(initialMembers);
+ const [selectMode, setSelectMode] = useState(false);
+ const [selectedMembers, setSelectedMembers] = useState([]);
+ const [updateDialogOpen, setUpdateDialogOpen] = useState(false);
+ const [addDialogOpen, setAddDialogOpen] = useState(false);
+ const [currentMember, setCurrentMember] = useState(null);
+
+ const toggleSelectMode = () => {
+ setSelectMode(!selectMode);
+ setSelectedMembers([]);
+ };
+
+ const toggleMemberSelection = (userId: string) => {
+ setSelectedMembers((prev) =>
+ prev.includes(userId)
+ ? prev.filter((id) => id !== userId)
+ : [...prev, userId],
+ );
+ };
+
+ const handleUpdate = (member: Member) => {
+ setCurrentMember(member);
+ setUpdateDialogOpen(true);
+ };
+
+ const handleDelete = (userId: string) => {
+ setMembers((prev) =>
+ prev.filter((member) => member.user_id !== userId),
+ );
+ };
+
+ const handleAdd = (newMember: Member) => {
+ setMembers((prev) => [
+ ...prev,
+ { ...newMember, user_id: String(prev.length + 1) },
+ ]);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ {selectMode && (
+
+ Select
+
+ )}
+ User ID
+ First Name
+ Last Name
+ Email
+ Password
+ Phone
+ Role
+
+ Actions
+
+
+
+
+ {members.map((member) => (
+
+ {selectMode && (
+
+
+ toggleMemberSelection(
+ member.user_id,
+ )
+ }
+ />
+
+ )}
+ {member.user_id}
+ {member.firstname}
+ {member.lastname}
+ {member.email}
+ {member.password}
+ {member.phone}
+ {member.role}
+
+
+
+
+
+ ))}
+
+
+
+
+
setUpdateDialogOpen(false)}
+ member={currentMember}
+ onUpdate={(updatedMember) => {
+ setMembers((prev) =>
+ prev.map((m) =>
+ m.user_id === updatedMember.user_id
+ ? updatedMember
+ : m,
+ ),
+ );
+ setUpdateDialogOpen(false);
+ }}
+ />
+ setAddDialogOpen(false)}
+ onAdd={handleAdd}
+ />
+
+ );
+}
diff --git a/frontend/components/planning.tsx.tsx b/frontend/components/planning.tsx.tsx
new file mode 100644
index 0000000..675612c
--- /dev/null
+++ b/frontend/components/planning.tsx.tsx
@@ -0,0 +1,356 @@
+"use client";
+
+import { ApiResponse, request, useApi } from "@/hooks/use-api";
+import "@schedule-x/theme-shadcn/dist/index.css";
+import { useNextCalendarApp, ScheduleXCalendar } from "@schedule-x/react";
+import { createEventsServicePlugin } from "@schedule-x/events-service";
+import { createDragAndDropPlugin } from "@schedule-x/drag-and-drop";
+import { createResizePlugin } from "@schedule-x/resize";
+import { createEventRecurrencePlugin } from "@schedule-x/event-recurrence";
+import {
+ CalendarEventExternal,
+ createViewDay,
+ createViewWeek,
+} from "@schedule-x/calendar";
+import { useEffect, useState } from "react";
+import { format } from "date-fns";
+import { Dialog, DialogProps } from "@radix-ui/react-dialog";
+import {
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { Label } from "@/components/ui/label";
+import { Input } from "@/components/ui/input";
+import { Button } from "@/components/ui/button";
+import { KeyedMutator } from "swr";
+
+const Planning: React.FC<{
+ events: CalendarEventExternal[];
+ mutate?: KeyedMutator>;
+}> = ({ events, mutate }) => {
+ const plugins = [
+ createEventsServicePlugin(),
+ createDragAndDropPlugin(),
+ createResizePlugin(),
+ createEventRecurrencePlugin(),
+ ];
+ const [eventSelected, setEventSelected] =
+ useState(null);
+ const [newEvent, setNewEvent] = useState | null>(null);
+
+ const handleEventUpdate = async (eventSelected: CalendarEventExternal) => {
+ const event: CalendarEventExternal = {
+ ...eventSelected,
+ start: `${new Date(eventSelected.start).toISOString()}`,
+ end: `${new Date(eventSelected.end).toISOString()}`,
+ };
+ try {
+ const res = await request(`/events/${event.id}/update`, {
+ method: "PATCH",
+ body: event,
+ requiresAuth: true,
+ csrfToken: false,
+ });
+ if (res.status === "Error") {
+ console.log("Error");
+ }
+ if (res.status === "Success") {
+ calendar?.events?.update(eventSelected);
+ }
+ } catch (e) {
+ console.log(e);
+ }
+ };
+
+ const calendar = useNextCalendarApp(
+ {
+ theme: "shadcn",
+ views: [createViewDay(), createViewWeek()],
+ defaultView: "week",
+ isDark: true,
+ isResponsive: true,
+ locale: "fr-FR",
+ dayBoundaries: {
+ start: "06:00",
+ end: "00:00",
+ },
+ events: events.map((event) => ({
+ ...event,
+ start: format(new Date(event.start), "yyyy-MM-dd HH:mm"),
+ end: format(new Date(event.end), "yyyy-MM-dd HH:mm"),
+ })),
+ callbacks: {
+ onEventClick(event, e) {
+ setEventSelected(event);
+ },
+ async onEventUpdate(event) {
+ await handleEventUpdate(event);
+ },
+ },
+ },
+ plugins,
+ );
+
+ useEffect(() => {
+ calendar?.events.getAll();
+ }, []);
+
+ const AddButton: React.FC = () => (
+
+ );
+
+ return (
+
+
+ {newEvent && (
+
{
+ setNewEvent((e) => (open ? e : null));
+ }}
+ event={newEvent}
+ onStartChange={(e) => {
+ const val = e.currentTarget.value;
+ setNewEvent((ev) => {
+ if (ev)
+ return {
+ ...ev,
+ start: val,
+ };
+ return ev;
+ });
+ }}
+ onEndChange={(e) => {
+ const val = e.currentTarget.value;
+ setNewEvent((ev) => {
+ if (ev)
+ return {
+ ...ev,
+ end: val,
+ };
+ return ev;
+ });
+ }}
+ onAdd={async () => {
+ try {
+ const event: Omit = {
+ ...newEvent,
+ start: `${new Date(newEvent.start).toISOString()}`,
+ end: `${new Date(newEvent.end).toISOString()}`,
+ };
+ const res = await request(
+ `/events/new`,
+ {
+ method: "POST",
+ body: event,
+ requiresAuth: true,
+ csrfToken: false,
+ },
+ );
+ if (res.status === "Error") {
+ console.log("Error");
+ }
+ if (res.status === "Success") {
+ mutate?.();
+ console.log("Success");
+ }
+ } catch (e) {
+ console.log(e);
+ }
+ }}
+ />
+ )}
+ {eventSelected && (
+ {
+ setEventSelected((e) => (open ? e : null));
+ }}
+ event={eventSelected}
+ onStartChange={(e) => {
+ const val = e.currentTarget.value;
+ setEventSelected((ev) => {
+ if (ev)
+ return {
+ ...ev,
+ start: val,
+ };
+ return ev;
+ });
+ }}
+ onEndChange={(e) => {
+ const val = e.currentTarget.value;
+ setEventSelected((ev) => {
+ if (ev)
+ return {
+ ...ev,
+ end: val,
+ };
+ return ev;
+ });
+ }}
+ onDelete={async () => {
+ calendar?.events?.remove(eventSelected.id);
+ try {
+ const res = await request(
+ `/events/${eventSelected.id}/delete`,
+ {
+ method: "DELETE",
+ body: eventSelected,
+ requiresAuth: false,
+ csrfToken: false,
+ },
+ );
+ if (res.status === "Error") {
+ console.log("Error");
+ }
+ if (res.status === "Success") {
+ console.log("Success");
+ }
+ } catch (e) {
+ console.log(e);
+ }
+ setEventSelected(null);
+ }}
+ onUpdate={async () => {
+ await handleEventUpdate(eventSelected);
+ setEventSelected(null);
+ }}
+ />
+ )}
+
+ );
+};
+
+const EventDialog: React.FC<
+ {
+ onEndChange: React.ChangeEventHandler;
+ onStartChange: React.ChangeEventHandler;
+ onDelete?: () => void;
+ onUpdate?: () => void;
+ onAdd?: () => void;
+ event: CalendarEventExternal | Omit;
+ } & DialogProps
+> = ({
+ open,
+ onOpenChange,
+ onEndChange,
+ onStartChange,
+ onDelete,
+ onUpdate,
+ onAdd,
+ event,
+}) => {
+ return (
+
+ );
+};
+
+export default Planning;
diff --git a/frontend/components/shortcode-dialogue.tsx b/frontend/components/shortcode-dialogue.tsx
index c80a401..d0c4564 100644
--- a/frontend/components/shortcode-dialogue.tsx
+++ b/frontend/components/shortcode-dialogue.tsx
@@ -9,55 +9,47 @@ import {
DialogFooter,
DialogHeader,
DialogTitle,
- DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import type IShortcode from "@/interfaces/IShortcode";
interface ShortcodeDialogProps {
- onSave: (shortcode: Omit) => void;
+ onSave: (shortcode: IShortcode) => void;
+ open: boolean;
+ setOpen: () => void;
+ shortcode?: IShortcode;
}
-export default function ShortcodeDialog({ onSave }: ShortcodeDialogProps) {
- const [open, setOpen] = useState(false);
- const [code, setCode] = useState("");
- const [type, setType] = useState<"value" | "media">("value");
- const [value, setValue] = useState("");
- const [mediaId, setMediaId] = useState("");
+export default function ShortcodeDialog({
+ onSave,
+ open,
+ setOpen,
+ shortcode,
+}: ShortcodeDialogProps) {
+ const [_shortcode, setShortcode] = useState(
+ shortcode ?? { code: "", type: "", id: 0 },
+ );
const handleSave = () => {
- onSave({ code, type, value, media_id: mediaId });
- setOpen(false);
+ onSave(_shortcode);
+ setOpen();
resetForm();
};
const resetForm = () => {
- setCode("");
- setType("value");
- setValue("");
- setMediaId("");
+ setShortcode({ code: "", type: "", id: 0 });
};
return (
@@ -111,7 +120,7 @@ export default function ShortcodeDialog({ onSave }: ShortcodeDialogProps) {
diff --git a/frontend/components/shortcodes-table.tsx b/frontend/components/shortcodes-table.tsx
index ff6a3e9..95b30e5 100644
--- a/frontend/components/shortcodes-table.tsx
+++ b/frontend/components/shortcodes-table.tsx
@@ -18,6 +18,7 @@ import {
import { MoreHorizontal } from "lucide-react";
import type IShortcode from "@/interfaces/IShortcode";
import ShortcodeDialog from "@/components/shortcode-dialogue";
+import { useState } from "react";
interface ShortcodeTableProps {
shortcodes: IShortcode[];
@@ -32,10 +33,25 @@ export function ShortcodeTable({
onDelete,
onAdd,
}: ShortcodeTableProps) {
+ const [shortcodeSelected, setUpdateDialog] = useState(
+ null,
+ );
+ const [addDialog, setAddDialog] = useState(false);
return (
-
+
+ setAddDialog(false)}
+ />
@@ -44,7 +60,7 @@ export function ShortcodeTable({
ID
Code
Type
- Value
+ Valeur
Media ID
Actions
@@ -69,7 +85,7 @@ export function ShortcodeTable({
className="h-8 w-8 p-0"
>
- Open menu
+ Ouvrir le menu
@@ -77,17 +93,17 @@ export function ShortcodeTable({
- onUpdate(shortcode)
+ setUpdateDialog(shortcode)
}
>
- Update
+ Mettre à jour
onDelete(shortcode.code)
}
>
- Delete
+ Supprimer
@@ -96,6 +112,15 @@ export function ShortcodeTable({
))}
+
+ {shortcodeSelected && (
+
setUpdateDialog(null)}
+ />
+ )}
);
diff --git a/frontend/components/ui/checkbox.tsx b/frontend/components/ui/checkbox.tsx
new file mode 100644
index 0000000..577375b
--- /dev/null
+++ b/frontend/components/ui/checkbox.tsx
@@ -0,0 +1,30 @@
+"use client";
+
+import * as React from "react";
+import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
+import { Check } from "lucide-react";
+
+import { cn } from "@/lib/utils";
+
+const Checkbox = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+
+));
+Checkbox.displayName = CheckboxPrimitive.Root.displayName;
+
+export { Checkbox };
diff --git a/frontend/components/ui/scroll-area.tsx b/frontend/components/ui/scroll-area.tsx
new file mode 100644
index 0000000..98234fc
--- /dev/null
+++ b/frontend/components/ui/scroll-area.tsx
@@ -0,0 +1,50 @@
+"use client";
+
+import * as React from "react";
+import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
+
+import { cn } from "@/lib/utils";
+
+const ScrollArea = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+ {children}
+
+
+
+
+));
+ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
+
+const ScrollBar = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef<
+ typeof ScrollAreaPrimitive.ScrollAreaScrollbar
+ >
+>(({ className, orientation = "vertical", ...props }, ref) => (
+
+
+
+));
+ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
+
+export { ScrollArea, ScrollBar };
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 38b23fb..38596ed 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -11,20 +11,26 @@
"@hookform/resolvers": "^3.10.0",
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-avatar": "^1.1.2",
+ "@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-collapsible": "^1.1.2",
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-navigation-menu": "^1.2.3",
"@radix-ui/react-popover": "^1.1.4",
+ "@radix-ui/react-scroll-area": "^1.2.2",
"@radix-ui/react-select": "^2.1.4",
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-switch": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.6",
+ "@schedule-x/drag-and-drop": "^2.15.1",
+ "@schedule-x/event-modal": "^2.15.1",
+ "@schedule-x/event-recurrence": "^2.15.1",
"@schedule-x/events-service": "^2.14.3",
"@schedule-x/react": "^2.13.3",
+ "@schedule-x/resize": "^2.15.1",
"@schedule-x/theme-default": "^2.14.3",
"@schedule-x/theme-shadcn": "^2.14.3",
"class-variance-authority": "^0.7.1",
@@ -1067,6 +1073,36 @@
}
}
},
+ "node_modules/@radix-ui/react-checkbox": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.3.tgz",
+ "integrity": "sha512-HD7/ocp8f1B3e6OHygH0n7ZKjONkhciy1Nh0yuBgObqThc3oyx+vuMfFHKAknXRHHWVE9XvXStxJFyjUmB8PIw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.1",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "@radix-ui/react-use-previous": "1.1.0",
+ "@radix-ui/react-use-size": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-collapsible": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.2.tgz",
@@ -1588,6 +1624,37 @@
}
}
},
+ "node_modules/@radix-ui/react-scroll-area": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.2.tgz",
+ "integrity": "sha512-EFI1N/S3YxZEW/lJ/H1jY3njlvTd8tBmgKEn4GHi51+aMm94i6NmAJstsm5cu3yJwYqYc93gpCPm21FeAbFk6g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/number": "1.1.0",
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-presence": "1.1.2",
+ "@radix-ui/react-primitive": "2.0.1",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-select": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.4.tgz",
@@ -1936,6 +2003,28 @@
"preact": "^10.19.2"
}
},
+ "node_modules/@schedule-x/drag-and-drop": {
+ "version": "2.15.1",
+ "resolved": "https://registry.npmjs.org/@schedule-x/drag-and-drop/-/drag-and-drop-2.15.1.tgz",
+ "integrity": "sha512-CBT2AUgVfMTz0tGDk8U++gzx7cnl/WrvX3XBENJ+cSb7PqR/4nz8ONvv3smJGsEM/GR53Efv9gdeBIAln9Mt7w==",
+ "license": "MIT"
+ },
+ "node_modules/@schedule-x/event-modal": {
+ "version": "2.15.1",
+ "resolved": "https://registry.npmjs.org/@schedule-x/event-modal/-/event-modal-2.15.1.tgz",
+ "integrity": "sha512-pSSI9W7JE7ClU3wXuPNbiirX4kVK6kZ40NryWmRyx1Unko6VmlLLEOeQrqkeEH6A89jTHUCgWyxZWzIdQCLHxQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@preact/signals": "^1.1.5",
+ "preact": "^10.19.2"
+ }
+ },
+ "node_modules/@schedule-x/event-recurrence": {
+ "version": "2.15.1",
+ "resolved": "https://registry.npmjs.org/@schedule-x/event-recurrence/-/event-recurrence-2.15.1.tgz",
+ "integrity": "sha512-jkkGzofxq4C1mnX4RCbIoA1e5Z4G3+riBALOEusd7AoBXGxUFBtks+f0S1YZH0Taa7WCD6b2RptihwoNbDP6Rg==",
+ "license": "MIT"
+ },
"node_modules/@schedule-x/events-service": {
"version": "2.14.3",
"resolved": "https://registry.npmjs.org/@schedule-x/events-service/-/events-service-2.14.3.tgz",
@@ -1953,6 +2042,11 @@
"react-dom": "^16.7.0 || ^17 || ^18 || ^19"
}
},
+ "node_modules/@schedule-x/resize": {
+ "version": "2.15.1",
+ "resolved": "https://registry.npmjs.org/@schedule-x/resize/-/resize-2.15.1.tgz",
+ "integrity": "sha512-NPTJ08ATPFcv38uO/9Of1Re1SiU7VZXvVgLVBZpOGGcwDBPt8FzD6LkWCQBgx6Bz+DLLtSd+QjEgt1tOhi2sJA=="
+ },
"node_modules/@schedule-x/theme-default": {
"version": "2.14.3",
"resolved": "https://registry.npmjs.org/@schedule-x/theme-default/-/theme-default-2.14.3.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 3a8e60b..994a335 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -12,20 +12,26 @@
"@hookform/resolvers": "^3.10.0",
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-avatar": "^1.1.2",
+ "@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-collapsible": "^1.1.2",
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-navigation-menu": "^1.2.3",
"@radix-ui/react-popover": "^1.1.4",
+ "@radix-ui/react-scroll-area": "^1.2.2",
"@radix-ui/react-select": "^2.1.4",
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-switch": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.6",
+ "@schedule-x/drag-and-drop": "^2.15.1",
+ "@schedule-x/event-modal": "^2.15.1",
+ "@schedule-x/event-recurrence": "^2.15.1",
"@schedule-x/events-service": "^2.14.3",
"@schedule-x/react": "^2.13.3",
+ "@schedule-x/resize": "^2.15.1",
"@schedule-x/theme-default": "^2.14.3",
"@schedule-x/theme-shadcn": "^2.14.3",
"class-variance-authority": "^0.7.1",
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index c7ff983..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "latosa-escrima.fr",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {}
-}