Add CSV export for orders and update UI symbols

Introduces an exportOrdersToCSV function in lib/api-client.ts to allow exporting orders by status as a CSV file. Updates various UI components to use the '•' (bullet) symbol instead of '·' (middle dot) and replaces some emoji/unicode characters for improved consistency and compatibility. Also normalizes the 'use client' directive to include a BOM in many files.
This commit is contained in:
g
2025-12-15 17:57:18 +00:00
parent 07dcaf55c0
commit 0176f89cb7
91 changed files with 232 additions and 136 deletions

View File

@@ -377,6 +377,99 @@ export const getCustomerDetails = async (userId: string): Promise<CustomerStats>
return clientFetch(`/customers/${userId}`);
};
/**
* Export orders by status to CSV
* @param status Order status to filter by
* @param storeId Optional store ID (uses authenticated user's store if not provided)
* @returns Promise that resolves when download is triggered
*/
export const exportOrdersToCSV = async (status: string, storeId?: string): Promise<void> => {
try {
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
const normalizedEndpoint = '/orders/export-csv';
// Handle API endpoint construction
let url;
if (apiUrl === '/api' || apiUrl.startsWith('/api')) {
url = `/api${normalizedEndpoint}`;
} else {
url = `${apiUrl}${normalizedEndpoint}`;
}
// Add query parameters
const params = new URLSearchParams({ status });
if (storeId) {
params.append('storeId', storeId);
}
url = `${url}?${params.toString()}`;
// Get auth token
const authToken = getAuthToken();
// Prepare headers
const headers: Record<string, string> = {};
if (authToken && authToken !== 'HTTP_ONLY_COOKIE') {
headers['Authorization'] = `Bearer ${authToken}`;
}
// Fetch the CSV file
const response = await fetch(url, {
method: 'GET',
credentials: 'include',
headers,
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
const errorMessage = errorData.message || errorData.error || 'Failed to export orders';
throw new Error(errorMessage);
}
// Get the CSV content
const blob = await response.blob();
// Get filename from Content-Disposition header or generate one
const contentDisposition = response.headers.get('Content-Disposition');
let filename = `orders_${status}_${new Date().toISOString().split('T')[0]}.csv`;
if (contentDisposition) {
const filenameMatch = contentDisposition.match(/filename="?(.+)"?/);
if (filenameMatch) {
filename = filenameMatch[1];
}
}
// Create download link and trigger download
const downloadUrl = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = downloadUrl;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(downloadUrl);
} catch (error) {
console.error('Error exporting orders to CSV:', error);
const message = error instanceof Error ? error.message : 'Failed to export orders';
// Show error toast
if (typeof window !== 'undefined') {
if (toast?.title && toast?.description) {
toast({
title: 'Export Failed',
description: message,
variant: 'destructive',
});
} else if (typeof toast?.error === 'function') {
toast.error(message);
} else {
console.error('CSV export error:', message);
}
}
throw error;
}
};
/**
* Enhanced client-side fetch function with caching and automatic invalidation
*/

View File

@@ -10,6 +10,9 @@ export {
getCustomers,
getCustomerDetails,
// Orders API
exportOrdersToCSV,
// Types
type CustomerStats,
type CustomerResponse,