Skip to content

Commit 95fbd40

Browse files
committed
fix: stabilize companies and form6k page data handling
1 parent cce56c0 commit 95fbd40

File tree

4 files changed

+76
-36
lines changed

4 files changed

+76
-36
lines changed

frontend/src/app/api/client.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,23 @@ class ApiClient {
3939
}
4040

4141
async get<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
42-
const response = await this.client.get<ApiResponse<T>>(url, config);
43-
return response.data.data;
42+
const response = await this.client.get<ApiResponse<T> | T>(url, config);
43+
return this.unwrapResponse<T>(response.data);
4444
}
4545

4646
async post<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {
47-
const response = await this.client.post<ApiResponse<T>>(url, data, config);
48-
return response.data.data;
47+
const response = await this.client.post<ApiResponse<T> | T>(url, data, config);
48+
return this.unwrapResponse<T>(response.data);
4949
}
5050

5151
async put<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T> {
52-
const response = await this.client.put<ApiResponse<T>>(url, data, config);
53-
return response.data.data;
52+
const response = await this.client.put<ApiResponse<T> | T>(url, data, config);
53+
return this.unwrapResponse<T>(response.data);
5454
}
5555

5656
async delete<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
57-
const response = await this.client.delete<ApiResponse<T>>(url, config);
58-
return response.data.data;
57+
const response = await this.client.delete<ApiResponse<T> | T>(url, config);
58+
return this.unwrapResponse<T>(response.data);
5959
}
6060

