https://github.com/uniteam31/unishare-frontend
Coming soon...
https://github.com/uniteam31/unishare-frontend
feature-sliced-design jenkins react react-hook-form typescript webpack
Last synced: 3 months ago
JSON representation
Coming soon...
- Host: GitHub
- URL: https://github.com/uniteam31/unishare-frontend
- Owner: uniteam31
- Created: 2024-12-01T12:51:36.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-02-26T14:21:20.000Z (over 1 year ago)
- Last Synced: 2025-02-26T14:22:57.723Z (over 1 year ago)
- Topics: feature-sliced-design, jenkins, react, react-hook-form, typescript, webpack
- Language: TypeScript
- Homepage:
- Size: 1.58 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# unishare
### ССЫЛКИ
[DEV стенд](http://176.114.90.241/) (работает в режиме воруй-убивай)
[JENKINS CI/CD](https://176.114.90.241:8080/) (private)
[UNITEAM NOTION](https://www.notion.so/UNITEAM-1049780386b880adbbe1e3480e5159ce?pvs=4) (private)
[UNISHARE NOTION](https://www.notion.so/UNISHARE-1709780386b880388d2dfbbc751678c3?pvs=4) (private)
[YOUGILE](https://ru.yougile.com/board/kyihl3hhjnbh)
## DEVELOPER GUIDE
### Сборка Dockerfile (для локального теста docker-compose)
**ENV**: API_URL, BRANCH
**COMMANDS**:
1. Сборка образа -> `docker build --no-cache -t def1s/unishare-frontend --build-arg API_URL=... --build-arg BRANCH=... --build-arg NOTES_URL=... --build-arg FRIENDS_URL=... --build-arg ACCOUNT_SETTINGS_URL=... .` (точку не забывать)
2. Push -> `docker push def1s/unishare-frontend` (но смысла особо нет, в пайплайне все равно перепушит)
3. Run -> `docker run def1s/unishare-frontend`
4. Можно взять образ из DockerHub -> `docker pull def1s/unishare-frontend`
### ЗАЧЕМ И КАК
Для чистого и оптимального кода должен существовать единый набор правил и рекомендаций по разработке. В этом разделе кратко описаны
основные требования и практики, использующиеся при разработке модулей.
#### ПРОЦЕСС РАЗРАБОТКИ
1. Создается таска на [YOUGILE](https://ru.yougile.com/board/kyihl3hhjnbh)
1. Если задача содержит часть подзадач, то создаются подтаски.
2. Создается ветка с номером текущей таски. Каждый коммит комментируется с указанием таски: 'UNI-XX: some changes'
1. Ветка ВСЕГДА имеет номер таски, даже если выполняется подтаска этой задачи. В коммите можно
указать 'UNI-[главный номер]-[подзадача]', но не принципиально.
3. Задача всегда вливается через ПР в dev ветку. Если упал пайплайн, то [смотрим](https://176.114.90.241:8080/) что не так -> фиксим -> повторяем пока не соберется
4. После вливания в dev при условии успешной сборки изменения автоматически накатываются на [DEV стенд](http://176.114.90.241/)
5. Кайфуем
#### РЕКОМЕНДАЦИИ
1. Комментарии это **ОЧЕНЬ** хорошо, но еще лучше дробить функции на маленькие части и писать самодокументирующийся код
на основе названий функций. Большие функции - ЭТО ПЛОХО, а большие функции без комментариев - ЭТО ОЧЕНЬ ПЛОХО, потому что
понятно только тому, кто это написал и только в момент написания.
2. Писать сразу хорошо и **НИКОГДА** не откладывать что-то на рефакторинг. Хочется что-то отложить на потом, но нужно
помнить, что ПОТОМ - это скорее всего никогда, а кодовая база постоянно расширяется и задачи прибавляются.
#### ПРАКТИКИ
1. При написании интерфейсов мы используем префикс I, а для типов T. Интерфейсы чаще всего дублируют названия своей сущности.
`interface IExample`
`type TExample`
2. Интерфейсы используются для описания пропсов компонента, каждый интерфейс собирается из более мелких типов.
Типы используются для задания дополнительных свойств. Если интерфейс большой -> дробим на логические типы и собираем в один.
**entities/Note/model/types/note.ts**
```
import { TMeta } from 'shared/types/meta';
/** Поля у формы заметки */
export type TNoteFormFields = {
title?: string;
text?: string;
};
/** Данные заметки */
export type TNodeData = TNoteFormFields & {
author: string;
};
/** Целый экземпляр */
export interface INote extends TNodeData, TMeta {}
```
Чаще всего дробим интерфейс на форму, данные, не входящие в форму и мета данные.
3. Если компонент (entity, widget, ...) содержит сущности, которые логически связаны с
родителем, то наружу мы выпускаем компонент-обертку, собирающая эти сущности в
единое целое
**entities/Note/index.ts**
```
import { Item } from './ui/Item/Item';
import { List } from './ui/List/List';
import { ListItem } from './ui/ListItem/ListItem';
export type { INote, TNodeData, TNoteFormFields } from './model/types/note';
type TNoteComponents = {
List: typeof List;
ListItem: typeof ListItem;
Item: typeof Item;
};
/** Экспортируем обертку для компонентов, которые связаны логически */
export const Note: TNoteComponents = {
List,
Item,
ListItem,
};
export { useNoteStore } from './model/slice/useNoteStore';
export { useGetNotes } from './api/useGetNotes';
export { useCreateNote } from './api/useCreateNote';
export { useUpdateNote } from './api/useUpdateNote';
export { useDeleteNote } from './api/useDeleteNote';
```
Улучшается читаемость и нет пересечений между компонентами по типу Item, Title и т.п.
4. Все формы оборачиваем в FormWrapper и прокидываем в него тип для значений (см. пункт 2)
```
...
const methods = useForm();
return (
methods={methods}>
);
```
Получается строгая типизация формы.
5. Все состояния (загрузка, ошибки) управляются компонентом с наибольшей ответственностью за ui сущности.
На примере entites/Note.List заметим, что он имеет в пропсах isLoading и error, но вот виджет заметки, рисующий часть заметок,
контролирует сам себя, потому что entites/Note.ListItem не имеет под собой большой ответственности за ui самого виджета.
6. На данный момент (пока что!) все методы по работе с бэкендом выносятся в api сущности в виде хуков. Все get запросы
контролируются с помощью SWR, который предоставляет стейт с состояниями, в остальных методах вручную пишем
стейты с загрузкой и ошибкой.