feat(admin-center): implement admin center settings retrieval and enhance holiday population logic
- Added a new API endpoint in AdminCenterController to fetch admin center settings, including organization details. - Updated the admin center API router to include the new settings route. - Enhanced the holiday controller to check for recent holiday population before attempting to repopulate, preventing duplicate entries. - Improved the holiday calendar component to manage holiday population attempts and display loading states. - Updated localization files to support new messages related to calculation methods and holiday settings.
This commit is contained in:
@@ -303,4 +303,9 @@ export const adminCenterApiService = {
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async getAdminCenterSettings(): Promise<IServerResponse<IOrganization>> {
|
||||
const response = await apiClient.get<IServerResponse<IOrganization>>(`${rootUrl}/settings`);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -55,6 +55,8 @@ const HolidayCalendar: React.FC<HolidayCalendarProps> = ({ themeMode, workingDay
|
||||
const [editModalVisible, setEditModalVisible] = useState(false);
|
||||
const [selectedHoliday, setSelectedHoliday] = useState<IHolidayCalendarEvent | null>(null);
|
||||
const [currentDate, setCurrentDate] = useState<Dayjs>(dayjs());
|
||||
const [isPopulatingHolidays, setIsPopulatingHolidays] = useState(false);
|
||||
const [hasAttemptedPopulation, setHasAttemptedPopulation] = useState(false);
|
||||
|
||||
const fetchHolidayTypes = async () => {
|
||||
try {
|
||||
@@ -69,9 +71,18 @@ const HolidayCalendar: React.FC<HolidayCalendarProps> = ({ themeMode, workingDay
|
||||
|
||||
const populateHolidaysIfNeeded = async () => {
|
||||
// Check if we have holiday settings with a country code but no holidays
|
||||
if (holidaySettings?.country_code && holidays.length === 0) {
|
||||
// Also check if we haven't already attempted population and we're not currently populating
|
||||
if (
|
||||
holidaySettings?.country_code &&
|
||||
holidays.length === 0 &&
|
||||
!hasAttemptedPopulation &&
|
||||
!isPopulatingHolidays
|
||||
) {
|
||||
try {
|
||||
console.log('🔄 No holidays found, attempting to populate official holidays...');
|
||||
setIsPopulatingHolidays(true);
|
||||
setHasAttemptedPopulation(true);
|
||||
|
||||
const populateRes = await holidayApiService.populateCountryHolidays();
|
||||
if (populateRes.done) {
|
||||
console.log('✅ Official holidays populated successfully');
|
||||
@@ -80,6 +91,8 @@ const HolidayCalendar: React.FC<HolidayCalendarProps> = ({ themeMode, workingDay
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Could not populate official holidays:', error);
|
||||
} finally {
|
||||
setIsPopulatingHolidays(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -110,7 +123,12 @@ const HolidayCalendar: React.FC<HolidayCalendarProps> = ({ themeMode, workingDay
|
||||
// Check if we need to populate holidays when holiday settings are loaded
|
||||
useEffect(() => {
|
||||
populateHolidaysIfNeeded();
|
||||
}, [holidaySettings, holidays.length]);
|
||||
}, [holidaySettings]);
|
||||
|
||||
// Reset population attempt state when holiday settings change
|
||||
useEffect(() => {
|
||||
setHasAttemptedPopulation(false);
|
||||
}, [holidaySettings?.country_code]);
|
||||
|
||||
const customHolidays = useMemo(() => {
|
||||
return holidays.filter(holiday => holiday.source === 'custom');
|
||||
@@ -300,6 +318,11 @@ const HolidayCalendar: React.FC<HolidayCalendarProps> = ({ themeMode, workingDay
|
||||
{holidaySettings.country_code}
|
||||
{holidaySettings.state_code && ` (${holidaySettings.state_code})`}
|
||||
</span>
|
||||
{isPopulatingHolidays && (
|
||||
<span style={{ marginLeft: 8, color: '#faad14' }}>
|
||||
🔄 Populating official holidays...
|
||||
</span>
|
||||
)}
|
||||
</Typography.Text>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -400,7 +400,7 @@ const RateCardDrawer = ({
|
||||
handleDeleteRole(index);
|
||||
}}
|
||||
>
|
||||
<Tooltip title="Delete">
|
||||
<Tooltip title={t('deleteTooltip') || 'Delete'}>
|
||||
<Button size="small" icon={<DeleteOutlined />} />
|
||||
</Tooltip>
|
||||
</Popconfirm>
|
||||
@@ -504,10 +504,10 @@ const RateCardDrawer = ({
|
||||
action={
|
||||
<Space direction="horizontal">
|
||||
<Button size="small" type="primary" onClick={handleConfirmSave}>
|
||||
Save
|
||||
{t('saveButton') || 'Save'}
|
||||
</Button>
|
||||
<Button size="small" danger onClick={handleConfirmDiscard}>
|
||||
Discard
|
||||
{t('discardButton') || 'Discard'}
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
@@ -568,8 +568,10 @@ const RateCardDrawer = ({
|
||||
<Alert
|
||||
message={
|
||||
isManDaysMethod
|
||||
? `Organization is using man days calculation (${organization.hours_per_day || 8}h/day). Rates above represent daily rates.`
|
||||
: 'Organization is using hourly calculation. Rates above represent hourly rates.'
|
||||
? t('manDaysCalculationMessage', {
|
||||
hours: organization.hours_per_day || 8
|
||||
}) || `Organization is using man days calculation (${organization.hours_per_day || 8}h/day). Rates above represent daily rates.`
|
||||
: t('hourlyCalculationMessage') || 'Organization is using hourly calculation. Rates above represent hourly rates.'
|
||||
}
|
||||
type="info"
|
||||
showIcon
|
||||
|
||||
@@ -83,6 +83,14 @@ export const fetchOrganizationDetails = createAsyncThunk(
|
||||
}
|
||||
);
|
||||
|
||||
export const fetchAdminCenterSettings = createAsyncThunk(
|
||||
'adminCenter/fetchAdminCenterSettings',
|
||||
async () => {
|
||||
const res = await adminCenterApiService.getAdminCenterSettings();
|
||||
return res.body;
|
||||
}
|
||||
);
|
||||
|
||||
export const fetchOrganizationAdmins = createAsyncThunk(
|
||||
'adminCenter/fetchOrganizationAdmins',
|
||||
async () => {
|
||||
@@ -207,6 +215,17 @@ const adminCenterSlice = createSlice({
|
||||
state.loadingOrganization = false;
|
||||
});
|
||||
|
||||
builder.addCase(fetchAdminCenterSettings.pending, (state, action) => {
|
||||
state.loadingOrganization = true;
|
||||
});
|
||||
builder.addCase(fetchAdminCenterSettings.fulfilled, (state, action) => {
|
||||
state.organization = action.payload;
|
||||
state.loadingOrganization = false;
|
||||
});
|
||||
builder.addCase(fetchAdminCenterSettings.rejected, (state, action) => {
|
||||
state.loadingOrganization = false;
|
||||
});
|
||||
|
||||
builder.addCase(fetchOrganizationAdmins.pending, (state, action) => {
|
||||
state.loadingOrganizationAdmins = true;
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ import { PageHeader } from '@ant-design/pro-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import logger from '@/utils/errorLogger';
|
||||
import { scheduleAPIService } from '@/api/schedule/schedule.api.service';
|
||||
import { adminCenterApiService } from '@/api/admin-center/admin-center.api.service';
|
||||
import { Settings } from '@/types/schedule/schedule-v2.types';
|
||||
import OrganizationCalculationMethod from '@/components/admin-center/overview/organization-calculation-method/organization-calculation-method';
|
||||
import HolidayCalendar from '@/components/admin-center/overview/holiday-calendar/holiday-calendar';
|
||||
@@ -25,6 +26,7 @@ import { useAppSelector } from '@/hooks/useAppSelector';
|
||||
import { RootState } from '@/app/store';
|
||||
import {
|
||||
fetchOrganizationDetails,
|
||||
fetchAdminCenterSettings,
|
||||
fetchOrganizationAdmins,
|
||||
fetchHolidaySettings,
|
||||
updateHolidaySettings,
|
||||
@@ -49,11 +51,11 @@ const SettingsPage: React.FC = () => {
|
||||
|
||||
const { t } = useTranslation('admin-center/settings');
|
||||
|
||||
const getOrganizationDetails = async () => {
|
||||
const getAdminCenterSettings = async () => {
|
||||
try {
|
||||
await dispatch(fetchOrganizationDetails()).unwrap();
|
||||
await dispatch(fetchAdminCenterSettings()).unwrap();
|
||||
} catch (error) {
|
||||
logger.error('Error getting organization details', error);
|
||||
logger.error('Error getting admin center settings', error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -111,7 +113,7 @@ const SettingsPage: React.FC = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getOrganizationDetails();
|
||||
getAdminCenterSettings();
|
||||
getOrganizationAdmins();
|
||||
getOrgWorkingSettings();
|
||||
dispatch(fetchHolidaySettings());
|
||||
@@ -202,10 +204,12 @@ const SettingsPage: React.FC = () => {
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<OrganizationCalculationMethod
|
||||
organization={organization}
|
||||
refetch={getOrganizationDetails}
|
||||
/>
|
||||
{organization && (
|
||||
<OrganizationCalculationMethod
|
||||
organization={organization}
|
||||
refetch={getAdminCenterSettings}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Card>
|
||||
<Typography.Title level={5} style={{ margin: 0 }}>
|
||||
|
||||
Reference in New Issue
Block a user