add number input
This commit is contained in:
73
src/components/input/NumberInput.tsx
Normal file
73
src/components/input/NumberInput.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -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 = () => {
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 = () => {
|
||||||
|
|||||||
@@ -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]">
|
||||||
|
|||||||
@@ -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 = () => {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
Reference in New Issue
Block a user