From 92a4c30ce2781d03cc7c300c5f6e39a652cc87ef Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sat, 18 May 2024 13:42:58 +0900 Subject: [PATCH] Implement Auth --- backend/routes/auth/signin.js | 4 +- backend/routes/auth/signup.js | 3 +- frontend/messages/en.json | 17 +- frontend/messages/ja.json | 18 +- frontend/src/app/[locale]/auth/authPage.tsx | 234 +++++++++--------- frontend/src/app/[locale]/auth/layout.tsx | 11 + .../src/app/[locale]/auth/signin/page.tsx | 19 +- .../src/app/[locale]/auth/signup/page.tsx | 28 +++ .../src/app/[locale]/auth/validate.test.ts | 24 ++ frontend/src/app/[locale]/auth/validate.ts | 19 ++ frontend/types/user.ts | 17 +- 11 files changed, 269 insertions(+), 125 deletions(-) create mode 100644 frontend/src/app/[locale]/auth/layout.tsx create mode 100644 frontend/src/app/[locale]/auth/validate.test.ts create mode 100644 frontend/src/app/[locale]/auth/validate.ts diff --git a/backend/routes/auth/signin.js b/backend/routes/auth/signin.js index 96c38fe..aa0057d 100644 --- a/backend/routes/auth/signin.js +++ b/backend/routes/auth/signin.js @@ -2,11 +2,13 @@ const express = require("express"); const router = express.Router(); const defineUser = require("../../models/users"); const { DataTypes } = require("sequelize"); +const bcrypt = require('bcrypt'); +const jwt = require('jsonwebtoken'); module.exports = function (sequelize) { const User = defineUser(sequelize, DataTypes); - router.post("/auth/signin", async (req, res) => { + router.post("/signin", async (req, res) => { try { const { email, password } = req.body; const user = await User.findOne({ diff --git a/backend/routes/auth/signup.js b/backend/routes/auth/signup.js index 684fd3c..0196a79 100644 --- a/backend/routes/auth/signup.js +++ b/backend/routes/auth/signup.js @@ -3,11 +3,12 @@ const router = express.Router(); const defineUser = require("../../models/users"); const { DataTypes } = require("sequelize"); const roles = require("./roles"); +const bcrypt = require('bcrypt'); module.exports = function (sequelize) { const User = defineUser(sequelize, DataTypes); - router.post("/auth/signup", async (req, res) => { + router.post("/signup", async (req, res) => { try { const { email, password, username } = req.body; const hashedPassword = await bcrypt.hash(password, 10); diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 61159a9..dd11ebe 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -26,7 +26,22 @@ }, "Auth": { "signup": "Sign up", - "signin": "Sign in" + "signin": "Sign in", + "or_signup": "You need sign up?", + "or_signin": "You need sign in?", + "email": "Email", + "username": "User name", + "password": "Password", + "confirm_password": "Password (confirm)", + "invalid_email": "Invalid email", + "invalid_password": "Password must be at least 8 characters", + "username_empty": "username is empty", + "password_empty": "password is empty", + "password_not_match": "Pasword does not match", + "email_already_exist": "Already registered email", + "email_not_exist": "Email address not found", + "signup_error": "Sign up failed", + "signin_error": "Sign in failed" }, "Projects": { "projectList": "Project List", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index 2a8b1b0..1c10f55 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -25,8 +25,22 @@ "projects": "プロジェクト" }, "Auth": { - "signup": "サインアップ", - "signin": "サインイン" + "signup": "新規登録", + "signin": "サインイン", + "or_signup": "新規登録ページ", + "or_signin": "サインインページ", + "email": "メールアドレス", + "username": "ユーザー名", + "password": "パスワード", + "confirm_password": "パスワード(確認)", + "invalid_email": "無効なメールアドレスです", + "invalid_password": "パスワードは8文字以上である必要があります", + "username_empty": "ユーザー名が入力されていません", + "password_not_match": "パスワードが一致しません", + "email_already_exist": "登録済みのメールアドレスです", + "email_not_exist": "メールアドレスが見つかりません", + "signup_error": "新規登録できません", + "signin_error": "サインインできません" }, "Projects": { "projectList": "プロジェクト一覧", diff --git a/frontend/src/app/[locale]/auth/authPage.tsx b/frontend/src/app/[locale]/auth/authPage.tsx index 62640ad..1488f3c 100644 --- a/frontend/src/app/[locale]/auth/authPage.tsx +++ b/frontend/src/app/[locale]/auth/authPage.tsx @@ -1,25 +1,20 @@ "use client"; import React from "react"; -import { useState, useEffect } from "react"; -import { Input, Button } from "@nextui-org/react"; -import { Eye, EyeOff } from "lucide-react"; +import { useState } from "react"; +import { Input, Button, Card, CardHeader, CardBody } from "@nextui-org/react"; +import { Link } from "@/src/navigation"; +import { ChevronRight, Eye, EyeOff } from "lucide-react"; import { UserType, AuthMessages } from "@/types/user"; import { roles } from "@/config/selection"; -import { usePathname } from "next/navigation"; import { signUp, signIn } from "./authControl"; +import { isValidEmail, isValidPassword } from "./validate"; type Props = { + isSignup: Boolean; messages: AuthMessages; locale: string; }; -export default function AuthPage({ messages, locale }: Props) { - const [isSignup, setIsSignup] = useState(false); - const pathname = usePathname(); - console.log(pathname); - if (pathname.includes("signup")) { - setIsSignup(true); - } - +export default function AuthPage({ isSignup, messages, locale }: Props) { const [user, setUser] = useState({ id: null, email: "", @@ -28,6 +23,7 @@ export default function AuthPage({ messages, locale }: Props) { role: roles.findIndex((entry) => entry.uid === "user"), avatarPath: "", }); + const [confirmPassword, setConfirmPassword] = useState(""); const [errorMessage, setErrorMessage] = useState(""); const [isPasswordVisible, setIsPasswordVisible] = useState(false); @@ -35,19 +31,26 @@ export default function AuthPage({ messages, locale }: Props) { setIsPasswordVisible(!isPasswordVisible); const validate = async () => { - if (!user.email) { - setErrorMessage("email can't be empty"); + if (!isValidEmail(user.email)) { + setErrorMessage(messages.invalidEmail); return; } - if (!user.password) { - setErrorMessage("password can't be empty"); + if (!isValidPassword(user.password)) { + setErrorMessage(messages.invalidPassword); return; } - if (!user.username) { - setErrorMessage("username can't be empty"); - return; + if (isSignup) { + if (!user.username) { + setErrorMessage(messages.usernameEmpty); + return; + } + + if (user.password !== confirmPassword) { + setErrorMessage(messages.passwordDoesNotMatch); + return; + } } await submit(); @@ -59,108 +62,109 @@ export default function AuthPage({ messages, locale }: Props) { console.log(signUpRet); // if success, move to signin page } else { - const signInRet = await signUp(user); + const signInRet = await signIn(user); console.log(signInRet); // if success, move to account page } }; return ( -
- { - setUser({ - ...user, - email: e.target.value, - }); - }} - /> - { - setUser({ - ...user, - username: e.target.value, - }); - }} - /> - + +

{messages.title}

+ + - } - type={isPasswordVisible ? "text" : "password"} - onChange={(e) => { - setUser({ - ...user, - password: e.target.value, - }); - }} - className="max-w-xs" - /> - -
- // { - // onCancel(); - // }} - // > - // - // - // {messages.project} - // - // - // { - // setProjectName({ - // ...projectName, - // text: e.target.value, - // }); - // }} - // /> - //