Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion userProfile/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<title>React Interface</title>
</head>
<body>
<p>Hi! I don't have React. Yet</p>
<div id="root"></div>
<script src="build/index.js"></script>
</body>
</html>
19 changes: 19 additions & 0 deletions userProfile/src/InputRow.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="inputRow">
<Gapped gap={20}>
<p className="title">{title}</p>
<div>
<Input placeholder={placeholder} onChange={e => onInputChange(e.target.value)} />
{isError && <p className="error-message">Заполните поле</p>}
</div>
</Gapped>
</div>
);
};

export default InputRow;
19 changes: 19 additions & 0 deletions userProfile/src/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ModeOnSaveProps } from './types';
import { Button, Modal } from '@skbkontur/react-ui';
import React from 'react';

const ModalOnSave = ({ close, changeMessage }: ModeOnSaveProps) => (
<Modal onClose={close}>
<Modal.Header>Пользователь сохранен</Modal.Header>
<Modal.Body>
{changeMessage.map((data, i) => (
<p key={i}>{data}</p>
))}
</Modal.Body>
<Modal.Footer>
<Button onClick={close}>Закрыть</Button>
</Modal.Footer>
</Modal>
);

export default ModalOnSave;
23 changes: 23 additions & 0 deletions userProfile/src/SelectRow.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="inputRow">
<Gapped gap={20}>
<p className="title">{title}</p>
<Select<string>
items={cities}
placeholder="Выберете город"
onValueChange={value => {
onInputChange(value);
}}
/>
</Gapped>
</div>
);
};

export default SelectRow;
154 changes: 97 additions & 57 deletions userProfile/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,99 @@
import { Button, Gapped } from '@skbkontur/react-ui';
import React, { useState } from 'react';
import ReactDom from 'react-dom';
import './style.css';
import ModalOnSave from './Modal';
import InputRow from './InputRow';
import SelectRow from './SelectRow';

/**
* Итак, перед тобой пустой проект. Давай его чем-то заполним. Не стесняйся подсматривать в уже сделанные задачи,
* чтобы оттуда что-то скопировать.
*
* 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 = () => (
* <div>
* Click this button <Button onClick={() => console.log('Hey!')}>Click me</Button>
* </div>
* );
*
*
* Тут можно посмотреть, как компонентами пользоваться, какие у них атрибуты есть:
* 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*. Необязательная задача.
* Добавь в эту форму еще поля: пол, дата рождения, город рождения, семейное положение,
* гражданство, национальность, номер телефона и адрес электронной почты.
* Придумай, как избежать излишнего дублирования.
*/

console.log('Hi from script!');
// Выполнены задания 1-8

const fieldRepo: { [key: string]: string } = {
Имя: '',
Фамилия: '',
Город: ''
};

const Form = () => {
const [isOpened, setOpenedState] = useState(false);

const [name, setName] = useState('');
const [surname, setSurname] = useState('');
const [city, setCity] = useState('');

const [nameEmpty, setNameEmpty] = useState(false);
const [surnameEmpty, setSurnameEmpty] = useState(false);

const openModal = () => {
setOpenedState(true);
};
const closeModal = () => {
setOpenedState(false);
};

const [changeMessage, setChangeMessage] = useState(Array<string>());
const saveChanges = () => {
if (!name) setNameEmpty(true);
if (!surname) setSurnameEmpty(true);

if (!(name && surname)) return;

const newChangeMessage = [
addIfUpdated('Имя', name),
addIfUpdated('Фамилия', surname),
addIfUpdated('Город', city)
];

setChangeMessage(newChangeMessage);
openModal();
};

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) {
return `${field_name}: Было ${old_value}, стало ${new_value}`;
}
return '';
};

return (
<div className="form">
<Gapped vertical gap={20}>
<p className="form-title">Информация о пользователе</p>
<InputRow
title="Имя"
placeholder="Введите имя пользователя"
onInputChange={value => {
setName(value);
setNameEmpty(false);
}}
isError={nameEmpty}
/>

<InputRow
title="Фамилия"
placeholder="Введите фамилию пользователя"
onInputChange={value => {
setSurname(value);
setSurnameEmpty(false);
}}
isError={surnameEmpty}
/>

<SelectRow
title="Город"
onInputChange={value => {
setCity(value);
}}
/>
<Button use="primary" onClick={saveChanges}>
Сохранить
</Button>
</Gapped>
{isOpened && <ModalOnSave close={closeModal} changeMessage={changeMessage} />}
</div>
);
};

ReactDom.render(<Form />, document.getElementById('root'));
19 changes: 19 additions & 0 deletions userProfile/src/style.css
Original file line number Diff line number Diff line change
@@ -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;
}
55 changes: 55 additions & 0 deletions userProfile/src/task.txt
Original file line number Diff line number Diff line change
@@ -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 = () => (
* <div>
* Click this button <Button onClick={() => console.log("Hey!")}>Click me</Button>
* </div>
* );
*
*
* Тут можно посмотреть, как компонентами пользоваться, какие у них атрибуты есть:
* 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*. Необязательная задача.
* Добавь в эту форму еще поля: пол, дата рождения, город рождения, семейное положение,
* гражданство, национальность, номер телефона и адрес электронной почты.
* Придумай, как избежать излишнего дублирования.
*/
18 changes: 18 additions & 0 deletions userProfile/src/types.tsx
Original file line number Diff line number Diff line change
@@ -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[];
};