Skip to content

Commit

Permalink
Factor out remaining API fetches
Browse files Browse the repository at this point in the history
  • Loading branch information
azlyth committed Feb 23, 2025
1 parent 0d2f693 commit ee642f2
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 250 deletions.
3 changes: 3 additions & 0 deletions frontend/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export interface Order {
city: string;
state: string;
zip_code: string;
country?: string;
customer_name?: string;
customer_phone?: string;
};
customer_phone?: string;
stores: {
Expand Down
17 changes: 2 additions & 15 deletions frontend/src/app/hooks/useStoreRoles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useEffect } from 'react';
import { useAuth } from '../contexts/auth';
import { config } from '@/config';
import { storesApi } from '@/api';

export function useStoreRoles(storeId: string) {
const { user } = useAuth();
Expand All @@ -15,20 +15,7 @@ export function useStoreRoles(storeId: string) {
}

try {
const response = await fetch(
`${config.apiUrl}/api/v0/stores/${storeId}/roles`,
{
headers: {
'Authorization': `Bearer ${user.token}`
}
}
);

if (!response.ok) {
throw new Error('Failed to fetch store roles');
}

const data = await response.json();
const data = await storesApi.getStoreRoles(user.token, storeId);
setRoles(data.roles);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to fetch store roles');
Expand Down
67 changes: 12 additions & 55 deletions frontend/src/app/orders/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

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

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

interface OrderItem {
id: string;
name: string;
quantity: number;
price: number;
}

interface Store {
store: {
id: string;
name: string;
};
items: OrderItem[];
}

interface Order {
id: string;
created: string;
status: string;
payment_status: string;
delivery_fee: number;
total_amount: number;
tax_amount: number;
delivery_address?: {
street_address: string[];
city: string;
state: string;
zip_code: string;
};
customer_phone?: string;
stores: Store[];
}

const formatDateTime = (isoString: string) => {
const utcDate = new Date(isoString + 'Z');
return new Intl.DateTimeFormat('en-US', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
}).format(utcDate);
};

// Mock coordinates for demo (we'll replace these with real geocoding later)
const MOCK_COORDINATES: { store: LatLngTuple; delivery: LatLngTuple } = {
store: [40.7594, -73.9229],
Expand All @@ -96,6 +54,15 @@ const DeliveryMarker = () => (
</div>
);

const formatDateTime = (isoString: string) => {
const utcDate = new Date(isoString + 'Z');
return new Intl.DateTimeFormat('en-US', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
}).format(utcDate);
};

export default function OrderViewPage() {
const { user } = useAuth();
const [order, setOrder] = useState<Order | null>(null);
Expand All @@ -112,18 +79,8 @@ export default function OrderViewPage() {
if (!user?.token || !orderId) return;

try {
const response = await fetch(`${config.apiUrl}/api/v0/orders`, {
headers: {
'Authorization': `Bearer ${user.token}`,
},
});

if (!response.ok) {
throw new Error('Failed to fetch orders');
}

const orders = await response.json();
const order = orders.find((o: Order) => o.id === orderId);
const orders = await ordersApi.getAdminOrders(user.token);
const order = orders.find(o => o.id === orderId);

if (!order) {
throw new Error('Order not found');
Expand Down
79 changes: 16 additions & 63 deletions frontend/src/app/orders/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { config } from '@/config';
import { CurrencyDollarIcon, ShoppingBagIcon, ClockIcon, ChartBarIcon } from '@heroicons/react/24/outline';
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import { useRouter } from 'next/navigation';
import { ordersApi, Order } from '@/api';

interface OrderItem {
id: string;
Expand All @@ -19,31 +20,6 @@ interface OrderItem {
};
}

interface Order {
id: string;
created: string;
status: string;
payment_status: string;
delivery_fee: number;
total_amount: number;
delivery_address: {
street_address: string[];
city: string;
state: string;
zip_code: string;
country: string;
customer_name: string;
customer_phone?: string;
} | null;
stores: Array<{
store: {
id: string;
name: string;
};
items: OrderItem[];
}>;
}

interface DailyCount {
date: string;
timestamp: number;
Expand Down Expand Up @@ -240,57 +216,34 @@ export default function OrdersDashboard() {
return;
}

const response = await fetch(`${config.apiUrl}/api/v0/orders`, {
headers: {
'Authorization': `Bearer ${user?.token}`,
},
});

if (!response.ok) {
throw new Error('Failed to fetch orders');
}

const data = await response.json();
setOrders(data);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to fetch orders');
const orders = await ordersApi.getAdminOrders(user.token);
setOrders(orders);
} catch (error) {
console.error('Error fetching orders:', error);
setError(error instanceof Error ? error.message : 'Failed to fetch orders');
} finally {
setLoading(false);
}
};

if (user) {
if (user?.token) {
fetchOrders();
}
}, [user]);

const updateOrderStatus = async (orderId: string, newStatus: string) => {
try {
const response = await fetch(`${config.apiUrl}/api/v0/orders/${orderId}/status`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${user?.token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ status: newStatus })
});

if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.detail || 'Failed to update order status');
}
if (!user?.token) return;

setOrders(currentOrders =>
currentOrders.map(order =>
order.id === orderId
? { ...order, status: newStatus }
: order
try {
const updatedOrder = await ordersApi.updateOrderStatus(user.token, orderId, newStatus);
setOrders(prevOrders =>
prevOrders.map(order =>
order.id === orderId ? updatedOrder : order
)
);

toast.success('Order status updated');
} catch (err) {
console.error('Status update error:', err);
toast.success('Order status updated successfully');
} catch (error) {
console.error('Error updating order status:', error);
toast.error('Failed to update order status');
}
};
Expand Down
75 changes: 20 additions & 55 deletions frontend/src/app/store/[id]/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { use } from 'react';
import { CurrencyDollarIcon, ShoppingBagIcon, ClockIcon, ChartBarIcon } from '@heroicons/react/24/outline';
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import Link from 'next/link';
import { storesApi, ordersApi, Order } from '@/api';

interface OrderItem {
id: string;
Expand All @@ -26,25 +27,6 @@ interface Store {
items: OrderItem[];
}

interface Order {
id: string;
created: string;
status: string;
payment_status: string;
delivery_fee: number;
total_amount: number;
delivery_address: {
street_address: string[];
city: string;
state: string;
zip_code: string;
country: string;
customer_name: string;
customer_phone?: string;
} | null;
stores: Store[];
}

interface DailyCount {
date: string;
timestamp: number;
Expand Down Expand Up @@ -249,51 +231,34 @@ export default function StoreDashboard({ params }: { params: Promise<{ id: strin

useEffect(() => {
const fetchOrders = async () => {
if (!user?.token || rolesLoading) return; // Don't fetch if still loading roles
if (!user?.token) return;

try {
const response = await fetch(`${config.apiUrl}/api/v0/stores/${storeId}/orders`, {
headers: {
'Authorization': `Bearer ${user.token}`,
},
});

if (!response.ok) {
throw new Error('Failed to fetch orders');
}

const data = await response.json();
setOrders(data);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to fetch orders');
} finally {
setLoading(false);
const orders = await storesApi.getStoreOrders(user.token, storeId);
setOrders(orders);
} catch (error) {
console.error('Error fetching orders:', error);
setError(error instanceof Error ? error.message : 'Failed to fetch orders');
}
};

if (isAdmin) {
fetchOrders();
}
}, [user, storeId, isAdmin, rolesLoading]);

// Fetch store details
useEffect(() => {
const fetchStore = async () => {
try {
const response = await fetch(`${config.apiUrl}/api/v0/stores/${storeId}`);
if (!response.ok) {
throw new Error('Failed to fetch store details');
}
const data = await response.json();
setStore(data);
} catch (err) {
console.error('Error fetching store:', err);
setError(err instanceof Error ? err.message : 'Failed to fetch store details');
const store = await storesApi.getStore(storeId);
setStore(store);
} catch (error) {
console.error('Error fetching store:', error);
setError(error instanceof Error ? error.message : 'Failed to fetch store');
} finally {
setLoading(false);
}
};

fetchStore();
}, [storeId]);
if (isAdmin) {
fetchOrders();
fetchStore();
}
}, [storeId, isAdmin, user]);

// Toggle status filter
const toggleStatus = (status: string) => {
Expand Down Expand Up @@ -327,7 +292,7 @@ export default function StoreDashboard({ params }: { params: Promise<{ id: strin
const lowercaseSearch = searchTerm.toLowerCase();
result = result.filter(order =>
order.id.toLowerCase().includes(lowercaseSearch) ||
order.delivery_address?.customer_name.toLowerCase().includes(lowercaseSearch)
order.delivery_address?.customer_name?.toLowerCase().includes(lowercaseSearch) || false
);
}

Expand Down
Loading

0 comments on commit ee642f2

Please sign in to comment.