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

[FEATURE] Settings Edit Main Profile Page #448 #457

Merged
merged 3 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import AuthRoute from "./pages/AuthRoute";
import SecurityRoutes from "./components/Other/Security/SecurityRoutes";
import ExploreRoutes from "./components/Explore/ExploreRoutes";
import Leaderboard from "./components/Other/CyberGames/Leaderboard/Leaderboard";
import SettingsRoute from "./components/Dashboard/Settings";

const App = () => {
const [isLoading, setIsLoading] = useState(true);
Expand Down Expand Up @@ -117,6 +118,8 @@ const App = () => {

<Route path={"/security/*"} element={<SecurityRoutes />} />

<Route path={"/dashboard/settings/*"} element={<SettingsRoute />} />

<Route path={"/dashboard/*"} element={<DashboardRoute />} />

<Route exact path={"/contact"} element={<ContactForm />} />
Expand Down
5 changes: 5 additions & 0 deletions src/components/Dashboard/Settings/Account/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "react";

export default function Account() {
return <section style={{ width: "100%" }}>Account</section>;
}
5 changes: 5 additions & 0 deletions src/components/Dashboard/Settings/Appearance/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "react";

export default function Appearance() {
return <section style={{ width: "100%" }}>Appearance</section>;
}
5 changes: 5 additions & 0 deletions src/components/Dashboard/Settings/Display/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "react";

export default function Display() {
return <section style={{ width: "100%" }}>Display</section>;
}
5 changes: 5 additions & 0 deletions src/components/Dashboard/Settings/Notifications/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "react";

export default function Notifications() {
return <section style={{ width: "100%" }}>Notification</section>;
}
101 changes: 101 additions & 0 deletions src/components/Dashboard/Settings/Profile/ProfileForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React, { useState } from "react";
import { validateEmail } from "../../../../utils/validateEmail";
import { useSelector } from "react-redux";

export default function SettingsForm() {
const { username: reduxUsername, email: reduxEmail } = useSelector((state) => state.auth).user;
const [username, setUsername] = useState({
value: reduxUsername,
error: "",
});
const [password, setPassword] = useState({
value: "",
error: "",
});
const [email, setEmail] = useState({
value: reduxEmail,
error: "",
});
const disabled = username.value === reduxUsername && email.value === reduxEmail;

function handleChange(e, setState) {
setState(() => ({
value: e.target.value,
error: "",
}));
}

function handleSubmit(e) {
e.preventDefault();

if (!username.value)
return setUsername((curr) => ({
...curr,
error: "Username required!",
}));

if (!password.value)
return setPassword((curr) => ({
...curr,
error: "Password required!",
}));

// used to test a valid email address
if (!validateEmail(email.value))
return setEmail((curr) => ({
...curr,
error: "Email required!",
}));

console.log("new username: ", username.value);
console.log("new password: ", password.value);
console.log("new email: ", email.value);
}

return (
<form onSubmit={handleSubmit} className="settings-profile-form">
<div className="settings-profile-input-wrapper">
<label htmlFor="username">Username</label>
<br />
<input
type="text"
value={username.value}
id="username"
name="username"
placeholder="Your cool username"
onChange={(e) => handleChange(e, setUsername)}
/>
{username.error && <p className="profile-error">{username.error}</p>}
</div>
<div className="settings-profile-input-wrapper">
<label htmlFor="password">Password</label>
<br />
<input
type="text"
value={password.value}
id="password"
name="password"
placeholder="Your awesome password"
onChange={(e) => handleChange(e, setPassword)}
/>
{password.error && <p className="profile-error">{password.error}</p>}
</div>
<div className="settings-profile-input-wrapper">
<label htmlFor="email">Email</label>
<br />
<input
type="text"
value={email.value}
id="email"
name="email"
placeholder="Your email"
onChange={(e) => handleChange(e, setEmail)}
/>
{email.error && <p className="profile-error">{email.error}</p>}
</div>
<button type="submit" className="settings-profile-form-submitbtn" disabled={disabled}>
Submit
</button>
</form>
);
}
19 changes: 19 additions & 0 deletions src/components/Dashboard/Settings/Profile/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";
import SettingsForm from "./ProfileForm";
import "./profile.css";

export default function Proofile() {
return (
<section style={{ width: "100%" }}>
<div>
<div className="settings-profile">
<h3 className="profile-heading">Profile</h3>
<p className="profile-info">This is how others will see you on the site.</p>
</div>
<div>
<SettingsForm />
</div>
</div>
</section>
);
}
78 changes: 78 additions & 0 deletions src/components/Dashboard/Settings/Profile/profile.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
.settings-profile {
border-bottom: 1px solid #27272a;
max-width: 672px;
padding-block: 1em;
}

.profile-heading {
margin-bottom: 0;
}

.profile-info {
font-size: 14px;
color: #a1a1a1;
}

.settings-profile-form {
padding: 1.75em 0;
max-width: 672px;
}

.settings-profile-input-wrapper {
margin-bottom: 1em;
}

.settings-profile-form input {
background-color: #000000;
outline: none;
border: 1px solid #27272a;
height: 40px;
padding-inline-start: 1em;
border-radius: 6px;
letter-spacing: 0.7px;
color: #ffffff;
width: 100%;
margin-top: 0.5em;
transition: 300ms;
}

.settings-profile-form input:is(:hover, :focus) {
border: 1px solid #ffffff;
}

.settings-profile-form input::placeholder {
color: #a1a1a1;
}

.profile-error {
color: red;
font-size: 12px;
padding-top: 0.4em;
padding-left: 0.4em;
}

.settings-profile-form-submitbtn {
background-color: #ff6b08;
color: #000000;
font-family: Roboto, sans-serif;
width: 100%;
height: 40px;
border-radius: 6px;
border: 2px solid #ff6b08;
transition: 300ms;
font-weight: 500;
font-size: 16px;
}

.settings-profile-form-submitbtn:is(:hover, :focus) {
background-color: #000000;
color: #ff6b08;
cursor: pointer;
}

.settings-profile-form-submitbtn:disabled {
opacity: 0.7;
cursor: not-allowed;
background-color: #ff6b08;
color: #000000;
}
46 changes: 46 additions & 0 deletions src/components/Dashboard/Settings/SettingsSidebar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from "react";
import { Link, useLocation } from "react-router-dom";

const SIDEBAR_LINKS = [
{
id: 1,
label: "Profile",
href: "/dashboard/settings/profile",
},
{
id: 2,
label: "Account",
href: "/dashboard/settings/account",
},
{
id: 3,
label: "Appearance",
href: "/dashboard/settings/appearance",
},
{
id: 4,
label: "Notifications",
href: "/dashboard/settings/notifications",
},
{
id: 5,
label: "Display",
href: "/dashboard/settings/display",
},
];

export default function Sidebar() {
const { pathname } = useLocation();

return (
<article className="settings-sidebar-wrapper">
{SIDEBAR_LINKS.map(({ id, label, href }) => {
return (
<Link key={id} to={href} className={`${pathname === href ? "active" : ""}`}>
{label}
</Link>
);
})}
</article>
);
}
34 changes: 34 additions & 0 deletions src/components/Dashboard/Settings/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from "react";
import { Route, Routes } from "react-router-dom";
import Profile from "./Profile";
import Sidebar from "./SettingsSidebar";
import "./settings.css";
import Account from "./Account";
import Appearance from "./Appearance";
import Notifications from "./Notifications";
import Display from "./Display";
import NotFound from "../../../NotFound";

export default function SettingsRoute() {
return (
<section>
<div className="settings-wrapper">
<div className="settings-header">
<h2 className="settings-header-h2">Settings</h2>
<p className="settings-header-info">Manage your account settings and set e-mail preferences.</p>
</div>
<div className="settings-profile-wrapper">
<Sidebar />
<Routes>
<Route path={"profile"} element={<Profile />} />
<Route path={"account"} element={<Account />} />
<Route path={"appearance"} element={<Appearance />} />
<Route path={"notifications"} element={<Notifications />} />
<Route path={"display"} element={<Display />} />
<Route path={"*"} element={<NotFound />} />
</Routes>
</div>
</div>
</section>
);
}
58 changes: 58 additions & 0 deletions src/components/Dashboard/Settings/settings.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.settings-wrapper {
color: #f5f5f5;
width: 95%;
margin-inline: auto;
}

.settings-header {
padding: 2.5em 0 1.5em;
border-bottom: 1px solid #27272a;
}

.settings-header-h2 {
font-size: 34px;
margin-bottom: 0;
}

.settings-header-info {
font-size: 14px;
color: #a1a1a1;
}

.settings-profile-wrapper {
margin-left: 0.5em;
margin-top: 1em;
display: flex;
align-items: start;
justify-content: start;
gap: 2em;
}

.settings-sidebar-wrapper {
display: flex;
align-items: start;
justify-content: center;
flex-direction: column;
width: 100%;
max-width: 250px;
}

.settings-sidebar-wrapper a {
color: #ffffff;
padding: 0.5em 1em;
display: block;
width: 100%;
border-radius: 6px;
}

.settings-sidebar-wrapper a.active {
background-color: #27272a;
}

.settings-sidebar-wrapper a.active:is(:hover, :focus) {
text-decoration: none;
}

.settings-sidebar-wrapper a:is(:hover, :focus) {
text-decoration: underline;
}
Loading