Skip to content

Commit 4262555

Browse files
committed
refactor(capabilities): centralize state management in provider and remove prop drilling
1 parent 859123e commit 4262555

File tree

7 files changed

+9
-97
lines changed

7 files changed

+9
-97
lines changed

components/ui/DataTableDrawer.tsx

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,6 @@ interface DataTableDrawerProps {
107107
onOpenChange: (open: boolean) => void
108108
data?: Transaction
109109
apps: any[]
110-
selectedCapabilities: SelectedCapability[]
111-
onSelectedCapabilitiesChange?: (capabilities: SelectedCapability[]) => void // Made optional since we use provider
112110
}
113111

114112
const categories = [
@@ -696,8 +694,6 @@ export function DataTableDrawer({
696694
onOpenChange,
697695
data = defaultTransaction,
698696
apps,
699-
selectedCapabilities, // This comes from the provider now
700-
onSelectedCapabilitiesChange, // Optional fallback
701697
}: DataTableDrawerProps) {
702698
const status = expense_statuses.find(
703699
(item) => item.value === data?.expense_status,
@@ -706,8 +702,8 @@ export function DataTableDrawer({
706702
const { addCapability, removeCapability } = useCapabilityActions()
707703
const lastPinnedToolId = useLastPinnedTool()
708704

709-
// Use capabilities from provider, fallback to prop
710-
const actualSelectedCapabilities = config.selectedCapabilities.length > 0 ? config.selectedCapabilities : selectedCapabilities
705+
// Always use capabilities from provider - it's the source of truth
706+
const actualSelectedCapabilities = config.selectedCapabilities
711707

712708
// Starter templates (from legacy Build page)
713709
const starterTemplates = [
@@ -772,11 +768,11 @@ export function DataTableDrawer({
772768
documentationUrl: capability.documentationUrl
773769
}
774770

775-
const isAlreadySelected = selectedCapabilities.some(f => f.id === compositeId)
771+
const isAlreadySelected = actualSelectedCapabilities.some(f => f.id === compositeId)
776772
if (isAlreadySelected) {
777-
onSelectedCapabilitiesChange(selectedCapabilities.filter(f => f.id !== compositeId))
773+
removeCapability(compositeId)
778774
} else {
779-
onSelectedCapabilitiesChange([...selectedCapabilities, selectedCapability])
775+
addCapability(selectedCapability)
780776
}
781777
}
782778

components/ui/navbar.tsx

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"use client";
22

3-
import { Sparkles, Info, Wand2, Leaf, Globe, Star } from "lucide-react";
3+
import { Wand2, Globe, Star } from "lucide-react";
44
import { Logo } from "@/features/dashboard/components/Logo";
55
import { Button } from "@/components/ui/button";
66
import { NavbarSearch } from "@/features/public-site/components/search/NavbarSearch";
77
import { DataTableDrawer } from "@/components/ui/DataTableDrawer";
88
import { cn } from "@/lib/utils";
9-
import { useState, useEffect } from "react";
9+
import { useState } from "react";
1010

1111
interface NavbarProps {
1212
className?: string;
@@ -15,27 +15,6 @@ interface NavbarProps {
1515

1616
export default function Navbar({ className, apps }: NavbarProps) {
1717
const [drawerOpen, setDrawerOpen] = useState(false);
18-
const [selectedCapabilities, setSelectedCapabilities] = useState([]);
19-
20-
useEffect(() => {
21-
try {
22-
const saved = localStorage.getItem('pinnedCapabilities');
23-
if (saved) {
24-
setSelectedCapabilities(JSON.parse(saved));
25-
}
26-
} catch (error) {
27-
console.error('Error loading capabilities:', error);
28-
}
29-
}, []);
30-
31-
const handleSelectedCapabilitiesChange = (capabilities) => {
32-
setSelectedCapabilities(capabilities);
33-
try {
34-
localStorage.setItem('pinnedCapabilities', JSON.stringify(capabilities));
35-
} catch (error) {
36-
console.error('Error saving capabilities:', error);
37-
}
38-
};
3918

4019
return (
4120
<>
@@ -112,8 +91,6 @@ export default function Navbar({ className, apps }: NavbarProps) {
11291
open={drawerOpen}
11392
onOpenChange={setDrawerOpen}
11493
apps={apps}
115-
selectedCapabilities={selectedCapabilities}
116-
onSelectedCapabilitiesChange={handleSelectedCapabilitiesChange}
11794
/>
11895
</>
11996
);

features/public-site/components/landing/HeroAlternatives.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Link from 'next/link';
1111
import { cn } from '@/lib/utils';
1212
import { AnimatePresence, motion, useMotionTemplate, useMotionValue, type MotionStyle, type MotionValue, type Variants } from 'framer-motion';
1313
import type { MouseEvent } from 'react';
14-
import { useCapabilityActions, useSelectedCapabilities } from '@/hooks/use-capabilities-config';
14+
import { useCapabilityActions } from '@/hooks/use-capabilities-config';
1515
import type { SelectedCapability } from '@/hooks/use-capabilities-config';
1616
import { DataTableDrawer } from '@/components/ui/DataTableDrawer';
1717
import { makeGraphQLRequest } from '../../lib/graphql/client';
@@ -503,7 +503,6 @@ export default function HeroAlternatives() {
503503
const [isTyping, setIsTyping] = useState(true);
504504
const [isDeleting, setIsDeleting] = useState(false);
505505
const [drawerOpen, setDrawerOpen] = useState(false);
506-
const selectedCapabilities = useSelectedCapabilities();
507506

508507
// Fetch all open source apps for the drawer
509508
const { data: apps = [] } = useQuery({
@@ -585,11 +584,6 @@ export default function HeroAlternatives() {
585584
handleStepChange(nextIndex);
586585
};
587586

588-
const handleSelectedCapabilitiesChange = (capabilities: any) => {
589-
// The provider handles the sync through the context
590-
console.log('Capability change handled by provider', capabilities);
591-
};
592-
593587
return (
594588
<>
595589
<div className="space-y-8">
@@ -651,8 +645,6 @@ export default function HeroAlternatives() {
651645
open={drawerOpen}
652646
onOpenChange={setDrawerOpen}
653647
apps={apps}
654-
selectedCapabilities={selectedCapabilities}
655-
onSelectedCapabilitiesChange={handleSelectedCapabilitiesChange}
656648
/>
657649
</>
658650
);

features/public-site/screens/AlternativesPage.tsx

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { HeroSection } from '../components/alternatives/HeroSection';
66
import { EventsSection } from '../components/alternatives/EventsSection';
77
import StatsCard from '../components/alternatives/StatsCard';
88
import { DataTableDrawer } from '@/components/ui/DataTableDrawer';
9-
import { useSelectedCapabilities, useCapabilityActions } from '@/hooks/use-capabilities-config';
109
import { useQuery } from '@tanstack/react-query';
1110
import { queryKeys } from '../lib/query-keys';
1211
import { makeGraphQLRequest } from '../lib/graphql/client';
@@ -51,8 +50,6 @@ const GET_ALL_OPEN_SOURCE_APPS = `
5150

5251
export function AlternativesPageClient({ slug }: AlternativesPageClientProps) {
5352
const [drawerOpen, setDrawerOpen] = useState(false);
54-
const selectedCapabilities = useSelectedCapabilities();
55-
const { addCapability, removeCapability } = useCapabilityActions();
5653

5754
// This data is already prefetched by server, so it loads instantly
5855
const { data: proprietaryApp, error: alternativesError } = useAlternatives(slug);
@@ -68,12 +65,6 @@ export function AlternativesPageClient({ slug }: AlternativesPageClientProps) {
6865
gcTime: 15 * 60 * 1000, // 15 minutes
6966
});
7067

71-
const handleSelectedCapabilitiesChange = (capabilities: any) => {
72-
// This is called when capabilities are changed from the BuildStatsCard - but we use the provider now
73-
// The provider will automatically handle the sync through the context
74-
console.log('Capability change handled by provider', capabilities);
75-
};
76-
7768
// Since data is prefetched, this should never show loading
7869
// But handle error state
7970
if (alternativesError || !proprietaryApp) {
@@ -121,8 +112,6 @@ export function AlternativesPageClient({ slug }: AlternativesPageClientProps) {
121112
open={drawerOpen}
122113
onOpenChange={setDrawerOpen}
123114
apps={apps}
124-
selectedCapabilities={selectedCapabilities}
125-
onSelectedCapabilitiesChange={handleSelectedCapabilitiesChange}
126115
/>
127116
</div>
128117
);

features/public-site/screens/CapabilitiesPage.tsx

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { CapabilitiesHeroSection } from '../components/alternatives/Capabilities
66
import { EventsSection } from '../components/alternatives/EventsSection';
77
import StatsCard from '../components/alternatives/StatsCard';
88
import { DataTableDrawer } from '@/components/ui/DataTableDrawer';
9-
import { useSelectedCapabilities, useCapabilityActions } from '@/hooks/use-capabilities-config';
109
import { useQuery } from '@tanstack/react-query';
1110
import { queryKeys } from '../lib/query-keys';
1211
import { makeGraphQLRequest } from '../lib/graphql/client';
@@ -50,8 +49,6 @@ const GET_ALL_OPEN_SOURCE_APPS = `
5049

5150
export function CapabilitiesPageClient({ slug }: CapabilitiesPageClientProps) {
5251
const [drawerOpen, setDrawerOpen] = useState(false);
53-
const selectedCapabilities = useSelectedCapabilities();
54-
const { addCapability, removeCapability } = useCapabilityActions();
5552

5653
// This data is already prefetched by server, so it loads instantly
5754
const { data: capabilityData, error: capabilityError } = useCapabilityApplications(slug);
@@ -67,12 +64,6 @@ export function CapabilitiesPageClient({ slug }: CapabilitiesPageClientProps) {
6764
gcTime: 15 * 60 * 1000, // 15 minutes
6865
});
6966

70-
const handleSelectedCapabilitiesChange = (capabilities: any) => {
71-
// This is called when capabilities are changed from the BuildStatsCard - but we use the provider now
72-
// The provider will automatically handle the sync through the context
73-
console.log('Capability change handled by provider', capabilities);
74-
};
75-
7667
// Since data is prefetched, this should never show loading
7768
// But handle error state
7869
if (capabilityError || !capabilityData) {
@@ -123,8 +114,6 @@ export function CapabilitiesPageClient({ slug }: CapabilitiesPageClientProps) {
123114
open={drawerOpen}
124115
onOpenChange={setDrawerOpen}
125116
apps={apps}
126-
selectedCapabilities={selectedCapabilities}
127-
onSelectedCapabilitiesChange={handleSelectedCapabilitiesChange}
128117
/>
129118
</div>
130119
);

features/public-site/screens/OsAlternativesPage.tsx

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { OsAlternativesHeroSection } from '../components/alternatives/OsAlternat
66
import { EventsSection } from '../components/alternatives/EventsSection';
77
import StatsCard from '../components/alternatives/StatsCard';
88
import { DataTableDrawer } from '@/components/ui/DataTableDrawer';
9-
import { useSelectedCapabilities, useCapabilityActions } from '@/hooks/use-capabilities-config';
109
import { useQuery } from '@tanstack/react-query';
1110
import { queryKeys } from '../lib/query-keys';
1211
import { makeGraphQLRequest } from '../lib/graphql/client';
@@ -50,8 +49,6 @@ const GET_ALL_OPEN_SOURCE_APPS = `
5049

5150
export function OsAlternativesPageClient({ slug }: OsAlternativesPageClientProps) {
5251
const [drawerOpen, setDrawerOpen] = useState(false);
53-
const selectedCapabilities = useSelectedCapabilities();
54-
const { addCapability, removeCapability } = useCapabilityActions();
5552

5653
// This data is already prefetched by server, so it loads instantly
5754
const { data: osAlternativesData, error: osAlternativesError } = useOsAlternatives(slug);
@@ -67,12 +64,6 @@ export function OsAlternativesPageClient({ slug }: OsAlternativesPageClientProps
6764
gcTime: 15 * 60 * 1000, // 15 minutes
6865
});
6966

70-
const handleSelectedCapabilitiesChange = (capabilities: any) => {
71-
// This is called when capabilities are changed from the BuildStatsCard - but we use the provider now
72-
// The provider will automatically handle the sync through the context
73-
console.log('Capability change handled by provider', capabilities);
74-
};
75-
7667
// Since data is prefetched, this should never show loading
7768
// But handle error state
7869
if (osAlternativesError || !osAlternativesData) {
@@ -123,8 +114,6 @@ export function OsAlternativesPageClient({ slug }: OsAlternativesPageClientProps
123114
open={drawerOpen}
124115
onOpenChange={setDrawerOpen}
125116
apps={apps}
126-
selectedCapabilities={selectedCapabilities}
127-
onSelectedCapabilitiesChange={handleSelectedCapabilitiesChange}
128117
/>
129118
</div>
130119
);

hooks/use-capabilities-config.tsx

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ const defaultCapabilitiesConfig: CapabilitiesConfig = {
6363

6464
const saveToLS = (storageKey: string, config: CapabilitiesConfig) => {
6565
try {
66-
// Save to localStorage - using same key as existing implementation
67-
localStorage.setItem('pinnedCapabilities', JSON.stringify(config.selectedCapabilities))
68-
69-
// Also save the complete config as JSON for easier future management
7066
localStorage.setItem(storageKey, JSON.stringify(config))
7167
} catch {
7268
// Unsupported
@@ -77,7 +73,6 @@ const loadFromLS = (storageKey: string, defaultConfig: CapabilitiesConfig): Capa
7773
if (isServer) return defaultConfig
7874

7975
try {
80-
// Try to load from new JSON format first
8176
const savedConfig = localStorage.getItem(storageKey)
8277
if (savedConfig) {
8378
const parsed = JSON.parse(savedConfig) as CapabilitiesConfig
@@ -94,21 +89,6 @@ const loadFromLS = (storageKey: string, defaultConfig: CapabilitiesConfig): Capa
9489
}
9590
}
9691

97-
// Fallback to legacy pinnedCapabilities key for backward compatibility
98-
const pinnedCapabilities = localStorage.getItem('pinnedCapabilities')
99-
if (pinnedCapabilities) {
100-
const selectedCapabilities = JSON.parse(pinnedCapabilities) as SelectedCapability[]
101-
const config: CapabilitiesConfig = {
102-
...defaultConfig,
103-
selectedCapabilities,
104-
}
105-
106-
// Migrate to new format
107-
saveToLS(storageKey, config)
108-
109-
return config
110-
}
111-
11292
return defaultConfig
11393
} catch {
11494
return defaultConfig
@@ -182,7 +162,7 @@ const CapabilitiesRoot = ({
182162
// localStorage event handling for cross-tab synchronization
183163
React.useEffect(() => {
184164
const handleStorage = (e: StorageEvent) => {
185-
if (e.key !== storageKey && e.key !== 'pinnedCapabilities') {
165+
if (e.key !== storageKey) {
186166
return
187167
}
188168

0 commit comments

Comments
 (0)