From cd62d45af431eae331f5dbdeaa564426ceaaef89 Mon Sep 17 00:00:00 2001 From: Artemii Kurganov Date: Mon, 17 Oct 2022 21:45:48 +0500 Subject: [PATCH 1/2] Task 1-8 done --- userProfile/index.html | 2 +- userProfile/src/index.tsx | 149 +++++++++++++++++++++++++++++++++++++- userProfile/src/style.css | 19 +++++ 3 files changed, 168 insertions(+), 2 deletions(-) diff --git a/userProfile/index.html b/userProfile/index.html index e7fc644..5bacefd 100644 --- a/userProfile/index.html +++ b/userProfile/index.html @@ -5,7 +5,7 @@ React Interface -

Hi! I don't have React. Yet

+
\ No newline at end of file diff --git a/userProfile/src/index.tsx b/userProfile/src/index.tsx index df4d969..16f82f7 100644 --- a/userProfile/src/index.tsx +++ b/userProfile/src/index.tsx @@ -1,3 +1,6 @@ +import { Button, Gapped, Input, Modal, Select } from '@skbkontur/react-ui'; +import React, { useState } from 'react'; +import ReactDom from 'react-dom'; import './style.css'; /** @@ -56,4 +59,148 @@ import './style.css'; * Придумай, как избежать излишнего дублирования. */ -console.log('Hi from script!'); +// Выполнены задания 1-8 + +const fieldRepo : {[key: string] : string}= { + 'Имя': '', + 'Фамилия': '', + 'Город': '', +} + + const Form = () => { + let [isOpened, setOpenedState] = useState(false); + + let [name, setName] = useState(''); + let [surname, setSurname] = useState(''); + let [city, setCity] = useState(''); + + let [nameEmpty, setNameEmpty] = useState(false); + let [surnameEmpty, setSurnameEmpty] = useState(false); + + const openModal = () => {setOpenedState(true)}; + const closeModal = () => {setOpenedState(false)}; + + let [changeMessage, setChangeMessage] = useState(Array()); + const saveChanges = () => { + if (!name) + setNameEmpty(true); + if (!surname) + setSurnameEmpty(true); + + if (!(name && surname)) + return; + + const newChangeMessage = [ + add_if_updated('Имя', name), + add_if_updated('Фамилия', surname), + add_if_updated('Город', city), + ]; + + setChangeMessage(newChangeMessage); + openModal(); + }; + + const add_if_updated = (field_name: string, new_value: string) => { + const old_value = fieldRepo[field_name]; + fieldRepo[field_name] = new_value; + if (old_value && old_value !== new_value){ + return `${field_name}: Было ${old_value}, стало ${new_value}`; + } + return '' + }; + + return ( +
+ +

Информация о пользователе

