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

[SOK-16] #8

Merged
merged 7 commits into from
Oct 2, 2024
Merged

[SOK-16] #8

merged 7 commits into from
Oct 2, 2024

Conversation

gloginov
Copy link
Collaborator

+add backendApi
+create axios interceptors
+add userReducer and create function for use yandex api +add env
*update SignIn.tsx for use backendApi
*update SignUp.tsx for use backendApi
*format and lint

Какую задачу решаем

packages/client/src/store/reducers/user-reducer.ts Outdated Show resolved Hide resolved
packages/client/src/store/reducers/user-reducer.ts Outdated Show resolved Hide resolved
packages/client/src/store/reducers/user-reducer.ts Outdated Show resolved Hide resolved
packages/client/src/store/reducers/user-reducer.ts Outdated Show resolved Hide resolved
packages/client/src/store/reducers/user-reducer.ts Outdated Show resolved Hide resolved
@gloginov gloginov requested a review from VladToby September 27, 2024 08:40
@gloginov gloginov force-pushed the SOK-16_authorization branch from ab29ccb to 80fb9c2 Compare September 27, 2024 10:40
Copy link
Collaborator

@k0ndratov k0ndratov left a comment

Choose a reason for hiding this comment

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

Крутая работа.

Оставил пару моментов, которые меня волнуют.

packages/client/src/layouts/private-layout.tsx Outdated Show resolved Hide resolved
}, [user])

// if the user is full, show page
return user === null ? <h1>Загрузка...</h1> : <Outlet />
Copy link
Collaborator

@k0ndratov k0ndratov Sep 27, 2024

Choose a reason for hiding this comment

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

Выглядит так, что если запрос не пройдет, то будет бесконечно "Загрузка...". Возможно стоит при ошибке в backendApi перебрасывать на <Error>, чтобы хотя бы понятно было, что дальше нет смысла ждать.

Copy link
Owner

Choose a reason for hiding this comment

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

Он кидает на авторизацию при неудачном запросе, сделаю компонент прелоадера для таких целей.

import { AppDispatch, InferAppActions } from '@/store'
import backendApi from '@/api/backendApi'

export type UserType = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Может такую штуку использовать?

type Nullable<T> = T | null

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Не стал использовать. Не понимаю в чем преимущество. Поясни

