From 64f435643ce7d28ea9d6a5f32a1ba29ade3ed896 Mon Sep 17 00:00:00 2001 From: LaPaNu4 <120036931+LaPaNu4@users.noreply.github.com> Date: Thu, 4 Jan 2024 18:20:11 +0200 Subject: [PATCH 1/2] pass/bag fix --- src/components/App.jsx | 20 ++- src/components/ChangePass/ChangePass.jsx | 131 +++++++++++++++++++- src/components/Header/Header.jsx | 56 +++++---- src/components/PrivateRoute.jsx | 6 +- src/components/SearchForm/SearchForm.jsx | 14 ++- src/pages/AccountPage/AccountPage.jsx | 13 +- src/pages/ChangePassPage/ChangePassPage.jsx | 2 +- src/redux/auth/operations.js | 12 +- src/redux/user/opetations.js | 18 +-- src/redux/user/userSlice.js | 4 +- 10 files changed, 217 insertions(+), 59 deletions(-) diff --git a/src/components/App.jsx b/src/components/App.jsx index 8ee95ba..2a2f42d 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -43,10 +43,22 @@ export function App() { } /> } /> - } /> - }> - } /> - + + + + } + /> + + + + } + /> diff --git a/src/components/ChangePass/ChangePass.jsx b/src/components/ChangePass/ChangePass.jsx index 93210ff..97e0637 100644 --- a/src/components/ChangePass/ChangePass.jsx +++ b/src/components/ChangePass/ChangePass.jsx @@ -1,3 +1,132 @@ +import { useDispatch, useSelector } from 'react-redux'; +import * as Yup from 'yup'; +import { Formik } from 'formik'; +import { useEffect, useState } from 'react'; +import { selectError } from 'redux/auth/selectors'; +import { selectUser } from 'redux/user/selectors'; +import { changePass } from 'redux/user/opetations'; +import { Button, ErrorMessage, Field, Form, Label, Wraper } from 'components/ForgotPass/ForgotPass.styled'; +import { HidePassword, PasswordInput } from 'components/LoginForm/LoginForm.styled'; +import { ErrorSVG, ViewSVG } from 'components/LoginForm/chackBox'; + +const userSchema = Yup.object().shape({ + password: Yup.string() + .required('Введіть пароль') + .min(5, 'Пароль повинен містити принаймні 5 символів') + .matches( + /^[^\u0400-\u04FF]*$/, + 'Пароль не повинен містити кириличні символи' + ) + .matches( + /^(?=.*[A-Z])/, + 'Пароль повинен містити принаймні одну велику літеру' + ) + .matches( + /^(?=.*[a-z])/, + 'Пароль повинен містити принаймні одну малу літеру' + ) + .matches(/^(?=.*\d)/, 'Пароль повинен містити принаймні одну цифру') + .matches(/^[^\s]*$/, 'Пароль не повинен містити пробіли'), + password2: Yup.string() + .required('Повторіть новий пароль') + .test('passwords-match', 'Паролі повинні співпадати', function (value) { + return value === this.parent.password; + }), +}); + export default function ChangePass() { - return ; + const [showPassword, setShowPassword] = useState(false); + const [showPassword2, setShowPassword2] = useState(false); + const dispatch = useDispatch(); + const [refError, setRefError] = useState(false); + const requestError = useSelector(selectError); + const userInfo = useSelector(selectUser); + + const handleSubmit = (values, { resetForm, setSubmitting }) => { + const { password } = values; + try { + dispatch(changePass({ email: userInfo.email, password: password })); + resetForm(); + setSubmitting(false); + } catch (error) { + console.error('Error submitting form:', error); + } + }; + + const handleShowPassword = () => { + setShowPassword(!showPassword); + }; + const handleShowPassword2 = () => { + setShowPassword2(!showPassword2); + }; + + useEffect(() => { + if (requestError) setRefError(true); + }, [requestError]); + + return ( + + {values => { + return ( + + Заміна паролю + + Спочатку введіть новий пароль. А потім повторіть його + + + + + + + {refError ? ( + + + + ) : null} + + + + + + + + + + + + {refError ? ( + + + + ) : null} + + + + + + + + Зберегти + + + ); + }} + + ); } diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index 654afa2..6403277 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -18,33 +18,37 @@ const Header = () => { - - - Нові - - - Вживані - - - Під пригон - - - - - - - - Продати - - - - - - + + + Нові + + + Вживані + + + + Під пригон + + + + + + + + + Продати + - - - + + + + + + + + + + ); }; diff --git a/src/components/PrivateRoute.jsx b/src/components/PrivateRoute.jsx index be0f115..c369839 100644 --- a/src/components/PrivateRoute.jsx +++ b/src/components/PrivateRoute.jsx @@ -1,9 +1,9 @@ import { useSelector } from 'react-redux'; -import { Navigate, Outlet } from 'react-router-dom'; +import { Navigate } from 'react-router-dom'; import { selectIsLoggedIn } from '../redux/auth/selectors'; -export const PrivateRoute = () => { +export const PrivateRoute = ({ children, redirectTo = '/' }) => { const IsLoggedIn = useSelector(selectIsLoggedIn); - return IsLoggedIn ? : ; + return IsLoggedIn ? children : ; }; \ No newline at end of file diff --git a/src/components/SearchForm/SearchForm.jsx b/src/components/SearchForm/SearchForm.jsx index e29495c..444fc0a 100644 --- a/src/components/SearchForm/SearchForm.jsx +++ b/src/components/SearchForm/SearchForm.jsx @@ -4,10 +4,12 @@ import { useEffect, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import { setIsOpen } from 'redux/modal/modalSlice'; import { Arrow, DropArrow } from './SearchFormSVG'; +import { useLocation } from 'react-router-dom'; export const SearchForm = ({ initialValues, onSubmit }) => { const [selectedBrand, setSelectedBrand] = useState(''); const [selectedModel, setSelectedModel] = useState(''); + const location = useLocation(); const carMark = { BMW: ['X5', 'M3', 'I3'], Toyota: ['Camry', 'Corolla', 'Avalon'], @@ -32,6 +34,14 @@ export const SearchForm = ({ initialValues, onSubmit }) => { formikRef.current.resetForm({ values: initialValues }); } }, [initialValues]); + useEffect(() => { + const searchParams = new URLSearchParams(location.search); + const favouritesParam = searchParams.get('status'); + console.log(favouritesParam); + if (favouritesParam) { + formikRef.current.setFieldValue('status', favouritesParam); + } + }, [location.search]); const clearForm = () => { distatch(setIsOpen(true)); @@ -336,8 +346,6 @@ export const SearchForm = ({ initialValues, onSubmit }) => { }; export default SearchForm; - - // {/* // // // -// ; */} \ No newline at end of file +// ; */} diff --git a/src/pages/AccountPage/AccountPage.jsx b/src/pages/AccountPage/AccountPage.jsx index 47979f0..4cfc21b 100644 --- a/src/pages/AccountPage/AccountPage.jsx +++ b/src/pages/AccountPage/AccountPage.jsx @@ -7,18 +7,23 @@ import ProfileForm from '../../components/ProfileForm/ProfileForm'; import { getUser } from 'redux/user/opetations'; import { selectUser } from 'redux/user/selectors'; import { SVG1 } from './AccPageSVG'; +import { useLocation } from 'react-router-dom'; const AccountPage = () => { const dispatch = useDispatch(); - const [selectedNavItem, setSelectedNavItem] = useState('personal'); - + const [selectedNavItem, setSelectedNavItem] = useState('personal'); + const location = useLocation(); const userInfo = useSelector(selectUser) useEffect(() => { dispatch(getUser()); - }, [dispatch]); - + const searchParams = new URLSearchParams(location.search); + const favouritesParam = searchParams.get('favourites'); + if (favouritesParam === 'true') { + setSelectedNavItem('favourites'); + } + }, [dispatch, location.search]); const handleLogout = () => { diff --git a/src/pages/ChangePassPage/ChangePassPage.jsx b/src/pages/ChangePassPage/ChangePassPage.jsx index 1603855..c9bf2dd 100644 --- a/src/pages/ChangePassPage/ChangePassPage.jsx +++ b/src/pages/ChangePassPage/ChangePassPage.jsx @@ -7,7 +7,7 @@ import { acceptCode } from 'redux/user/opetations'; import { selectUser } from 'redux/user/selectors'; export default function ChangePassPage() { - const [success, setSuccess] = useState(false); + const [success, setSuccess] = useState(true); const dispatch = useDispatch(); const { code } = useParams(); const user = useSelector(selectUser); diff --git a/src/redux/auth/operations.js b/src/redux/auth/operations.js index 0577644..8dcbf0c 100644 --- a/src/redux/auth/operations.js +++ b/src/redux/auth/operations.js @@ -1,6 +1,6 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; -import { Notify } from 'notiflix/build/notiflix-notify-aio'; +// import { Notify } from 'notiflix/build/notiflix-notify-aio'; export const instance = axios.create({ @@ -21,11 +21,11 @@ export const register = createAsyncThunk( async (credentials, { rejectWithValue }) => { try { const response = await instance.post('api/auth/signup', credentials); - Notify.success(`Welcome!!!`); + console.log(`Welcome!!!`); return response.data; } catch (error) { - Notify.failure(`This email is already in use`); + console.log(`This email is already in use`); return rejectWithValue(error.message); } } @@ -38,10 +38,10 @@ export const login = createAsyncThunk( const response = await instance.post('api/auth/login', credentials); setToken(response.data.data.jwtAccessToken); console.log(response); - Notify.success(`Welcome back!!!`); + console.log(`Welcome back!!!`); return response.data; } catch (error) { - Notify.failure(`Login failed. Try again`); + console.log(`Login failed. Try again`); return rejectWithValue(error.message); } } @@ -94,7 +94,7 @@ export const logoutOperation = createAsyncThunk( // async (credentials, { rejectWithValue }) => { // try { // const { data } = await instance.patch('api/auth/update', credentials); -// Notify.success(`Your profile has been updated`); +// console.log(`Your profile has been updated`); // return data; // } catch (error) { // return rejectWithValue(error.message); diff --git a/src/redux/user/opetations.js b/src/redux/user/opetations.js index 95182e4..098e846 100644 --- a/src/redux/user/opetations.js +++ b/src/redux/user/opetations.js @@ -1,5 +1,5 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; -import { Notify } from 'notiflix/build/notiflix-notify-aio'; +// import { Notify } from 'notiflix/build/notiflix-notify-aio'; import { instance } from 'redux/auth/operations'; export const getUser = createAsyncThunk( @@ -20,10 +20,10 @@ export const changeUser = createAsyncThunk( async (credentials, { rejectWithValue }) => { try { await instance.put('api/users/user', credentials); - Notify.success(`User changed successfully`); + console.log(`User changed successfully`); return; } catch (error) { - Notify.failure(`Change failed. Try again`); + console.log(`Change failed. Try again`); return rejectWithValue(error.message); } } @@ -34,10 +34,10 @@ export const deleteUser = createAsyncThunk( async ({ id }, { rejectWithValue }) => { try { await instance.delete(`api/users/${id}`); - Notify.success(`User delete successfully`); + console.log(`User delete successfully`); return; } catch (error) { - Notify.failure(`failed. Try again`); + console.log(`failed. Try again`); return rejectWithValue(error.message); } } @@ -49,10 +49,10 @@ export const forgotPass = createAsyncThunk( async (credentials, { rejectWithValue }) => { try { await instance.put('api/users/forgot/password', credentials); - Notify.success(`Check your email`); + console.log(`Check your email`); return; } catch (error) { - Notify.failure(`Oops. Try again`); + console.log(`Oops. Try again`); return rejectWithValue(error.message); } } @@ -63,10 +63,10 @@ export const changePass = createAsyncThunk( async (credentials, { rejectWithValue }) => { try { await instance.put('api/users/change/password', credentials); - Notify.success(`Password changed successfully`); + console.log(`Password changed successfully`); return; } catch (error) { - Notify.failure(`Change failed. Try again`); + console.log(`Change failed. Try again`); return rejectWithValue(error.message); } } diff --git a/src/redux/user/userSlice.js b/src/redux/user/userSlice.js index 25e1e69..f2ca127 100644 --- a/src/redux/user/userSlice.js +++ b/src/redux/user/userSlice.js @@ -2,7 +2,7 @@ import { createSlice } from '@reduxjs/toolkit'; import { acceptCode, changePass, changeUser, deleteUser, forgotPass, getUser } from './opetations'; const initialState = { - user: null, + user: {}, isLoading: false, error: null, }; @@ -13,7 +13,7 @@ export const userSlice = createSlice({ extraReducers: builder => { builder .addCase(getUser.fulfilled, (state, { payload }) => { - state.user = payload; + state.user = {...payload}; state.isLoading = false; state.error = null; }) From 5de6374171b18dbe006066e5ae6af60c24bdd2f7 Mon Sep 17 00:00:00 2001 From: LaPaNu4 <120036931+LaPaNu4@users.noreply.github.com> Date: Thu, 4 Jan 2024 18:21:22 +0200 Subject: [PATCH 2/2] Update ChangePassPage.jsx --- src/pages/ChangePassPage/ChangePassPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ChangePassPage/ChangePassPage.jsx b/src/pages/ChangePassPage/ChangePassPage.jsx index c9bf2dd..1603855 100644 --- a/src/pages/ChangePassPage/ChangePassPage.jsx +++ b/src/pages/ChangePassPage/ChangePassPage.jsx @@ -7,7 +7,7 @@ import { acceptCode } from 'redux/user/opetations'; import { selectUser } from 'redux/user/selectors'; export default function ChangePassPage() { - const [success, setSuccess] = useState(true); + const [success, setSuccess] = useState(false); const dispatch = useDispatch(); const { code } = useParams(); const user = useSelector(selectUser);
+ Спочатку введіть новий пароль. А потім повторіть його +