/** * Shipment Tracking Hooks */ import { useState, useEffect, useCallback } from 'react' import { TrackingSettings, Carrier, TrackedOrder, TrackingAnalytics, DEFAULT_SETTINGS } from '../types' declare const window: Window & { swiftCommerceData?: { apiUrl: string restNonce: string } } const getApiUrl = () => window.swiftCommerceData?.apiUrl || '/wp-json/swift-commerce/v1' const getNonce = () => window.swiftCommerceData?.restNonce || '' /** * Hook to manage tracking settings */ export function useTrackingSettings() { const [settings, setSettings] = useState(DEFAULT_SETTINGS) const [originalSettings, setOriginalSettings] = useState(DEFAULT_SETTINGS) const [carriers, setCarriers] = useState>({}) const [isLoading, setIsLoading] = useState(true) const [isSaving, setIsSaving] = useState(false) const [error, setError] = useState(null) // Check if there are unsaved changes const hasChanges = JSON.stringify(settings) !== JSON.stringify(originalSettings) const fetchSettings = useCallback(async () => { setIsLoading(true) setError(null) try { const response = await fetch(`${getApiUrl()}/shipment-tracking/settings`, { headers: { 'X-WP-Nonce': getNonce(), }, }) if (!response.ok) { throw new Error('Failed to fetch settings') } const data = await response.json() setSettings(data.settings) setOriginalSettings(data.settings) setCarriers(data.carriers || {}) } catch (err) { setError(err instanceof Error ? err.message : 'An error occurred') } finally { setIsLoading(false) } }, []) const saveSettings = useCallback(async (newSettings: Partial) => { setIsSaving(true) setError(null) try { const response = await fetch(`${getApiUrl()}/shipment-tracking/settings`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': getNonce(), }, body: JSON.stringify(newSettings), }) if (!response.ok) { throw new Error('Failed to save settings') } const data = await response.json() setSettings(data.settings) setOriginalSettings(data.settings) return true } catch (err) { setError(err instanceof Error ? err.message : 'An error occurred') return false } finally { setIsSaving(false) } }, []) const updateSetting = useCallback(( key: K, value: TrackingSettings[K] ) => { setSettings(prev => ({ ...prev, [key]: value })) }, []) const resetToDefaults = useCallback(() => { setSettings(DEFAULT_SETTINGS) }, []) useEffect(() => { fetchSettings() }, [fetchSettings]) return { settings, carriers, isLoading, isSaving, error, hasChanges, saveSettings, updateSetting, resetToDefaults, refetch: fetchSettings, } } /** * Hook to manage tracked orders */ export function useTrackedOrders() { const [orders, setOrders] = useState([]) const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) const [page, setPage] = useState(1) const [hasMore, setHasMore] = useState(true) const fetchOrders = useCallback(async (pageNum: number = 1, status: string = 'any') => { setIsLoading(true) setError(null) try { const response = await fetch( `${getApiUrl()}/shipment-tracking/orders?page=${pageNum}&per_page=20&status=${status}`, { headers: { 'X-WP-Nonce': getNonce(), }, } ) if (!response.ok) { throw new Error('Failed to fetch orders') } const data = await response.json() if (pageNum === 1) { setOrders(data.orders) } else { setOrders(prev => [...prev, ...data.orders]) } setHasMore(data.orders.length >= 20) setPage(pageNum) } catch (err) { setError(err instanceof Error ? err.message : 'An error occurred') } finally { setIsLoading(false) } }, []) const loadMore = useCallback(() => { if (!isLoading && hasMore) { fetchOrders(page + 1) } }, [fetchOrders, isLoading, hasMore, page]) useEffect(() => { fetchOrders() }, [fetchOrders]) return { orders, isLoading, error, hasMore, loadMore, refetch: () => fetchOrders(1), } } /** * Hook to manage tracking analytics */ export function useTrackingAnalytics(period: string = '30days') { const [analytics, setAnalytics] = useState(null) const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) const fetchAnalytics = useCallback(async (p: string) => { setIsLoading(true) setError(null) try { const response = await fetch(`${getApiUrl()}/shipment-tracking/analytics?period=${p}`, { headers: { 'X-WP-Nonce': getNonce(), }, }) if (!response.ok) { throw new Error('Failed to fetch analytics') } const data = await response.json() setAnalytics(data) } catch (err) { setError(err instanceof Error ? err.message : 'An error occurred') } finally { setIsLoading(false) } }, []) useEffect(() => { fetchAnalytics(period) }, [fetchAnalytics, period]) return { analytics, isLoading, error, refetch: () => fetchAnalytics(period), } } /** * Hook to add tracking to an order */ export function useAddTracking() { const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) const addTracking = useCallback(async ( orderId: number, data: { carrier: string tracking_number: string date_shipped?: string estimated_delivery_date?: string custom_url?: string send_notification?: boolean } ) => { setIsLoading(true) setError(null) try { const response = await fetch(`${getApiUrl()}/shipment-tracking/order/${orderId}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': getNonce(), }, body: JSON.stringify(data), }) if (!response.ok) { throw new Error('Failed to add tracking') } const result = await response.json() return result } catch (err) { setError(err instanceof Error ? err.message : 'An error occurred') return null } finally { setIsLoading(false) } }, []) return { addTracking, isLoading, error, } } /** * Hook to delete tracking from an order */ export function useDeleteTracking() { const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) const deleteTracking = useCallback(async (orderId: number, index: number) => { setIsLoading(true) setError(null) try { const response = await fetch(`${getApiUrl()}/shipment-tracking/order/${orderId}?index=${index}`, { method: 'DELETE', headers: { 'X-WP-Nonce': getNonce(), }, }) if (!response.ok) { throw new Error('Failed to delete tracking') } const result = await response.json() return result } catch (err) { setError(err instanceof Error ? err.message : 'An error occurred') return null } finally { setIsLoading(false) } }, []) return { deleteTracking, isLoading, error, } }