diff --git a/src/components/HelpSheet.tsx b/src/components/HelpSheet.tsx new file mode 100644 index 0000000..3f99c94 --- /dev/null +++ b/src/components/HelpSheet.tsx @@ -0,0 +1,311 @@ +"use client"; + +import { usePathname } from "next/navigation"; +import { + Sheet, + SheetContent, + SheetHeader, + SheetTitle, +} from "@/components/ui/sheet"; +import { + Accordion, + AccordionItem, + AccordionTrigger, + AccordionContent, +} from "@/components/ui/accordion"; +import { + LayoutDashboard, + Map, + BarChart3, + School, + BookOpen, + FileUp, + Settings, + TrendingUp, + TrendingDown, + Minus, + ShoppingBasket, +} from "lucide-react"; +import type { ReactNode } from "react"; + +interface HelpSheetProps { + open: boolean; + onOpenChange: (open: boolean) => void; +} + +// Small reusable inline indicator components +function GreenDot() { + return ( + + ); +} + +function OutlinedDot() { + return ( + + ); +} + +function TrendLegend() { + return ( +
+
+ + Increase from prior year +
+
+ + Decrease from prior year +
+
+ + No change or no prior year data +
+
+ ); +} + +function CartBadge() { + return ( + + + + 2 + + + ); +} + +interface Page { + value: string; + label: string; + icon: React.ElementType; + description: string; + features: ReactNode[]; +} + +const pages: Page[] = [ + { + value: "/", + label: "Dashboard", + icon: LayoutDashboard, + description: + "A high-level summary of MHD program data for a selected year.", + features: [ + <> + Use the year selector to switch between available data years. A{" "} + filled green dot next to a year means data is + available for that year. + , + "View total counts for students, projects, teachers, and schools.", + <> + Each stat card shows a percentage change from the prior year: + + , + "Click any stat card to jump to the Chart page filtered to that metric.", + "The two line graphs show total projects and schools over the past 6 years.", + ], + }, + { + value: "/map", + label: "Map", + icon: Map, + description: + "An interactive heatmap of participating schools across Massachusetts.", + features: [ + "Switch the Counts dropdown between Students, Projects, and Teachers to change what the heatmap visualizes.", + <> + In the Year dropdown, a filled green dot next to a + year means data is available for that year. + , + "Change Region View to zoom into pre-set views of competition regions.", + "Open Filters to toggle school markers, the heatmap overlay, and region boundaries on or off.", + "Enable Gateway Schools Only to restrict the view to gateway city schools.", + "Click a school marker to see a popup with that school's data. Click the View Profile button to redirect to that school's profile page.", + "Export saves the current map as a PDF.", + "Copy link shares the exact view and filter state via URL.", + <> + Add to cart to collect maps and charts for a combined export. + The Cart button shows how many items you've + collected — click it to open the cart and initiate a bulk + export. + , + "Use the ‹ or › arrow keys to switch between available years.", + "Keyboard: ⌘S opens the export dialog, ⌘P downloads a PDF directly.", + ], + }, + { + value: "/chart", + label: "Chart", + icon: BarChart3, + description: + "Bar and line charts for exploring project data with detailed filtering.", + features: [ + "Toggle between Bar and Line chart types using the tabs at the top.", + "Use the date range picker in the top right to set the timeframe. Choose from the past 3 or 5 years relative to the latest year of data, or set a custom year range.", + "Open the Filters panel to narrow data by school, city, project type, teacher experience, and more. Filters are organized by type — you can select one value per filter type, and multiple filter types can be active at the same time.", + "Measured As controls what the y-axis measures — use the dropdown to select from the available count and rate options.", + "Use Group By to combine data points into common categories such as school, city, or project type.", + "Export saves the current chart as a PDF.", + "Copy link shares the current filter state via URL.", + <> + Add to cart to collect charts and maps for a combined export. + The Cart button shows how many items you've + collected — click it to open the cart and initiate a bulk + export. + , + "Keyboard: ⌘S opens the export dialog, ⌘P downloads a PDF directly, B switches to bar chart, L switches to line chart.", + "Certain combinations of chart customizations do not make sense. For example, measuring total school count grouped by project type is such a combination. Such charts may yield nonsensical data or no data at all.", + ], + }, + { + value: "/schools", + label: "Schools", + icon: School, + description: + "A table of all participating schools and their data for a selected year.", + features: [ + <> + In the Year dropdown, a filled green dot means data + is available for that year. + , + "Search by school name, city, or region using the search bar.", + <> + The # Students, # Teachers, and # Projects columns show + year-over-year change: + + , + "Use the ‹ or › arrow keys to switch between available years.", + "Click any school name to open that school's detailed profile page.", + "Click column headers to sort the table by that metric in ascending or descending order.", + ], + }, + { + value: "/schools/profile", + label: "School Profile", + icon: BookOpen, + description: + "A detailed view of a single school's data, history, and project records.", + features: [ + <> + In the Year dropdown: a filled dot means the school + participated that year; an outlined dot means + data exists for that year but the school did not participate. + , + <> + The three stat cards show projects, teachers, and students for + the selected year with year-over-year trend indicators: + + , + "The student count line graph shows enrollment history over the past 5 years. Click it to open the Chart page filtered to this school.", + "The project type distribution pie chart breaks down projects by category for the selected year.", + "School Location shows the school's pin on a map. Click anywhere on the map to update its coordinates. Regions are automatically updated based on the new coordinates.", + "The View and Edit Data table lists all project records for the selected year. Double-click any cell to edit it. Teacher changes apply globally across all of that teacher's projects.", + "Double-click the school name at the top of the page to rename the school.", + "Use the ⋮ menu to access Merge School, which combines this school's records with another school.", + ], + }, + { + value: "/upload", + label: "Upload Data", + icon: FileUp, + description: + "A multi-step process for importing new yearly program data, broken into tabs.", + features: [ + "Step 1 — Enter the year for the data being uploaded (new year or overwrite an existing year) and upload the student spreadsheet. A template is available to download. Drag and drop the file or click to browse.", + "Step 2 — Validation checks the student spreadsheet format and data types. Any errors are highlighted so you can correct the source file and re-upload.", + "Step 3 — Upload the school spreadsheet in the same way. Another template is available for this file as well.", + "Step 4 — Validation checks the school spreadsheet, then schools are matched to their locations on the map based on previously known schools.", + "Step 5 — Any schools whose locations could not be matched must be placed manually. Click anywhere on the map to place each unmatched school. Regions are automatically set for both matched and unmatched schools.", + "Step 6 — Review a summary and confirm the upload to commit all data to the database.", + ], + }, + { + value: "/settings", + label: "Settings", + icon: Settings, + description: + "Admin tools for configuring application-wide settings and school metadata.", + features: [ + "Gateway Schools: add or remove schools designated as schools representing students from gateway cities.", + "School Locations: edit the map coordinates for individual schools. Regions are automatically updated based on the new coordinates.", + "Years of Data: delete or upload years of participation data across the app.", + "Changes are not saved automatically — click Save to apply all edits.", + ], + }, +]; + +function pathnameToValue(pathname: string): string { + if (pathname === "/") return "/"; + if (pathname.startsWith("/schools/")) return "/schools/profile"; + const clean = pathname.replace(/\/$/, ""); + const match = pages.find( + (p) => p.value !== "/" && clean.startsWith(p.value), + ); + return match?.value ?? "/"; +} + +export function HelpSheet({ open, onOpenChange }: HelpSheetProps) { + const pathname = usePathname(); + const defaultValue = pathnameToValue(pathname); + + return ( + + + + Help + +
+ + {pages.map( + ({ + value, + label, + icon: Icon, + description, + features, + }) => ( + + + + + {label} + + + +

+ {description} +

+
    + {features.map((feature, i) => ( +
  • + + + {feature} + +
  • + ))} +
+
+
+ ), + )} +
+
+
+
+ ); +} diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 071b5ea..e1afbf1 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -12,6 +12,7 @@ import { Settings as SettingsIcon, LogOut, MoreHorizontal, + MessageCircleQuestion, } from "lucide-react"; import { authClient } from "@/lib/auth-client"; import Image from "next/image"; @@ -23,11 +24,13 @@ import { import { DEV_BYPASS, DEV_BYPASS_COOKIE } from "@/lib/dev-config"; // TO DO - REMOVE: dev auth bypass import { DEV_SESSION_USER } from "@/lib/dev-session"; // TO DO - REMOVE: dev auth bypass import { useUnsavedChanges } from "@/components/UnsavedChangesContext"; +import { HelpSheet } from "@/components/HelpSheet"; export default function Sidebar() { const pathname = usePathname(); const router = useRouter(); const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const [isHelpOpen, setIsHelpOpen] = useState(false); const { data: authSession, isPending } = authClient.useSession(); const { onNavigationAttempt } = useUnsavedChanges(); // TO DO - REMOVE: dev auth bypass - show dev user when in dev mode with no real session @@ -160,118 +163,143 @@ export default function Sidebar() { ]; return ( - + + + ); } diff --git a/src/components/ui/accordion.tsx b/src/components/ui/accordion.tsx index aa15cfc..5b06a7c 100644 --- a/src/components/ui/accordion.tsx +++ b/src/components/ui/accordion.tsx @@ -28,7 +28,7 @@ const AccordionTrigger = React.forwardRef< svg]:rotate-180", + "flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline text-left cursor-pointer [&[data-state=open]>svg]:rotate-180", className, )} {...props}