import { useEffect } from 'react'; import { Alert, Button, Card, Flex, Form, InputNumber, Switch, Tooltip, Typography, theme, } from '@/shared/antd-imports'; import { CrownOutlined, InfoCircleOutlined } from '@ant-design/icons'; import { useTranslation } from 'react-i18next'; import { useAppDispatch } from '@/hooks/useAppDispatch'; import { useAppSelector } from '@/hooks/useAppSelector'; import { fetchOrgConfig, updateOrgConfig } from '@/features/org-config/org-config.slice'; import { useAuthService } from '@/hooks/useAuth'; import { canUseFeature, hasBusinessFeatureAccess } from '@/utils/subscription-utils'; import { toggleUpgradeModal } from '@/features/admin-center/admin-center.slice'; const ConfigurationSettings = () => { const { t } = useTranslation('settings/configuration'); const { token } = theme.useToken(); const dispatch = useAppDispatch(); const auth = useAuthService(); const session = auth.getCurrentSession(); const isOwnerOrAdmin = auth.isOwnerOrAdmin(); // Time-log backdating has no registry feature yet, so it keeps the Business check. const hasBusinessAccess = hasBusinessFeatureAccess(session); const canRestrictTaskCreation = canUseFeature(session, 'restrict_task_creation'); const orgConfig = useAppSelector(state => state.orgConfigReducer); const [form] = Form.useForm(); const backdateLimitEnabled = orgConfig.timelog_backdate_limit_days > 0; useEffect(() => { void dispatch(fetchOrgConfig()); }, [dispatch]); useEffect(() => { form.setFieldsValue({ restrict_task_creation: orgConfig.restrict_task_creation, timelog_backdate_limit_days: orgConfig.timelog_backdate_limit_days, enforce_daily_time_limit: orgConfig.enforce_daily_time_limit, }); }, [form, orgConfig.restrict_task_creation, orgConfig.timelog_backdate_limit_days, orgConfig.enforce_daily_time_limit]); const handleRestrictTaskCreationChange = async (checked: boolean) => { if (!canRestrictTaskCreation) return; await dispatch(updateOrgConfig({ restrict_task_creation: checked })); }; const handleDailyTimeLimitToggle = async (checked: boolean) => { if (!isOwnerOrAdmin) return; await dispatch(updateOrgConfig({ enforce_daily_time_limit: checked })); }; // 0 means "no limit", so toggling on needs a sensible starting value. const handleBackdateLimitToggle = async (checked: boolean) => { if (!hasBusinessAccess) return; await dispatch(updateOrgConfig({ timelog_backdate_limit_days: checked ? 7 : 0 })); }; const handleBackdateLimitDaysChange = async (value: number | null) => { if (!hasBusinessAccess) return; const days = Math.floor(Number(value)); if (!Number.isFinite(days) || days < 1 || days > 365) return; if (days === orgConfig.timelog_backdate_limit_days) return; await dispatch(updateOrgConfig({ timelog_backdate_limit_days: days })); }; const handleUpgradeClick = () => { dispatch(toggleUpgradeModal()); }; const renderBusinessPlanAlert = (locked: boolean) => locked && ( {t('businessPlanRequiredDescription', { defaultValue: 'Organization-level task restriction settings are available on Business and Enterprise plans.', })} } /> ); return ( {t('configurationTitle', { defaultValue: 'Configuration' })} {t('configurationDescription', { defaultValue: 'Manage organization-wide settings that apply across all projects.', })} {t('taskManagementSection', { defaultValue: 'Task Management' })} } > {renderBusinessPlanAlert(!canRestrictTaskCreation)}
{t('restrictTaskCreation', { defaultValue: 'Restrict task assignment to Admins, Team Leads, and Project Managers', })} } >
{t('restrictTaskCreationNote', { defaultValue: 'Note: Project-level settings take priority over this organization-level setting. Changes take effect immediately.', })}
{t('timeTrackingSection', { defaultValue: 'Time Tracking' })} } > {renderBusinessPlanAlert(!hasBusinessAccess)}
{t('enforceDailyTimeLimit', { defaultValue: 'Enforce 24-hour daily time tracking limit', })} } > {t('limitTimelogBackdating', { defaultValue: 'Limit how far back time can be logged', })} } > {backdateLimitEnabled && ( {t('timelogBackdateLimitDays', { defaultValue: 'Maximum days a time log can be backdated', })} } style={{ marginBlockEnd: 12 }} > handleBackdateLimitDaysChange(Number(event.target.value))} onPressEnter={event => handleBackdateLimitDaysChange(Number((event.target as HTMLInputElement).value)) } addonAfter={t('days', { defaultValue: 'days' })} aria-label={t('timelogBackdateLimitDays', { defaultValue: 'Maximum days a time log can be backdated', })} /> )}
{t('timelogBackdateLimitNote', { defaultValue: 'Note: Existing time logs are never altered. Editing an already-old log stays possible as long as its date is not changed.', })}
); }; export default ConfigurationSettings;