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

Fix/contacts - Исправление раздела "Контакты" #206

Merged
merged 17 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
3f5ad9e
feat: подключить бэкенд для загрузки контактов, добавить редактирован…
IvannaBalanyuk Jun 12, 2024
788a7f4
fix: исправить верстку, реализовать адаптивность
IvannaBalanyuk Jun 12, 2024
8e11927
Merge branch 'develop' of github.com:ya-pomogau/frontend into fix/con…
IvannaBalanyuk Jun 12, 2024
ecd7ab9
fix: исправить импорт для TContacts
IvannaBalanyuk Jun 12, 2024
6a845a2
fix: вернуть usePermission к исходному состоянию
IvannaBalanyuk Jun 12, 2024
2474682
hotfix: вынести повторяющийся блок верстки в функцию getContactContainer
IvannaBalanyuk Jun 12, 2024
4505018
hotfix: убрать слайс для contacts и его применение
IvannaBalanyuk Jun 12, 2024
c709164
hotfix: для инпутов применить useForm вместо useState
IvannaBalanyuk Jun 12, 2024
2d0fa42
hotfix: убрать условную конструкцию if из onSubmit
IvannaBalanyuk Jun 12, 2024
e066e90
Merge branch 'develop' of github.com:ya-pomogau/frontend into fix/con…
IvannaBalanyuk Jun 12, 2024
888d280
fix: вернуть usePermission к исходному состоянию
IvannaBalanyuk Jun 12, 2024
d700dba
hotfix: поправить паддинги у container (поправка на разницу в высоте …
IvannaBalanyuk Jun 12, 2024
aab1c45
fix: перенести useUpdateContactsMutation в adminApi
IvannaBalanyuk Jun 12, 2024
c083ab0
fix: внести правки в части обновления контактов (добавить id в запрос)
IvannaBalanyuk Jun 13, 2024
27f716e
hotfix: добавить валидацию из useform, убрать передачу id в params пр…
IvannaBalanyuk Jun 13, 2024
d7f8d83
fix: вернуть usePermission к исходному состоянию
IvannaBalanyuk Jun 13, 2024
d6dcb68
hotfix: вернуть setValues из useForm, применить в useEffect в Contact…
IvannaBalanyuk Jun 13, 2024
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
5 changes: 5 additions & 0 deletions src/app/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { configureStore } from '@reduxjs/toolkit';

import { userModel } from 'entities/user/model';
import { contactsModel } from 'entities/contacts/model';
import { createRequestModel } from 'features/create-request/model/create-request';
import { usersApi } from 'services/user-api';
import { contactsApi } from 'services/contacts-api';
import { tasksApi } from 'services/tasks-api';
import { authAdminApi } from 'services/auth-admin-api';
import { categoriesApi } from 'services/categories-api';
Expand All @@ -16,9 +18,11 @@ export const store = configureStore({
reducer: {
error: errorModel.reducer,
user: userModel.reducer,
contacts: contactsModel.reducer,
createRequest: createRequestModel.reducer,
system: systemSliceReducer,
[usersApi.reducerPath]: usersApi.reducer,
[contactsApi.reducerPath]: contactsApi.reducer,
[tasksApi.reducerPath]: tasksApi.reducer,
[userTasksApi.reducerPath]: userTasksApi.reducer,
[authAdminApi.reducerPath]: authAdminApi.reducer,
Expand All @@ -29,6 +33,7 @@ export const store = configureStore({
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware()
.concat(usersApi.middleware)
.concat(contactsApi.middleware)
.concat(tasksApi.middleware)
.concat(authAdminApi.middleware)
.concat(categoriesApi.middleware)
Expand Down
20 changes: 20 additions & 0 deletions src/entities/contacts/model/contacts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { TContacts } from '../types';

const initialState: TContacts = {
email: null,
socialNetwork: null,
};

export const contactsModel = createSlice({
name: 'contacts',
initialState,
reducers: {
setContacts: (state, { payload }: PayloadAction<TContacts | null>) => {
state.email = payload?.email;
state.socialNetwork = payload?.socialNetwork;
},
},
});

export const { setContacts } = contactsModel.actions;
1 change: 1 addition & 0 deletions src/entities/contacts/model/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './contacts';
4 changes: 4 additions & 0 deletions src/entities/contacts/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type TContacts = {
email: string | null | undefined;
socialNetwork: string | null | undefined;
};
172 changes: 132 additions & 40 deletions src/pages/contacts/contacts.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,86 @@
import React, { ChangeEvent, SyntheticEvent } from 'react';
import { ChangeEvent, SyntheticEvent, useEffect, useState } from 'react';
import classNames from 'classnames';
import { Icon } from 'shared/ui/icons';
import { SmartHeader } from 'shared/ui/smart-header';

import styles from './styles.module.css';
import { useAppDispatch, useAppSelector } from '../../app/hooks';
import { SmartHeader } from '../../shared/ui/smart-header';
import { Icon } from '../../shared/ui/icons';
import { Button } from '../../shared/ui/button';
import usePermission from 'shared/hooks/use-permission';
import { UserRole, UserStatus } from 'shared/types/common.types';
import usePermission from '../../shared/hooks/use-permission';
import { UserRole, UserStatus } from '../../shared/types/common.types';
import {
useGetContactsQuery,
useUpdateContactsMutation,
} from '../../services/contacts-api';
import { setContacts } from '../../entities/contacts/model';
import { TContacts } from '../../entities/contacts/types';

export function ContactsPage() {
const roleChecker = usePermission([UserStatus.VERIFIED], UserRole.ADMIN);
const isEditAllowed = usePermission([UserStatus.VERIFIED], UserRole.ADMIN);

const [userData, setUserData] = React.useState({
userEmail: 'www@yandex.ru',
userVKLink: 'https://vk.com/me2help',
const [contactsData, setContactsData] = useState<TContacts>({
Copy link
Collaborator

Choose a reason for hiding this comment

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

По-хорошему, тут должен быть хук useForm

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • переписала код с использованием хука useForm

Не смогла решить такую проблему - при обновлении страницы инпуты опустошаются и значения снова отображаются только после ререндера (например, после нажатия на кнопку редактирования или перехода между вкладками)

Copy link
Collaborator

Choose a reason for hiding this comment

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

  • переписала код с использованием хука useForm

Не смогла решить такую проблему - при обновлении страницы инпуты опустошаются и значения снова отображаются только после ререндера (например, после нажатия на кнопку редактирования или перехода между вкладками)

Проблема актуальна?

Copy link
Contributor Author

@IvannaBalanyuk IvannaBalanyuk Jun 13, 2024

Choose a reason for hiding this comment

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

Да, корректно в этом плане работало только когда обращение за данными на бэк и setContsctsData были обернуты в UseEffect (по отдельности). Тогда при обновлении происходил запрос к бэку и после этого отрабатывал второй useEffect (с setContsctsData), так как у него в зависимостях были данные, получаемые с бэка.

Может из хука useForm ёще setValues возвращать?

Вот так всё работает корректно:

image

Copy link
Collaborator

@INextYP INextYP Jun 13, 2024

Choose a reason for hiding this comment

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

Да, так в принципе можно сделать, только вынести за пределы компонента:

const initialContactsValues = {
    email: null,
    socialNetwork: null,
  }

export function ContactsPage() {
...
,...
....
const { values, handleChange, isValid, setValues } = useForm<TContacts>(initialContactsValues);

Чуть позже мы перейдем на нормальный хук)

Как исправишь - пингани, я апрувну

Copy link
Collaborator

Choose a reason for hiding this comment

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

Да, корректно в этом плане работало только когда обращение за данными на бэк и setContsctsData были обернуты в UseEffect (по отдельности). Тогда при обновлении происходил запрос к бэку и после этого отрабатывал второй useEffect (с setContsctsData), так как у него в зависимостях были данные, получаемые с бэка.

@INextYP слушай, а может просто завести слайс system в хранилище, и туда прям на монтировании App затягивать конфиденциальность, контакты и всё прочее такое?

А потом по WS сделаем апдейты при изменении.

email: null,
socialNetwork: null,
});

const [enableEdit, setEnableEdit] = React.useState(false);
const [editingInput, setEditingInput] = useState<
'email' | 'socialNetwork' | null
>(null);

const dispatch = useAppDispatch();
const { email, socialNetwork } = useAppSelector((state) => state.contacts);
INextYP marked this conversation as resolved.
Show resolved Hide resolved
const [updateContacts, { isLoading }] = useUpdateContactsMutation();
const getContactsResult = useGetContactsQuery();
INextYP marked this conversation as resolved.
Show resolved Hide resolved

const onSubmit = (e: SyntheticEvent) => {
useEffect(() => {
INextYP marked this conversation as resolved.
Show resolved Hide resolved
if (getContactsResult.data) {
dispatch(setContacts(getContactsResult.data));
setContactsData({
email: email,
socialNetwork: socialNetwork,
});
}
}, [getContactsResult, email, socialNetwork]);

const onSubmit = async (e: SyntheticEvent) => {
e.preventDefault();
setEnableEdit(false);
console.log(
`Данные email:${userData.userEmail} и VK:${userData.userVKLink} отправлены на сервер`
);
if (isEditAllowed) {
INextYP marked this conversation as resolved.
Show resolved Hide resolved
try {
const resultAction = await updateContacts(contactsData);
INextYP marked this conversation as resolved.
Show resolved Hide resolved
if ('data' in resultAction) {
dispatch(setContacts(resultAction.data));
} else {
console.error('Ошибка при сохранении данных:', resultAction.error);
}
setEditingInput(null);
setContactsData({
email: email,
socialNetwork: socialNetwork,
});
} catch (error) {
console.error('Ошибка при сохранении данных:', error);
}
} else {
setEditingInput(null);
setContactsData({
email: email,
socialNetwork: socialNetwork,
});
console.log(
'Изменение контактых данных не доступно для текущего пользователя'
);
}
};

const emailHandler = () => {
setEditingInput('email');
};
const handleEnableEdit = () => {
setEnableEdit(true);

const socialNetworkHandler = () => {
setEditingInput('socialNetwork');
};

const onChange = (e: ChangeEvent<HTMLInputElement>) => {
INextYP marked this conversation as resolved.
Show resolved Hide resolved
setUserData({ ...userData, [e.target.name]: e.target.value });
setContactsData({ ...contactsData, [e.target.name]: e.target.value });
};

return (
Expand All @@ -39,38 +89,59 @@ export function ContactsPage() {
text="Контакты"
icon={<Icon color="blue" icon="ContactsIcon" size="54" />}
/>
<form onSubmit={onSubmit}>
<form className={styles.form} onSubmit={onSubmit}>
<div className={styles.container}>
<div className={styles.element_box}>
<h2
className={classNames(
'text',
'text_size_large',
'text_type_regular',
'm-0',
styles.title
)}
>
Эл. почта
</h2>
<input
type="text"
className={styles.input}
className={`${styles.input} ${
editingInput === 'email'
? styles.input_mode_edit
: styles.input_mode_link
}`}
onChange={onChange}
name="userEmail"
defaultValue={userData.userEmail}
readOnly={!enableEdit}
name="email"
value={contactsData.email || ''}
readOnly={editingInput !== 'email'}
onClick={(e) => {
if (!enableEdit) {
if (editingInput !== 'email') {
e.preventDefault();
window.location.href = `mailto:${userData.userEmail}`;
window.location.href = `mailto:${contactsData.email}`;
}
}}
/>
</div>
{roleChecker && (
<div onClick={handleEnableEdit} className={styles.edit_box}>
{isEditAllowed && (
<div
onClick={emailHandler}
className={
editingInput === 'email'
? styles.edit_box_hidden
: styles.edit_box
}
>
<Icon color="blue" icon="EditIcon" />
<p className={styles.edit_text}>Изменить данные</p>
<p
className={classNames(
'text',
'text_size_small',
'text_type_regular',
'm-0'
)}
>
Изменить данные
</p>
</div>
)}
</div>
Expand All @@ -81,38 +152,59 @@ export function ContactsPage() {
'text',
'text_size_large',
'text_type_regular',
'm-0',
styles.title
)}
>
Страница VK
</h2>
<input
type="text"
className={styles.input}
className={`${styles.input} ${
editingInput === 'socialNetwork'
? styles.input_mode_edit
: styles.input_mode_link
}`}
onChange={onChange}
name="userVKLink"
defaultValue={userData.userVKLink}
readOnly={!enableEdit}
name="socialNetwork"
value={contactsData.socialNetwork || ''}
readOnly={editingInput !== 'socialNetwork'}
onClick={(e) => {
if (!enableEdit) {
if (editingInput !== 'socialNetwork') {
e.preventDefault();
window.location.href = `${userData.userVKLink}`;
window.location.href = `${contactsData.socialNetwork}`;
}
}}
/>
</div>
{roleChecker && (
<div onClick={handleEnableEdit} className={styles.edit_box}>
{isEditAllowed && (
INextYP marked this conversation as resolved.
Show resolved Hide resolved
<div
onClick={socialNetworkHandler}
className={
editingInput === 'socialNetwork'
? styles.edit_box_hidden
: styles.edit_box
}
>
<Icon color="blue" icon="EditIcon" />
<p className={styles.edit_text}>Изменить данные</p>
<p
className={classNames(
'text',
'text_size_small',
'text_type_regular',
'm-0'
)}
>
Изменить данные
INextYP marked this conversation as resolved.
Show resolved Hide resolved
</p>
</div>
)}
</div>
{roleChecker && (
{isEditAllowed && (
<Button
buttonType="primary"
label="Сохранить"
disabled={!enableEdit}
disabled={editingInput === null}
type="submit"
/>
)}
Expand Down
Loading