111 lines
3.4 KiB
TypeScript
111 lines
3.4 KiB
TypeScript
import { useState, useEffect } from 'react';
|
||
import {
|
||
Box,
|
||
Typography,
|
||
TextField,
|
||
Button,
|
||
Paper,
|
||
Alert,
|
||
} from '@mui/material';
|
||
import { useSettingsQuery, useUpdateSettings } from '../../hooks/useSettings';
|
||
import { DEFAULT_ESTIMATE_CONFIG } from '../../utils/estimate';
|
||
|
||
export function SettingsPage() {
|
||
const { data: settings, isLoading } = useSettingsQuery();
|
||
const updateSettings = useUpdateSettings();
|
||
|
||
const [hoursPerDay, setHoursPerDay] = useState(
|
||
String(DEFAULT_ESTIMATE_CONFIG.hoursPerDay),
|
||
);
|
||
const [daysPerWeek, setDaysPerWeek] = useState(
|
||
String(DEFAULT_ESTIMATE_CONFIG.daysPerWeek),
|
||
);
|
||
|
||
useEffect(() => {
|
||
if (settings) {
|
||
setHoursPerDay(
|
||
String(settings.hoursPerDay ?? DEFAULT_ESTIMATE_CONFIG.hoursPerDay),
|
||
);
|
||
setDaysPerWeek(
|
||
String(settings.daysPerWeek ?? DEFAULT_ESTIMATE_CONFIG.daysPerWeek),
|
||
);
|
||
}
|
||
}, [settings]);
|
||
|
||
const handleSave = () => {
|
||
const hpd = Number(hoursPerDay);
|
||
const dpw = Number(daysPerWeek);
|
||
if (hpd > 0 && hpd <= 24 && dpw > 0 && dpw <= 7) {
|
||
updateSettings.mutate({ hoursPerDay: hpd, daysPerWeek: dpw });
|
||
}
|
||
};
|
||
|
||
const hpdNum = Number(hoursPerDay);
|
||
const dpwNum = Number(daysPerWeek);
|
||
const isValid =
|
||
hpdNum > 0 && hpdNum <= 24 && dpwNum > 0 && dpwNum <= 7;
|
||
|
||
if (isLoading) return null;
|
||
|
||
return (
|
||
<Box sx={{ maxWidth: 500 }}>
|
||
<Typography variant="h5" sx={{ mb: 3 }}>
|
||
Настройки
|
||
</Typography>
|
||
|
||
<Paper sx={{ p: 3 }}>
|
||
<Typography variant="h6" sx={{ mb: 2 }}>
|
||
Формат оценки трудозатрат
|
||
</Typography>
|
||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||
Эти значения используются для конвертации оценок из формата «1w 3d 7h»
|
||
в часы и обратно.
|
||
</Typography>
|
||
|
||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||
<TextField
|
||
label="Часов в рабочем дне"
|
||
type="number"
|
||
value={hoursPerDay}
|
||
onChange={(e) => setHoursPerDay(e.target.value)}
|
||
slotProps={{ htmlInput: { min: 1, max: 24 } }}
|
||
helperText="От 1 до 24"
|
||
error={!hpdNum || hpdNum < 1 || hpdNum > 24}
|
||
size="small"
|
||
/>
|
||
<TextField
|
||
label="Рабочих дней в неделе"
|
||
type="number"
|
||
value={daysPerWeek}
|
||
onChange={(e) => setDaysPerWeek(e.target.value)}
|
||
slotProps={{ htmlInput: { min: 1, max: 7 } }}
|
||
helperText="От 1 до 7"
|
||
error={!dpwNum || dpwNum < 1 || dpwNum > 7}
|
||
size="small"
|
||
/>
|
||
</Box>
|
||
|
||
<Box sx={{ mt: 3, display: 'flex', alignItems: 'center', gap: 2 }}>
|
||
<Button
|
||
variant="contained"
|
||
onClick={handleSave}
|
||
disabled={!isValid || updateSettings.isPending}
|
||
>
|
||
Сохранить
|
||
</Button>
|
||
{updateSettings.isSuccess && (
|
||
<Alert severity="success" sx={{ py: 0 }}>
|
||
Сохранено
|
||
</Alert>
|
||
)}
|
||
{updateSettings.isError && (
|
||
<Alert severity="error" sx={{ py: 0 }}>
|
||
Ошибка сохранения
|
||
</Alert>
|
||
)}
|
||
</Box>
|
||
</Paper>
|
||
</Box>
|
||
);
|
||
}
|