if (data) {
dispatch(actions.setUser(null))

window.location.href = '/'
Copy link
Collaborator

Choose a reason for hiding this comment

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

А нельзя с помощью роутера перебросить, чтобы не ломать spa?

if (data) {
dispatch(actions.setUser(null))

window.location.href = '/'
Copy link
Collaborator

Choose a reason for hiding this comment

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

И еще момент, я не разбираюсь в реакте. Нормально ли, что redux управляет редиректами? Я просто думал, что его задача исключительно управлять состоянием приложения. А тут получается что он начинает реализовывать это состояние.

Или я тут заблуждаюсь?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Наверно не нормально. Переделал, логика в компоненте

if (error.response?.status === 401) {
localStorage.removeItem('user')
// save page where we get 401 and redirect after login
window.location.href = '/sign-in?redirectUrl=' + window.location.pathname
Copy link
Collaborator

Choose a reason for hiding this comment

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

Может быть можно роутером перебросить?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Переделал на роутер

window.location.href = '/sign-in?redirectUrl=' + window.location.pathname
}

if (axios.isCancel(error)) return Promise.reject(error)
Copy link
Collaborator

Choose a reason for hiding this comment

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

А есть смысл в этом условии, если все равно возвращается тоже самое?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Убрал

function (error: AxiosError) {
// if app get response code 401 (died token), redirect user to sign-in form
if (error.response?.status === 401) {
localStorage.removeItem('user')
Copy link
Collaborator

Choose a reason for hiding this comment

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

Возможно не стоит давать backendApi возможность манипулировать localStorage`ем? Начинаем как будто смешивать логику запросов и управления состоянием.

Возможно стоит сделать какой-то errorHandler, который опознает ошибку и вызовет нужный контролер.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Манипуляцию localstorage уберу

if (error.response?.status === 401) {
localStorage.removeItem('user')
// save page where we get 401 and redirect after login
window.location.href = '/sign-in?redirectUrl=' + window.location.pathname
Copy link
Collaborator

Choose a reason for hiding this comment

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

И возможно тоже смешивается логика. Теперь получается, что backendApi управляет роутами и локал сторажем. Как будто много на себя берет, не?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Он берет на себя одну функцию - отловить 401 (что говорит о том что авторизация слетела) и что-то сделать. Подумаю как оформить

href?: string
className?: string | undefined
useFixWidth?: boolean | undefined
href?: string | undefined
Copy link
Collaborator

Choose a reason for hiding this comment

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

Не будет чуть путацины с href`ом для кнопки? Вроде ожидается, что кнопка делает экшены, а ссылки перебрасывают.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Тут ты наверно прав. Уберу href оставлю только событие

Choose a reason for hiding this comment

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

Хороший поинт от @k0ndratov 👍

Copy link
Owner

@Timur233 Timur233 left a comment

Choose a reason for hiding this comment

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

Привет! Отличная работа! Сейчас попробую затянуть к себе и сделать кнопку "профиль" в шапке, с именем пользователя ))

У меня пара комментов:

  • Давай запретим посещение страниц, авторизации и регистрации авторизованным пользователям.
  • И я бы убрал ненужные комментарии в коде, пример ниже.

// if user is empty call backend
if (user === null) { dispatch(getUser()) }

useEffect(() => {
// if user is empty call backend
if (user === null) {
dispatch(getUser())
Copy link
Owner

Choose a reason for hiding this comment

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

Обратил внимание, что при загрузке страницы запрос улетает 2 раза подряд.
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Дважды улетает только в dev из-за strict mode
https://legacy.reactjs.org/docs/strict-mode.html

}, [user])

// if the user is full, show page
return user === null ? <h1>Загрузка...</h1> : <Outlet />
Copy link
Owner

Choose a reason for hiding this comment

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

Он кидает на авторизацию при неудачном запросе, сделаю компонент прелоадера для таких целей.

if (error.response?.status === 401) {
localStorage.removeItem('user')
// save page where we get 401 and redirect after login
window.location.href = '/sign-in?redirectUrl=' + window.location.pathname
Copy link
Owner

Choose a reason for hiding this comment

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

Чуть смущает camelCase в гет параметрах. Это не правка, просто коммент.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Убрал вообще этот код. Сделал иначе

+add backendApi
+create axios interceptors
+add userReducer and create function for use yandex api
+add env
*update SignIn.tsx for use backendApi
*update SignUp.tsx for use backendApi
*format and lint
*fix lint error
*add types from yandex api for user
*rename UserReducer to AuthReducer
*rename methods in auth-reducer.ts
-remove origin host from methods in auth-reducer.ts because base url set in backendApi
*update backendApi
*change reducer for async/await
*redirects with router (spa)
+add toast for error message
@gloginov gloginov force-pushed the SOK-16_authorization branch from bc559fc to 9960d7c Compare October 1, 2024 16:42
*fix format
*fix lint
@k0ndratov k0ndratov self-requested a review October 1, 2024 22:39
Copy link

@MikeDevice MikeDevice left a comment

Choose a reason for hiding this comment

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

Ты молодец. Большая работа и это действительно сложная задачка. Описал всякие нюансы, как можно сделать лучше, но критических замечаний нет.

Вообще глобальная рекомендация:

  1. Из реакт компонента кидать один экшн dispatch(login()), например, а в санке уже ловить этот экшн и отправлять запросы на сервер там. Так логика будет чище.
  2. Ну и меньше копипасты и больше обобщений!

Choose a reason for hiding this comment

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

Интересно, что у вас в проекте есть и package-lock, и yarn.lock. Обычно используется что-то одно из двух. Возможно, у вас в команде кто-то устанавливает зависимости через npm install, а кто-то через yarn. Нужно разобраться с этим придти к единообразию.

import axios from 'axios'

const instance = axios.create({
baseURL: import.meta.env.VITE_AUTH_URL,

Choose a reason for hiding this comment

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

Круто, что такие штуки унесены в переменные окружения 👍

Choose a reason for hiding this comment

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

Отдельный лайк за абстракцию в виде backendApi, а не использование чистого axios во всех местах

/* eslint-disable */
import App from './App'
import { render, screen } from '@testing-library/react'
// import App from './App'

Choose a reason for hiding this comment

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

А что тут такое? Почему ты закоментил? Этот тест сейчас не запускается никогда?

href?: string
className?: string | undefined
useFixWidth?: boolean | undefined
href?: string | undefined

Choose a reason for hiding this comment

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

Хороший поинт от @k0ndratov 👍

useFixWidth?: boolean | undefined
href?: string | undefined
/* eslint-disable @typescript-eslint/no-explicit-any */
onClick?: (() => Promise<void>) | (() => any) | undefined

Choose a reason for hiding this comment

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

ESlint не зря ругается. Лучше вместо any использовать unknown, а ещё лучше чётко прописывать нужный тип.

Пытаюсь понять, а зачем три типа подаёшь? Смотри, так как у тебя после onClick идёт вопросительный знак, значит тип undefined можно смело удалить, останется два, но всё равно не пойму, зачем тут промис.

Ты просто кидаешь в button функцию onClick. Нативная кнопка промис не возвращает.

Нужно исправить это Вообще любой такой onClick обычно имеет тип (): void или такой же, только с параметром event внутри

</label>
<Button
text={'зарегистрироваться'}
useFixWidth={true}

Choose a reason for hiding this comment

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

Suggested change
useFixWidth={true}
useFixWidth

Можно просто без true

import { combineReducers } from '@reduxjs/toolkit'

const rootReducer = combineReducers({
AuthReducer,

Choose a reason for hiding this comment

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

Можно лучше: обычно пишут с маленькой буквы:

Suggested change
AuthReducer,
authReducer: AuthReducer,

Comment on lines +22 to +30
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comment: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export type InferAppActions<T> = T extends {
[keys: string]: (...args: unknown[]) => infer U
}
? U
: never

Choose a reason for hiding this comment

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

Воу! прикольно! 👍

}

const initialState = {
user: null as unknown as UserType,

Choose a reason for hiding this comment

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

так обычно плохо делать. Лучше создать тип:

type InitialState = { user: UserType | null }
const initialState:  InitialState  = { ... }

)

export type ActionsType = InferAppActions<typeof actions>
export default AuthReducer

Choose a reason for hiding this comment

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

Можно лучше: Все санки похожи между собой. Рекомендую написать базовый санк, который ба содержал в себе обработку ошибок, и потом его использовать во всех местах.

*fix some comment for PR
*format
*fix lint
@gloginov gloginov merged commit 2def654 into develop Oct 2, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants