fix utm visual selector
This commit is contained in:
parent
639929d825
commit
75aca56c01
@ -125,9 +125,7 @@ export default function QuizMarkCreate() {
|
||||
fullWidth
|
||||
size="small"
|
||||
sx={{
|
||||
|
||||
width: "100%",
|
||||
maxWidth: "118px",
|
||||
width: "137px",
|
||||
height: "24px",
|
||||
}}
|
||||
>
|
||||
|
||||
@ -26,21 +26,36 @@ const OverTime = () => {
|
||||
Math.max(0, (initialOverTime.endsAt || 0) - Date.now())
|
||||
);
|
||||
|
||||
const [isEditing, setIsEditing] = useState<boolean>(false);
|
||||
|
||||
const daysRef = useRef<HTMLInputElement | null>(null);
|
||||
const hoursRef = useRef<HTMLInputElement | null>(null);
|
||||
const minutesRef = useRef<HTMLInputElement | null>(null);
|
||||
const secondsRef = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
const isAnyTimeInputFocused = (): boolean => {
|
||||
const active = document.activeElement as HTMLElement | null;
|
||||
return [daysRef.current, hoursRef.current, minutesRef.current, secondsRef.current].some(
|
||||
(ref) => ref !== null && ref === active
|
||||
);
|
||||
};
|
||||
|
||||
const toDigits = (value: string): string => (value || "").replace(/\D+/g, "");
|
||||
const clampTwoDigits = (value: string): string => {
|
||||
const digits = toDigits(value).slice(0, 2);
|
||||
if (digits.length === 0) return "";
|
||||
const num = Number(digits);
|
||||
if (isNaN(num)) return "";
|
||||
if (num > 60) return "60";
|
||||
return digits;
|
||||
};
|
||||
const clampTwoDigitsDays = (value: string): string => toDigits(value).slice(0, 2);
|
||||
const clampTwoDigits = (value: string): string => {
|
||||
const digits = toDigits(value).slice(0, 2);
|
||||
if (digits.length === 0) return "";
|
||||
const num = Number(digits);
|
||||
if (isNaN(num)) return "";
|
||||
return num > 60 ? "60" : digits;
|
||||
};
|
||||
const clampTwoDigitsDays = (value: string): string => {
|
||||
return toDigits(value).slice(0, 2);
|
||||
};
|
||||
|
||||
const pad2 = (value: string): string => {
|
||||
const d = toDigits(value);
|
||||
return (d.length === 0 ? "00" : d.padStart(2, "0").slice(-2));
|
||||
};
|
||||
|
||||
const allowControlKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
const allowed = ["Backspace", "Delete", "ArrowLeft", "ArrowRight", "Tab", "Home", "End", "Enter"];
|
||||
@ -95,16 +110,6 @@ const OverTime = () => {
|
||||
const cfgEndsAt = (quiz as any)?.config?.overTime?.endsAt ?? 0;
|
||||
const ms = Math.max(0, cfgEndsAt - Date.now());
|
||||
setRemainingMs(ms);
|
||||
if (ms <= 0) {
|
||||
// выключаем флаг
|
||||
setEnabled(false);
|
||||
updateQuiz(quiz!.id, (q) => {
|
||||
const cfg: any = (q as any).config;
|
||||
if (!cfg.overTime) cfg.overTime = { enabled: false, endsAt: 0, description: "" };
|
||||
cfg.overTime.enabled = false;
|
||||
cfg.overTime.endsAt = 0;
|
||||
});
|
||||
}
|
||||
};
|
||||
// первый расчёт по requestAnimationFrame для мгновенного обновления
|
||||
rafId = window.requestAnimationFrame(() => tick());
|
||||
@ -135,6 +140,19 @@ const OverTime = () => {
|
||||
return { d, h, m, s };
|
||||
}, [remainingMs]);
|
||||
|
||||
// Показываем обратный отсчёт в полях ввода, когда счётчик включён
|
||||
useEffect(() => {
|
||||
if (!enabled || isEditing) return;
|
||||
const dStr = String(rem.d).padStart(2, "0").slice(-2);
|
||||
const hStr = fmt(rem.h).slice(-2);
|
||||
const mStr = fmt(rem.m).slice(-2);
|
||||
const sStr = fmt(rem.s).slice(-2);
|
||||
setDays(dStr);
|
||||
setHours(hStr);
|
||||
setMinutes(mStr);
|
||||
setSeconds(sStr);
|
||||
}, [enabled, rem, isEditing]);
|
||||
|
||||
if (!quiz) return null;
|
||||
return (
|
||||
<Box sx={{ display: "flex", flexDirection: "column", mt: "20px", padding: "15px", backgroundColor: "#F2F3F7", width: "100%", maxWidth: "357px", height: "295px", borderRadius: "8px" }}>
|
||||
@ -204,14 +222,22 @@ const OverTime = () => {
|
||||
<CustomTextField
|
||||
placeholder="00"
|
||||
value={days}
|
||||
onChange={(e) => {
|
||||
const next = clampTwoDigitsDays(e.target.value);
|
||||
onChange={(e) => {
|
||||
const next = clampTwoDigitsDays(e.target.value);
|
||||
setDays(next);
|
||||
persistEndsAt(next, hours, minutes, seconds);
|
||||
}}
|
||||
onKeyDown={handleTwoDigitKeyDown(days) as any}
|
||||
inputRef={daysRef}
|
||||
onFocus={() => daysRef.current?.select()}
|
||||
onFocus={() => { setIsEditing(true); daysRef.current?.select(); }}
|
||||
onBlur={() => setTimeout(() => {
|
||||
setIsEditing(isAnyTimeInputFocused());
|
||||
const nd = pad2(days);
|
||||
const nh = pad2(hours);
|
||||
const nm = pad2(minutes);
|
||||
const ns = pad2(seconds);
|
||||
setDays(nd);
|
||||
persistEndsAt(nd, nh, nm, ns);
|
||||
}, 0)}
|
||||
onClick={() => daysRef.current?.select()}
|
||||
InputProps={{ inputProps: { pattern: "\\d*", inputMode: "numeric", maxLength: 2 } }}
|
||||
sx={{ height: "48px", width: "100%", maxWidth: "51px", backgroundColor: "white", p: "8px 6px" }}
|
||||
@ -231,14 +257,22 @@ const OverTime = () => {
|
||||
<CustomTextField
|
||||
placeholder="00"
|
||||
value={hours}
|
||||
onChange={(e) => {
|
||||
const next = clampTwoDigits(e.target.value);
|
||||
onChange={(e) => {
|
||||
const next = clampTwoDigits(e.target.value);
|
||||
setHours(next);
|
||||
persistEndsAt(days, next, minutes, seconds);
|
||||
}}
|
||||
onKeyDown={handleTwoDigitKeyDown(hours) as any}
|
||||
inputRef={hoursRef}
|
||||
onFocus={() => hoursRef.current?.select()}
|
||||
onFocus={() => { setIsEditing(true); hoursRef.current?.select(); }}
|
||||
onBlur={() => setTimeout(() => {
|
||||
setIsEditing(isAnyTimeInputFocused());
|
||||
const nd = pad2(days);
|
||||
const nh = pad2(hours);
|
||||
const nm = pad2(minutes);
|
||||
const ns = pad2(seconds);
|
||||
setHours(nh);
|
||||
persistEndsAt(nd, nh, nm, ns);
|
||||
}, 0)}
|
||||
onClick={() => hoursRef.current?.select()}
|
||||
InputProps={{ inputProps: { pattern: "\\d*", inputMode: "numeric", maxLength: 2 } }}
|
||||
sx={{ height: "48px", width: "100%", maxWidth: "51px", backgroundColor: "white", p: "8px 6px" }}
|
||||
@ -258,14 +292,22 @@ const OverTime = () => {
|
||||
<CustomTextField
|
||||
placeholder="00"
|
||||
value={minutes}
|
||||
onChange={(e) => {
|
||||
const next = clampTwoDigits(e.target.value);
|
||||
onChange={(e) => {
|
||||
const next = clampTwoDigits(e.target.value);
|
||||
setMinutes(next);
|
||||
persistEndsAt(days, hours, next, seconds);
|
||||
}}
|
||||
onKeyDown={handleTwoDigitKeyDown(minutes) as any}
|
||||
inputRef={minutesRef}
|
||||
onFocus={() => minutesRef.current?.select()}
|
||||
onFocus={() => { setIsEditing(true); minutesRef.current?.select(); }}
|
||||
onBlur={() => setTimeout(() => {
|
||||
setIsEditing(isAnyTimeInputFocused());
|
||||
const nd = pad2(days);
|
||||
const nh = pad2(hours);
|
||||
const nm = pad2(minutes);
|
||||
const ns = pad2(seconds);
|
||||
setMinutes(nm);
|
||||
persistEndsAt(nd, nh, nm, ns);
|
||||
}, 0)}
|
||||
onClick={() => minutesRef.current?.select()}
|
||||
InputProps={{ inputProps: { pattern: "\\d*", inputMode: "numeric", maxLength: 2 } }}
|
||||
sx={{ height: "48px", width: "100%", maxWidth: "51px", backgroundColor: "white", p: "8px 6px" }}
|
||||
@ -285,14 +327,22 @@ const OverTime = () => {
|
||||
<CustomTextField
|
||||
placeholder="00"
|
||||
value={seconds}
|
||||
onChange={(e) => {
|
||||
const next = clampTwoDigits(e.target.value);
|
||||
onChange={(e) => {
|
||||
const next = clampTwoDigits(e.target.value);
|
||||
setSeconds(next);
|
||||
persistEndsAt(days, hours, minutes, next);
|
||||
}}
|
||||
onKeyDown={handleTwoDigitKeyDown(seconds) as any}
|
||||
inputRef={secondsRef}
|
||||
onFocus={() => secondsRef.current?.select()}
|
||||
onFocus={() => { setIsEditing(true); secondsRef.current?.select(); }}
|
||||
onBlur={() => setTimeout(() => {
|
||||
setIsEditing(isAnyTimeInputFocused());
|
||||
const nd = pad2(days);
|
||||
const nh = pad2(hours);
|
||||
const nm = pad2(minutes);
|
||||
const ns = pad2(seconds);
|
||||
setSeconds(ns);
|
||||
persistEndsAt(nd, nh, nm, ns);
|
||||
}, 0)}
|
||||
onClick={() => secondsRef.current?.select()}
|
||||
InputProps={{ inputProps: { pattern: "\\d*", inputMode: "numeric", maxLength: 2 } }}
|
||||
sx={{ height: "48px", width: "100%", maxWidth: "51px", backgroundColor: "white", p: "8px 6px" }}
|
||||
@ -309,13 +359,7 @@ const OverTime = () => {
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
{enabled && (
|
||||
<Box sx={{ mt: "10px" }}>
|
||||
<Typography sx={{ fontWeight: 500, color: theme.palette.grey3.main, fontSize: "16px" }}>
|
||||
До конца: {rem.d} д {fmt(rem.h)}:{fmt(rem.m)}:{fmt(rem.s)}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
{/* Удалён маленький таймер с обратным отсчётом */}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user