Skip to content

Commit

Permalink
Merge pull request #73 from jphacks/feat/yama/create-logout-button
Browse files Browse the repository at this point in the history
ログアウトボタンとメール通知の切り替えボタン&APIを追加
  • Loading branch information
nose221834 authored Nov 16, 2024
2 parents e665854 + b21fdcf commit 7992352
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 59 deletions.
1 change: 0 additions & 1 deletion app/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ model User {
experiencePoint ExperiencePoint? @relation()
rateId Int @default(1)
ratePoint Int
// todo メール受信のフラグを追記。APIは別で作成する
isReceivedMail Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
Expand Down
1 change: 1 addition & 0 deletions app/src/app/api/mailer/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export async function POST() {
try {
const usersEmails = (
await prisma.user.findMany({
where: { isReceivedMail: true },
select: {
email: true,
},
Expand Down
27 changes: 27 additions & 0 deletions app/src/app/api/user/updateReceivedMail/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { prisma } from "@lib/prisma";
import type { NextRequest } from "next/server";

export async function PUT(req: NextRequest) {
try {
const { uid, isReceivedMail } = await req.json();

await prisma.user.update({
where: { uid },
data: { isReceivedMail },
});

return new Response(JSON.stringify({ message: "設定を更新しました" }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
} catch (error) {
console.error("設定更新エラー:", error);
return new Response(
JSON.stringify({ error: "設定の更新に失敗しました。" }),
{
status: 500,
headers: { "Content-Type": "application/json" },
},
);
}
}
148 changes: 98 additions & 50 deletions app/src/app/user/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import PlayerRankCard from "@/components/view/user/PlayerRankCard";
import { StatusChangeDialog } from "@/components/view/user/StatusChangeDialog";
import { StatusList } from "@/components/view/user/StatusList";
import { useStatusChangeDialog } from "@/lib/atom";
import { signOut } from "@/lib/signOut";
import type {
ChangeStatus,
MyScoreDetail,
Expand All @@ -20,32 +21,43 @@ import { LuClock, LuFlame, LuTrophy } from "react-icons/lu";
import { VscAccount } from "react-icons/vsc";

const UserPage = () => {
const [userData, setUserData] = useState<User>();
const [userData, setUserData] = useState<User | null>(null);
const [myScore, setMyScore] = useState<MyScoreDetail[]>([]);
const [userStatus, setUserStatus] = useState<experiencePoint>();
const [point, setPoint] = useState<ChangeStatus>();
const [isEditing, setIsEditing] = useState(false);
const [isSubscribed, setIsSubscribed] = useState<boolean>(true);
const [isOpen, setIsOpen] = useStatusChangeDialog();
const handleOpenDialog = () => setIsOpen(true);
const [isLoading, setIsLoading] = useState<boolean>(true);

useEffect(() => {
const fetchData = async () => {
const userIdString = localStorage.getItem("userID");
if (!userIdString) {
window.location.href = "/login";
return;
}
const userIdString = localStorage.getItem("userID");
if (!userIdString) {
window.location.href = "/login";
return;
}

const userData: User = JSON.parse(userIdString);
setUserData(userData);

const userData = JSON.parse(userIdString);
setUserData(userData);
const fetchUserData = async () => {
try {
const response = await fetch(`/api/score/me/${userData.uid}?all=true`);
if (!response.ok) {
throw new Error("データの取得に失敗しました");
const [userResponse, scoreResponse] = await Promise.all([
fetch(`/api/user?uid=${userData.uid}`),
fetch(`/api/score/me/${userData.uid}?all=true`),
]);

if (!userResponse.ok) {
throw new Error("ユーザー情報の取得に失敗しました");
}
const userDetails = await userResponse.json();
setIsSubscribed(userDetails.isReceivedMail);

const data = await response.json();
if (!scoreResponse.ok) {
throw new Error("データの取得に失敗しました");
}
const data = await scoreResponse.json();
setMyScore(data);
} catch (error) {
console.error("エラーが発生しました:", error);
Expand All @@ -70,9 +82,35 @@ const UserPage = () => {
}
setIsLoading(false);
};
fetchData();

fetchUserData();
}, []);

const handleToggleEmailSubscription = async () => {
if (!userData) return;

try {
const response = await fetch("/api/user/updateReceivedMail", {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
uid: userData.uid,
isReceivedMail: !isSubscribed,
}),
});

if (!response.ok) {
throw new Error("設定の更新に失敗しました");
}

setIsSubscribed((prev) => !prev);
} catch (error) {
console.error("エラーが発生しました:", error);
}
}

if (!userData) return null;
if (isLoading) {
return <LoadingSpinner />;
Expand All @@ -95,15 +133,11 @@ const UserPage = () => {
{isEditing ? (
<div className="flex flex-col gap-2">
<Input type="text" placeholder="新しいユーザー名を入力" />
<div>
<Button variant={"default"} className="bg-[#333333]">
<div className="flex gap-2">
<Button variant="default" className="bg-[#333333]">
保存
</Button>
<Button
variant={"outline"}
className="ml-2"
onClick={() => setIsEditing(false)}
>
<Button variant="outline" onClick={() => setIsEditing(false)}>
キャンセル
</Button>
</div>
Expand All @@ -114,7 +148,7 @@ const UserPage = () => {
{userData.name || "[email protected]"}
</span>
<Button
variant={"primary"}
variant="primary"
className="ml-2"
onClick={() => setIsEditing(true)}
>
Expand Down Expand Up @@ -151,37 +185,51 @@ const UserPage = () => {
</button>
<Card className="flex flex-col items-center border-none p-8">
<h2 className="text-2xl font-bold mb-4">過去のチャレンジ</h2>
{myScore.length === 0 ? (
<div className="text-gray-500 text-center py-8">
<p>まだチャレンジの記録がありません</p>
<p className="text-sm mt-2">
新しいチャレンジに挑戦してみましょう!
</p>
</div>
) : (
myScore.map((score) => (
<div
key={score.id}
className="flex w-full items-center mb-2 border rounded-md"
>
<img
src={score.imageUrl || "https://placehold.jp/150x150.png"}
alt="チャレンジ画像"
className="w-1/4 h-auto rounded-l-md"
/>
<div className="flex flex-col items-start justify-center w-1/2 text-xs">
<div className="pl-4 flex flex-col gap-1">
<p className="font-bold">{score.assignment}</p>
<div className="flex items-center gap-1">
<LuClock />
<p className="pb-0.5">{score.answerTime}</p>
<div className="w-full overflow-y-auto">
{myScore.length === 0 ? (
<div className="text-gray-500 text-center py-8">
<p>まだチャレンジの記録がありません</p>
<p className="text-sm mt-2">
新しいチャレンジに挑戦してみましょう!
</p>
</div>
) : (
myScore.map((score) => (
<div
key={score.id}
className="flex w-full items-center mb-2 border rounded-md"
>
<img
src={score.imageUrl || "https://placehold.jp/150x150.png"}
alt="チャレンジ画像"
className="w-1/4 h-auto rounded-l-md"
/>
<div className="flex flex-col items-start justify-center w-1/2 text-xs">
<div className="pl-4 flex flex-col gap-1">
<p className="font-bold">{score.assignment}</p>
<div className="flex items-center gap-1">
<LuClock />
<p className="pb-0.5">{score.answerTime}</p>
</div>
</div>
</div>
<p className="w-1/4 text-lg font-bold">{score.point}</p>
</div>
<p className="w-1/4 text-lg font-bold">{score.point}</p>
</div>
))
)}
))
)}
</div>
</Card>
<Card className="flex justify-center gap-2 w-[21rem] p-8">
<Button
variant="default"
onClick={signOut}
className="px-6 bg-[#333333]"
>
ログアウト
</Button>
<Button variant="outline" onClick={handleToggleEmailSubscription}>
{isSubscribed ? "メール通知を停止" : "メール通知を再開"}
</Button>
</Card>
</div>
);
Expand Down
20 changes: 12 additions & 8 deletions app/src/lib/signInAndUp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@ export const signInOrUp = async (firebaseUser: FirebaseUser) => {
},
});

const userData = await res.json();
if (res.status === 200) {
const userData = await res.json();

const user: DBUser = { ...userData };
const user: DBUser = { ...userData };

if (userData) {
storeStorageUser(user);
if (!userData.experiencePoint) {
await createExp(userData.id);
if (userData) {
storeStorageUser(user);
if (!userData.experiencePoint) {
await createExp(userData.id);
}
toRoot();
}
toRoot();
} else {
} else if (res.status === 404) {
await signUp(firebaseUser);
} else {
console.error(`Unexpected status code: ${res.status}`);
}
} catch (error) {
console.error("エラーが発生しました:", error);
Expand Down

0 comments on commit 7992352

Please sign in to comment.