Skip to content

Commit

Permalink
add validate profile update
Browse files Browse the repository at this point in the history
  • Loading branch information
stambekovbera committed Mar 15, 2024
1 parent ca6841d commit 92279a1
Show file tree
Hide file tree
Showing 14 changed files with 138 additions and 11 deletions.
4 changes: 4 additions & 0 deletions extractedTranslations/en/profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,9 @@
"profile_lastname_input_placeholder": "profile_lastname_input_placeholder",
"profile_title": "",
"profile_username_input_placeholder": "",
"profile_validate_incorrect_age_text": "",
"profile_validate_incorrect_user_age": "profile_validate_incorrect_user_age",
"profile_validate_incorrect_user_data_text": "profile_validate_incorrect_user_data_text",
"profile_validate_incorrect_username_text": "profile_validate_incorrect_username_text",
"save_button_text": "save_button_text"
}
3 changes: 3 additions & 0 deletions extractedTranslations/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
"profile_navbar": "profile_navbar",
"profile_title": "profile_title",
"profile_username_input_placeholder": "profile_username_input_placeholder",
"profile_validate_incorrect_age_text": "profile_validate_incorrect_age_text",
"profile_validate_incorrect_user_data_text": "profile_validate_incorrect_user_data_text",
"profile_validate_incorrect_username_text": "profile_validate_incorrect_username_text",
"save_button_text": "save_button_text",
"throw_error": "throw_error",
"username": "username",
Expand Down
6 changes: 6 additions & 0 deletions extractedTranslations/ru/profile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"profile_validate_incorrect_age_text": "profile_validate_incorrect_age_text",
"profile_validate_incorrect_user_age": "profile_validate_incorrect_user_age",
"profile_validate_incorrect_user_data_text": "profile_validate_incorrect_user_data_text",
"profile_validate_incorrect_username_text": "profile_validate_incorrect_username_text"
}
3 changes: 3 additions & 0 deletions extractedTranslations/ru/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
"profile_navbar": "profile_navbar",
"profile_title": "profile_title",
"profile_username_input_placeholder": "profile_username_input_placeholder",
"profile_validate_incorrect_age_text": "profile_validate_incorrect_age_text",
"profile_validate_incorrect_user_data_text": "profile_validate_incorrect_user_data_text",
"profile_validate_incorrect_username_text": "profile_validate_incorrect_username_text",
"save_button_text": "save_button_text",
"throw_error": "throw_error",
"username": "username",
Expand Down
11 changes: 10 additions & 1 deletion public/locales/en/profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,14 @@
"profile_city_input_placeholder": "Your city",
"profile_avatar_input_placeholder": "Your avatar",
"profile_username_input_placeholder": "Your username",
"profile_avatar_img_alt": "Your avatar"
"profile_avatar_img_alt": "Your avatar",
"profile_validate_incorrect_user_data_text": "Check that the entered data is correct",
"profile_validate_incorrect_age_text": "Check that the age entered is correct",
"profile_validate_incorrect_username_text": "Check that the username you entered is correct",
"profile_validate_incorrect_city_text": "Check that the city you entered is correct",
"profile_validate_incorrect_currency_text": "Check that the selected currency is correct",
"profile_validate_incorrect_avatar_text": "Check the correctness of the selected avatar",
"profile_validate_incorrect_country_text": "Check that the selected country is correct",
"profile_validate_server_error_text": "Server error",
"profile_validate_no_data_error_text": "No data"
}
11 changes: 10 additions & 1 deletion public/locales/ru/profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,14 @@
"profile_city_input_placeholder": "Ваш город",
"profile_avatar_input_placeholder": "Ваш аватар",
"profile_username_input_placeholder": "Ваше имя пользователя",
"profile_avatar_img_alt": "Ваша аватарка"
"profile_avatar_img_alt": "Ваша аватарка",
"profile_validate_incorrect_user_data_text": "Проверьте правильность введенных данных",
"profile_validate_incorrect_age_text": "Проверьте правильность введенного возраста",
"profile_validate_incorrect_username_text": "Проверьте правильность введенного имени пользователя",
"profile_validate_incorrect_city_text": "Проверьте правильность введенного города",
"profile_validate_incorrect_currency_text": "Проверьте правильность выбранной валюты",
"profile_validate_incorrect_avatar_text": "Проверьте правильность выбранной аватарки",
"profile_validate_incorrect_country_text": "Проверьте правильность выбранной страны",
"profile_validate_server_error_text": "Ошибка сервера",
"profile_validate_no_data_error_text": "Нет данных"
}
11 changes: 11 additions & 0 deletions src/entities/Profile/const/validateProfileErrors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const validateProfileErrors = {
INCORRECT_USER_DATA: 'profile_validate_incorrect_user_data_text',
INCORRECT_AGE: 'profile_validate_incorrect_age_text',
INCORRECT_USERNAME: 'profile_validate_incorrect_username_text',
INCORRECT_CITY: 'profile_validate_incorrect_city_text',
INCORRECT_CURRENCY: 'profile_validate_incorrect_currency_text',
INCORRECT_AVATAR: 'profile_validate_incorrect_avatar_text',
INCORRECT_COUNTRY: 'profile_validate_incorrect_country_text',
SERVER_ERROR: 'profile_validate_server_error_text',
NO_DATA: 'profile_validate_no_data_error_text',
} as const;
5 changes: 4 additions & 1 deletion src/entities/Profile/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export { IProfile, IProfileSchema } from './model/types/profile';
export { IProfile, IProfileSchema, TValidateProfileError } from './model/types/profile';

