mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-22 14:38:10 +02:00
fix(grid): preserve active grid query in store to restore context on navigation
This commit is contained in:
1 parent
9493a39d12
commit
a94489dd07
3 files changed
+36
-4
No files matched your search
@@ -4,6 +4,8 @@ import { LayoutGrid, Camera, FileDown, Settings, Package, BarChart3 } from "luci
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { useGridStore } from "@/features/grid/store/use-grid-store";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
const NAV_ITEMS = [
|
const NAV_ITEMS = [
|
||||||
{ icon: LayoutGrid, label: "Grille", href: "/grid" },
|
{ icon: LayoutGrid, label: "Grille", href: "/grid" },
|
||||||
@@ -15,6 +17,12 @@ const NAV_ITEMS = [
|
|||||||
|
|
||||||
export function Sidebar() {
|
export function Sidebar() {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
const activeGridQuery = useGridStore((s) => s.activeGridQuery);
|
||||||
|
const [isMounted, setIsMounted] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsMounted(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside
|
<aside
|
||||||
@@ -37,10 +45,17 @@ export function Sidebar() {
|
|||||||
<nav className="px-2 pt-2.5 space-y-0.5">
|
<nav className="px-2 pt-2.5 space-y-0.5">
|
||||||
{NAV_ITEMS.map(({ icon: Icon, label, href }) => {
|
{NAV_ITEMS.map(({ icon: Icon, label, href }) => {
|
||||||
const isActive = pathname.startsWith(href);
|
const isActive = pathname.startsWith(href);
|
||||||
|
|
||||||
|
// Restore grid context if navigating back to the grid
|
||||||
|
let resolvedHref = href;
|
||||||
|
if (href === "/grid" && isMounted && activeGridQuery) {
|
||||||
|
resolvedHref = `/grid${activeGridQuery}`;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={href}
|
key={href}
|
||||||
href={href}
|
href={resolvedHref}
|
||||||
style={{
|
style={{
|
||||||
color: isActive ? "var(--text-primary)" : "var(--text-secondary)",
|
color: isActive ? "var(--text-primary)" : "var(--text-secondary)",
|
||||||
background: isActive ? "var(--bg-elevated)" : "transparent",
|
background: isActive ? "var(--bg-elevated)" : "transparent",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import type { ProductRow } from "@/types/grid";
|
|||||||
import { CheckCircle, AlertCircle, Loader2 } from "lucide-react";
|
import { CheckCircle, AlertCircle, Loader2 } from "lucide-react";
|
||||||
|
|
||||||
import { useScoreSettingsStore } from "@/features/score/store/use-score-settings-store";
|
import { useScoreSettingsStore } from "@/features/score/store/use-score-settings-store";
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
import { computeProductScores } from "@/lib/score-engine";
|
import { computeProductScores } from "@/lib/score-engine";
|
||||||
|
|
||||||
interface GridClientProps {
|
interface GridClientProps {
|
||||||
@@ -25,6 +26,9 @@ interface GridClientProps {
|
|||||||
|
|
||||||
export function GridClient({ initialRows, nomFournisseur, fournisseurs, magasins, magasin, nomenclature }: GridClientProps) {
|
export function GridClient({ initialRows, nomFournisseur, fournisseurs, magasins, magasin, nomenclature }: GridClientProps) {
|
||||||
const setRows = useGridStore((s) => s.setRows);
|
const setRows = useGridStore((s) => s.setRows);
|
||||||
|
const setActiveGridQuery = useGridStore((s) => s.setActiveGridQuery);
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
const seuilAxeFort = useScoreSettingsStore((s) => s.seuilAxeFort);
|
const seuilAxeFort = useScoreSettingsStore((s) => s.seuilAxeFort);
|
||||||
const bonusParAxe = useScoreSettingsStore((s) => s.bonusParAxe);
|
const bonusParAxe = useScoreSettingsStore((s) => s.bonusParAxe);
|
||||||
|
|
||||||
@@ -36,10 +40,17 @@ export function GridClient({ initialRows, nomFournisseur, fournisseurs, magasins
|
|||||||
const [isMounted, setIsMounted] = useState(false);
|
const [isMounted, setIsMounted] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
||||||
setIsMounted(true);
|
setIsMounted(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Sync active search params to the store
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isMounted) return;
|
||||||
|
const currentQueryString = searchParams.toString();
|
||||||
|
// Set the active query, ensuring it starts with ? if not empty
|
||||||
|
setActiveGridQuery(currentQueryString ? `?${currentQueryString}` : "");
|
||||||
|
}, [searchParams, setActiveGridQuery, isMounted]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isMounted) return;
|
if (!isMounted) return;
|
||||||
// Deep clone to avoid mutating the React prop directly across re-renders
|
// Deep clone to avoid mutating the React prop directly across re-renders
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ interface GridState {
|
|||||||
filters: GridFilters;
|
filters: GridFilters;
|
||||||
summary: GridSummary;
|
summary: GridSummary;
|
||||||
displayDensity: "compact" | "normal" | "comfortable";
|
displayDensity: "compact" | "normal" | "comfortable";
|
||||||
|
/** The active URL search parameters (e.g. ?fournisseur=123&magasin=TOTAL) */
|
||||||
|
activeGridQuery: string;
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
setRows: (rows: ProductRow[]) => void;
|
setRows: (rows: ProductRow[]) => void;
|
||||||
@@ -19,6 +21,7 @@ interface GridState {
|
|||||||
resetDrafts: () => void;
|
resetDrafts: () => void;
|
||||||
setFilter: (key: keyof GridFilters, value: string | null) => void;
|
setFilter: (key: keyof GridFilters, value: string | null) => void;
|
||||||
setDisplayDensity: (density: "compact" | "normal" | "comfortable") => void;
|
setDisplayDensity: (density: "compact" | "normal" | "comfortable") => void;
|
||||||
|
setActiveGridQuery: (query: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeSummary(rows: ProductRow[], drafts: Record<string, GammeCode>): GridSummary {
|
function computeSummary(rows: ProductRow[], drafts: Record<string, GammeCode>): GridSummary {
|
||||||
@@ -59,6 +62,7 @@ export const useGridStore = create<GridState>()(
|
|||||||
tauxMargeGlobal: 0,
|
tauxMargeGlobal: 0,
|
||||||
},
|
},
|
||||||
displayDensity: "normal",
|
displayDensity: "normal",
|
||||||
|
activeGridQuery: "",
|
||||||
|
|
||||||
setRows: (rows) => {
|
setRows: (rows) => {
|
||||||
set({ rows, summary: computeSummary(rows, get().draftChanges) });
|
set({ rows, summary: computeSummary(rows, get().draftChanges) });
|
||||||
@@ -74,17 +78,19 @@ export const useGridStore = create<GridState>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
setFilter: (key, value) => {
|
setFilter: (key, value) => {
|
||||||
set((state) => ({ filters: { ...state.filters, [key]: value } }));
|
set((state) => ({ ...state, filters: { ...state.filters, [key]: value } }));
|
||||||
},
|
},
|
||||||
setDisplayDensity: (density) => set({ displayDensity: density }),
|
setDisplayDensity: (density) => set({ displayDensity: density }),
|
||||||
|
setActiveGridQuery: (query) => set({ activeGridQuery: query }),
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: "collectflow-grid-storage",
|
name: "collectflow-grid-storage",
|
||||||
// Only persist filters and display density, do not persist data rows and drafts
|
// Only persist filters, display density, drafts, and active grid query
|
||||||
partialize: (state) => ({
|
partialize: (state) => ({
|
||||||
filters: state.filters,
|
filters: state.filters,
|
||||||
displayDensity: state.displayDensity,
|
displayDensity: state.displayDensity,
|
||||||
draftChanges: state.draftChanges,
|
draftChanges: state.draftChanges,
|
||||||
|
activeGridQuery: state.activeGridQuery,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in new issue
Block a user