|
@@ -0,0 +1,429 @@
|
|
|
|
+import './App.css';
|
|
|
|
+import { useState, useEffect } from 'react';
|
|
|
|
+import ClockFace from './images/ClockFace.png';
|
|
|
|
+import ClockFace_H from './images/ClockFace_H.png';
|
|
|
|
+import ClockFace_M from './images/ClockFace_M.png';
|
|
|
|
+import ClockFace_S from'./images/ClockFace_S.png';
|
|
|
|
+
|
|
|
|
+const LoginForm = ({ onLogin }) => {
|
|
|
|
+ const [login, setLogin] = useState('');
|
|
|
|
+ const [password, setPassword] = useState('');
|
|
|
|
+ return <>
|
|
|
|
+ <input className='inputForm' value={login } onChange={e => {setLogin(e.target.value); }}/>
|
|
|
|
+ <input className='inputForm' value={password } onChange={e => {setPassword(e.target.value)}}/>
|
|
|
|
+ <button disabled={!(login&&password)} onClick={(e) => {
|
|
|
|
+ onLogin(login, password);
|
|
|
|
+ }}>Login</button>
|
|
|
|
+ </>
|
|
|
|
+}
|
|
|
|
+const Section = ({name, children}) =>
|
|
|
|
+<section className='sectionWrapper'>
|
|
|
|
+ <h2>{name.toUpperCase()}</h2>
|
|
|
|
+ { children}
|
|
|
|
+ </section>
|
|
|
|
+
|
|
|
|
+//Task1
|
|
|
|
+const Spoiler = ({ header = "+", open, children }) => {
|
|
|
|
+ const [value, setValue] = useState(open);
|
|
|
|
+ return <>
|
|
|
|
+ <div onClick={e => {setValue(!value) }}>{header}</div><div>{value&&children}</div>
|
|
|
|
+ </>
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//Task2
|
|
|
|
+const RangeInput = ({ min, max }) => {
|
|
|
|
+ let unConfirmed = false;
|
|
|
|
+ let [state, setState] = useState(['', unConfirmed]);
|
|
|
|
+ let value = state[0];
|
|
|
|
+ (value&&((value.length < min) || (value.length > max))) && (unConfirmed = true);
|
|
|
|
+ return <input className="passInput" data-confirm={unConfirmed} onInput={e => { setState(state=>[e.target.value, unConfirmed]) }}/>
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//Task3
|
|
|
|
+const PasswordConfirm = ({ min }) => {
|
|
|
|
+ const [value1, setValue1] = useState('');
|
|
|
|
+ const [value2, setValue2] = useState('');
|
|
|
|
+ const [commentState, setComment] = useState(['', false]);
|
|
|
|
+ let [comment, confirmed] = commentState;
|
|
|
|
+ const checkPass = () => {
|
|
|
|
+ if (value1 && value2) {
|
|
|
|
+ // setComment('');
|
|
|
|
+ //Проверка на минимальное кол-во символов
|
|
|
|
+ if ((value1.length < min) || (value2.length < min)) { (setComment([('Password should contain more than ' + min + ' symbols'), false])) }
|
|
|
|
+ else {
|
|
|
|
+ //Проверка на равенство паролей
|
|
|
|
+ if (!(value1 === value2)) { (setComment(["Passwords don't match", false])) }
|
|
|
|
+ else {
|
|
|
|
+ //Проверка на наличие заглавной буквы и цифры
|
|
|
|
+ let character = '';
|
|
|
|
+ let i = null;
|
|
|
|
+ let [upC, num] = [false, false];
|
|
|
|
+
|
|
|
|
+ while ((i < value1.length) || (!upC && !num)) {
|
|
|
|
+ character = value1.charAt(i);
|
|
|
|
+ if (isNaN(character)) { (character === character.toUpperCase()) && (upC = true); }
|
|
|
|
+ else { num = true };
|
|
|
|
+ i++;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ !upC && (setComment(["Password should include at least 1 uppercase letter", false]));
|
|
|
|
+ !num && (setComment(["Password should include at least 1 number", false]));
|
|
|
|
+ (upC&&num) &&(setComment(["Password confirmed", true]));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else (setComment(["Enter password", false]));
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return <>
|
|
|
|
+ <input type='password' placeholder='Enter password' className='inputForm' onChange={e => {setValue1(e.target.value) } }/>
|
|
|
|
+ <input type='password' placeholder='Repeat password' className='inputForm' onChange={e => { setValue2(e.target.value) } }/>
|
|
|
|
+ <button onClick={(e) => {checkPass()}}>Confirm</button>
|
|
|
|
+ <p className="confirmComment" data-confirm={confirmed}>{comment}</p>
|
|
|
|
+ </>
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+//Task4
|
|
|
|
+const Timer = ({ sec }) => {
|
|
|
|
+ const [counter, setCounter] = useState(sec);
|
|
|
|
+ const [btnState, setBtnState] = useState(false);
|
|
|
|
+ let [hours, minutes, secs] = [Math.floor(counter / (60 * 60)), Math.floor(counter % (60 * 60) / 60), counter % (60 * 60) % 60];
|
|
|
|
+ const funcShow = (number) => (number < 10) ? ("0" + number) : number;
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ let interval;
|
|
|
|
+ let step = counter;
|
|
|
|
+ if (btnState) {
|
|
|
|
+ interval = setInterval(() => { (step > 0) ? ((step--) && setCounter(counter => (counter - 1))) : (setBtnState(false)&&clearInterval(interval))}, 1000);
|
|
|
|
+ }
|
|
|
|
+ return () => { clearInterval(interval) }
|
|
|
|
+ }, [btnState])
|
|
|
|
+
|
|
|
|
+ return <>
|
|
|
|
+ <div className='timerBoard'> <span className="timeCell">{funcShow(hours)}</span>:<span className="timeCell">{ funcShow(minutes)}</span>:<span className="timeCell">{ funcShow(secs)}</span></div>
|
|
|
|
+ <button className='timerBtn' onClick={(e) => { setBtnState(!btnState)}}> { btnState ? "Pause" : "Start"}</button>
|
|
|
|
+ </>
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+//Task5
|
|
|
|
+const TimerControl1 = () => {
|
|
|
|
+ //Начальные значения состояний
|
|
|
|
+ const initialState = { resBtn: true, startBtn: false, inCount: 0 }
|
|
|
|
+ //Состояние таймера
|
|
|
|
+ const [counter, setCounter] = useState(initialState.inCount);
|
|
|
|
+ // Состояние кнопки Старта/Пауза
|
|
|
|
+ const [btnState, setBtnState] = useState(initialState.startBtn);
|
|
|
|
+ // Состояние кнопки сброса
|
|
|
|
+ const [btnResetState, setResetState] = useState(initialState.resBtn);
|
|
|
|
+//Состояние инпутов
|
|
|
|
+ const [time, setTime] = useState({hours: '', mins:'', secs:''});
|
|
|
|
+ let [hoursMod, minsMod, secsMod] = [Math.floor(counter / (60 * 60)), Math.floor(counter % (60 * 60) / 60), counter % (60 * 60) % 60];
|
|
|
|
+ let [hoursPart, minsPart, secsPart] = [0, 0, 0];
|
|
|
|
+
|
|
|
|
+ //Вносит ввод пользователя в стейт инпутов
|
|
|
|
+ const handleUserInput = (inputValue, timeType) => {
|
|
|
|
+ (timeType === 'hours') && setTime({ ...time, hours: inputValue });
|
|
|
|
+ (timeType === 'mins') && setTime({ ...time, mins: inputValue });
|
|
|
|
+ (timeType === 'secs') && setTime({ ...time, secs: inputValue });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ //Показывает числа в аутпуте: если был сброс, то нули. Если этап монтирования компонента, то нули. Если запущен таймер, то отсчет
|
|
|
|
+ const timeShow = (timeType) => {return btnResetState ? '00' : (counter?addZero((timeType==='hours'&& hoursMod)||(timeType==='mins'&& minsMod)||(timeType==='secs'&& secsMod)):'00'); }
|
|
|
|
+
|
|
|
|
+ //Добавляет ноль в аутпут, если число однозначное (для красоты)
|
|
|
|
+ const addZero = (number) => { !number && (number = 0); return ((number < 10) ? ("0" + number) : number) };
|
|
|
|
+
|
|
|
|
+ //Пересчитывает введенное время в секундах и устанавливает начальное значение таймера
|
|
|
|
+ const handleCounter = ({hours, mins, secs }) => {
|
|
|
|
+ hoursPart = hours * 60 * 60;
|
|
|
|
+ minsPart = mins * 60;
|
|
|
|
+ secsPart = Number(secs);
|
|
|
|
+ console.log(hoursPart, minsPart, secsPart);
|
|
|
|
+ return (!counter ? hoursPart + minsPart + secsPart : counter);
|
|
|
|
+ };
|
|
|
|
+ //Сброс до начальных значений
|
|
|
|
+ function clearFunc({resBtn, startBtn, inCount }=initialState) {
|
|
|
|
+ setResetState( resBtn );
|
|
|
|
+ setBtnState( startBtn );
|
|
|
|
+ setCounter(inCount);
|
|
|
|
+ setTime({ hours:'', mins:'', secs:''});
|
|
|
|
+ }
|
|
|
|
+ //Запуск таймера
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ let interval;
|
|
|
|
+ let step = counter;
|
|
|
|
+ if (btnState) {
|
|
|
|
+ interval = setInterval(() => { (step > 0) ? ((step--) && setCounter(counter => (counter - 1))) : (setBtnState(false)&&clearInterval(interval))}, 1000);
|
|
|
|
+ }
|
|
|
|
+ return () => { clearInterval(interval) }
|
|
|
|
+ }, [btnState])
|
|
|
|
+
|
|
|
|
+ return <>
|
|
|
|
+ <div className='timerBoard'>
|
|
|
|
+ <input className="timeCell" name="inputHours" maxLength="2" disabled={!counter ? false : true} value={time.hours} placeholder="hh" onClick={e => { setResetState(false) }} onInput={e => {handleUserInput(e.target.value, 'hours') }} />
|
|
|
|
+ <span>:</span>
|
|
|
|
+ <input className="timeCell"name="inputMins" maxLength="2" disabled={!counter?false:true } value={time.mins} placeholder="mm" onClick={e=>setResetState(false)} onInput={e => {handleUserInput(e.target.value, 'mins') }}/>
|
|
|
|
+ <span>:</span>
|
|
|
|
+ <input className="timeCell" name="inputSecs" maxLength="2" disabled={!counter ? false : true} value={time.secs} placeholder="ss" onClick={e => setResetState(false)} onInput={e => {handleUserInput(e.target.value, 'secs') }}/>
|
|
|
|
+ </div>
|
|
|
|
+ <div className='timerBoard'>
|
|
|
|
+ <span className="timeCell">{timeShow('hours')}</span> : <span className="timeCell">{timeShow('mins')}</span> : <span className="timeCell">{timeShow('secs')}</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div className='controlsWrapper'>
|
|
|
|
+ <button className='timerBtn' onClick={(e) => { setBtnState(!btnState); setCounter(()=>handleCounter(time))}}> { btnState ? "Pause" : "Start"}</button>
|
|
|
|
+ <button className='timerBtn' onClick={() => clearFunc() }> Reset</button>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ </>
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const TimerControl2 = () => {
|
|
|
|
+ //Начальные значения состояний
|
|
|
|
+ const initialState = { resBtn: true, startBtn: false, inCount: 0 }
|
|
|
|
+ //Состояние таймера
|
|
|
|
+ const [counter, setCounter] = useState(initialState.inCount);
|
|
|
|
+ // Состояние кнопки Старта/Пауза
|
|
|
|
+ const [btnState, setBtnState] = useState(initialState.startBtn);
|
|
|
|
+ // Состояние кнопки сброса
|
|
|
|
+ const [btnResetState, setResetState] = useState(initialState.resBtn);
|
|
|
|
+//Состояние инпутов
|
|
|
|
+ const [time, setTime] = useState({hours: '', mins:'', secs:''});
|
|
|
|
+ let [hoursMod, minsMod, secsMod] = [Math.floor(counter / (60 * 60)), Math.floor(counter % (60 * 60) / 60), counter % (60 * 60) % 60];
|
|
|
|
+ let [hoursPart, minsPart, secsPart] = [0, 0, 0];
|
|
|
|
+
|
|
|
|
+ //Вносит ввод пользователя в стейт инпутов
|
|
|
|
+ const handleUserInput = (inputValue, timeType) => {
|
|
|
|
+ (timeType === 'hours') && setTime({ ...time, hours: inputValue });
|
|
|
|
+ (timeType === 'mins') && setTime({ ...time, mins: inputValue });
|
|
|
|
+ (timeType === 'secs') && setTime({ ...time, secs: inputValue });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ //Показывает числа в аутпуте: если был сброс, то нули. Если этап монтирования компонента, то нули. Если запущен таймер, то отсчет
|
|
|
|
+ const timeShow = (timeType) => {return btnResetState ? '00' : (counter?addZero((timeType==='hours'&& hoursMod)||(timeType==='mins'&& minsMod)||(timeType==='secs'&& secsMod)):'00'); }
|
|
|
|
+
|
|
|
|
+ //Добавляет ноль в аутпут, если число однозначное (для красоты)
|
|
|
|
+ const addZero = (number) => { !number && (number = 0); return ((number < 10) ? ("0" + number) : number) };
|
|
|
|
+
|
|
|
|
+ //Пересчитывает введенное время в секундах и устанавливает начальное значение таймера
|
|
|
|
+ const handleCounter = ({hours, mins, secs }) => {
|
|
|
|
+ hoursPart = hours * 60 * 60;
|
|
|
|
+ minsPart = mins * 60;
|
|
|
|
+ secsPart = Number(secs);
|
|
|
|
+ // console.log(hoursPart, minsPart, secsPart);
|
|
|
|
+ return (!counter ? hoursPart + minsPart + secsPart : counter);
|
|
|
|
+ };
|
|
|
|
+ //Сброс до начальных значений
|
|
|
|
+ function clearFunc({resBtn, startBtn, inCount }=initialState) {
|
|
|
|
+ setResetState( resBtn );
|
|
|
|
+ setBtnState( startBtn );
|
|
|
|
+ setCounter(inCount);
|
|
|
|
+ setTime({ hours:'', mins:'', secs:''});
|
|
|
|
+ }
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ let interval;
|
|
|
|
+ let step = counter;
|
|
|
|
+ if (btnState) {
|
|
|
|
+ interval = setInterval(() => {(step>0)?((step--)&&setCounter(counter => (counter - 1))):(setBtnState(false)&&clearInterval(interval))}, 1000);
|
|
|
|
+ }
|
|
|
|
+ return () => { clearInterval(interval) }
|
|
|
|
+ }, [btnState])
|
|
|
|
+
|
|
|
|
+ return <>
|
|
|
|
+ <div className='timerBoard'>
|
|
|
|
+ <input className="timeCell" name="inputHours" maxLength="2" disabled={!counter ? false : true} value={!btnState ? (time.hours):timeShow('hours')} placeholder="hh" onClick={e => { setResetState(false)}} onInput={e => {handleUserInput(e.target.value, 'hours') } }/>
|
|
|
|
+ <span>:</span>
|
|
|
|
+ <input className="timeCell"name="inputMins" maxLength="2" disabled={!counter?false:true } value={!btnState ? (time.mins):timeShow('mins')} placeholder="mm" onClick={e=>setResetState(false)} onInput={e => {handleUserInput(e.target.value, 'mins') }}/>
|
|
|
|
+ <span>:</span>
|
|
|
|
+ <input className="timeCell" name="inputSecs" maxLength="2" disabled={!counter ? false : true} value={!btnState ? (time.secs):timeShow('secs')} placeholder="ss" onClick={e => setResetState(false)} onInput={ e => {handleUserInput(e.target.value, 'secs') }}/>
|
|
|
|
+ </div>
|
|
|
|
+ <div className='controlsWrapper'>
|
|
|
|
+ <button className='timerBtn' onClick={(e) => { setBtnState(!btnState); setCounter(()=>handleCounter(time))}}> { btnState ? "Pause" : "Start"}</button>
|
|
|
|
+ <button className='timerBtn' onClick={(e) => { clearFunc(e)}}> Reset</button>
|
|
|
|
+</div>
|
|
|
|
+ </>
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+const TimerContainer = ({ seconds, refresh, render }) => {
|
|
|
|
+ const [counter, setCounter] = useState(seconds);
|
|
|
|
+ const [btnState, setBtnState] = useState(false);
|
|
|
|
+ const t0 = performance.now();
|
|
|
|
+ const handleClick = () => setBtnState(!btnState);
|
|
|
|
+ let pauseState = seconds;
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ let interval;
|
|
|
|
+ // (btnState && pauseState <= refresh) && (pauseState=seconds);
|
|
|
|
+ (pauseState*1000 <= refresh) && (pauseState=seconds);
|
|
|
|
+ setCounter(pauseState);
|
|
|
|
+ if (btnState) {
|
|
|
|
+ interval = setInterval(() => {
|
|
|
|
+ const currentState = counter - (performance.now() - t0) / 1000;
|
|
|
|
+ (!(currentState < 0)) ? setCounter(currentState) : (setBtnState(false) && clearInterval(interval));
|
|
|
|
+ }, refresh);
|
|
|
|
+ }
|
|
|
|
+ return () => {clearInterval(interval) }
|
|
|
|
+ }, [btnState]);
|
|
|
|
+ const Render = (props) => { return render(props) };
|
|
|
|
+ pauseState = counter;
|
|
|
|
+ return <><Render seconds={counter.toFixed(2)} />
|
|
|
|
+ <button className='timerBtn' onClick= { handleClick } > {btnState ? "Pause" : "Start"}</button>
|
|
|
|
+ </>
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const SecondsTimer = ({ seconds } ) => <h2>{seconds}</h2>;
|
|
|
|
+
|
|
|
|
+const LCD = ({ seconds}) => {
|
|
|
|
+ let [hoursMod, minsMod, secsMod, mSecsMod] = [Math.floor(seconds / (60 * 60)), Math.floor(seconds % (60 * 60) / 60), Math.floor(seconds % (60 * 60) % 60), Math.trunc((seconds-Math.trunc(seconds))*100) ];
|
|
|
|
+ const addZero = (number) => { !number && (number = 0); return ((number < 10) ? ("0" + number) : number) };
|
|
|
|
+ return <>
|
|
|
|
+ <div className='timerBoard ms'> <span className="timeCell">{addZero(hoursMod)}</span>:<span className="timeCell">{ addZero(minsMod)}</span>:<span className="timeCell">{ addZero(secsMod)}</span>:<span className="timeCell">{addZero(mSecsMod)}</span></div>
|
|
|
|
+ </>
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const Watch = ({ seconds }) => {
|
|
|
|
+ let [hoursMod, minsMod, secsMod] = [seconds / (60 * 60), seconds % (60 * 60) / 60, seconds -Math.floor(seconds / (60 * 60))*3600-Math.floor(seconds % (60 * 60) / 60)*60];
|
|
|
|
+ const hourDeg = 'rotate(' + 30 * hoursMod + 'deg)';
|
|
|
|
+ const minDeg = 'rotate(' + 6 * minsMod + 'deg)';
|
|
|
|
+ const secDeg = 'rotate(' + 6 * secsMod + 'deg)';
|
|
|
|
+ // console.log(hoursMod, minsMod, secsMod);
|
|
|
|
+ return <div className='clockWrapper'>
|
|
|
|
+ <img className="clock" src={ClockFace} alt=''></img>
|
|
|
|
+ <img className="clock arrowH" style={{ transform: hourDeg }} src={ClockFace_H} alt=''></img>
|
|
|
|
+ <img className="clock arrowM" style={{ transform: minDeg }} src={ClockFace_M} alt=''></img>
|
|
|
|
+ <img className="clock arrowS" style={{ transform: secDeg }} src={ClockFace_S} alt=''></img>
|
|
|
|
+ </div>
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+const TimerContainerReset = ({ seconds, refresh, render }) => {
|
|
|
|
+//Начальные значения состояний
|
|
|
|
+ const initialState = { resBtn: true, startBtn: false, inCount: seconds }
|
|
|
|
+ //Состояние таймера
|
|
|
|
+ const [counter, setCounter] = useState(initialState.inCount);
|
|
|
|
+ // Состояние кнопки Старта/Пауза
|
|
|
|
+ const [btnState, setBtnState] = useState(initialState.startBtn);
|
|
|
|
+ // Состояние кнопки сброса
|
|
|
|
+ const [btnResetState, setResetState] = useState(initialState.resBtn);
|
|
|
|
+ let [hoursMod, minsMod, secsMod] = [Math.floor(counter / (60 * 60)), Math.floor(counter % (60 * 60) / 60), counter % (60 * 60) % 60];
|
|
|
|
+ //Состояние инпутов
|
|
|
|
+ const [time, setTime] = useState({ hours: '', mins: '', secs: '' });
|
|
|
|
+
|
|
|
|
+ let [hoursPart, minsPart, secsPart] = [0, 0, 0];
|
|
|
|
+ let t0;
|
|
|
|
+ const handleClick = () => { setBtnState(!btnState); setCounter(()=>handleCounter(time)) }
|
|
|
|
+ function clearFunc({resBtn, startBtn, inCount }=initialState) {
|
|
|
|
+ setResetState( resBtn );
|
|
|
|
+ setBtnState( startBtn );
|
|
|
|
+ setCounter(inCount);
|
|
|
|
+ setTime({ hours:'', mins:'', secs:''});
|
|
|
|
+ }
|
|
|
|
+ //Вносит ввод пользователя в стейт инпутов
|
|
|
|
+ const handleUserInput = (inputValue, timeType) => {
|
|
|
|
+ (timeType === 'hours') && setTime({ ...time, hours: inputValue });
|
|
|
|
+ (timeType === 'mins') && setTime({ ...time, mins: inputValue });
|
|
|
|
+ (timeType === 'secs') && setTime({ ...time, secs: inputValue });
|
|
|
|
+ };
|
|
|
|
+ //Пересчитывает введенное время в секундах и устанавливает начальное значение таймера
|
|
|
|
+ const handleCounter = (time) => {
|
|
|
|
+ hoursPart = time.hours * 60 * 60;
|
|
|
|
+ minsPart = time.mins * 60;
|
|
|
|
+ secsPart = Number(time.secs);
|
|
|
|
+ console.log(hoursPart, minsPart, secsPart);
|
|
|
|
+ return (!counter ? hoursPart + minsPart + secsPart : counter);
|
|
|
|
+ };
|
|
|
|
+ // console.log(time);
|
|
|
|
+
|
|
|
|
+ let pauseState=counter;
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ t0 = performance.now();
|
|
|
|
+ let interval;
|
|
|
|
+ (pauseState*1000 <= refresh) && (pauseState=initialState.inCount);
|
|
|
|
+ setCounter(pauseState);
|
|
|
|
+
|
|
|
|
+ if (btnState) {
|
|
|
|
+ interval = setInterval(() => {
|
|
|
|
+ const currentState = counter - (performance.now() - t0) / 1000;
|
|
|
|
+ (!(currentState < 0)) ? setCounter(currentState) : (setBtnState(false) && clearInterval(interval));
|
|
|
|
+ console.log(counter);
|
|
|
|
+ }, refresh);
|
|
|
|
+ }
|
|
|
|
+ return () => {clearInterval(interval) }
|
|
|
|
+ }, [btnState]);
|
|
|
|
+ const Render = (props) => { return render(props) };
|
|
|
|
+ pauseState = counter;
|
|
|
|
+ return <><TimerControlInput counter={counter} handleUserInput={handleUserInput} time={ time}/>
|
|
|
|
+ <Render seconds={counter.toFixed(2)} />
|
|
|
|
+ <div className='controlsWrapper'>
|
|
|
|
+ <button className='timerBtn' onClick={handleClick}> { btnState ? "Pause" : "Start"}</button>
|
|
|
|
+ <button className='timerBtn' onClick={() => clearFunc() }> Reset</button>
|
|
|
|
+ </div>
|
|
|
|
+ </>
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+const TimerControlInput = ({ counter, handleUserInput, time}) => {
|
|
|
|
+ return <>
|
|
|
|
+ <div className='timerBoard ms'>
|
|
|
|
+ <input className="timeCell" name="inputHours" maxLength="2" disabled={!counter ? false : true} value={time.hours} placeholder="hh" onInput={e => { handleUserInput(e.target.value, 'hours') }} />
|
|
|
|
+ <span>:</span>
|
|
|
|
+ <input className="timeCell"name="inputMins" maxLength="2" disabled={!counter?false:true } value={time.mins} placeholder="mm" onInput={e => {handleUserInput(e.target.value, 'mins') }}/>
|
|
|
|
+ <span>:</span>
|
|
|
|
+ <input className="timeCell" name="inputSecs" maxLength="2" disabled={!counter ? false : true} value={time.secs} placeholder="ss" onInput={e => {handleUserInput(e.target.value, 'secs') }}/>
|
|
|
|
+ </div>
|
|
|
|
+ </>
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function App() {
|
|
|
|
+ return (
|
|
|
|
+ <div className="App">
|
|
|
|
+ <header className="App-header">
|
|
|
|
+ </header>
|
|
|
|
+ <Section name='classwork'>
|
|
|
|
+ <LoginForm onLogin={(login, password) => console.log(login, password)} />
|
|
|
|
+ </Section>
|
|
|
|
+ <Section name='task-1 Spoiler'>
|
|
|
|
+ <Spoiler header={<h1>Заголовок</h1>} open>
|
|
|
|
+ Контент 1
|
|
|
|
+ <p>
|
|
|
|
+ лорем ипсум траливали и тп.
|
|
|
|
+ </p>
|
|
|
|
+</Spoiler>
|
|
|
|
+<Spoiler>
|
|
|
|
+ <h2>Контент 2</h2>
|
|
|
|
+ <p>
|
|
|
|
+ лорем ипсум траливали и тп.
|
|
|
|
+ </p>
|
|
|
|
+</Spoiler>
|
|
|
|
+ </Section>
|
|
|
|
+ <Section name='task-2 Range_Input'>
|
|
|
|
+ <RangeInput min={2} max={10} />
|
|
|
|
+ </Section>
|
|
|
|
+ <Section name='task-3 Password_Confirm'>
|
|
|
|
+ <PasswordConfirm min={2} />
|
|
|
|
+ </Section>
|
|
|
|
+ <Section name='task-4 Timer'>
|
|
|
|
+ <Timer sec={20} />
|
|
|
|
+ </Section>
|
|
|
|
+ <Section name='task-5.1 Timer_Control1'>
|
|
|
|
+ <TimerControl1 />
|
|
|
|
+ </Section>
|
|
|
|
+ <Section name='task-5.2 Timer_Control2'>
|
|
|
|
+ <TimerControl2 />
|
|
|
|
+ </Section>
|
|
|
|
+ <Section name='task-6 Timer_Container'>
|
|
|
|
+ <TimerContainer seconds={10} refresh={50} render={SecondsTimer} />
|
|
|
|
+ </Section>
|
|
|
|
+ <Section name='task-7 LCD'>
|
|
|
|
+ <TimerContainer seconds={10} refresh={50} render={LCD} />
|
|
|
|
+ </Section>
|
|
|
|
+ <Section name='task-8 Watch'>
|
|
|
|
+ <TimerContainer seconds={3467} refresh={50} render={Watch} />
|
|
|
|
+ </Section>
|
|
|
|
+ <Section name='task-9 TimerControl + TimerContainer'>
|
|
|
|
+ <TimerContainerReset seconds={0} refresh={50} render={LCD} getData={TimerControlInput } />
|
|
|
|
+ </Section>
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+export default App;
|