export { validateProfileErrors } from './const/validateProfileErrors';

export { profileReducer, profileActions } from './model/slice/profileSlice';

Expand All @@ -11,3 +13,4 @@ export { getProfileData } from './model/selectors/getProfileData/getProfileData'
export { getProfileIsLoading } from './model/selectors/getProfileIsLoading/getProfileIsLoading';
export { getProfileError } from './model/selectors/getProfileError/getProfileError';
export { getProfileReadonly } from './model/selectors/getProfileReadonly/getProfileReadonly';
export { getProfileValidateErrors } from './model/selectors/getProfileValidateErrors/getProfileValidateErrors';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { IStateSchema } from 'shared/config/storeConfig/StateSchema';

export const getProfileValidateErrors = (state: IStateSchema) => state.profile?.validateErrors;
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import { IThunkConfig } from 'shared/config/storeConfig/StateSchema';
import { IProfile } from '../../types/profile';
import { IProfile, TValidateProfileError } from '../../types/profile';
import { getProfileForm } from '../../selectors/getProfileForm/getProfileForm';
import { validateProfileData } from 'entities/Profile/model/services/validateProfileData/validateProfileData';

export const updateProfileData= createAsyncThunk<IProfile, undefined, IThunkConfig<string>>(
export const updateProfileData = createAsyncThunk<IProfile, undefined, IThunkConfig<TValidateProfileError[]>>(
'profile/updateProfileData',
async (_, thunkAPI) => {
const { extra, getState } = thunkAPI;
const formData = getProfileForm( getState() );

if (!formData) {
return thunkAPI.rejectWithValue( [ 'NO_DATA' ] );
}

const errors = validateProfileData( formData );

if (errors.length > 0) {
return thunkAPI.rejectWithValue( errors );
}

try {
const response = await extra.api.put<IProfile>( '/profile', formData );

thunkAPI.fulfillWithValue( response.data );

return response.data;
} catch (err) {
return thunkAPI.rejectWithValue( 'error' );
return thunkAPI.rejectWithValue( [ 'SERVER_ERROR' ] );
}
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { IProfile, TValidateProfileError } from '../../types/profile';

export const validateProfileData = (profile: IProfile) => {
const {
country,
avatar,
currency,
age,
city,
username,
lastname,
firstname
} = profile;

const errors: TValidateProfileError[] = [];

if (!firstname || !lastname) {
errors.push( 'INCORRECT_USER_DATA' );
}

if (!username) {
errors.push( 'INCORRECT_USERNAME' );
}

if (!age || !Number.isInteger( age )) {
errors.push( 'INCORRECT_AGE' );
}

if (!city) {
errors.push( 'INCORRECT_CITY' );
}

if (!currency) {
errors.push( 'INCORRECT_CURRENCY' );
}

if (!avatar) {
errors.push( 'INCORRECT_AVATAR' );
}

if (!country) {
errors.push( 'INCORRECT_COUNTRY' );
}

return errors;
};
8 changes: 5 additions & 3 deletions src/entities/Profile/model/slice/profileSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const initialState: IProfileSchema = {
error: undefined,
data: undefined,
form: undefined,
validateErrors: [],
};

export const profileSlice = createSlice( {
Expand All @@ -21,6 +22,7 @@ export const profileSlice = createSlice( {
cancelEdit: (state) => {
state.readonly = true;
state.form = state.data;
state.validateErrors = undefined;
},
updateProfile: (state, action: PayloadAction<IProfile>) => {
state.form = {
Expand Down Expand Up @@ -48,18 +50,18 @@ export const profileSlice = createSlice( {
} )
.addCase( updateProfileData.pending, (state) => {
state.isLoading = true;
state.error = undefined;
state.validateErrors = undefined;
} )
.addCase( updateProfileData.fulfilled, (state, action) => {
state.isLoading = false;
state.data = action.payload;
state.form = action.payload;
state.error = undefined;
state.validateErrors = undefined;
state.readonly = true;
} )
.addCase( updateProfileData.rejected, (state, action) => {
state.isLoading = false;
state.error = action.payload;
state.validateErrors = action.payload;
} );
}
} );
Expand Down
4 changes: 4 additions & 0 deletions src/entities/Profile/model/types/profile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { TCurrency } from 'entities/Currency';
import { TCountry } from 'entities/Country';
import { validateProfileErrors } from '../../const/validateProfileErrors';

export type TValidateProfileError = keyof typeof validateProfileErrors;

export interface IProfile {
firstname?: string;
Expand All @@ -18,4 +21,5 @@ export interface IProfileSchema {
isLoading: boolean;
error?: string;
readonly: boolean;
validateErrors?: TValidateProfileError[];
}
17 changes: 15 additions & 2 deletions src/pages/ProfilePage/ui/ProfilePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import {
getProfileError,
getProfileIsLoading,
getProfileReadonly,
getProfileValidateErrors,
profileActions,
ProfileCard,
profileReducer
profileReducer,
validateProfileErrors
} from 'entities/Profile';
import { useAppDispatch } from 'shared/lib/hooks/useAppDispatch/useAppDispatch';
import classes from './ProfilePage.module.scss';
Expand All @@ -19,6 +21,7 @@ import { getProfileForm } from 'entities/Profile/model/selectors/getProfileForm/
import { isNumeric } from 'shared/lib/isNumeric/isNumeric';
import { TCurrency } from 'entities/Currency';
import { TCountry } from 'entities/Country';
import { Text } from 'shared/ui/Text/Text';

interface IProfilePageProps {
className?: string;
Expand All @@ -33,12 +36,13 @@ const ProfilePage = React.memo( (props: IProfilePageProps) => {
className,
} = props;

const { t } = useTranslation();
const { t } = useTranslation('profile');
const dispatch = useAppDispatch();
const formData = useSelector( getProfileForm );
const isLoading = useSelector( getProfileIsLoading );
const error = useSelector( getProfileError );
const readonly = useSelector( getProfileReadonly );
const validateErrors = useSelector( getProfileValidateErrors );

useEffect( () => {
dispatch( fetchProfileData() );
Expand Down Expand Up @@ -82,6 +86,15 @@ const ProfilePage = React.memo( (props: IProfilePageProps) => {
<DynamicModuleLoader reducers={ reducers } removeAfterUnmount>
<div className={ classNames( classes.page, {}, [ className ] ) }>
<ProfilePageHeader/>

{ validateErrors && validateErrors.length > 0 && validateErrors.map( (error) => (
<Text
key={ `profile-page-validate-error-${ error }` }
theme='error'
text={ t(validateProfileErrors[error]) }
/>
) ) }

<ProfileCard
data={ formData }
isLoading={ isLoading }
Expand Down

0 comments on commit 92279a1

Please sign in to comment.