+ { setName(value); setNameEmpty(false); }} + isError={nameEmpty} + /> + + { setSurname(value); setSurnameEmpty(false); }} + isError={surnameEmpty} + /> + + {setCity(value) }} + /> + +
+ {isOpened && } +
+ ); + } + +const ModalOnSave = ({close, changeMessage} : ModeOnSaveType) => ( + + Пользователь сохранен + + { changeMessage.map(data =>

{data}

) } +
+ + + +
+) + +const InputRow = ({title, placeholder='', onInputChange, isError} : RowType) => { + return ( +
+ +

{title}

+
+ onInputChange(e.target.value)}> + {isError &&

Заполните поле

} +
+
+ +
+ ) +} + +const SelectRow = ({title, onInputChange} : SelectType) => { + const cities = ['Москва', 'Санкт-Петербург', 'Екатеринбург']; + return ( +
+ +

{title}

+ {/* Почему-то здесь ругается IDE, хотя по документации должно быть всё ок. Код запускается и работает*/} + +
+
+ ) +} + +type InputType = { + title: string, + onInputChange: (value: string) => void, +} + +interface RowType extends InputType { + placeholder?: string, + isError: boolean, +}; + +interface SelectType extends InputType { + title: string, +}; + +type ModeOnSaveType = { + close: () => void, + changeMessage: string[], +}; + + +ReactDom.render( +
, + document.getElementById('someId') +); + + diff --git a/userProfile/src/style.css b/userProfile/src/style.css index 582e3b7..9f879f5 100644 --- a/userProfile/src/style.css +++ b/userProfile/src/style.css @@ -1,3 +1,22 @@ +p { + margin: 0 0; +} + body { font-family: "Segoe UI", Helvetica, sans-serif; } + +.form .inputRow .error-message { + color: red; + font-size: 10px; + font-style: italic; +} + +.form .form-title { + font-size: 28px; + font-weight: bold; +} + +.form .inputRow .title{ + width: 100px; +} From 63920eb265946b9f6c74d2f2a3b22697703afde2 Mon Sep 17 00:00:00 2001 From: Artemii Kurganov Date: Wed, 19 Oct 2022 11:51:46 +0500 Subject: [PATCH 2/2] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=87=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- userProfile/index.html | 2 +- userProfile/src/InputRow.tsx | 19 +++ userProfile/src/Modal.tsx | 19 +++ userProfile/src/SelectRow.tsx | 23 ++++ userProfile/src/index.tsx | 229 +++++++++------------------------- userProfile/src/task.txt | 55 ++++++++ userProfile/src/types.tsx | 18 +++ 7 files changed, 196 insertions(+), 169 deletions(-) create mode 100644 userProfile/src/InputRow.tsx create mode 100644 userProfile/src/Modal.tsx create mode 100644 userProfile/src/SelectRow.tsx create mode 100644 userProfile/src/task.txt create mode 100644 userProfile/src/types.tsx diff --git a/userProfile/index.html b/userProfile/index.html index 5bacefd..6abe956 100644 --- a/userProfile/index.html +++ b/userProfile/index.html @@ -5,7 +5,7 @@ React Interface -
+
\ No newline at end of file diff --git a/userProfile/src/InputRow.tsx b/userProfile/src/InputRow.tsx new file mode 100644 index 0000000..b6c382b --- /dev/null +++ b/userProfile/src/InputRow.tsx @@ -0,0 +1,19 @@ +import { RowProps } from './types'; +import { Gapped, Input } from '@skbkontur/react-ui'; +import React from 'react'; + +const InputRow = ({ title, placeholder = '', onInputChange, isError }: RowProps) => { + return ( +
+ +

{title}

+
+ onInputChange(e.target.value)} /> + {isError &&

Заполните поле

} +
+
+
+ ); +}; + +export default InputRow; diff --git a/userProfile/src/Modal.tsx b/userProfile/src/Modal.tsx new file mode 100644 index 0000000..85c7bd6 --- /dev/null +++ b/userProfile/src/Modal.tsx @@ -0,0 +1,19 @@ +import { ModeOnSaveProps } from './types'; +import { Button, Modal } from '@skbkontur/react-ui'; +import React from 'react'; + +const ModalOnSave = ({ close, changeMessage }: ModeOnSaveProps) => ( + + Пользователь сохранен + + {changeMessage.map((data, i) => ( +

{data}

+ ))} +
+ + + +
+); + +export default ModalOnSave; diff --git a/userProfile/src/SelectRow.tsx b/userProfile/src/SelectRow.tsx new file mode 100644 index 0000000..9d612d2 --- /dev/null +++ b/userProfile/src/SelectRow.tsx @@ -0,0 +1,23 @@ +import { SelectProps } from './types'; +import { Gapped, Select } from '@skbkontur/react-ui'; +import React from 'react'; + +const SelectRow = ({ title, onInputChange }: SelectProps) => { + const cities = ['Москва', 'Санкт-Петербург', 'Екатеринбург']; + return ( +
+ +

{title}

+ + items={cities} + placeholder="Выберете город" + onValueChange={value => { + onInputChange(value); + }} + /> +
+
+ ); +}; + +export default SelectRow; diff --git a/userProfile/src/index.tsx b/userProfile/src/index.tsx index 16f82f7..8b18078 100644 --- a/userProfile/src/index.tsx +++ b/userProfile/src/index.tsx @@ -1,206 +1,99 @@ -import { Button, Gapped, Input, Modal, Select } from '@skbkontur/react-ui'; +import { Button, Gapped } from '@skbkontur/react-ui'; import React, { useState } from 'react'; import ReactDom from 'react-dom'; import './style.css'; - -/** - * Итак, перед тобой пустой проект. Давай его чем-то заполним. Не стесняйся подсматривать в уже сделанные задачи, - * чтобы оттуда что-то скопировать. - * - * 1. Создай в файле index.html (он на уровень выше в файловой структуре) div с каким-нибудь id - * 2. Импортируй сюда библиотеку React и ReactDom - * 3. Отрендери "Hello world" на странице при помощи Реакта. - * - * 4. Добавь в разметку Button из библиотеки компонентов Контура (@skbkontur/react-ui). - * npm-пакет с библиотекой уже добавлен в проект. - * - * Импортируется компонент на страницу так: - * - * import { Button } from '@skbkontur/react-ui'; - * - * Используется компонент так: - * - * const MyApp = () => ( - *
- * Click this button - *
- * ); - * - * - * Тут можно посмотреть, как компонентами пользоваться, какие у них атрибуты есть: - * http://tech.skbkontur.ru/react-ui/ - * - * 5. Теперь, когда ты знаешь все основное, сверстай при помощи react-ui форму, - * как на картинке drafts/reactForm.png (можно открыть в браузере http://localhost:8080/drafts/reactForm.png) - * Для вертикальных отступов между элементами используй компонент Gapped из библиотеки. - * Если хочешь что-то стилизовать, используй файл style.css. - * Список городов придумай сам. - * - * 6. Сделай так, чтобы при клике по кнопке "Сохранить", - * показывалось модальное окно (компонент Modal из библиотеки) с текстом "Пользователь сохранен". - * выглядеть будет примерно как на картинке drafts/reactModal.png (http://localhost:8080/drafts/reactModal.png) - * - * 7. Сделай так, чтобы в той же модалке (в теле модального окна — Modal.Body) показывались изменения в полях. - * Смотри drafts/reactDiff.png (http://localhost:8080/drafts/reactDiff.png). - * Пример сообщения: - * - * Измененные данные: - * Фамилия: было "Петров", стало "Петрова" - * - * Для этого надо хранить где-то предыдущее (и текущее) значение. Придумай, как лучше это сделать. - * - * 8*. Необязательная задача. - * Сделай так, чтобы форма не сохранялась, если поле имя или фамилия не заполнено. - * Незаполненное поле должно анимацией покачаться из стороны в сторону (или придумай любой другой эффект). - * - * 9*. Необязательная задача. - * Добавь в эту форму еще поля: пол, дата рождения, город рождения, семейное положение, - * гражданство, национальность, номер телефона и адрес электронной почты. - * Придумай, как избежать излишнего дублирования. - */ +import ModalOnSave from './Modal'; +import InputRow from './InputRow'; +import SelectRow from './SelectRow'; // Выполнены задания 1-8 -const fieldRepo : {[key: string] : string}= { - 'Имя': '', - 'Фамилия': '', - 'Город': '', -} +const fieldRepo: { [key: string]: string } = { + Имя: '', + Фамилия: '', + Город: '' +}; + +const Form = () => { + const [isOpened, setOpenedState] = useState(false); - const Form = () => { - let [isOpened, setOpenedState] = useState(false); - - let [name, setName] = useState(''); - let [surname, setSurname] = useState(''); - let [city, setCity] = useState(''); + const [name, setName] = useState(''); + const [surname, setSurname] = useState(''); + const [city, setCity] = useState(''); - let [nameEmpty, setNameEmpty] = useState(false); - let [surnameEmpty, setSurnameEmpty] = useState(false); + const [nameEmpty, setNameEmpty] = useState(false); + const [surnameEmpty, setSurnameEmpty] = useState(false); - const openModal = () => {setOpenedState(true)}; - const closeModal = () => {setOpenedState(false)}; + const openModal = () => { + setOpenedState(true); + }; + const closeModal = () => { + setOpenedState(false); + }; - let [changeMessage, setChangeMessage] = useState(Array()); + const [changeMessage, setChangeMessage] = useState(Array()); const saveChanges = () => { - if (!name) - setNameEmpty(true); - if (!surname) - setSurnameEmpty(true); - - if (!(name && surname)) - return; + if (!name) setNameEmpty(true); + if (!surname) setSurnameEmpty(true); + + if (!(name && surname)) return; const newChangeMessage = [ - add_if_updated('Имя', name), - add_if_updated('Фамилия', surname), - add_if_updated('Город', city), + addIfUpdated('Имя', name), + addIfUpdated('Фамилия', surname), + addIfUpdated('Город', city) ]; setChangeMessage(newChangeMessage); openModal(); }; - const add_if_updated = (field_name: string, new_value: string) => { + const addIfUpdated = (field_name: string, new_value: string) => { const old_value = fieldRepo[field_name]; fieldRepo[field_name] = new_value; - if (old_value && old_value !== new_value){ + if (old_value && old_value !== new_value) { return `${field_name}: Было ${old_value}, стало ${new_value}`; } - return '' + return ''; }; return ( -
+

