Commit 9c4b08df authored by Nawasan Wisitsingkhon's avatar Nawasan Wisitsingkhon

finish state: login front and back;

parent 69925dae
...@@ -3,5 +3,5 @@ ...@@ -3,5 +3,5 @@
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings # See the documentation for all the connection string options: https://pris.ly/d/connection-strings
JWT_TOKEN=
DATABASE_URL="mysql://<username>:<password>@localhost:3306/<db_name>?schema=public" DATABASE_URL="mysql://<username>:<password>@localhost:3306/<db_name>?schema=public"
\ No newline at end of file
import { Request, Response } from "express"; import { Request, Response } from "express";
import { SHA1 } from "crypto-js"; import { SHA1 } from "crypto-js";
import db from "../models/prismaClient"; import db from "../models/prismaClient";
import { JwtGenerate } from "@/components/lib/jwttoken";
const UserController = { const UserController = {
/** /**
...@@ -62,6 +63,44 @@ const UserController = { ...@@ -62,6 +63,44 @@ const UserController = {
}); });
} }
}, },
/**
*
* @param {Request} req
* @param {Response} res
*/
async login(req, res) {
try {
let { username, password } = req.body;
if (!(username && password)) throw 202;
password = SHA1(password).toString();
let user = await db.user.findFirst({
where: { AND: { username } },
});
if (!user) throw 203;
if (user.password !== password) throw 203;
let token = JwtGenerate({
id: user.id,
name: user.name,
email: user.email,
phone: user.phone,
photo: user.photo,
username: user.username,
rank: user.rank,
});
return res.json({ status: 201, token, message: "login success" });
} catch (err) {
if (err === 203)
return res.json({
status: 203,
message: "usrname or password is wrong",
});
else if (err === 202)
res.json({ status: 202, message: "error data emty", req: req.body });
else {
res.json({ status: 200, err, message: "error something" });
}
}
},
}; };
export default UserController; export default UserController;
...@@ -5,6 +5,7 @@ const route = express.Router(); ...@@ -5,6 +5,7 @@ const route = express.Router();
route.get("/", WelcomeController.index); route.get("/", WelcomeController.index);
route.post("/user/auth", UserController.login);
route.post("/user", UserController.create); route.post("/user", UserController.create);
route.get("/user", (req, res) => { route.get("/user", (req, res) => {
res.json({ res.json({
......
...@@ -13,17 +13,11 @@ import Menu from "@mui/material/Menu"; ...@@ -13,17 +13,11 @@ import Menu from "@mui/material/Menu";
import MenuIcon from "@mui/icons-material/Menu"; import MenuIcon from "@mui/icons-material/Menu";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import AccountCircle from "@mui/icons-material/AccountCircle"; import AccountCircle from "@mui/icons-material/AccountCircle";
import MailIcon from "@mui/icons-material/Mail";
import { Divider } from "@mui/material";
import List from "@mui/material/List";
import { ListItem } from "@mui/material";
import { ListItemButton } from "@mui/material";
import { ListItemIcon } from "@mui/material";
import InboxIcon from "@mui/icons-material/MoveToInbox";
import ListItemText from "@mui/material/ListItemText";
import ShoppingCart from "@mui/icons-material/ShoppingCart"; import ShoppingCart from "@mui/icons-material/ShoppingCart";
import { UserContext } from "@/pages/_app"; import { UserContext } from "@/pages/_app";
import Link from "next/link"; import Link from "next/link";
import { Favorite } from "@mui/icons-material";
import { Logout } from "@mui/icons-material";
const Search = styled("div")(({ theme }) => ({ const Search = styled("div")(({ theme }) => ({
position: "relative", position: "relative",
...@@ -65,26 +59,6 @@ const StyledInputBase = styled(InputBase)(({ theme }) => ({ ...@@ -65,26 +59,6 @@ const StyledInputBase = styled(InputBase)(({ theme }) => ({
}, },
})); }));
const drawer = (
<div>
<Toolbar />
<Divider />
<List>
{["Inbox", "Starred", "Send email", "Drafts"].map((text, index) => (
<ListItem key={index} disablePadding>
<ListItemButton>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItemButton>
</ListItem>
))}
</List>
{/* <Divider /> */}
</div>
);
function Navbar(props) { function Navbar(props) {
const user = useContext(UserContext); const user = useContext(UserContext);
const { window } = props; const { window } = props;
...@@ -143,7 +117,21 @@ function Navbar(props) { ...@@ -143,7 +117,21 @@ function Navbar(props) {
const MenuList = user?.value?.name const MenuList = user?.value?.name
? [ ? [
{ {
id: 0, label: "สินค้าที่ชอบ",
link: "/wishlist",
element: (
<IconButton
size="large"
aria-label="show 4 new mails"
color="inherit"
>
<Badge badgeContent={4} color="error">
<Favorite />
</Badge>
</IconButton>
),
},
{
label: "ตระกร้า", label: "ตระกร้า",
link: "/cart", link: "/cart",
element: ( element: (
...@@ -159,8 +147,7 @@ function Navbar(props) { ...@@ -159,8 +147,7 @@ function Navbar(props) {
), ),
}, },
{ {
id: 1, label: user.value.name,
label: "โปรไฟล์",
link: "/profile", link: "/profile",
element: ( element: (
<IconButton <IconButton
...@@ -175,15 +162,39 @@ function Navbar(props) { ...@@ -175,15 +162,39 @@ function Navbar(props) {
</IconButton> </IconButton>
), ),
}, },
{
label: "ออกจากระบบ",
link: "/logout",
element: (
<IconButton
size="large"
aria-label="show 4 new mails"
color="inherit"
>
<Badge color="error">
<Logout />
</Badge>
</IconButton>
),
},
] ]
: [ : [
{ {
id: 0, id: 0,
label: "Register", label: "Register",
element: <span className="inline-block mx-3 hover:underline">Register</span>, element: (
<span className="inline-block mx-3 hover:underline">Register</span>
),
link: "/register", link: "/register",
}, },
{ id: 1, lable: "Login", element: <span className="inline-block mx-3 hover:underline">Login</span>, link: "/login" }, {
id: 1,
lable: "Login",
element: (
<span className="inline-block mx-3 hover:underline">Login</span>
),
link: "/login",
},
]; ];
const mobileMenuId = "primary-search-account-menu-mobile"; const mobileMenuId = "primary-search-account-menu-mobile";
......
import jwt from "jsonwebtoken";
/**
*
* @param {{id: number, name: string, email: string, phone: string, photo: string, username: string }} data
*/
export const JwtGenerate = (data) => {
let token = jwt.sign(data, process.env.JWT_TOKEN, { algorithm: "HS256" });
return token;
};
...@@ -7,6 +7,12 @@ class userCookie { ...@@ -7,6 +7,12 @@ class userCookie {
isLogin() { isLogin() {
return !!this.token; return !!this.token;
} }
store(token) {
Cookies.set("token", token);
}
delete() {
Cookies.remove("token");
}
} }
export default userCookie; export default userCookie;
...@@ -5,12 +5,25 @@ import "@fontsource/roboto/500.css"; ...@@ -5,12 +5,25 @@ import "@fontsource/roboto/500.css";
import "@fontsource/roboto/700.css"; import "@fontsource/roboto/700.css";
import { createContext, useState, useEffect } from "react"; import { createContext, useState, useEffect } from "react";
import UserLayout from "@/components/layout/UserLayout"; import UserLayout from "@/components/layout/UserLayout";
import userCookie from "@/components/lib/userCookie";
// axios.defaults.baseURL = "" // axios.defaults.baseURL = ""
export const UserContext = createContext(null); export const UserContext = createContext(null);
export default function App({ Component, pageProps }) { export default function App({ Component, pageProps }) {
const [user, setUser] = useState({}); const [user, setUser] = useState({});
useEffect(() => {
const usrcookie = new userCookie();
let token = usrcookie.token.split(".")[1];
if (token) {
let user_info = JSON.parse(atob(token));
user_info.token = usrcookie.token;
setUser(user_info);
console.log(user_info);
}
}, []);
return ( return (
<UserContext.Provider value={{ value: user, set: setUser }}> <UserContext.Provider value={{ value: user, set: setUser }}>
<UserLayout> <UserLayout>
......
import { Box, Button, Divider, Grid, TextField } from "@mui/material";
import { Snackbar } from "@mui/material";
import React from "react";
import { useContext } from "react";
import { UserContext } from "./_app";
import { Container } from "@mui/material";
import { Google } from "@mui/icons-material";
import { useState } from "react";
import axios from "axios";
import userCookie from "@/components/lib/userCookie";
export default function Login() {
const user = useContext(UserContext);
const [errorMessage, setErrorMessage] = useState("");
const [successMessage, setSuccessMessage] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
if (user.value?.name)
return (
<div>
<h3>{user.value.name}</h3>
</div>
);
/**
*
* @param {FormDataEvent} e
*/
async function onSubmitForm(e) {
e.preventDefault();
let response = await axios.post("/api/user/auth", { username, password });
console.log(response.data);
if (response.data.status === 201) {
const usrsto = new userCookie();
usrsto.store(response.data.token);
window.location.href = '/'
} else if (response.data.status === 203) {
setErrorMessage("ชื่อผู้ใช้หรือระหัสผ่านไม่ถูกต้อง");
setTimeout(() => {
setErrorMessage("");
}, 3000);
}
}
return (
<div>
<Container>
<Snackbar
ContentProps={{ className: "bg-red-500" }}
anchorOrigin={{ horizontal: "center", vertical: "top" }}
open={!!errorMessage.length}
message={errorMessage}
/>
<Snackbar
ContentProps={{ className: "bg-green-500" }}
anchorOrigin={{ horizontal: "center", vertical: "top" }}
open={!!successMessage.length}
message={successMessage}
/>
<Grid container>
<Grid item lg={3} md={0}></Grid>
<Grid item lg={6} md={12}>
<div className="border border-red-500 bg-white py-3 text-center rounded-lg">
<form onSubmit={onSubmitForm} className="">
<Box component={"h2"} className="text-gray-700">
เข้าสู่ระบบ
</Box>
<TextField
label="username"
variant="standard"
className="mx-3 my-1"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
/>
<TextField
label="password"
type="password"
variant="standard"
className="mx-3 my-1"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<div className="text-right px-10 sm:px-16">
<Button
className="my-5 text-lg"
variant="contained"
type="submit"
>
เข้าสู่ระบบ
</Button>
</div>
</form>
<Divider />
<Box component={"h4"}>หรือเข้าสู่ระบบด้วยบัญชี google</Box>
<button className="bg-white rounded-full border-none hover:shadow-md shadow-gray-400 duration-300 hover:-translate-y-1 cursor-pointer hover:scale-105">
<Google color="primary" fontSize="large" />
</button>
</div>
</Grid>
<Grid item lg={3} md={0}></Grid>
</Grid>
</Container>
</div>
);
}
import userCookie from "@/components/lib/userCookie";
import { useRouter } from "next/router";
import React from "react";
export default function Logout() {
React.useEffect(() => {
const usr = new userCookie();
usr.delete();
window.location.href = '/'
}, []);
return <div>Logout</div>;
}
...@@ -70,13 +70,13 @@ export default function Login() { ...@@ -70,13 +70,13 @@ export default function Login() {
<Snackbar <Snackbar
ContentProps={{ className: "bg-red-500" }} ContentProps={{ className: "bg-red-500" }}
anchorOrigin={{ horizontal: "center", vertical: "top" }} anchorOrigin={{ horizontal: "center", vertical: "top" }}
open={errorMessage.length} open={!!errorMessage.length}
message={errorMessage} message={errorMessage}
/> />
<Snackbar <Snackbar
ContentProps={{ className: "bg-green-500" }} ContentProps={{ className: "bg-green-500" }}
anchorOrigin={{ horizontal: "center", vertical: "top" }} anchorOrigin={{ horizontal: "center", vertical: "top" }}
open={successMessage.length} open={!!successMessage.length}
message={successMessage} message={successMessage}
/> />
<Grid container> <Grid container>
...@@ -136,6 +136,7 @@ export default function Login() { ...@@ -136,6 +136,7 @@ export default function Login() {
className="mx-3 my-1" className="mx-3 my-1"
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
required
/> />
<div className="text-right px-10 sm:px-16"> <div className="text-right px-10 sm:px-16">
<Button <Button
...@@ -149,7 +150,7 @@ export default function Login() { ...@@ -149,7 +150,7 @@ export default function Login() {
</form> </form>
<Divider /> <Divider />
<Box component={"h4"}>หรือสมัครด้วยบัญชี google</Box> <Box component={"h4"}>หรือสมัครด้วยบัญชี google</Box>
<button className="bg-white rounded-full border-none hover:shadow-md shadow-gray-400 duration-300 hover:-translate-y-1"> <button className="bg-white rounded-full border-none hover:shadow-md shadow-gray-400 duration-300 hover:-translate-y-1 cursor-pointer hover:scale-105">
<Google color="primary" fontSize="large" /> <Google color="primary" fontSize="large" />
</button> </button>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment