@@ -24,18 +24,37 @@ export const CompaniesPage: React.FC = () => {
2424 const [ isViewModalOpen , setIsViewModalOpen ] = useState ( false ) ;
2525 const [ isEditModalOpen , setIsEditModalOpen ] = useState ( false ) ;
2626 const [ deleteId , setDeleteId ] = useState < number | null > ( null ) ;
27+
28+ // Track which tabs have been loaded to avoid duplicate calls
29+ const [ loadedTabs , setLoadedTabs ] = useState < Set < string > > ( new Set ( [ 'active' ] ) ) ;
2730
2831 const [ filters , setFilters ] = useState < CompanyFilterState > ( {
2932 search : '' ,
3033 status : '' ,
3134 workType : ''
3235 } ) ;
3336
34- const fetchData = async ( ) => {
37+ const fetchDataForTab = async ( tab : 'active' | 'dropped' | 'past' ) => {
3538 setIsLoading ( true ) ;
3639 try {
37- const data = await companiesApi . getAll ( ) ;
40+ let data : CRMEntry [ ] ;
41+
42+ switch ( tab ) {
43+ case 'active' :
44+ data = await companiesApi . getOnboarded ( ) ;
45+ break ;
46+ case 'dropped' :
47+ data = await companiesApi . getClosed ( ) ;
48+ break ;
49+ case 'past' :
50+ data = await companiesApi . getDone ( ) ;
51+ break ;
52+ default :
53+ data = [ ] ;
54+ }
55+
3856 setCrmEntries ( data ) ;
57+ setLoadedTabs ( prev => new Set ( prev ) . add ( tab ) ) ;
3958 } catch ( error ) {
4059 console . error ( "Failed to fetch data" , error ) ;
4160 showToast ( "Failed to load companies" , "error" ) ;
@@ -44,36 +63,28 @@ export const CompaniesPage: React.FC = () => {
4463 }
4564 } ;
4665
66+ // Initial load - fetch only onboarded (active) companies
4767 useEffect ( ( ) => {
4868 let mounted = true ;
4969 const loadData = async ( ) => {
5070 if ( mounted ) {
51- await fetchData ( ) ;
71+ await fetchDataForTab ( 'active' ) ;
5272 }
5373 } ;
5474 loadData ( ) ;
5575 return ( ) => { mounted = false ; } ;
5676 } , [ ] ) ;
5777
58- const allCompanies = useMemo ( ( ) => {
59- // Registry now strictly includes those that have passed initial lead stages
60- return crmEntries . filter ( entry => [ 'onboarded' , 'on progress' , 'Quote Sent' , 'completed' , 'drop' ] . includes ( entry . status ) ) ;
61- } , [ crmEntries ] ) ;
62-
63- const categorizedData = useMemo ( ( ) => {
64- // Onboarded, On Progress, and Quote Sent are considered active Focus nodes in the registry
65- const active = allCompanies . filter ( c => [ 'onboarded' , 'on progress' , 'Quote Sent' ] . includes ( c . status ) ) ;
66- const dropped = allCompanies . filter ( c => c . status === 'drop' ) ;
67- const past = allCompanies . filter ( c => c . status === 'completed' ) ;
68- return { active, dropped, past } ;
69- } , [ allCompanies ] ) ;
78+ // Handle tab changes - fetch data only if not already loaded
79+ useEffect ( ( ) => {
80+ if ( ! loadedTabs . has ( activeTab ) ) {
81+ fetchDataForTab ( activeTab ) ;
82+ }
83+ } , [ activeTab ] ) ;
7084
85+ // No need for categorization - data comes pre-filtered from backend
7186 const displayData = useMemo ( ( ) => {
72- let sourceList = categorizedData . active ;
73- if ( activeTab === 'dropped' ) sourceList = categorizedData . dropped ;
74- if ( activeTab === 'past' ) sourceList = categorizedData . past ;
75-
76- let result = sourceList . filter ( item => {
87+ let result = crmEntries . filter ( item => {
7788 const matchesSearch = filters . search === '' ||
7889 ( item . company || '' ) . toLowerCase ( ) . includes ( filters . search . toLowerCase ( ) ) ||
7990 ( item . contactName && item . contactName . toLowerCase ( ) . includes ( filters . search . toLowerCase ( ) ) ) ||
@@ -86,7 +97,7 @@ export const CompaniesPage: React.FC = () => {
8697 } ) ;
8798
8899 return result . sort ( ( a , b ) => b . id - a . id ) ;
89- } , [ categorizedData , activeTab , filters ] ) ;
100+ } , [ crmEntries , filters ] ) ;
90101
91102 const handleEdit = ( company : CRMEntry ) => {
92103 setEditingCompany ( company ) ;
@@ -107,8 +118,10 @@ export const CompaniesPage: React.FC = () => {
107118 try {
108119 await companiesApi . update ( updatedEntry . id , updatedEntry ) ;
109120 showToast ( "Company details updated" , "success" ) ;
121+ // Refresh current tab data
122+ await fetchDataForTab ( activeTab ) ;
110123 } catch ( e ) {
111- fetchData ( ) ;
124+ await fetchDataForTab ( activeTab ) ;
112125 showToast ( "Failed to update company" , "error" ) ;
113126 }
114127 }
@@ -125,12 +138,15 @@ export const CompaniesPage: React.FC = () => {
125138 try {
126139 await companiesApi . update ( company . id , updatedEntry ) ;
127140 showToast ( `Status updated to ${ newStatus } ` , "success" ) ;
128- // If status changes out of registry criteria, re-fetch to update view
129- if ( ! [ 'onboarded' , 'on progress' , 'Quote Sent' , 'completed' , 'drop' ] . includes ( newStatus ) ) {
130- fetchData ( ) ;
131- }
141+
142+ // Status change may move company to different tab
143+ // Clear loaded tabs cache to force refresh when switching tabs
144+ setLoadedTabs ( new Set ( [ activeTab ] ) ) ;
145+
146+ // Refresh current tab to reflect changes
147+ await fetchDataForTab ( activeTab ) ;
132148 } catch ( e ) {
133- fetchData ( ) ;
149+ await fetchDataForTab ( activeTab ) ;
134150 showToast ( "Failed to update status" , "error" ) ;
135151 }
136152 } ;
@@ -177,7 +193,7 @@ export const CompaniesPage: React.FC = () => {
177193 } `}
178194 >
179195 Active Focus
180- < span className = "ml-2 px-1.5 lg:px-2 py-0.5 rounded bg-brand-50 text-brand-600 text-[9px] lg:text-[10px]" > { categorizedData . active . length } </ span >
196+ { activeTab === 'active' && < span className = "ml-2 px-1.5 lg:px-2 py-0.5 rounded bg-brand-50 text-brand-600 text-[9px] lg:text-[10px]" > { crmEntries . length } </ span > }
181197 </ button >
182198 < button
183199 onClick = { ( ) => setActiveTab ( 'past' ) }
@@ -188,7 +204,7 @@ export const CompaniesPage: React.FC = () => {
188204 } `}
189205 >
190206 Historical
191- < span className = "ml-2 px-1.5 lg:px-2 py-0.5 rounded bg-emerald-50 text-emerald-600 text-[9px] lg:text-[10px]" > { categorizedData . past . length } </ span >
207+ { activeTab === 'past' && < span className = "ml-2 px-1.5 lg:px-2 py-0.5 rounded bg-emerald-50 text-emerald-600 text-[9px] lg:text-[10px]" > { crmEntries . length } </ span > }
192208 </ button >
193209 < button
194210 onClick = { ( ) => setActiveTab ( 'dropped' ) }
@@ -199,12 +215,12 @@ export const CompaniesPage: React.FC = () => {
199215 } `}
200216 >
201217 Archived
202- < span className = "ml-2 px-1.5 lg:px-2 py-0.5 rounded bg-rose-50 text-rose-600 text-[9px] lg:text-[10px]" > { categorizedData . dropped . length } </ span >
218+ { activeTab === 'dropped' && < span className = "ml-2 px-1.5 lg:px-2 py-0.5 rounded bg-rose-50 text-rose-600 text-[9px] lg:text-[10px]" > { crmEntries . length } </ span > }
203219 </ button >
204220 </ div >
205221 </ div >
206222
207- < CompaniesFilters filters = { filters } setFilters = { setFilters } onRefresh = { fetchData } />
223+ < CompaniesFilters filters = { filters } setFilters = { setFilters } onRefresh = { ( ) => fetchDataForTab ( activeTab ) } />
208224
209225 < div className = "pt-4 pb-10 overflow-x-auto" >
210226 < CompaniesTable
0 commit comments