Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Курганов Артемий #36

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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="someId"></div>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Неплохой, конечно, айдишник, но если бы это был код в реальном проекте, я бы докопалась) Хотя бы универсальным root его назвать, или что-то более конкретное, типа formPage

<script src="build/index.js"></script>
</body>
</html>
149 changes: 148 additions & 1 deletion userProfile/src/index.tsx
Original file line number Diff line number Diff line change
@@ -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';

/**
Expand Down Expand Up @@ -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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Эти штуки лучше объявить через const, линтер в моей IDE даже ругается на это) Они же действительно никогда не меняются в обычном джаваскриптовом смысле — если они меняются, то это значит, что компонент ререндерится == функция Form выполняется заново, и это уже новые объекты в памяти, а не старые


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

let [changeMessage, setChangeMessage] = useState(Array<string>());
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) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Какой-то python_case проскочил, атата))

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>
);
}

const ModalOnSave = ({close, changeMessage} : ModeOnSaveType) => (
<Modal onClose={close}>
<Modal.Header>Пользователь сохранен</Modal.Header>
<Modal.Body>
{ changeMessage.map(data => <p>{data}</p>) }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Во время рендера модалки в консоли ошибки, что у элементов нет свойства key. Лучше всегда его указывать, когда вот так через map рендеришь компоненты

</Modal.Body>
<Modal.Footer>
<Button onClick={close}>Закрыть</Button>
</Modal.Footer>
</Modal>
)

const InputRow = ({title, placeholder='', onInputChange, isError} : RowType) => {
return (
<div className='inputRow'>
<Gapped gap={20}>
<p className='title'>{title}</p>
<div>
<Input placeholder={placeholder} onChange={(e) => onInputChange(e.target.value)}></Input>
{isError && <p className='error-message'>Заполните поле</p>}
</div>
</Gapped>

</div>
)
}

const SelectRow = ({title, onInputChange} : SelectType) => {
const cities = ['Москва', 'Санкт-Петербург', 'Екатеринбург'];
return (
<div className='inputRow'>
<Gapped gap={20}>
<p className='title'>{title}</p>
{/* Почему-то здесь ругается IDE, хотя по документации должно быть всё ок. Код запускается и работает*/}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это потому, что в селект можно передать items самых разных типов, и onValueChange работает как раз с тем же типом, что и у items. Да, ты передаёшь массив строк, но тайпскрипт всё равно не справляется с автовыводом типов, и ему надо помочь, явно его указав, вот так: <Select items={cities} ... />

Copy link
Author

@artemijkurganov artemijkurganov Oct 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<Select<string> items={cities} ... />
Markdown съел дженерик 😄

<Select items={cities} placeholder='Выберете город' onValueChange={(value: string) => { onInputChange(value)}}></Select>
</Gapped>
</div>
)
}

type InputType = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Типам, которые описывают параметры компонентов, принято добавлять в конец Props. То есть это должен быть не InputType, а InputProps

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(
<Form></Form>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если у компонента или элемента нет детей, то можно сократить, и написать вот так: <Form/>
Аналогичные моменты есть и выше, с инпутами и селектом

document.getElementById('someId')
);


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;
}