diff --git a/components/AuthGuard.tsx b/components/AuthGuard.tsx index d026cb06..5542cc69 100644 --- a/components/AuthGuard.tsx +++ b/components/AuthGuard.tsx @@ -9,14 +9,14 @@ import { UserInfo } from "@/entities/UserInfo"; export const AuthGuard: React.FC = ({ children }) => { const router = useRouter(); - const { data: session } = useSession(); + const session = useSession(); const [userId, setUserId] = useAtom(userIdAtom); const setUserInfo = useSetAtom(userInfoAtom); const [canShowContents, setCanShowContents] = useState(false); useEffect(() => { let timerId: NodeJS.Timeout; - if (!session) { + if (session?.status === "unauthenticated") { timerId = setTimeout(() => { router.push("/login"); }, 1000); @@ -58,7 +58,7 @@ export const AuthGuard: React.FC = ({ children }) => { .catch((error) => { console.error("Error:", error); }); - }, [router, userId]); + }, [router, setUserInfo, userId]); if (!canShowContents) { return <>; diff --git a/components/RegisterContainer.tsx b/components/RegisterContainer.tsx new file mode 100644 index 00000000..c1b41e16 --- /dev/null +++ b/components/RegisterContainer.tsx @@ -0,0 +1,164 @@ +import axios from "axios"; +import { useSetAtom, useAtomValue } from "jotai"; +import { useRouter } from "next/router"; +import { useState, useCallback, FormEvent } from "react"; +import { FaRegTimesCircle } from "react-icons/fa"; +import { userInfoAtom, userIdAtom } from "../utils/atoms"; +import { prefectures } from "../utils/constants"; +import { Prefecture, UserGenderType } from "../utils/types"; +import { UserInfo } from "../entities/UserInfo"; + +export const RegisterContainer: React.FC = () => { + const [name, setName] = useState(""); + const [prefecture, setPrefecture] = useState(); + const [birthdate, setBirthdate] = useState(""); + const [gender, setGender] = useState("選択しない"); + const setUserInfo = useSetAtom(userInfoAtom); + const [isSendingRequest, setIsSendingRequest] = useState(false); + const [isResultError, setIsResultError] = useState(false); + const [errorMessage, setErrorMessage] = useState(""); + + const router = useRouter(); + const userId = useAtomValue(userIdAtom); + + const handleSubmit = useCallback( + async (event: FormEvent) => { + event.preventDefault(); + + try { + let errors = []; + + if (!name) { + errors.push("ユーザー名"); + } + if (!prefecture) { + errors.push("都道府県"); + } + if (!birthdate) { + errors.push("誕生日"); + } + if (!gender) { + errors.push("性別"); + } + + if (errors.length > 0) { + setIsResultError(true); + throw new Error(`${errors.join(", ")} が未入力です`); + } + setIsSendingRequest(true); + + const response = await axios.put("/api/user", { + id: userId, + name: name, + prefecture: prefecture, + birthdate: birthdate, + gender: gender, + }); + + const userInfo: UserInfo = { + name: response.data.name.S, + prefecture: response.data.prefecture.S, + birthdate: response.data.birthdate.S, + gender: response.data.gender.S, + }; + + setUserInfo(userInfo); + router.push("/"); + } catch (error: unknown) { + console.log(error); + setIsResultError(true); + + if (error instanceof Error) { + setErrorMessage(error.message); + } else { + setErrorMessage("Error occurred."); + } + } finally { + setTimeout(() => { + setIsResultError(false); + }, 3000); + setIsSendingRequest(false); + } + }, + [name, prefecture, birthdate, gender, userId, setUserInfo, router] + ); + + return ( +
+ {isSendingRequest && ( + + )} + {isResultError && ( +
+ + {errorMessage} +
+ )} +
+

新規登録

+
+
+ + setName(e.target.value)} + className="rounded-md p-2 w-full text-white bg-slate-900" + /> +
+ +
+ + + + 生年月日: + setBirthdate(String(e.target.value))} + /> + + + +
+ + +
+
+
+ ); +}; diff --git a/components/UserInfo.tsx b/components/UserInfo.tsx index 92507e89..dbc5d82b 100644 --- a/components/UserInfo.tsx +++ b/components/UserInfo.tsx @@ -2,103 +2,146 @@ import { FaRegUserCircle } from "react-icons/fa"; import { Prefecture, UserGenderType } from "@/utils/types"; import { prefectures } from "@/utils/constants"; import { useUserInfo } from "@/hooks/useUserInfo"; -import { useState } from "react"; +import { useCallback, useState } from "react"; const UserInfo = () => { - const { - editUserInfo, - userInfo, - isEditMode, setIsEditMode, - - } = useUserInfo(); + const { editUserInfo, deleteUserInfo, userInfo, isEditMode, setIsEditMode } = + useUserInfo(); const [name, setName] = useState(userInfo?.name as string); - const [prefecture, setPrefecture] = useState(userInfo?.prefecture as Prefecture); - const [birthdate, setBirthdate] = useState(userInfo?.birthdate as string); - const [gender, setGender] = useState(userInfo?.gender as UserGenderType); + const [prefecture, setPrefecture] = useState( + userInfo?.prefecture as Prefecture + ); + const [birthdate, setBirthdate] = useState( + userInfo?.birthdate as string + ); + const [gender, setGender] = useState( + userInfo?.gender as UserGenderType + ); - const handleSubmit = (e:any) => { + const handleSubmit = (e: any) => { e.preventDefault(); - editUserInfo(name,prefecture,birthdate,gender); + editUserInfo(name, prefecture, birthdate, gender); }; + const handleUserDelete = useCallback(() => { + const ok = confirm("ユーザーを削除しますか?"); + if (ok) { + deleteUserInfo(); + } + }, [deleteUserInfo]); + return ( <>

ユーザー情報

- {isEditMode ? - <> - : -
setIsEditMode(true)}>編集する
- } + {isEditMode ? ( +
+ +
+ ) : ( +
setIsEditMode(true)} + > + 編集する +
+ )}
- { - isEditMode ? -
+ {isEditMode ? ( +
- +
- setName(e.target.value)} className="rounded-md p-2 w-full"/> + setName(e.target.value)} + className="rounded-md p-2 w-full" + />
- +
- setPrefecture(e.target.value as Prefecture)} + > + {prefectures.map((prefecture, index) => { + return ( + + ); + })} - + 生年月日: - setBirthdate(e.target.value)}/> - + setBirthdate(e.target.value)} + /> + - setGender(e.target.value as UserGenderType)} + >
-
setIsEditMode(false)}>キャンセル
- +
setIsEditMode(false)}> + キャンセル +
+
-
- : + ) : (
- +

{userInfo?.name}

- -
- 都道府県: -

{userInfo?.prefecture}

-
-
- 誕生日: -

{userInfo?.birthdate}

-
- -
- 性別: -

{userInfo?.gender}

-
+ +
+ 都道府県: +

{userInfo?.prefecture}

+
+
+ 誕生日: +

{userInfo?.birthdate}

+
+ +
+ 性別: +

{userInfo?.gender}

+
- } + )} - ); }; -export default UserInfo; \ No newline at end of file +export default UserInfo; diff --git a/hooks/useUserInfo.ts b/hooks/useUserInfo.ts index b0d6d7d7..d5332b22 100644 --- a/hooks/useUserInfo.ts +++ b/hooks/useUserInfo.ts @@ -3,47 +3,78 @@ import { userIdAtom, userInfoAtom } from "@/utils/atoms"; import { Prefecture, UserGenderType } from "@/utils/types"; import axios from "axios"; import { useAtom, useAtomValue } from "jotai"; -import { useState } from "react"; +import { signOut } from "next-auth/react"; +import { useCallback, useState } from "react"; export const useUserInfo = () => { const userId = useAtomValue(userIdAtom); - const [isEditMode,setIsEditMode] = useState(false); + const [isEditMode, setIsEditMode] = useState(false); const [userInfo, setUserInfo] = useAtom(userInfoAtom); - -const editUserInfo = (userName: string, userPrefecture: Prefecture, userBirthdate: string, userGender: UserGenderType) => { - if (!userId) return; - axios.post(`/api/user`, { - id: userId, - name: userName, - prefecture: userPrefecture, - birthdate: userBirthdate, - gender: userGender, - }, { - headers: { - 'Content-Type': 'application/json', + const editUserInfo = useCallback( + ( + userName: string, + userPrefecture: Prefecture, + userBirthdate: string, + userGender: UserGenderType + ) => { + if (!userId) return; + + axios + .post( + `/api/user`, + { + id: userId, + name: userName, + prefecture: userPrefecture, + birthdate: userBirthdate, + gender: userGender, + }, + { + headers: { + "Content-Type": "application/json", + }, + } + ) + .then((response) => { + const userInfo: UserInfo = { + name: response.data.name.S, + prefecture: response.data.prefecture.S, + birthdate: response.data.birthdate.S, + gender: response.data.gender.S, + }; + setIsEditMode(false); + setUserInfo(userInfo); + }) + .catch((error) => { + console.error("Error:", error); + }); + }, + [userId, setUserInfo] + ); + + const deleteUserInfo = useCallback(async () => { + try { + await axios(`/api/user`, { + method: "DELETE", + data: { + id: userId, + }, + }); + setUserInfo(null); + await signOut(); + } catch (error) { + console.error("Error:", error); } - }) - .then(response => { - const userInfo: UserInfo = { - name: response.data.name.S, - prefecture: response.data.prefecture.S, - birthdate: response.data.birthdate.S, - gender: response.data.gender.S - }; - setIsEditMode(false); - setUserInfo(userInfo); - }) - .catch(error => { - console.error('Error:', error); - }); -}; + }, [userId, setUserInfo]); return { userId, editUserInfo, - - userInfo, setUserInfo, - isEditMode, setIsEditMode + deleteUserInfo, + userInfo, + setUserInfo, + isEditMode, + setIsEditMode, }; -}; \ No newline at end of file +}; diff --git a/pages/login.tsx b/pages/login.tsx index 76b219fe..d8154b0d 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -4,6 +4,7 @@ import { useRouter } from "next/router"; import { useCallback, useEffect } from "react"; import { userIdAtom } from "../utils/atoms"; import { fetchUserId } from "../features/fetchUserId"; +import { AppHead } from "../components/AppHead"; export default function LoginPage() { // session取得、ログインしている場合はindex.tsxへリダイレクト @@ -30,31 +31,34 @@ export default function LoginPage() { }, []); return ( -
-
-

AILLA

-

- AI英会話サービス「AILLA」へようこそ! -
- LINEアカウントでログインしてサービスを開始しましょう! -

-
-
+ -
+ onClick={() => signin()} + > + LINEログイン + + + ); } diff --git a/pages/register.tsx b/pages/register.tsx index 4e432d15..5a8eab6f 100644 --- a/pages/register.tsx +++ b/pages/register.tsx @@ -1,183 +1,26 @@ -import { prefectures } from "@/utils/constants"; -import { Prefecture, UserGenderType} from "@/utils/types"; -import { - FormEvent, - useCallback, - useState, -} from "react"; -import { useRouter } from "next/router"; -import { useAtomValue, useSetAtom } from "jotai"; -import { userIdAtom, userInfoAtom } from "@/utils/atoms"; -import axios from 'axios'; -import { FaRegTimesCircle } from "react-icons/fa"; - -import { UserInfo } from "@/entities/UserInfo"; +import { useSession } from "next-auth/react"; +import { AppHead } from "../components/AppHead"; +import { RegisterContainer } from "../components/RegisterContainer"; +import { useEffect } from "react"; +import router from "next/router"; +import { useAtomValue } from "jotai"; +import { userIdAtom } from "../utils/atoms"; export default function RegisterPage() { - const [name, setName] = useState(""); - const [prefecture, setPrefecture] = useState(); - const [birthdate, setBirthdate] = useState(""); - const [gender, setGender] = useState("選択しない"); - const setUserInfo = useSetAtom(userInfoAtom); - const [isSendingRequest, setIsSendingRequest] = useState(false); - const [isResultError, setIsResultError] = useState(false); - const [errorMessage, setErrorMessage] = useState(""); - - - const router = useRouter(); + const session = useSession(); + useEffect(() => { + if (session.status === "unauthenticated") { + router.push("/login"); + } + }, [session]); const userId = useAtomValue(userIdAtom); - const handleSubmit = useCallback( - async (event: FormEvent) => { - event.preventDefault(); - - try { - let errors = []; - - if (!name) { - errors.push('ユーザー名'); - } - if (!prefecture) { - errors.push('都道府県'); - } - if (!birthdate) { - errors.push('誕生日'); - } - if (!gender) { - errors.push('性別'); - } - - if (errors.length > 0) { - setIsResultError(true); - throw new Error(`${errors.join(', ')} が未入力です`); - } - setIsSendingRequest(true); - - const response = await axios.put('/api/user', { - id: userId, - name: name, - prefecture: prefecture, - birthdate: birthdate, - gender: gender, - }); - - const userInfo: UserInfo = { - name: response.data.name.S, - prefecture: response.data.prefecture.S, - birthdate: response.data.birthdate.S, - gender: response.data.gender.S, - } - - setUserInfo(userInfo); - router.push("/"); - } catch (error: unknown) { - console.log(error); - setIsResultError(true); - - if (error instanceof Error) { - setErrorMessage(error.message); - } else { - setErrorMessage('Error occurred.'); - } - - } finally { - setTimeout(() => { - setIsResultError(false); - }, 3000); - setIsSendingRequest(false); - } - }, - [ - name, - prefecture, - birthdate, - gender, - userId, - setUserInfo, - router, - ] - ); - return ( -
- { - isSendingRequest && - - } - { - isResultError && -
- - {errorMessage} -
- } -
-

新規登録

-
-
- - setName(e.target.value)} - className="rounded-md p-2 w-full text-white bg-slate-900" - /> -
- -
- - - - 生年月日: - setBirthdate(String(e.target.value))} - /> - - - -
- - -
-
-
+ <> + userid: {userId} + {session &&

session: {JSON.stringify(session)}

} + + + ); }