Skip to content

Commit ee642f2

Browse files
committed
Factor out remaining API fetches
1 parent 0d2f693 commit ee642f2

File tree

7 files changed

+65
-250
lines changed

7 files changed

+65
-250
lines changed

frontend/src/api/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ export interface Order {
4444
city: string;
4545
state: string;
4646
zip_code: string;
47+
country?: string;
48+
customer_name?: string;
49+
customer_phone?: string;
4750
};
4851
customer_phone?: string;
4952
stores: {

frontend/src/app/hooks/useStoreRoles.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useState, useEffect } from 'react';
22
import { useAuth } from '../contexts/auth';
3-
import { config } from '@/config';
3+
import { storesApi } from '@/api';
44

55
export function useStoreRoles(storeId: string) {
66
const { user } = useAuth();
@@ -15,20 +15,7 @@ export function useStoreRoles(storeId: string) {
1515
}
1616

1717
try {
18-
const response = await fetch(
19-
`${config.apiUrl}/api/v0/stores/${storeId}/roles`,
20-
{
21-
headers: {
22-
'Authorization': `Bearer ${user.token}`
23-
}
24-
}
25-
);
26-
27-
if (!response.ok) {
28-
throw new Error('Failed to fetch store roles');
29-
}
30-
31-
const data = await response.json();
18+
const data = await storesApi.getStoreRoles(user.token, storeId);
3219
setRoles(data.roles);
3320
} catch (err) {
3421
setError(err instanceof Error ? err.message : 'Failed to fetch store roles');

frontend/src/app/orders/[id]/page.tsx

Lines changed: 12 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import { useState, useEffect } from 'react';
44
import { useAuth } from '@/app/contexts/auth';
5-
import { config } from '@/config';
65
import { formatCurrency } from '@/utils/currency';
76
import { MapPinIcon, BuildingStorefrontIcon, XMarkIcon, ClockIcon } from '@heroicons/react/24/outline';
87
import { useRouter, useParams } from 'next/navigation';
@@ -12,6 +11,7 @@ import type { LatLngExpression, LatLngTuple } from 'leaflet';
1211
import styles from './map.module.css';
1312
import ReactDOMServer from 'react-dom/server';
1413
import L from 'leaflet';
14+
import { ordersApi, Order } from '@/api';
1515

1616
// Dynamically import the map components to avoid SSR issues
1717
const MapContainer = dynamic(
@@ -35,48 +35,6 @@ const Polyline = dynamic(
3535
{ ssr: false }
3636
);
3737

38-
interface OrderItem {
39-
id: string;
40-
name: string;
41-
quantity: number;
42-
price: number;
43-
}
44-
45-
interface Store {
46-
store: {
47-
id: string;
48-
name: string;
49-
};
50-
items: OrderItem[];
51-
}
52-
53-
interface Order {
54-
id: string;
55-
created: string;
56-
status: string;
57-
payment_status: string;
58-
delivery_fee: number;
59-
total_amount: number;
60-
tax_amount: number;
61-
delivery_address?: {
62-
street_address: string[];
63-
city: string;
64-
state: string;
65-
zip_code: string;
66-
};
67-
customer_phone?: string;
68-
stores: Store[];
69-
}
70-
71-
const formatDateTime = (isoString: string) => {
72-
const utcDate = new Date(isoString + 'Z');
73-
return new Intl.DateTimeFormat('en-US', {
74-
dateStyle: 'medium',
75-
timeStyle: 'short',
76-
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
77-
}).format(utcDate);
78-
};
79-
8038
// Mock coordinates for demo (we'll replace these with real geocoding later)
8139
const MOCK_COORDINATES: { store: LatLngTuple; delivery: LatLngTuple } = {
8240
store: [40.7594, -73.9229],
@@ -96,6 +54,15 @@ const DeliveryMarker = () => (
9654
</div>
9755
);
9856

57+
const formatDateTime = (isoString: string) => {
58+
const utcDate = new Date(isoString + 'Z');
59+
return new Intl.DateTimeFormat('en-US', {
60+
dateStyle: 'medium',
61+
timeStyle: 'short',
62+
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
63+
}).format(utcDate);
64+
};
65+
9966
export default function OrderViewPage() {
10067
const { user } = useAuth();
10168
const [order, setOrder] = useState<Order | null>(null);
@@ -112,18 +79,8 @@ export default function OrderViewPage() {
11279
if (!user?.token || !orderId) return;
11380

11481
try {
115-
const response = await fetch(`${config.apiUrl}/api/v0/orders`, {
116-
headers: {
117-
'Authorization': `Bearer ${user.token}`,
118-
},
119-
});
120-
121-
if (!response.ok) {
122-
throw new Error('Failed to fetch orders');
123-
}
124-
125-
const orders = await response.json();
126-
const order = orders.find((o: Order) => o.id === orderId);
82+
const orders = await ordersApi.getAdminOrders(user.token);
83+
const order = orders.find(o => o.id === orderId);
12784

12885
if (!order) {
12986
throw new Error('Order not found');

frontend/src/app/orders/page.tsx

Lines changed: 16 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { config } from '@/config';
77
import { CurrencyDollarIcon, ShoppingBagIcon, ClockIcon, ChartBarIcon } from '@heroicons/react/24/outline';
88
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Legend } from 'recharts';
99
import { useRouter } from 'next/navigation';
10+
import { ordersApi, Order } from '@/api';
1011

1112
interface OrderItem {
1213
id: string;
@@ -19,31 +20,6 @@ interface OrderItem {
1920
};
2021
}
2122

22-
interface Order {
23-
id: string;
24-
created: string;
25-
status: string;
26-
payment_status: string;
27-
delivery_fee: number;
28-
total_amount: number;
29-
delivery_address: {
30-
street_address: string[];
31-
city: string;
32-
state: string;
33-
zip_code: string;
34-
country: string;
35-
customer_name: string;
36-
customer_phone?: string;
37-
} | null;
38-
stores: Array<{
39-
store: {
40-
id: string;
41-
name: string;
42-
};
43-
items: OrderItem[];
44-
}>;
45-
}
46-
4723
interface DailyCount {
4824
date: string;
4925
timestamp: number;
@@ -240,57 +216,34 @@ export default function OrdersDashboard() {
240216
return;
241217
}
242218

243-
const response = await fetch(`${config.apiUrl}/api/v0/orders`, {
244-
headers: {
245-
'Authorization': `Bearer ${user?.token}`,
246-
},
247-
});
248-
249-
if (!response.ok) {
250-
throw new Error('Failed to fetch orders');
251-
}
252-
253-
const data = await response.json();
254-
setOrders(data);
255-
} catch (err) {
256-
setError(err instanceof Error ? err.message : 'Failed to fetch orders');
219+
const orders = await ordersApi.getAdminOrders(user.token);
220+
setOrders(orders);
221+
} catch (error) {
222+
console.error('Error fetching orders:', error);
223+
setError(error instanceof Error ? error.message : 'Failed to fetch orders');
257224
} finally {
258225
setLoading(false);
259226
}
260227
};
261228

262-
if (user) {
229+
if (user?.token) {
263230
fetchOrders();
264231
}
265232
}, [user]);
266233

267234
const updateOrderStatus = async (orderId: string, newStatus: string) => {
268-
try {
269-
const response = await fetch(`${config.apiUrl}/api/v0/orders/${orderId}/status`, {
270-
method: 'PATCH',
271-
headers: {
272-
'Authorization': `Bearer ${user?.token}`,
273-
'Content-Type': 'application/json'
274-
},
275-
body: JSON.stringify({ status: newStatus })
276-
});
277-
278-
if (!response.ok) {
279-
const errorData = await response.json();
280-
throw new Error(errorData.detail || 'Failed to update order status');
281-
}
235+
if (!user?.token) return;
282236

283-
setOrders(currentOrders =>
284-
currentOrders.map(order =>
285-
order.id === orderId
286-
? { ...order, status: newStatus }
287-
: order
237+
try {
238+
const updatedOrder = await ordersApi.updateOrderStatus(user.token, orderId, newStatus);
239+
setOrders(prevOrders =>
240+
prevOrders.map(order =>
241+
order.id === orderId ? updatedOrder : order
288242
)
289243
);
290-
291-
toast.success('Order status updated');
292-
} catch (err) {
293-
console.error('Status update error:', err);
244+
toast.success('Order status updated successfully');
245+
} catch (error) {
246+
console.error('Error updating order status:', error);
294247
toast.error('Failed to update order status');
295248
}
296249
};

frontend/src/app/store/[id]/dashboard/page.tsx

Lines changed: 20 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { use } from 'react';
1010
import { CurrencyDollarIcon, ShoppingBagIcon, ClockIcon, ChartBarIcon } from '@heroicons/react/24/outline';
1111
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Legend } from 'recharts';
1212
import Link from 'next/link';
13+
import { storesApi, ordersApi, Order } from '@/api';
1314

1415
interface OrderItem {
1516
id: string;
@@ -26,25 +27,6 @@ interface Store {
2627
items: OrderItem[];
2728
}
2829

29-
interface Order {
30-
id: string;
31-
created: string;
32-
status: string;
33-
payment_status: string;
34-
delivery_fee: number;
35-
total_amount: number;
36-
delivery_address: {
37-
street_address: string[];
38-
city: string;
39-
state: string;
40-
zip_code: string;
41-
country: string;
42-
customer_name: string;
43-
customer_phone?: string;
44-
} | null;
45-
stores: Store[];
46-
}
47-
4830
interface DailyCount {
4931
date: string;
5032
timestamp: number;
@@ -249,51 +231,34 @@ export default function StoreDashboard({ params }: { params: Promise<{ id: strin
249231

250232
useEffect(() => {
251233
const fetchOrders = async () => {
252-
if (!user?.token || rolesLoading) return; // Don't fetch if still loading roles
234+
if (!user?.token) return;
253235

254236
try {
255-
const response = await fetch(`${config.apiUrl}/api/v0/stores/${storeId}/orders`, {
256-
headers: {
257-
'Authorization': `Bearer ${user.token}`,
258-
},
259-
});
260-
261-
if (!response.ok) {
262-
throw new Error('Failed to fetch orders');
263-
}
264-
265-
const data = await response.json();
266-
setOrders(data);
267-
} catch (err) {
268-
setError(err instanceof Error ? err.message : 'Failed to fetch orders');
269-
} finally {
270-
setLoading(false);
237+
const orders = await storesApi.getStoreOrders(user.token, storeId);
238+
setOrders(orders);
239+
} catch (error) {
240+
console.error('Error fetching orders:', error);
241+
setError(error instanceof Error ? error.message : 'Failed to fetch orders');
271242
}
272243
};
273244

274-
if (isAdmin) {
275-
fetchOrders();
276-
}
277-
}, [user, storeId, isAdmin, rolesLoading]);
278-
279-
// Fetch store details
280-
useEffect(() => {
281245
const fetchStore = async () => {
282246
try {
283-
const response = await fetch(`${config.apiUrl}/api/v0/stores/${storeId}`);
284-
if (!response.ok) {
285-
throw new Error('Failed to fetch store details');
286-
}
287-
const data = await response.json();
288-
setStore(data);
289-
} catch (err) {
290-
console.error('Error fetching store:', err);
291-
setError(err instanceof Error ? err.message : 'Failed to fetch store details');
247+
const store = await storesApi.getStore(storeId);
248+
setStore(store);
249+
} catch (error) {
250+
console.error('Error fetching store:', error);
251+
setError(error instanceof Error ? error.message : 'Failed to fetch store');
252+
} finally {
253+
setLoading(false);
292254
}
293255
};
294256

295-
fetchStore();
296-
}, [storeId]);
257+
if (isAdmin) {
258+
fetchOrders();
259+
fetchStore();
260+
}
261+
}, [storeId, isAdmin, user]);
297262

298263
// Toggle status filter
299264
const toggleStatus = (status: string) => {
@@ -327,7 +292,7 @@ export default function StoreDashboard({ params }: { params: Promise<{ id: strin
327292
const lowercaseSearch = searchTerm.toLowerCase();
328293
result = result.filter(order =>
329294
order.id.toLowerCase().includes(lowercaseSearch) ||
330-
order.delivery_address?.customer_name.toLowerCase().includes(lowercaseSearch)
295+
order.delivery_address?.customer_name?.toLowerCase().includes(lowercaseSearch) || false
331296
);
332297
}
333298

0 commit comments

Comments
 (0)