fix(holiday-api): add error handling and fallback for countries with states API

- Implemented try-catch block in `getCountriesWithStates` to handle API errors gracefully.
- Added logging for errors when fetching countries, with a fallback to static data if the API call fails.
- Updated the `SettingsPage` to utilize the selected country code state for improved state selection logic.
This commit is contained in:
Chamika J
2025-08-01 17:17:57 +05:30
parent 8f407b45a9
commit 11a6224fb3
2 changed files with 50 additions and 38 deletions

View File

@@ -245,13 +245,15 @@ export const holidayApiService = {
// Countries with states
getCountriesWithStates: async (): Promise<IServerResponse<ICountryWithStates[]>> => {
const response = await apiClient.get<IServerResponse<ICountryWithStates[]>>(
`${API_BASE_URL}/admin-center/countries-with-states`
);
return response.data;
// Fallback to static data if API fails
/*const supportedCountries = [
try {
const response = await apiClient.get<IServerResponse<ICountryWithStates[]>>(
`${API_BASE_URL}/admin-center/countries-with-states`
);
return response.data;
} catch (error) {
logger.error('Error fetching countries with states from API, falling back to static data', error);
// Fallback to static data if API fails
const supportedCountries = [
{ code: 'AD', name: 'Andorra' },
{ code: 'AE', name: 'United Arab Emirates' },
{ code: 'AG', name: 'Antigua & Barbuda' },
@@ -687,10 +689,11 @@ export const holidayApiService = {
{ code: 'ZA', name: 'South Africa' }
];
return {
done: true,
body: supportedCountries,
} as IServerResponse<ICountryWithStates[]>;*/
return {
done: true,
body: supportedCountries,
} as IServerResponse<ICountryWithStates[]>;
}
},
// Combined holidays (official + custom) - Database-driven approach

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useMemo } from 'react';
import {
Button,
Card,
@@ -46,6 +46,7 @@ const SettingsPage: React.FC = () => {
const [workingHours, setWorkingHours] = useState<Settings['workingHours']>(8);
const [saving, setSaving] = useState(false);
const [savingHolidays, setSavingHolidays] = useState(false);
const [selectedCountryCode, setSelectedCountryCode] = useState<string | undefined>(undefined);
const [form] = Form.useForm();
const [holidayForm] = Form.useForm();
@@ -127,6 +128,7 @@ const SettingsPage: React.FC = () => {
state_code: holidaySettings.state_code,
auto_sync_holidays: holidaySettings.auto_sync_holidays ?? true,
});
setSelectedCountryCode(holidaySettings.country_code);
}
}, [holidaySettings, holidayForm]);
@@ -143,12 +145,12 @@ const SettingsPage: React.FC = () => {
}
};
const getSelectedCountryStates = () => {
const selectedCountryStates = useMemo(() => {
const selectedCountry = countriesWithStates.find(
country => country.code === holidayForm.getFieldValue('country_code')
country => country.code === selectedCountryCode
);
return selectedCountry?.states || [];
};
}, [countriesWithStates, selectedCountryCode]);
return (
<div style={{ width: '100%' }}>
@@ -193,9 +195,13 @@ const SettingsPage: React.FC = () => {
</Row>
</Checkbox.Group>
</Form.Item>
<Form.Item label={t('workingHours')} name="workingHours">
<Input type="number" min={1} max={24} suffix={t('hours')} width={100} />
</Form.Item>
<Row>
<Col span={6}>
<Form.Item label={t('workingHours')} name="workingHours">
<Input type="number" min={1} max={24} suffix={t('hours')} />
</Form.Item>
</Col>
</Row>
<Form.Item>
<Button type="primary" htmlType="submit" loading={saving}>
{t('saveButton') || 'Save'}
@@ -233,8 +239,9 @@ const SettingsPage: React.FC = () => {
<Select
placeholder={t('selectCountry') || 'Select country'}
loading={loadingCountries}
onChange={() => {
onChange={(value) => {
holidayForm.setFieldValue('state_code', undefined);
setSelectedCountryCode(value);
}}
showSearch
filterOption={(input, option) =>
@@ -249,25 +256,27 @@ const SettingsPage: React.FC = () => {
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label={t('state') || 'State/Province'} name="state_code">
<Select
placeholder={t('selectState') || 'Select state/province (optional)'}
allowClear
disabled={!holidayForm.getFieldValue('country_code')}
showSearch
filterOption={(input, option) =>
(option?.children as unknown as string)?.toLowerCase().includes(input.toLowerCase())
}
>
{getSelectedCountryStates().map(state => (
<Select.Option key={state.code} value={state.code}>
{state.name}
</Select.Option>
))}
</Select>
</Form.Item>
</Col>
{selectedCountryStates.length > 0 && (
<Col span={12}>
<Form.Item label={t('state') || 'State/Province'} name="state_code">
<Select
placeholder={t('selectState') || 'Select state/province (optional)'}
allowClear
disabled={!holidayForm.getFieldValue('country_code')}
showSearch
filterOption={(input, option) =>
(option?.children as unknown as string)?.toLowerCase().includes(input.toLowerCase())
}
>
{selectedCountryStates.map(state => (
<Select.Option key={state.code} value={state.code}>
{state.name}
</Select.Option>
))}
</Select>
</Form.Item>
</Col>
)}
</Row>
<Form.Item
label={t('autoSyncHolidays') || 'Automatically sync official holidays'}