Информация о пользователе

- { setName(value); setNameEmpty(false); }} - isError={nameEmpty} + { + setName(value); + setNameEmpty(false); + }} + isError={nameEmpty} /> - { setSurname(value); setSurnameEmpty(false); }} - isError={surnameEmpty} + { + setSurname(value); + setSurnameEmpty(false); + }} + isError={surnameEmpty} /> - {setCity(value) }} + { + setCity(value); + }} /> - +
- {isOpened && } + {isOpened && }
); - } - -const ModalOnSave = ({close, changeMessage} : ModeOnSaveType) => ( - - Пользователь сохранен - - { changeMessage.map(data =>

{data}

) } -
- - - -
-) - -const InputRow = ({title, placeholder='', onInputChange, isError} : RowType) => { - return ( -
- -

{title}

-
- onInputChange(e.target.value)}> - {isError &&

Заполните поле

} -
-
- -
- ) -} - -const SelectRow = ({title, onInputChange} : SelectType) => { - const cities = ['Москва', 'Санкт-Петербург', 'Екатеринбург']; - return ( -
- -

{title}

- {/* Почему-то здесь ругается IDE, хотя по документации должно быть всё ок. Код запускается и работает*/} - -
-
- ) -} - -type InputType = { - title: string, - onInputChange: (value: string) => void, -} - -interface RowType extends InputType { - placeholder?: string, - isError: boolean, -}; - -interface SelectType extends InputType { - title: string, }; -type ModeOnSaveType = { - close: () => void, - changeMessage: string[], -}; - - -ReactDom.render( -
, - document.getElementById('someId') -); - - +ReactDom.render(
, document.getElementById('root')); diff --git a/userProfile/src/task.txt b/userProfile/src/task.txt new file mode 100644 index 0000000..0289051 --- /dev/null +++ b/userProfile/src/task.txt @@ -0,0 +1,55 @@ +/** + * Итак, перед тобой пустой проект. Давай его чем-то заполним. Не стесняйся подсматривать в уже сделанные задачи, + * чтобы оттуда что-то скопировать. + * + * 1. Создай в файле index.html (он на уровень выше в файловой структуре) div с каким-нибудь id + * 2. Импортируй сюда библиотеку React и ReactDom + * 3. Отрендери "Hello world" на странице при помощи Реакта. + * + * 4. Добавь в разметку Button из библиотеки компонентов Контура (@skbkontur/react-ui). + * npm-пакет с библиотекой уже добавлен в проект. + * + * Импортируется компонент на страницу так: + * + * import { Button } from '@skbkontur/react-ui'; + * + * Используется компонент так: + * + * const MyApp = () => ( + *
+ * Click this button + *
+ * ); + * + * + * Тут можно посмотреть, как компонентами пользоваться, какие у них атрибуты есть: + * http://tech.skbkontur.ru/react-ui/ + * + * 5. Теперь, когда ты знаешь все основное, сверстай при помощи react-ui форму, + * как на картинке drafts/reactForm.png (можно открыть в браузере http://localhost:8080/drafts/reactForm.png) + * Для вертикальных отступов между элементами используй компонент Gapped из библиотеки. + * Если хочешь что-то стилизовать, используй файл style.css. + * Список городов придумай сам. + * + * 6. Сделай так, чтобы при клике по кнопке "Сохранить", + * показывалось модальное окно (компонент Modal из библиотеки) с текстом "Пользователь сохранен". + * выглядеть будет примерно как на картинке drafts/reactModal.png (http://localhost:8080/drafts/reactModal.png) + * + * 7. Сделай так, чтобы в той же модалке (в теле модального окна — Modal.Body) показывались изменения в полях. + * Смотри drafts/reactDiff.png (http://localhost:8080/drafts/reactDiff.png). + * Пример сообщения: + * + * Измененные данные: + * Фамилия: было "Петров", стало "Петрова" + * + * Для этого надо хранить где-то предыдущее (и текущее) значение. Придумай, как лучше это сделать. + * + * 8*. Необязательная задача. + * Сделай так, чтобы форма не сохранялась, если поле имя или фамилия не заполнено. + * Незаполненное поле должно анимацией покачаться из стороны в сторону (или придумай любой другой эффект). + * + * 9*. Необязательная задача. + * Добавь в эту форму еще поля: пол, дата рождения, город рождения, семейное положение, + * гражданство, национальность, номер телефона и адрес электронной почты. + * Придумай, как избежать излишнего дублирования. + */ diff --git a/userProfile/src/types.tsx b/userProfile/src/types.tsx new file mode 100644 index 0000000..d8d8f46 --- /dev/null +++ b/userProfile/src/types.tsx @@ -0,0 +1,18 @@ +type InputProps = { + title: string; + onInputChange: (value: string) => void; +}; + +export interface RowProps extends InputProps { + placeholder?: string; + isError: boolean; +} + +export interface SelectProps extends InputProps { + title: string; +} + +export type ModeOnSaveProps = { + close: () => void; + changeMessage: string[]; +};