add number input

This commit is contained in:
Виталий Лавшонок
2025-12-09 09:39:51 +03:00
parent fd34761745
commit a4622cf8d2
11 changed files with 97 additions and 15 deletions

View File

@@ -0,0 +1,73 @@
import React from 'react';
import { cn } from '../../lib/cn';
interface NumberInputProps {
name?: string;
error?: string;
disabled?: boolean;
required?: boolean;
label?: string;
placeholder?: string;
className?: string;
minValue?: number;
maxValue?: number;
onChange: (state: number) => void;
defaultState?: number;
}
export const NumberInput: React.FC<NumberInputProps> = ({
error = '',
// disabled = false,
// required = false,
label = '',
placeholder = '',
className = '',
onChange,
defaultState = 0,
minValue = 0,
maxValue = 365 * 24,
name = '',
}) => {
const [value, setValue] = React.useState<number>(defaultState);
React.useEffect(() => onChange(value), [value]);
React.useEffect(() => setValue(defaultState), [defaultState]);
return (
<div className={cn('relative', className)}>
<div
className={cn(
'text-[18px] text-liquid-white font-medium h-[23px] mb-[10px] transition-all',
label == '' && 'h-0 mb-0',
)}
>
{label}
</div>
<div className="relative pr-[5px]">
<input
className={cn(
'bg-liquid-lighter w-full rounded-[10px] outline-none pl-[16px] pr-[8px] py-[8px] placeholder:text-liquid-light',
)}
value={value}
name={name}
type={'number'}
min={minValue}
max={maxValue}
placeholder={placeholder}
onChange={(e) => {
setValue(Number(e.target.value));
}}
/>
</div>
<div
className={cn(
'text-liquid-red text-[14px] h-auto text-right mt-[5px] whitespace-pre-line ',
error == '' && 'h-0 mt-0',
)}
>
{error}
</div>
</div>
);
};

View File

