Big improvements to how we manage routes + planning

This commit is contained in:
Arthur Belleville 2025-07-09 08:41:48 +02:00
parent 01e194e767
commit b33e3ed123
No known key found for this signature in database
5 changed files with 104 additions and 144 deletions

View file

@ -23,6 +23,7 @@ import ChatProvider from "./providers/ChatProvider";
import { UserStoreProvider } from "./providers/UserStoreProvider";
import { ProtectedRoute } from "./components/ProtectedRoute";
import { JoinPage } from "@ui/pages/join";
import { CreateEventModal } from "./components/CreateEventModal";
// Register all Community features
ModuleRegistry.registerModules([AllCommunityModule]);
@ -38,109 +39,45 @@ export const App = () => {
>
<Routes>
<Route path="/" element={<ProtectedRoute fallback="/login" />}>
<Route
index
element={
<Layout>
<TabloPage />
</Layout>
}
/>
<Route
path="devis"
element={
<Layout>
<DevisPage />
</Layout>
}
/>
<Route
path="factures"
element={
<Layout>
<FacturesPage />
</Layout>
}
/>
<Route
path="planning"
element={
<Layout>
<PlanningPage />
</Layout>
}
/>
<Route
path="planning/:tablo_id"
element={
<Layout>
<PlanningPage />
</Layout>
}
/>
<Route
path="chantiers"
element={
<Layout>
<ChantiersPage />
</Layout>
}
/>
<Route
path="chat"
element={
<Layout>
<Route element={<Layout />}>
<Route index element={<TabloPage />} />
<Route path="tablo" element={<TabloPage />} />
<Route path="devis" element={<DevisPage />} />
<Route path="factures" element={<FacturesPage />} />
<Route path="planning" element={<PlanningPage />}>
<Route index />
<Route path=":tablo_id" />
<Route path="create" element={<CreateEventModal />} />
</Route>
<Route path="chantiers" element={<ChantiersPage />} />
<Route
path="chat"
element={
<ChatProvider>
{(client) => <ChatPage client={client} />}
</ChatProvider>
</Layout>
}
/>
<Route
path="chat/:channelId"
element={
<Layout>
<ChatProvider>
{(client) => <ChatPage client={client} />}
</ChatProvider>
</Layout>
}
/>
<Route
path="feedback"
element={
<Layout>
<FeedbackPage />
</Layout>
}
/>
<Route
path="support"
element={
<Layout>
<SupportPage />
</Layout>
}
/>
}
>
<Route index />
<Route path=":channelId" />
</Route>
<Route path="feedback" element={<FeedbackPage />} />
<Route path="support" element={<SupportPage />} />
</Route>
</Route>
<Route
element={
<ProtectedRoute
fallback="/login"
shouldRedirectToCurrentPage
/>
<>
<ProtectedRoute
fallback="/login"
shouldRedirectToCurrentPage
/>
<Layout />
</>
}
>
<Route
path="join/:tablo_name"
element={
<Layout>
<JoinPage />
</Layout>
}
/>
<Route path="join/:tablo_name" element={<JoinPage />} />
</Route>
<Route path="login-with-oauth" element={<OAuthSigninPage />} />
<Route path="landing" element={<LandingPage />} />

View file

@ -14,17 +14,22 @@ import { useTimePicker } from "@ui/ui-library/time-picker";
import { DatePicker, DatePickerButton } from "@ui/ui-library/date-picker";
import { Group } from "react-aria-components";
import { getLocalTimeZone, parseDate, today } from "@internationalized/date";
import { useNavigate, useSearchParams } from "react-router-dom";
interface EventModalProps {
date: Date;
onClose: () => void;
}
export const CreateEventModal = ({ date, onClose }: EventModalProps) => {
export const CreateEventModal = () => {
const user = useUser();
const [searchParams] = useSearchParams();
const tablo_id = searchParams.get("tablo_id");
const date = new Date(searchParams.get("date") || "");
const { data: tablos, isLoading: tablosLoading } = useTablosList();
const createEvent = useCreateEvent();
const timeOptions = useTimePicker({ intervalInMinute: 15 });
const navigate = useNavigate();
const onClose = () => {
navigate(-1);
};
// Get the local date string without timezone conversion
const getLocalDateString = (date: Date) => {
@ -61,7 +66,7 @@ export const CreateEventModal = ({ date, onClose }: EventModalProps) => {
start_date: date ? getLocalDateString(date) : "",
start_time: date ? getNearestTimeOption(date, "start") : "",
end_time: date ? getNearestTimeOption(date, "end") : "",
tablo_id: "",
tablo_id: tablo_id || "",
title: "",
created_by: user.id,
});

View file

@ -6,14 +6,7 @@ import { BrowserRouter } from "react-router-dom";
describe("Layout", () => {
it("renders the layout with children", () => {
renderWithProviders(
<Layout>
<div>Test Content</div>
</Layout>
);
// Check if the content is rendered
expect(screen.getByText("Test Content")).toBeInTheDocument();
renderWithProviders(<Layout />);
// Check if the mobile menu button is present
expect(screen.getByRole("button", { name: /menu/i })).toBeInTheDocument();
@ -27,9 +20,7 @@ describe("Layout", () => {
render(
<BrowserRouter>
<SessionProvider>
<Layout>
<div>Test Content</div>
</Layout>
<Layout />
</SessionProvider>
</BrowserRouter>
);
@ -52,11 +43,7 @@ describe("Layout", () => {
});
it("renders the side navigation", () => {
renderWithProviders(
<Layout>
<div>Test Content</div>
</Layout>
);
renderWithProviders(<Layout />);
// Check if the side navigation is present
expect(

View file

@ -1,15 +1,12 @@
import { ReactNode, useState } from "react";
import { useState } from "react";
import { SideNavigation } from "./NavigationBar";
import { Button } from "../ui-library/button";
import { Icon } from "../ui-library/icon";
import { MenuIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { Outlet } from "react-router-dom";
interface LayoutProps {
children: ReactNode;
}
export function Layout({ children }: LayoutProps) {
export function Layout() {
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
return (
@ -39,7 +36,9 @@ export function Layout({ children }: LayoutProps) {
<SideNavigation isMobileMenuOpen={isMobileMenuOpen} />
</div>
<main className="flex-1 overflow-auto">{children}</main>
<main className="flex-1 overflow-auto">
<Outlet />
</main>
</div>
);
}

View file

@ -1,7 +1,6 @@
import { useState } from "react";
import { useTablosList } from "@ui/hooks/tablos";
import { useEventsByTablo, useDeleteEvent } from "@ui/hooks/events";
import { CreateEventModal } from "@ui/components/CreateEventModal";
import {
Select,
SelectButton,
@ -9,14 +8,15 @@ import {
SelectListBox,
SelectListItem,
} from "@ui/ui-library/select";
import { useParams } from "react-router-dom";
import { Outlet, useNavigate, useParams } from "react-router-dom";
type ViewType = "month" | "week" | "day";
export const PlanningPage = () => {
const { tablo_id } = useParams();
const navigate = useNavigate();
const [currentDate, setCurrentDate] = useState(new Date());
const [selectedDate, setSelectedDate] = useState(new Date());
// const [selectedDate, setSelectedDate] = useState(new Date());
const [currentView, setCurrentView] = useState<ViewType>("month");
const [selectedTabloId, setSelectedTabloId] = useState<string>(
tablo_id || "all"
@ -31,8 +31,19 @@ export const PlanningPage = () => {
const deleteEvent = useDeleteEvent();
// Modal state
const [isEventModalOpen, setIsEventModalOpen] = useState(false);
const navigateToCreateEvent = (date: Date, tablo_id: string) => {
if (tablo_id === "all") {
navigate({
pathname: "/planning/create",
search: `date=${date.toISOString()}`,
});
} else {
navigate({
pathname: "/planning/create",
search: `date=${date.toISOString()}&tablo_id=${tablo_id}`,
});
}
};
const monthNames = [
"Janvier",
@ -147,7 +158,6 @@ export const PlanningPage = () => {
const goToToday = () => {
const today = new Date();
setCurrentDate(today);
setSelectedDate(today);
};
const getViewTitle = () => {
@ -261,8 +271,13 @@ export const PlanningPage = () => {
}`}
onClick={() => {
if (day) {
setSelectedDate(day);
setIsEventModalOpen(true);
navigate({
pathname: "/planning/create",
search:
selectedTabloId === "all"
? `?date=${day.toISOString()}`
: `?date=${day.toISOString()}&tablo_id=${selectedTabloId}`,
});
}
}}
>
@ -291,7 +306,13 @@ export const PlanningPage = () => {
}`}
onClick={(e) => {
e.stopPropagation();
setIsEventModalOpen(true);
navigate({
pathname: "/planning/create",
search:
selectedTabloId === "all"
? `?date=${day.toISOString()}`
: `?date=${day.toISOString()}&tablo_id=${selectedTabloId}`,
});
}}
>
<div className="truncate">
@ -376,8 +397,7 @@ export const PlanningPage = () => {
const [hour] = time.split(":").map(Number);
const dateWithTime = new Date(day);
dateWithTime.setHours(hour, 0, 0, 0);
setSelectedDate(dateWithTime);
setIsEventModalOpen(true);
navigateToCreateEvent(dateWithTime, selectedTabloId);
}}
>
{/* Current time indicator for today */}
@ -475,8 +495,7 @@ export const PlanningPage = () => {
const [hour] = time.split(":").map(Number);
const dateWithTime = new Date(currentDate);
dateWithTime.setHours(hour, 0, 0, 0);
setSelectedDate(dateWithTime);
setIsEventModalOpen(true);
navigateToCreateEvent(dateWithTime, selectedTabloId);
}}
>
<div className="w-20 p-2 text-xs text-gray-500 dark:text-gray-400 text-right border-r border-gray-200 dark:border-gray-700">
@ -595,7 +614,20 @@ export const PlanningPage = () => {
</div>
<button
onClick={() => setIsEventModalOpen(true)}
onClick={() => {
if (selectedTabloId === "all") {
navigate(
"/planning/create?date=" + currentDate.toISOString()
);
} else {
navigate(
"/planning/create?tablo_id=" +
selectedTabloId +
"&date=" +
currentDate.toISOString()
);
}
}}
className="w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium shadow-sm disabled:opacity-50 disabled:cursor-not-allowed"
>
+ Créer un événement
@ -630,8 +662,7 @@ export const PlanningPage = () => {
}`}
onClick={() => {
if (day) {
setSelectedDate(day);
setIsEventModalOpen(true);
navigateToCreateEvent(day, selectedTabloId);
}
}}
>
@ -744,13 +775,14 @@ export const PlanningPage = () => {
</div>
</div>
{/* Event Modal */}
{isEventModalOpen && (
{/* {isEventModalOpen && (
<CreateEventModal
date={selectedDate}
onClose={() => setIsEventModalOpen(false)}
close={() => setIsEventModalOpen(false)}
/>
)}
)} */}
<Outlet />
</div>
);
};