feat: Implement core application structure with new dashboard, settings, and help pages, and enhance opportunities management with persistence and filtering.

This commit is contained in:
2026-02-03 20:05:30 +00:00
parent 609b9da020
commit 885bbbf954
21 changed files with 1282 additions and 106 deletions

View File

@@ -1,11 +1,15 @@
"use client"
import * as React from "react"
import Link from "next/link"
import { usePathname } from "next/navigation"
import {
Command,
Frame,
HelpCircle,
Settings2,
Terminal,
Target,
Plus
} from "lucide-react"
@@ -26,11 +30,12 @@ import { useQuery, useMutation } from "convex/react"
import { api } from "@/convex/_generated/api"
import { Checkbox } from "@/components/ui/checkbox"
import { Label } from "@/components/ui/label"
import { Button } from "@/components/ui/button"
import { useProject } from "@/components/project-context"
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const pathname = usePathname()
const projects = useQuery(api.projects.getProjects);
const [selectedProjectId, setSelectedProjectId] = React.useState<string | null>(null);
const { selectedProjectId, setSelectedProjectId } = useProject();
// Set default selected project
React.useEffect(() => {
@@ -87,15 +92,51 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton tooltip="Dashboard" isActive>
<Terminal />
<span>Dashboard</span>
<SidebarMenuButton
asChild
tooltip="Dashboard"
isActive={pathname === "/dashboard"}
>
<Link href="/dashboard">
<Terminal />
<span>Dashboard</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton tooltip="Settings">
<Settings2 />
<span>Settings</span>
<SidebarMenuButton
asChild
tooltip="Opportunities"
isActive={pathname === "/opportunities"}
>
<Link href="/opportunities">
<Target />
<span>Opportunities</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton
asChild
tooltip="Settings"
isActive={pathname === "/settings"}
>
<Link href="/settings">
<Settings2 />
<span>Settings</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton
asChild
tooltip="Help"
isActive={pathname === "/help"}
>
<Link href="/help">
<HelpCircle />
<span>Help</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>

View File

@@ -0,0 +1,46 @@
"use client";
import { createContext, useContext, useEffect, useMemo, useState } from "react";
const STORAGE_KEY = "selectedProjectId";
type ProjectContextValue = {
selectedProjectId: string | null;
setSelectedProjectId: (id: string | null) => void;
};
const ProjectContext = createContext<ProjectContextValue | null>(null);
export function ProjectProvider({ children }: { children: React.ReactNode }) {
const [selectedProjectId, setSelectedProjectId] = useState<string | null>(null);
useEffect(() => {
const stored = window.localStorage.getItem(STORAGE_KEY);
if (stored) {
setSelectedProjectId(stored);
}
}, []);
useEffect(() => {
if (selectedProjectId) {
window.localStorage.setItem(STORAGE_KEY, selectedProjectId);
} else {
window.localStorage.removeItem(STORAGE_KEY);
}
}, [selectedProjectId]);
const value = useMemo(
() => ({ selectedProjectId, setSelectedProjectId }),
[selectedProjectId]
);
return <ProjectContext.Provider value={value}>{children}</ProjectContext.Provider>;
}
export function useProject() {
const context = useContext(ProjectContext);
if (!context) {
throw new Error("useProject must be used within a ProjectProvider.");
}
return context;
}