@@ -1,8 +1,8 @@
import { import {
FilterDropDown, FilterDropDown,
FilterItem, FilterItem,
} from '../../../components/drop-down-list/Filter'; } from '../../../components/filters/Filter';
import { SorterDropDown } from '../../../components/drop-down-list/Sorter'; import { SorterDropDown } from '../../../components/filters/Sorter';
import { SearchInput } from '../../../components/input/SearchInput'; import { SearchInput } from '../../../components/input/SearchInput';
const Filters = () => { const Filters = () => {

View File

@@ -15,7 +15,7 @@ import Filters from './Filter';
const Contests = () => { const Contests = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [modalActive, setModalActive] = useState<boolean>(false); const [modalActive, setModalActive] = useState<boolean>(true);
const { contests, status } = useAppSelector( const { contests, status } = useAppSelector(
(state) => state.contests.fetchContests, (state) => state.contests.fetchContests,

View File

@@ -1,8 +1,8 @@
import { import {
FilterDropDown, FilterDropDown,
FilterItem, FilterItem,
} from '../../../components/drop-down-list/Filter'; } from '../../../components/filters/Filter';
import { SorterDropDown } from '../../../components/drop-down-list/Sorter'; import { SorterDropDown } from '../../../components/filters/Sorter';
import { SearchInput } from '../../../components/input/SearchInput'; import { SearchInput } from '../../../components/input/SearchInput';
const Filters = () => { const Filters = () => {

View File

@@ -11,6 +11,8 @@ import {
import { CreateContestBody } from '../../../redux/slices/contests'; import { CreateContestBody } from '../../../redux/slices/contests';
import DateRangeInput from '../../../components/input/DateRangeInput'; import DateRangeInput from '../../../components/input/DateRangeInput';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { NumberInput } from '../../../components/input/NumberInput';
import { DropDownListItem } from '../../../components/filters/DropDownList';
function toUtc(localDateTime?: string): string { function toUtc(localDateTime?: string): string {
if (!localDateTime) return ''; if (!localDateTime) return '';
@@ -37,6 +39,12 @@ const ModalCreateContest: FC<ModalCreateContestProps> = ({
(state) => state.contests.createContest.status, (state) => state.contests.createContest.status,
); );
const scheduleTypeItems: DropDownListItem[] = [
{value: "", text: ""},
{value: "", text: ""},
{value: "", text: ""},
]
const [form, setForm] = useState<CreateContestBody>({ const [form, setForm] = useState<CreateContestBody>({
name: '', name: '',
description: '', description: '',
@@ -110,8 +118,11 @@ const ModalCreateContest: FC<ModalCreateContestProps> = ({
onChange={(v) => handleChange('description', v)} onChange={(v) => handleChange('description', v)}
/> />
<div className="grid grid-cols-2 gap-[10px] mt-[10px]"> <div className="grid grid-cols-2 gap-[10px] mt-[10px]">
<div> <div>
<label className="block text-sm mb-1"> <label className="block text-sm mb-1">
Тип расписания Тип расписания
</label> </label>
@@ -167,18 +178,16 @@ const ModalCreateContest: FC<ModalCreateContestProps> = ({
{/* Продолжительность и лимиты */} {/* Продолжительность и лимиты */}
<div className="grid grid-cols-2 gap-[10px] mt-[10px]"> <div className="grid grid-cols-2 gap-[10px] mt-[10px]">
<Input <NumberInput
name="attemptDurationMinutes" name="attemptDurationMinutes"
type="number"
label="Длительность попытки (мин)" label="Длительность попытки (мин)"
placeholder="Например: 60" placeholder="Например: 60"
onChange={(v) => onChange={(v) =>
handleChange('attemptDurationMinutes', Number(v)) handleChange('attemptDurationMinutes', Number(v))
} }
/> />
<Input <NumberInput
name="maxAttempts" name="maxAttempts"
type="number"
label="Макс. попыток" label="Макс. попыток"
placeholder="Например: 3" placeholder="Например: 3"
onChange={(v) => handleChange('maxAttempts', Number(v))} onChange={(v) => handleChange('maxAttempts', Number(v))}
@@ -186,7 +195,7 @@ const ModalCreateContest: FC<ModalCreateContestProps> = ({
</div> </div>
{/* Разрешить раннее завершение */} {/* Разрешить раннее завершение */}
<div className="flex items-center gap-[10px] mt-[15px]"> {/* <div className="flex items-center gap-[10px] mt-[15px]">
<input <input
id="allowEarlyFinish" id="allowEarlyFinish"
type="checkbox" type="checkbox"
@@ -198,7 +207,7 @@ const ModalCreateContest: FC<ModalCreateContestProps> = ({
<label htmlFor="allowEarlyFinish"> <label htmlFor="allowEarlyFinish">
Разрешить раннее завершение Разрешить раннее завершение
</label> </label>
</div> </div> */}
{/* Кнопки */} {/* Кнопки */}
<div className="flex flex-row w-full items-center justify-end mt-[20px] gap-[20px]"> <div className="flex flex-row w-full items-center justify-end mt-[20px] gap-[20px]">

View File

@@ -1,8 +1,8 @@
import { import {
FilterDropDown, FilterDropDown,
FilterItem, FilterItem,
} from '../../../components/drop-down-list/Filter'; } from '../../../components/filters/Filter';
import { SorterDropDown } from '../../../components/drop-down-list/Sorter'; import { SorterDropDown } from '../../../components/filters/Sorter';
import { SearchInput } from '../../../components/input/SearchInput'; import { SearchInput } from '../../../components/input/SearchInput';
const Filters = () => { const Filters = () => {

View File

@@ -11,7 +11,7 @@ import {
setGroupsStatus, setGroupsStatus,
} from '../../../../redux/slices/groups'; } from '../../../../redux/slices/groups';
import ConfirmModal from '../../../../components/modal/ConfirmModal'; import ConfirmModal from '../../../../components/modal/ConfirmModal';
import { DropDownList } from '../../../../components/drop-down-list/DropDownList'; import { DropDownList } from '../../../../components/filters/DropDownList';
import { ReverseButton } from '../../../../components/button/ReverseButton'; import { ReverseButton } from '../../../../components/button/ReverseButton';
interface ModalUpdateProps { interface ModalUpdateProps {

View File

@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import Editor from '@monaco-editor/react'; import Editor from '@monaco-editor/react';
import { upload } from '../../../assets/icons/input'; import { upload } from '../../../assets/icons/input';
import { cn } from '../../../lib/cn'; import { cn } from '../../../lib/cn';
import { DropDownList } from '../../../components/drop-down-list/DropDownList'; import { DropDownList } from '../../../components/filters/DropDownList';
const languageMap: Record<string, string> = { const languageMap: Record<string, string> = {
c: 'cpp', c: 'cpp',