Skip to content

Commit 7647510

Browse files
committed
add finished dashboard
1 parent ab43cdb commit 7647510

34 files changed

+3578
-11
lines changed

03-dashboard/.gitignore

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env.local
29+
.env.development.local
30+
.env.test.local
31+
.env.production.local
32+
33+
# vercel
34+
.vercel
35+
36+
# vscode
37+
.vscode

03-dashboard/README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Dashboard
2+
3+
...
4+
5+
<p align="center">
6+
<img src="screenshot.png">
7+
</p>
8+
9+
## Features
10+
11+
- ...
12+
13+
Based on [NextJS & React - The Complete Guide](https://www.udemy.com/course/nextjs-react-the-complete-guide/) by Maximilian Schwarzmüller (2021).
+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { useState, useRef } from "react";
2+
import { signIn } from "next-auth/client";
3+
import { useRouter } from "next/router";
4+
5+
import classes from "./auth-form.module.css";
6+
7+
async function createUser(email, password) {
8+
const response = await fetch("/api/auth/signup", {
9+
method: "POST",
10+
body: JSON.stringify({ email, password }),
11+
headers: { "Content-Type": "application/json" },
12+
});
13+
const data = await response.json();
14+
if (!response.ok) {
15+
throw new Error(data.message || "Something went wrong!");
16+
}
17+
return data;
18+
}
19+
20+
function AuthForm() {
21+
const router = useRouter();
22+
const emailInputRef = useRef();
23+
const passwordInputRef = useRef();
24+
const [isLogin, setIsLogin] = useState(true);
25+
26+
function switchAuthModeHandler() {
27+
setIsLogin((prevState) => !prevState);
28+
}
29+
30+
async function submitHandler(event) {
31+
event.preventDefault();
32+
const enteredEmail = emailInputRef.current.value;
33+
const enteredPassword = passwordInputRef.current.value;
34+
if (isLogin) {
35+
const result = await signIn("credentials", {
36+
redirect: false,
37+
email: enteredEmail,
38+
password: enteredPassword,
39+
});
40+
if (!result.error) {
41+
router.replace("/profile");
42+
}
43+
} else {
44+
try {
45+
const result = await createUser(enteredEmail, enteredPassword);
46+
console.log(result);
47+
} catch (error) {
48+
console.log(error);
49+
}
50+
}
51+
}
52+
53+
return (
54+
<section className={classes.auth}>
55+
<h1>{isLogin ? "Login" : "Sign Up"}</h1>
56+
<form onSubmit={submitHandler}>
57+
<div className={classes.control}>
58+
<label htmlFor="email">Your Email</label>
59+
<input type="email" id="email" required ref={emailInputRef} />
60+
</div>
61+
<div className={classes.control}>
62+
<label htmlFor="password">Your Password</label>
63+
<input
64+
type="password"
65+
id="password"
66+
required
67+
ref={passwordInputRef}
68+
/>
69+
</div>
70+
<div className={classes.actions}>
71+
<button>{isLogin ? "Login" : "Create Account"}</button>
72+
<button
73+
type="button"
74+
className={classes.toggle}
75+
onClick={switchAuthModeHandler}
76+
>
77+
{isLogin ? "Create new account" : "Login with existing account"}
78+
</button>
79+
</div>
80+
</form>
81+
</section>
82+
);
83+
}
84+
85+
export default AuthForm;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
.auth {
2+
margin: 3rem auto;
3+
width: 95%;
4+
max-width: 25rem;
5+
border-radius: 6px;
6+
background-color: #38015c;
7+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
8+
padding: 1rem;
9+
text-align: center;
10+
}
11+
12+
.auth h1 {
13+
text-align: center;
14+
color: white;
15+
}
16+
17+
.control {
18+
margin-bottom: 0.5rem;
19+
}
20+
21+
.control label {
22+
display: block;
23+
color: white;
24+
font-weight: bold;
25+
margin-bottom: 0.5rem;
26+
}
27+
28+
.control input {
29+
font: inherit;
30+
background-color: #f1e1fc;
31+
color: #38015c;
32+
border-radius: 4px;
33+
border: 1px solid white;
34+
width: 100%;
35+
text-align: left;
36+
padding: 0.25rem;
37+
}
38+
39+
.actions {
40+
margin-top: 1.5rem;
41+
display: flex;
42+
flex-direction: column;
43+
align-items: center;
44+
}
45+
46+
.actions button {
47+
cursor: pointer;
48+
font: inherit;
49+
color: white;
50+
background-color: #9f5ccc;
51+
border: 1px solid #9f5ccc;
52+
border-radius: 4px;
53+
padding: 0.5rem 2.5rem;
54+
}
55+
56+
.actions button:hover {
57+
background-color: #873abb;
58+
border-color: #873abb;
59+
}
60+
61+
.actions .toggle {
62+
margin-top: 1rem;
63+
background-color: transparent;
64+
color: #9f5ccc;
65+
border: none;
66+
padding: 0.15rem 1.5rem;
67+
}
68+
69+
.actions .toggle:hover {
70+
background-color: transparent;
71+
color: #ae82cc;
72+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Fragment } from 'react';
2+
3+
import MainNavigation from './main-navigation';
4+
5+
function Layout(props) {
6+
return (
7+
<Fragment>
8+
<MainNavigation />
9+
<main>{props.children}</main>
10+
</Fragment>
11+
);
12+
}
13+
14+
export default Layout;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import Link from "next/link";
2+
import { useSession, signOut } from "next-auth/client";
3+
4+
import classes from "./main-navigation.module.css";
5+
6+
function MainNavigation() {
7+
const [session, loading] = useSession();
8+
9+
function logoutHandler() {
10+
signOut();
11+
}
12+
return (
13+
<header className={classes.header}>
14+
<Link href="/">
15+
<a>
16+
<div className={classes.logo}>Dashboard</div>
17+
</a>
18+
</Link>
19+
<nav>
20+
<ul>
21+
{!session && !loading && (
22+
<li>
23+
<Link href="/auth">Login</Link>
24+
</li>
25+
)}
26+
{session && (
27+
<li>
28+
<Link href="/profile">Profile</Link>
29+
</li>
30+
)}
31+
{session && (
32+
<li>
33+
<button onClick={logoutHandler}>Logout</button>
34+
</li>
35+
)}
36+
</ul>
37+
</nav>
38+
</header>
39+
);
40+
}
41+
42+
export default MainNavigation;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
.header {
2+
width: 100%;
3+
height: 5rem;
4+
background-color: #38015c;
5+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
6+
display: flex;
7+
justify-content: space-between;
8+
align-items: center;
9+
padding: 0 10%;
10+
}
11+
12+
.logo {
13+
font-family: 'Lato', sans-serif;
14+
font-size: 2rem;
15+
color: white;
16+
margin: 0;
17+
}
18+
19+
.header ul {
20+
list-style: none;
21+
margin: 0;
22+
padding: 0;
23+
display: flex;
24+
align-items: baseline;
25+
}
26+
27+
.header li {
28+
margin: 0 1rem;
29+
}
30+
31+
.header a {
32+
text-decoration: none;
33+
color: white;
34+
font-weight: bold;
35+
}
36+
37+
.header button {
38+
font: inherit;
39+
background-color: transparent;
40+
border: 1px solid white;
41+
color: white;
42+
font-weight: bold;
43+
padding: 0.5rem 1.5rem;
44+
border-radius: 6px;
45+
cursor: pointer;
46+
}
47+
48+
.header a:hover {
49+
color: #c291e2;
50+
}
51+
52+
.header button:hover {
53+
background-color: #c291e2;
54+
color: #38015c;
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { useRef } from "react";
2+
3+
import classes from "./profile-form.module.css";
4+
5+
function ProfileForm(props) {
6+
const oldPasswordRef = useRef();
7+
const newPasswordRef = useRef();
8+
function submitHandler(event) {
9+
event.preventDefault();
10+
const enteredOldPassword = oldPasswordRef.current.value;
11+
const enteredNewPassword = newPasswordRef.current.value;
12+
props.onChangePassword({
13+
oldPassword: enteredOldPassword,
14+
newPassword: enteredNewPassword,
15+
});
16+
}
17+
return (
18+
<form className={classes.form} onSubmit={submitHandler}>
19+
<div className={classes.control}>
20+
<label htmlFor="new-password">New Password</label>
21+
<input type="password" id="new-password" ref={newPasswordRef} />
22+
</div>
23+
<div className={classes.control}>
24+
<label htmlFor="old-password">Old Password</label>
25+
<input type="password" id="old-password" ref={oldPasswordRef} />
26+
</div>
27+
<div className={classes.action}>
28+
<button>Change Password</button>
29+
</div>
30+
</form>
31+
);
32+
}
33+
34+
export default ProfileForm;

0 commit comments

Comments
 (0)