6161
async downloadFile(url: string, data?: unknown): Promise<Blob> {
@@ -68,6 +68,18 @@ class ApiClient {
6868
getBaseUrl(): string {
6969
return API_BASE_URL;
7070
}
71+
72+
private unwrapResponse<T>(payload: ApiResponse<T> | T): T {
73+
if (
74+
payload !== null &&
75+
typeof payload === 'object' &&
76+
'success' in payload &&
77+
'data' in payload
78+
) {
79+
return (payload as ApiResponse<T>).data;
80+
}
81+
return payload as T;
82+
}
7183
}
7284

7385
export const apiClient = new ApiClient();

frontend/src/app/hooks/useCompanies.ts

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,33 @@
11
import { useState, useEffect, useCallback } from 'react';
2-
import { companiesApi, Company, CompanyListItem, CompanySearchRequest, Filing, PaginatedResponse } from '../api';
2+
import { companiesApi, Company, CompanyListItem, CompanySearchRequest, Filing } from '../api';
33

44
export function useCompanies(initialParams: CompanySearchRequest = {}) {
5-
const [companies, setCompanies] = useState<PaginatedResponse<CompanyListItem> | null>(null);
5+
const [companies, setCompanies] = useState<CompanyListItem[]>([]);
66
const [loading, setLoading] = useState(true);
77
const [error, setError] = useState<string | null>(null);
8-
const [params, setParams] = useState<CompanySearchRequest>(initialParams);
8+
const [totalElements, setTotalElements] = useState(0);
9+
const [totalPages, setTotalPages] = useState(0);
10+
const [params, setParams] = useState<CompanySearchRequest>({
11+
page: 0,
12+
size: 20,
13+
sortBy: 'name',
14+
sortDir: 'asc',
15+
...initialParams,
16+
});
917

1018
const fetchCompanies = useCallback(async (searchParams: CompanySearchRequest) => {
1119
setLoading(true);
1220
setError(null);
1321
try {
1422
const data = await companiesApi.getCompanies(searchParams);
15-
setCompanies(data);
23+
setCompanies(data?.content ?? []);
24+
setTotalElements(data?.totalElements ?? 0);
25+
setTotalPages(data?.totalPages ?? 0);
1626
} catch (err) {
1727
setError(err instanceof Error ? err.message : 'Failed to load companies');
28+
setCompanies([]);
29+
setTotalElements(0);
30+
setTotalPages(0);
1831
} finally {
1932
setLoading(false);
2033
}
@@ -24,8 +37,13 @@ export function useCompanies(initialParams: CompanySearchRequest = {}) {
2437
fetchCompanies(params);
2538
}, [params, fetchCompanies]);
2639

27-
const search = useCallback((searchTerm: string) => {
28-
setParams(prev => ({ ...prev, searchTerm, page: 0 }));
40+
const search = useCallback((searchInput: CompanySearchRequest & { name?: string }) => {
41+
setParams(prev => ({
42+
...prev,
43+
...searchInput,
44+
searchTerm: searchInput.searchTerm ?? searchInput.name ?? prev.searchTerm,
45+
page: searchInput.page ?? 0,
46+
}));
2947
}, []);
3048

3149
const setPage = useCallback((page: number) => {
@@ -44,6 +62,8 @@ export function useCompanies(initialParams: CompanySearchRequest = {}) {
4462
companies,
4563
loading,
4664
error,
65+
totalElements,
66+
totalPages,
4767
params,
4868
search,
4969
setPage,
@@ -95,23 +115,29 @@ export function useCompanyByCik(cik: string | undefined) {
95115
return { company, loading, error };
96116
}
97117

98-
export function useCompanyFilings(companyId: string | undefined, page: number = 0, size: number = 10) {
99-
const [filings, setFilings] = useState<PaginatedResponse<Filing> | null>(null);
100-
const [loading, setLoading] = useState(true);
118+
export function useCompanyFilings() {
119+
const [filings, setFilings] = useState<Filing[]>([]);
120+
const [loading, setLoading] = useState(false);
101121
const [error, setError] = useState<string | null>(null);
102122

103-
useEffect(() => {
104-
if (!companyId) {
105-
setLoading(false);
123+
const fetchByCompany = useCallback(async (cik: string, page: number = 0, size: number = 10) => {
124+
if (!cik) {
125+
setFilings([]);
106126
return;
107127
}
108128

109129
setLoading(true);
110-
companiesApi.getCompanyFilings(companyId, page, size)
111-
.then(setFilings)
112-
.catch(err => setError(err.message))
113-
.finally(() => setLoading(false));
114-
}, [companyId, page, size]);
130+
setError(null);
131+
try {
132+
const data = await companiesApi.getCompanyFilingsByCik(cik, page, size);
133+
setFilings(data?.content ?? []);
134+
} catch (err) {
135+
setError(err instanceof Error ? err.message : 'Failed to load company filings');
136+
setFilings([]);
137+
} finally {
138+
setLoading(false);
139+
}
140+
}, []);
115141

116-
return { filings, loading, error };
142+
return { filings, loading, error, fetchByCompany };
117143
}

frontend/src/app/hooks/useForm6K.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@ export function useForm6KSearch() {
118118
setError(null);
119119
try {
120120
const data = await form6kApi.getByCik(cik, page, size);
121-
setFilings(data.content);
122-
setTotalElements(data.totalElements);
123-
setTotalPages(data.totalPages);
121+
setFilings(data?.content ?? []);
122+
setTotalElements(data?.totalElements ?? 0);
123+
setTotalPages(data?.totalPages ?? 0);
124124
} catch (err) {
125125
setError(err instanceof Error ? err.message : 'Failed to search filings');
126126
} finally {
@@ -133,9 +133,9 @@ export function useForm6KSearch() {
133133
setError(null);
134134
try {
135135
const data = await form6kApi.getBySymbol(symbol, page, size);
136-
setFilings(data.content);
137-
setTotalElements(data.totalElements);
138-
setTotalPages(data.totalPages);
136+
setFilings(data?.content ?? []);
137+
setTotalElements(data?.totalElements ?? 0);
138+
setTotalPages(data?.totalPages ?? 0);
139139
} catch (err) {
140140
setError(err instanceof Error ? err.message : 'Failed to search filings');
141141
} finally {
@@ -148,9 +148,9 @@ export function useForm6KSearch() {
148148
setError(null);
149149
try {
150150
const data = await form6kApi.getByDateRange(startDate, endDate, page, size);
151-
setFilings(data.content);
152-
setTotalElements(data.totalElements);
153-
setTotalPages(data.totalPages);
151+
setFilings(data?.content ?? []);
152+
setTotalElements(data?.totalElements ?? 0);
153+
setTotalPages(data?.totalPages ?? 0);
154154
} catch (err) {
155155
setError(err instanceof Error ? err.message : 'Failed to search filings');
156156
} finally {

frontend/src/app/pages/Form6K.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,9 @@ export function Form6KPage() {
226226

227227
const loading = recentLoading || searchLoading;
228228
const error = recentError || searchError;
229-
const displayFilings = hasSearched ? searchResults : recentFilings;
229+
const displayFilings = hasSearched
230+
? (Array.isArray(searchResults) ? searchResults : [])
231+
: (Array.isArray(recentFilings) ? recentFilings : []);
230232

231233
return (
232234
<div className="space-y-6">

0 commit comments

Comments
 (0)