Skip to content

Commit

Permalink
Merge pull request #29 from aivy-tokyo/feat/delete-user
Browse files Browse the repository at this point in the history
ユーザー削除のUI追加
  • Loading branch information
Nobuhiko Futagami authored Aug 31, 2023
2 parents fca8331 + 2577adb commit 5b9a97d
Show file tree
Hide file tree
Showing 6 changed files with 372 additions and 287 deletions.
6 changes: 3 additions & 3 deletions components/AuthGuard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import { UserInfo } from "@/entities/UserInfo";

export const AuthGuard: React.FC<PropsWithChildren> = ({ children }) => {
const router = useRouter();
const { data: session } = useSession();
const session = useSession();
const [userId, setUserId] = useAtom(userIdAtom);
const setUserInfo = useSetAtom(userInfoAtom);
const [canShowContents, setCanShowContents] = useState<boolean>(false);

useEffect(() => {
let timerId: NodeJS.Timeout;
if (!session) {
if (session?.status === "unauthenticated") {
timerId = setTimeout(() => {
router.push("/login");
}, 1000);
Expand Down Expand Up @@ -58,7 +58,7 @@ export const AuthGuard: React.FC<PropsWithChildren> = ({ children }) => {
.catch((error) => {
console.error("Error:", error);
});
}, [router, userId]);
}, [router, setUserInfo, userId]);

if (!canShowContents) {
return <></>;
Expand Down
164 changes: 164 additions & 0 deletions components/RegisterContainer.tsx
Original file line number Diff line number Diff line change
@@ -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<Prefecture>();
const [birthdate, setBirthdate] = useState<string>("");
const [gender, setGender] = useState<UserGenderType>("選択しない");
const setUserInfo = useSetAtom(userInfoAtom);
const [isSendingRequest, setIsSendingRequest] = useState(false);
const [isResultError, setIsResultError] = useState(false);
const [errorMessage, setErrorMessage] = useState<string>("");

const router = useRouter();
const userId = useAtomValue(userIdAtom);

const handleSubmit = useCallback(
async (event: FormEvent<HTMLFormElement>) => {
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 (
<div className="flex h-full text-black text-center">
{isSendingRequest && (
<button className="btn fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
<span className="loading loading-spinner"></span>
登録中...
</button>
)}
{isResultError && (
<div className="alert alert-error fixed top-2 left-1/2 w-[40vw] transform -translate-x-1/2">
<FaRegTimesCircle className="text-black text-[34px] " />
<span>{errorMessage}</span>
</div>
)}
<div className="bg-stone-300 rounded-xl bg-opacity-90 w-[500px] h-fit m-auto pt-5 flex flex-col items-center">
<h2 className="text-2xl">新規登録</h2>
<form onSubmit={handleSubmit} className="w-[80%] my-5">
<div className="mb-5">
<label htmlFor="">名前:</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="rounded-md p-2 w-full text-white bg-slate-900"
/>
</div>

<div className="flex flex-col mb-5">
<label>都道府県:</label>
<select
className="text-white rounded-md p-2 mb-5 bg-slate-900"
value={prefecture}
onChange={(e) => setPrefecture(e.target.value as Prefecture)}
>
<option value="" selected disabled>
選択してください
</option>
{prefectures.map((prefecture, index) => {
return (
<option key={index} value={prefecture}>
{prefecture}
</option>
);
})}
</select>

<span>生年月日:</span>
<input
type="text"
className="text-white rounded-md p-2 mb-5 bg-slate-900"
value={birthdate}
onChange={(e) => setBirthdate(String(e.target.value))}
/>

<label htmlFor="">性別:</label>
<select
name=""
id=""
value={gender}
className="text-white rounded-md p-2 mb-5 bg-slate-900"
onChange={(e) => setGender(e.target.value as UserGenderType)}
>
<option value="男性">男性</option>
<option value="女性">女性</option>
<option value="選択しない">選択しない</option>
</select>
</div>

<button
type="submit"
className="bg-sky-500 border border-sky-600 rounded-full text-white font-bold py-3 px-5"
>
登録してはじめる
</button>
</form>
</div>
</div>
);
};
157 changes: 100 additions & 57 deletions components/UserInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>(userInfo?.name as string);
const [prefecture, setPrefecture] = useState<Prefecture>(userInfo?.prefecture as Prefecture);
const [birthdate, setBirthdate] = useState<string>(userInfo?.birthdate as string);
const [gender, setGender] = useState<UserGenderType>(userInfo?.gender as UserGenderType);
const [prefecture, setPrefecture] = useState<Prefecture>(
userInfo?.prefecture as Prefecture
);
const [birthdate, setBirthdate] = useState<string>(
userInfo?.birthdate as string
);
const [gender, setGender] = useState<UserGenderType>(
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 (
<>
<div className="flex justify-between">
<h2 className="mb-3 font-bold">ユーザー情報</h2>
{isEditMode ?
<></>
:
<div className='bg-stone-300 h-7 w-20 text-black text-center rounded-md cursor-pointer' onClick={() => setIsEditMode(true)}>編集する</div>
}
{isEditMode ? (
<div className="flex items-center mb-5">
<button className="btn btn-error btn-xs" onClick={handleUserDelete}>
ユーザーの削除
</button>
</div>
) : (
<div
className="bg-stone-300 h-7 w-20 text-black text-center rounded-md cursor-pointer"
onClick={() => setIsEditMode(true)}
>
編集する
</div>
)}
</div>
{
isEditMode ?
<div>
{isEditMode ? (
<div className="mb-10">
<form onSubmit={handleSubmit}>
<div className="flex items-center mb-5">
<FaRegUserCircle className={`text-[50px] -ml-1 mr-5 text-white self-center`}/>
<FaRegUserCircle
className={`text-[50px] -ml-1 mr-5 text-white self-center`}
/>
<div>
<label htmlFor="">名前:</label>
<input type="text" value={name} onChange={(e) => setName(e.target.value)} className="rounded-md p-2 w-full"/>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="rounded-md p-2 w-full"
/>
</div>
</div>

<div className="flex flex-col mb-5">
<label>都道府県:</label>
<select className="rounded-md p-2 mb-5" value={prefecture} onChange={(e) => setPrefecture(e.target.value as Prefecture)}>
{
prefectures.map((prefecture,index)=> {
return (
<option key={index} value={prefecture}>{prefecture}</option>
);
})
}
<select
className="rounded-md p-2 mb-5"
value={prefecture}
onChange={(e) => setPrefecture(e.target.value as Prefecture)}
>
{prefectures.map((prefecture, index) => {
return (
<option key={index} value={prefecture}>
{prefecture}
</option>
);
})}
</select>

<span>生年月日:</span>
<input type="text" className="rounded-md p-2 mb-5" value={birthdate} onChange={(e) => setBirthdate(e.target.value)}/>

<input
type="text"
className="rounded-md p-2 mb-5"
value={birthdate}
onChange={(e) => setBirthdate(e.target.value)}
/>

<label htmlFor="">性別:</label>
<select name="" id="" value={gender} className="rounded-md p-2" onChange={(e) => setGender(e.target.value as UserGenderType)}>
<select
name=""
id=""
value={gender}
className="rounded-md p-2"
onChange={(e) => setGender(e.target.value as UserGenderType)}
>
<option value="男性">男性</option>
<option value="女性">女性</option>
<option value="選択しない">選択しない</option>
</select>
</div>
<div className="flex justify-between">
<div className='bg-stone-300 w-24 text-black text-center rounded-md cursor-pointer' onClick={() => setIsEditMode(false)}>キャンセル</div>
<button type="submit" className='bg-stone-300 w-24 text-black text-center rounded-md'>更新する</button>
<div className="btn" onClick={() => setIsEditMode(false)}>
キャンセル
</div>
<button type="submit" className="btn btn-primary">
更新する
</button>
</div>

</form>
</div>
:
) : (
<div className="w-full">
<div className="flex flex-col mb-5">
<div className="flex mb-5 items-center">
<FaRegUserCircle className={`text-[50px] -ml-1 mr-5 text-white self-start `}/>
<FaRegUserCircle
className={`text-[50px] -ml-1 mr-5 text-white self-start `}
/>
<p className="text-2xl">{userInfo?.name}</p>
</div>
<div className="mb-5">
都道府県:
<p>{userInfo?.prefecture}</p>
</div>
<div className="mb-5">
誕生日:
<p>{userInfo?.birthdate}</p>
</div>
<div className="mb-5">
性別:
<p>{userInfo?.gender}</p>
</div>

<div className="mb-5">
都道府県:
<p>{userInfo?.prefecture}</p>
</div>
<div className="mb-5">
誕生日:
<p>{userInfo?.birthdate}</p>
</div>

<div className="mb-5">
性別:
<p>{userInfo?.gender}</p>
</div>
</div>
</div>
}
)}
</>

);
};

export default UserInfo;
export default UserInfo;
Loading

0 comments on commit 5b9a97d

Please sign in to comment.