Skip to content

Commit

Permalink
feat: add profile page card / get profile data thunk
Browse files Browse the repository at this point in the history
  • Loading branch information
TomatoVan committed Nov 29, 2023
1 parent 27893e1 commit 1076368
Show file tree
Hide file tree
Showing 14 changed files with 141 additions and 6 deletions.
7 changes: 7 additions & 0 deletions extractedTranslations/en/profile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"Edit": "",
"Profile": "",
"Your lastname": "",
"Your name": "",
"Your surname": ""
}
Empty file added public/locales/en/profile.json
Empty file.
Empty file added public/locales/ru/profile.json
Empty file.
2 changes: 2 additions & 0 deletions src/entities/Profile/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export { Profile, ProfileSchema } from './model/types/profile';

export { profileActions, profileReducer } from './model/slice/profileSlice';
export { fetchProfileData } from './model/services/fetchProfileData/fetchProfileData';
export { ProfileCard } from '../Profile/ui/ProfileCard/ProfileCard';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { StateSchema } from 'app/providers/StoreProvider';

export const getProfileData = (state: StateSchema) => state.profile?.data;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { StateSchema } from 'app/providers/StoreProvider';

export const getProfileError = (state: StateSchema) => state.profile?.error;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { StateSchema } from 'app/providers/StoreProvider';

export const getProfileIsLoading = (state: StateSchema) => state.profile?.isLoading;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import { ThunkConfig } from 'app/providers/StoreProvider';
import { Profile } from '../../types/profile';

export const fetchProfileData = createAsyncThunk<
Profile,
void,
ThunkConfig<string>
>('profile/fetchProfileData', async (_, thunkAPI) => {
const { extra, rejectWithValue } = thunkAPI;

try {
const response = await extra.api.get<Profile>('/profile');

return response.data;
} catch (error) {
return rejectWithValue('error');
}
});
23 changes: 21 additions & 2 deletions src/entities/Profile/model/slice/profileSlice.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createSlice } from '@reduxjs/toolkit';
import { ProfileSchema } from '../types/profile';
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { fetchProfileData } from '../services/fetchProfileData/fetchProfileData';
import { Profile, ProfileSchema } from '../types/profile';

const initialState: ProfileSchema = {
readonly: true,
Expand All @@ -12,6 +13,24 @@ export const profileSlice = createSlice({
name: 'profile',
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchProfileData.pending, (state) => {
state.error = undefined;
state.isLoading = true;
})
.addCase(
fetchProfileData.fulfilled,
(state, action: PayloadAction<Profile>) => {
state.isLoading = false;
state.data = action.payload;
},
)
.addCase(fetchProfileData.rejected, (state, action) => {
state.isLoading = false;
state.error = action.payload;
});
},
});

export const { actions: profileActions } = profileSlice;
Expand Down
21 changes: 21 additions & 0 deletions src/entities/Profile/ui/ProfileCard/ProfileCard.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.ProfileCard {
padding: 20px;
border: 2px solid var(--inverted-bg-color);
}

.header {
display: flex;
}

.editBtn {
margin-left: auto;
}

.data {
margin-top: 30px;
}

.input {
margin-top: 10px;
}

46 changes: 46 additions & 0 deletions src/entities/Profile/ui/ProfileCard/ProfileCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { classNames } from 'shared/lib/classNames/classNames';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { Text } from 'shared/ui/Text/Text';
import { Button, ButtonTheme } from 'shared/ui/Button/Button';
import { Input } from 'shared/ui/Input/Input';
import { getProfileIsLoading } from '../../model/selectors/getProfileIsLoading/getProfileIsLoading';
import { getProfileError } from '../../model/selectors/getProfileError/getProfileError';
import { getProfileData } from '../../model/selectors/getProfileData/getProfileData';
import cls from './ProfileCard.module.scss';

interface ProfileCardProps {
className?: string;
}

export const ProfileCard = ({ className }: ProfileCardProps) => {
const { t } = useTranslation('profile');
const data = useSelector(getProfileData);
const isLoading = useSelector(getProfileIsLoading);
const error = useSelector(getProfileError);
return (
<div className={classNames(cls.ProfileCard, {}, [className])}>
<div className={cls.header}>
<Text title={t('Profile')} />
<Button
className={cls.editBtn}
theme={ButtonTheme.OUTLINE}
>
{t('Edit')}
</Button>
</div>
<div className={cls.data}>
<Input
value={data?.first}
placeholder={t('Your name')}
className={cls.input}
/>
<Input
value={data?.lastname}
placeholder={t('Your lastname')}
className={cls.input}
/>
</div>
</div>
);
};
13 changes: 10 additions & 3 deletions src/pages/ProfilePage/ui/ProfilePage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { classNames } from 'shared/lib/classNames/classNames';
import { useTranslation } from 'react-i18next';
import { memo } from 'react';
import { memo, useEffect } from 'react';
import { DynamicModuleLoader, ReducersList } from 'shared/lib/components/DynamicModuleLoared/DynamicModuleLoared';
import { profileReducer } from '../../../entities/Profile';
import { fetchProfileData, ProfileCard, profileReducer } from '../../../entities/Profile';
import { useAppDispatch } from '../../../shared/lib/hook/useAppDispatch/useAppDispatch';

const reducers: ReducersList = {
profile: profileReducer,
Expand All @@ -14,10 +15,16 @@ interface ProfilePageProps {

const ProfilePage = memo(({ className }: ProfilePageProps) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();

useEffect(() => {
dispatch(fetchProfileData());
}, [dispatch]);

return (
<DynamicModuleLoader reducers={reducers} removeAfterUnmount>
<div className={classNames('', {}, [className])}>
{t('PROFILE PAGE')}
<ProfileCard />
</div>
</DynamicModuleLoader>

Expand Down
6 changes: 5 additions & 1 deletion src/shared/lib/classNames/classNames.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
type Mods = Record<string, boolean | string>

export function classNames(cls: string, mods: Mods = {}, additional: string[] = []): string {
export function classNames(
cls: string,
mods: Mods = {},
additional: Array<string | undefined> = [],
): string {
return [
cls,
...additional.filter(Boolean),
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"moduleResolution": "node",
// Для абсолютного импорта
"baseUrl": ".",
"strict": true,
"paths": {
"*": ["./src/*"]
},
Expand Down

0 comments on commit 1076368

Please sign in to comment.