Big improvements to how we manage routes + planning
This commit is contained in:
parent
01e194e767
commit
b33e3ed123
5 changed files with 104 additions and 144 deletions
125
ui/src/App.tsx
125
ui/src/App.tsx
|
|
@ -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 />} />
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue