diff --git a/admin-spa/src/routes/Settings/Store.tsx b/admin-spa/src/routes/Settings/Store.tsx index 5e10939..34388f4 100644 --- a/admin-spa/src/routes/Settings/Store.tsx +++ b/admin-spa/src/routes/Settings/Store.tsx @@ -1,4 +1,6 @@ import React, { useState, useEffect } from 'react'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { api } from '@/lib/api'; import { SettingsLayout } from './components/SettingsLayout'; import { SettingsCard } from './components/SettingsCard'; import { SettingsSection } from './components/SettingsSection'; @@ -27,7 +29,7 @@ interface StoreSettings { } export default function StoreDetailsPage() { - const [isLoading, setIsLoading] = useState(true); + const queryClient = useQueryClient(); const [settings, setSettings] = useState({ storeName: '', contactEmail: '', @@ -48,36 +50,89 @@ export default function StoreDetailsPage() { dimensionUnit: 'cm', }); + // Fetch store settings + const { data: storeData, isLoading } = useQuery({ + queryKey: ['store-settings'], + queryFn: () => api.get('/store/settings'), + }); + + // Fetch countries + const { data: countries = [] } = useQuery({ + queryKey: ['store-countries'], + queryFn: () => api.get('/store/countries'), + staleTime: 60 * 60 * 1000, // 1 hour + }); + + // Fetch timezones + const { data: timezones = {} } = useQuery({ + queryKey: ['store-timezones'], + queryFn: () => api.get('/store/timezones'), + staleTime: 60 * 60 * 1000, // 1 hour + }); + + // Fetch currencies + const { data: currencies = [] } = useQuery({ + queryKey: ['store-currencies'], + queryFn: () => api.get('/store/currencies'), + staleTime: 60 * 60 * 1000, // 1 hour + }); + + // Update local state when data loads useEffect(() => { - // TODO: Load settings from API - setTimeout(() => { + if (storeData) { setSettings({ - storeName: 'WooNooW Store', - contactEmail: 'contact@example.com', - supportEmail: 'support@example.com', - phone: '+62 812 3456 7890', - country: 'ID', - address: 'Jl. Example No. 123', - city: 'Jakarta', - state: 'DKI Jakarta', - postcode: '12345', - currency: 'IDR', - currencyPosition: 'left', - thousandSep: '.', - decimalSep: ',', - decimals: 0, - timezone: 'Asia/Jakarta', - weightUnit: 'kg', - dimensionUnit: 'cm', + storeName: storeData.store_name || '', + contactEmail: storeData.contact_email || '', + supportEmail: storeData.support_email || '', + phone: storeData.phone || '', + country: storeData.country || 'ID', + address: storeData.address || '', + city: storeData.city || '', + state: '', + postcode: storeData.postcode || '', + currency: storeData.currency || 'IDR', + currencyPosition: storeData.currency_position || 'left', + thousandSep: storeData.thousand_separator || ',', + decimalSep: storeData.decimal_separator || '.', + decimals: storeData.number_of_decimals || 0, + timezone: storeData.timezone || 'Asia/Jakarta', + weightUnit: storeData.weight_unit || 'kg', + dimensionUnit: storeData.dimension_unit || 'cm', }); - setIsLoading(false); - }, 500); - }, []); + } + }, [storeData]); + + // Save mutation + const saveMutation = useMutation({ + mutationFn: (data: StoreSettings) => api.post('/store/settings', { + store_name: data.storeName, + contact_email: data.contactEmail, + support_email: data.supportEmail, + phone: data.phone, + country: data.country, + address: data.address, + city: data.city, + postcode: data.postcode, + currency: data.currency, + currency_position: data.currencyPosition, + thousand_separator: data.thousandSep, + decimal_separator: data.decimalSep, + number_of_decimals: data.decimals, + timezone: data.timezone, + weight_unit: data.weightUnit, + dimension_unit: data.dimensionUnit, + }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['store-settings'] }); + toast.success('Your store details have been updated successfully.'); + }, + onError: () => { + toast.error('Failed to save store settings'); + }, + }); const handleSave = async () => { - // TODO: Save to API - await new Promise((resolve) => setTimeout(resolve, 1000)); - toast.success('Your store details have been updated successfully.'); + await saveMutation.mutateAsync(settings); }; const updateSetting = ( @@ -184,11 +239,11 @@ export default function StoreDetailsPage() { - 🇮🇩 Indonesia - 🇺🇸 United States - 🇸🇬 Singapore - 🇲🇾 Malaysia - 🇹🇭 Thailand + {countries.map((country: { code: string; name: string }) => ( + + {country.name} + + ))} @@ -243,11 +298,11 @@ export default function StoreDetailsPage() { - Indonesian Rupiah (Rp) - US Dollar ($) - Euro (€) - Singapore Dollar (S$) - Malaysian Ringgit (RM) + {currencies.map((currency: { code: string; name: string; symbol: string }) => ( + + {currency.name} ({currency.symbol}) + + ))} @@ -327,11 +382,15 @@ export default function StoreDetailsPage() { - Asia/Jakarta (WIB) - Asia/Makassar (WITA) - Asia/Jayapura (WIT) - Asia/Singapore - America/New_York (EST) + {Object.entries(timezones).map(([continent, tzList]: [string, any]) => ( + + {tzList.map((tz: { value: string; label: string; offset: string }) => ( + + {tz.label} ({tz.offset}) + + ))} + + ))} diff --git a/admin-spa/src/routes/Settings/Store.tsx.bak b/admin-spa/src/routes/Settings/Store.tsx.bak new file mode 100644 index 0000000..5e10939 --- /dev/null +++ b/admin-spa/src/routes/Settings/Store.tsx.bak @@ -0,0 +1,381 @@ +import React, { useState, useEffect } from 'react'; +import { SettingsLayout } from './components/SettingsLayout'; +import { SettingsCard } from './components/SettingsCard'; +import { SettingsSection } from './components/SettingsSection'; +import { Input } from '@/components/ui/input'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { toast } from 'sonner'; + +interface StoreSettings { + storeName: string; + contactEmail: string; + supportEmail: string; + phone: string; + country: string; + address: string; + city: string; + state: string; + postcode: string; + currency: string; + currencyPosition: 'left' | 'right' | 'left_space' | 'right_space'; + thousandSep: string; + decimalSep: string; + decimals: number; + timezone: string; + weightUnit: string; + dimensionUnit: string; +} + +export default function StoreDetailsPage() { + const [isLoading, setIsLoading] = useState(true); + const [settings, setSettings] = useState({ + storeName: '', + contactEmail: '', + supportEmail: '', + phone: '', + country: 'ID', + address: '', + city: '', + state: '', + postcode: '', + currency: 'IDR', + currencyPosition: 'left', + thousandSep: ',', + decimalSep: '.', + decimals: 0, + timezone: 'Asia/Jakarta', + weightUnit: 'kg', + dimensionUnit: 'cm', + }); + + useEffect(() => { + // TODO: Load settings from API + setTimeout(() => { + setSettings({ + storeName: 'WooNooW Store', + contactEmail: 'contact@example.com', + supportEmail: 'support@example.com', + phone: '+62 812 3456 7890', + country: 'ID', + address: 'Jl. Example No. 123', + city: 'Jakarta', + state: 'DKI Jakarta', + postcode: '12345', + currency: 'IDR', + currencyPosition: 'left', + thousandSep: '.', + decimalSep: ',', + decimals: 0, + timezone: 'Asia/Jakarta', + weightUnit: 'kg', + dimensionUnit: 'cm', + }); + setIsLoading(false); + }, 500); + }, []); + + const handleSave = async () => { + // TODO: Save to API + await new Promise((resolve) => setTimeout(resolve, 1000)); + toast.success('Your store details have been updated successfully.'); + }; + + const updateSetting = ( + key: K, + value: StoreSettings[K] + ) => { + setSettings((prev) => ({ ...prev, [key]: value })); + }; + + // Currency preview + const formatCurrency = (amount: number) => { + const formatted = amount.toFixed(settings.decimals) + .replace('.', settings.decimalSep) + .replace(/\B(?=(\d{3})+(?!\d))/g, settings.thousandSep); + + const symbol = settings.currency === 'IDR' ? 'Rp' : settings.currency === 'USD' ? '$' : '€'; + + switch (settings.currencyPosition) { + case 'left': + return `${symbol}${formatted}`; + case 'right': + return `${formatted}${symbol}`; + case 'left_space': + return `${symbol} ${formatted}`; + case 'right_space': + return `${formatted} ${symbol}`; + default: + return `${symbol}${formatted}`; + } + }; + + return ( + + {/* Store Identity */} + + + updateSetting('storeName', e.target.value)} + placeholder="My Awesome Store" + /> + + + + updateSetting('contactEmail', e.target.value)} + placeholder="contact@example.com" + /> + + + + updateSetting('supportEmail', e.target.value)} + placeholder="support@example.com" + /> + + + + updateSetting('phone', e.target.value)} + placeholder="+62 812 3456 7890" + /> + + + + {/* Store Address */} + + + + + + + updateSetting('address', e.target.value)} + placeholder="Jl. Example No. 123" + /> + + +
+ + updateSetting('city', e.target.value)} + placeholder="Jakarta" + /> + + + + updateSetting('state', e.target.value)} + placeholder="DKI Jakarta" + /> + + + + updateSetting('postcode', e.target.value)} + placeholder="12345" + /> + +
+
+ + {/* Currency & Formatting */} + + + + + + + + + +
+ + updateSetting('thousandSep', e.target.value)} + maxLength={1} + placeholder="," + /> + + + + updateSetting('decimalSep', e.target.value)} + maxLength={1} + placeholder="." + /> + + + + + +
+ + {/* Live Preview */} +
+

Preview:

+

{formatCurrency(1234567.89)}

+
+
+ + {/* Standards & Formats */} + + + + + +
+ + + + + + + +
+
+ + {/* Summary Card */} +
+

+ 🇮🇩 Your store is located in {settings.country === 'ID' ? 'Indonesia' : settings.country} +

+

+ Prices will be displayed in {settings.currency} • Timezone: {settings.timezone} +

+
+
+ ); +}