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 Profile (split snippets and settings, issue #258) #271

Closed
wants to merge 54 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
0f8cb03
Created Snippets component
M4XPRD May 23, 2023
87e88f9
Profile route renamed
M4XPRD May 23, 2023
8b770b9
Improved CSS
M4XPRD May 23, 2023
0927165
Profile page refactoring
M4XPRD May 23, 2023
49f98bb
Account page created
M4XPRD May 23, 2023
45babfa
Improved locals
M4XPRD May 23, 2023
8fd124b
Profile route changed
M4XPRD May 23, 2023
cd5029e
Routes change and addition
M4XPRD May 23, 2023
75b6b22
Routes renamed and Links added
M4XPRD May 23, 2023
a7f4271
React scripts updated
M4XPRD May 23, 2023
9420b38
Packages updated
M4XPRD May 23, 2023
b38ac2a
Updated locales
M4XPRD May 23, 2023
f677ba5
Profile routes added
M4XPRD May 23, 2023
c62402b
Profile route from nav updated
M4XPRD May 23, 2023
ef99435
New css added for profile
M4XPRD May 23, 2023
aae1d41
Account settings in profile added
M4XPRD May 23, 2023
a186029
Profile refactoring
M4XPRD May 23, 2023
9d30ea9
Profile routes changed
M4XPRD May 23, 2023
f0d359b
Snippets in profile added
M4XPRD May 23, 2023
fee4025
Merge branch 'fix-profile' of https://github.com/M4XPRD/runit into fi…
M4XPRD May 23, 2023
0827b2d
Copy profile button commented
M4XPRD May 23, 2023
7f9cfc9
Merge branch 'hexlet-rus:main' into fix-profile
M4XPRD May 24, 2023
ed6a870
[#259] Delete copyProfileButton
NadyKamenskaya May 16, 2023
0cd68b3
[#259] Delete copyProfileButton from locales
NadyKamenskaya May 16, 2023
2f4b44c
Updated locales
M4XPRD May 23, 2023
37a807c
Profile routes added
M4XPRD May 23, 2023
cf3abf1
New css added for profile
M4XPRD May 23, 2023
0b01f18
Snippets in profile added
M4XPRD May 23, 2023
b4a468b
[#266] Set a configuration for validateOnBlur
NadyKamenskaya May 22, 2023
8f1d95d
fix
fey Apr 11, 2023
3e6f03a
add env example
fey Apr 20, 2023
c85a7a5
Copy profile button commented
M4XPRD May 23, 2023
26ac198
Merge branch 'fix-profile' of https://github.com/M4XPRD/runit into fi…
M4XPRD May 24, 2023
ff720c7
Profile CSS updated
M4XPRD May 24, 2023
3e5e56d
Profile text changes
M4XPRD May 24, 2023
fe4750d
Profile text changed + added custom CSS
M4XPRD May 24, 2023
4e13037
Profile routes added
M4XPRD May 23, 2023
e181c0f
New css added for profile
M4XPRD May 23, 2023
75e3f3f
Account settings in profile added
M4XPRD May 23, 2023
a8fadba
Copy profile button commented
M4XPRD May 23, 2023
4dfc3d5
Update files to match
NadyKamenskaya May 23, 2023
33d309a
Profile CSS updated
M4XPRD May 24, 2023
5c0e04a
Profile text changes
M4XPRD May 24, 2023
a14c9dc
Profile text changed + added custom CSS
M4XPRD May 24, 2023
ea4dd0f
Merge branch 'fix-profile' of https://github.com/M4XPRD/runit into fi…
M4XPRD May 24, 2023
ad4bae0
Profile routes added
M4XPRD May 23, 2023
d6517d3
New css added for profile
M4XPRD May 23, 2023
1e7d2d0
Account settings in profile added
M4XPRD May 23, 2023
99155c9
Profile refactoring
M4XPRD May 23, 2023
5a9430d
Copy profile button commented
M4XPRD May 23, 2023
1d05006
Profile CSS updated
M4XPRD May 24, 2023
9b7c25b
Profile text changes
M4XPRD May 24, 2023
41b4694
Profile text changed + added custom CSS
M4XPRD May 24, 2023
953673f
Merge branch 'fix-profile' of https://github.com/M4XPRD/runit into fi…
M4XPRD May 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"react-redux": "^8.0.5",
"react-router": "^6.8.1",
"react-router-dom": "^6.8.1",
"react-scripts": "5.0.1",
"react-scripts": "^5.0.1",
"sass-loader": "^13.2.0",
"web-vitals": "^3.1.1",
"xterm": "^5.1.0",
Expand Down
16 changes: 14 additions & 2 deletions frontend/src/AppRoutes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ function ProtectedRoute({ user, children }) {

function AuthRoute({ user, children }) {
if (user) {
return <Navigate to={routes.profilePagePath()} replace />;
return <Navigate to={routes.defaultProfilePagePath()} replace />;
return <Navigate to={routes.defaultProfilePagePath()} replace />;
}
return children || <Outlet />;
}
Expand All @@ -42,7 +43,18 @@ function AppRoutes() {
<Route path={routes.snippetPagePath()} element={<App />} />
<Route path={routes.aboutPagePath()} element={<About />} />
<Route element={<ProtectedRoute user={isLoggedIn} />}>
<Route path={routes.profilePagePath()} element={<Profile />} />
<Route
path={routes.profilePagePath()}
element={<Profile />}
/>
<Route
path={routes.defaultProfilePagePath()}
element={<Profile />}
/>
<Route
path={routes.profileSettingsPagePath()}
element={<Profile />}
/>
</Route>
<Route element={<AuthRoute user={isLoggedIn} />}>
<Route path={routes.signUpPagePath()} element={<SignUp />} />
Expand Down
102 changes: 102 additions & 0 deletions frontend/src/Pages/AccountSettings.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React from 'react';
import { Col, Button } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { actions as modalActions } from '../slices/modalSlice.js';
import classes from './Profile.module.css';

const AccountSettings = () => {
const { t } = useTranslation();
const dispatch = useDispatch();
const userInfo = useSelector((state) => state.user.userInfo);

const parseDate = (date) => {
try {
return new Intl.DateTimeFormat().format(new Date(date));
} catch {
return t('profile.successfulLoading');
}
};

const handleEditProfile = () => {
dispatch(
modalActions.openModal({
type: 'editProfile',
item: userInfo,
}),
);
};

const handleChangePassword = () => {
dispatch(
modalActions.openModal({
type: 'changePassword',
item: { id: userInfo.id },
}),
);
};

return (
<Col className={`col-md-3 px-2 rounded ${classes.profileColumn}`}>
<div className={`w-100 ${classes.profile}`}>
<div>
<h1 className="my-2" style={{ textAlign: 'center' }}>{userInfo.login}</h1>
<div style={{ paddingTop: '10px' }}>
<h5 className="my-2">
{t('profile.email')}
<span className="text-muted"> {userInfo.email}</span>
</h5>
<h5 className="my-2">
{t('profile.createdAt')}
<span className="text-muted">
{' '}
{parseDate(userInfo.created_at)}
</span>
</h5>
</div>
{/* <div>
{`${t('profile.email')} `}
<span className="text-muted">{userInfo.email}</span>
</div> */}
{/* "userdata.created_at", "userdata.id" are also available. Add if needed. */}
</div>
<div className={`${classes.profileButtons}`}>
<Button className={`${classes.button}`} onClick={handleEditProfile}>
<div>
<span>{t('profile.editProfileButton')}</span>
</div>
</Button>
{/* Кнопка скопировать ниже закомментирована*/}
{/* <Button
className={`${classes.button}`}
onClick={() => {
navigator.clipboard.writeText(window.location.href);
}}
>
<div>
<span>{t('profile.copyProfileButton')} </span>
</div>
</Button> */}
<Button
className={`${classes.button}`}
onClick={handleChangePassword}
>
<div>
<span>{t('modals.changePassword.header')}</span>
</div>
</Button>
</div>
<div className="gap" style={{ marginBottom: 'auto' }} />
<div
className="d-flex flex-md-column w-100"
style={{ alignItems: 'center' }}
>
{/* <span>{t('profile.createdAt')}</span>
<span>{parseDate(userInfo.created_at)}</span> */}
</div>
</div>
</Col>
);
};

export default AccountSettings;
157 changes: 59 additions & 98 deletions frontend/src/Pages/Profile.jsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,25 @@
import React, { useEffect } from 'react';
import { Row, Col, Button } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { actions as modalActions } from '../slices/modalSlice.js';
import { actions as editorActions } from '../slices/editorSlice.js';
import { useDispatch } from 'react-redux';
import { useDispatch } from 'react-redux';
import { fetchData } from '../slices/userSlice.js';
import classes from './Profile.module.css';
import Snippet from '../components/Snippet/Snippet.jsx';
import Snippets from './Snippets.jsx';
import { Link, useLocation } from 'react-router-dom';
import routes from '../routes.js';
import AccountSettings from './AccountSettings.jsx';
import Snippets from './Snippets.jsx';
import { Link, useLocation } from 'react-router-dom';
import routes from '../routes.js';
import AccountSettings from './AccountSettings.jsx';

function Profile() {
const Profile = () => {
const Profile = () => {
const { t } = useTranslation();
const dispatch = useDispatch();
const userInfo = useSelector((state) => state.user.userInfo);
const snippets = useSelector((state) => state.snippets.snippets);

const parseDate = (date) => {
try {
return new Intl.DateTimeFormat().format(new Date(date));
} catch {
return t('profile.successfulLoading');
}
};

const handleEditProfile = () => {
dispatch(
modalActions.openModal({
type: 'editProfile',
item: userInfo,
}),
);
};

const handleChangePassword = () => {
dispatch(
modalActions.openModal({
type: 'changePassword',
item: { id: userInfo.id },
}),
);
};

const handleGenNewRepl = () => {
dispatch(editorActions.resetCode());
dispatch(modalActions.openModal({ type: 'genNewRepl' }));
};
const location = useLocation();
const location = useLocation();

useEffect(() => {
dispatch(fetchData())
Expand All @@ -63,79 +39,64 @@ function Profile() {
<Col className={`col-md-3 px-2 rounded ${classes.profileColumn}`}>
<div className={`w-100 ${classes.profile}`}>
<div>
<h1 className="my-2">{userInfo.login}</h1>
<div>
{`${t('profile.email')} `}
<span className="text-muted">{userInfo.email}</span>
</div>
<h1 className="my-2" style={{ textAlign: 'center' }}>{`${t('navbar.profile')}`}</h1>
{/* <div>
Текст:
<span className="text-muted">описание</span>
</div> */}
{/* "userdata.created_at", "userdata.id" are also available. Add if needed. */}
</div>
<div className={`${classes.profileButtons}`}>
<Button
className={`${classes.button}`}
onClick={handleEditProfile}
>
<div>
<span>{t('profile.editProfileButton')}</span>
</div>
</Button>
</div>
<Button
className={`${classes.button}`}
onClick={handleChangePassword}
>
<div>
<span>{t('modals.changePassword.header')}</span>
<Link as={Link} to={routes.profileSettingsPagePath()}>
<Button className={`${classes.button}`}>
<div>
<span>{`${t('profile.settingsHeader')}`}</span>
</div>
</Button>
</Link>
</div>
</Button>
<div className="gap" style={{ marginBottom: 'auto' }} />
<div
className="d-flex flex-md-column w-100"
style={{ alignItems: 'center' }}
>
<span>{t('profile.createdAt')}</span>
<span>{parseDate(userInfo.created_at)}</span>
</div>
</div>
</Col>
<Col className={`rounded w-100 ${classes.replsCol}`}>
<div
className={`w-100 h-100 d-flex flex-column ${classes.repls}`}
style={{ paddingTop: '30px' }}
>
<Row
className="my-2 flex-md-row"
style={{ borderBottom: '1px solid #293746' }}
>
<div className="d-flex justify-content-between align-items-center flex-md-row w-100">
<h2>{t('profile.replsHeader')}</h2>
<div className={`${classes.newRepl}`}>
<div>
<Link as={Link} to={routes.defaultProfilePagePath()}>
<Button
className={`${classes.newReplButton}`}
onClick={handleGenNewRepl}
className={`${classes.button}`}
onClick={() => {
navigator.clipboard.writeText(window.location.href);
}}
>
{t('profile.newReplButton')}
<div>
<span>{`${t('profile.replsHeader')}`}</span>
</div>
</Button>
</div>
</Link>
</div>
</Row>
<Row xs={1} md={2} className="g-4 my-1">
{snippets.map(({ id, slug, name, code }) => (
<Snippet
key={id}
id={id}
slug={slug}
name={name}
code={code}
/>
))}
</Row>
</div>
</div>
<div className="gap" style={{ marginBottom: 'auto' }} />
<div
className="d-flex flex-md-column w-100"
style={{ alignItems: 'center' }}
></div>
></div>
</div>
</Col>
{location.pathname === routes.defaultProfilePagePath() && (
<Snippets />
)}
{location.pathname === routes.profileSettingsPagePath() && (
<AccountSettings />
)}
{location.pathname === routes.defaultProfilePagePath() && (
<Snippets />
)}
{location.pathname === routes.profileSettingsPagePath() && (
<AccountSettings />
)}
</Row>
</div>
</div>
);
}
};
};

export default Profile;
export default Profile;