Skip to content

Commit 5243e29

Browse files
authored
Merge pull request #82 from jphacks/fix/hikahana/rate-api-connect
userページにrateを繋ぎ込み
2 parents a93f6b4 + e5b5b6e commit 5243e29

File tree

4 files changed

+85
-85
lines changed

4 files changed

+85
-85
lines changed

app/src/app/api/rate/user/[id]/route.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export async function GET(req: NextRequest) {
1515
}
1616

1717
try {
18+
// ユーザー情報の取得
1819
const user = await prisma.user.findUnique({
1920
where: { id },
2021
include: {
@@ -32,30 +33,35 @@ export async function GET(req: NextRequest) {
3233
return NextResponse.json({ error: "User not found" }, { status: 404 });
3334
}
3435

36+
// 次のレート情報の取得
3537
const nextRate = await prisma.rate.findFirst({
36-
where: { minRange: { gt: user.rate.maxRange } },
38+
where: { minRange: { gt: user.ratePoint } },
3739
orderBy: { minRange: "asc" },
3840
select: { name: true, minRange: true },
3941
});
4042

41-
const nextRateName = nextRate ? nextRate.name : "";
42-
const pointsToNextRate = nextRate
43-
? nextRate.minRange - user.ratePoint
44-
: user.rate.maxRange - user.ratePoint;
45-
43+
// 必要なレスポンスデータの組み立て
4644
const result = {
4745
ratePoint: user.ratePoint,
4846
rate: {
4947
name: user.rate.name,
5048
minRange: user.rate.minRange,
5149
maxRange: user.rate.maxRange,
52-
nextRateName,
53-
pointsToNextRate,
5450
},
51+
nextRate: nextRate
52+
? {
53+
name: nextRate.name,
54+
pointsToNextRate: nextRate.minRange - user.ratePoint,
55+
}
56+
: {
57+
name: "",
58+
pointsToNextRate: 0,
59+
},
5560
};
5661

5762
return NextResponse.json(result, { status: 200 });
5863
} catch (error) {
64+
console.error("RatePoint取得エラー:", error);
5965
return NextResponse.json(
6066
{ error: "Failed to get ratePoint", details: error },
6167
{ status: 500 },

app/src/app/user/page.tsx

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {
1313
ChangeStatus,
1414
MyScoreDetail,
1515
DBUser as User,
16+
UserRate,
1617
experiencePoint,
1718
} from "@/types";
1819
import { useEffect, useState } from "react";
@@ -30,6 +31,7 @@ const UserPage = () => {
3031
const [isOpen, setIsOpen] = useStatusChangeDialog();
3132
const handleOpenDialog = () => setIsOpen(true);
3233
const [isLoading, setIsLoading] = useState<boolean>(true);
34+
const [userRate, setUserRate] = useState<UserRate>();
3335

3436
useEffect(() => {
3537
const userIdString = localStorage.getItem("userID");
@@ -62,24 +64,36 @@ const UserPage = () => {
6264
} catch (error) {
6365
console.error("エラーが発生しました:", error);
6466
}
65-
6667
try {
67-
const response = await fetch(`/api/experiencePoint/me/${userData.id}`);
68-
if (!response.ok) {
69-
throw new Error("データの取得に失敗しました");
68+
const [experienceResponse, rateResponse] = await Promise.all([
69+
fetch(`/api/experiencePoint/me/${userData.id}`),
70+
fetch(`/api/rate/user/${userData.id}`),
71+
]);
72+
73+
if (!experienceResponse.ok) {
74+
throw new Error("経験値データの取得に失敗しました");
7075
}
76+
if (!rateResponse.ok) {
77+
throw new Error("レートデータの取得に失敗しました");
78+
}
79+
80+
const [experienceData, rateData] = await Promise.all([
81+
experienceResponse.json(),
82+
rateResponse.json(),
83+
]);
7184

72-
const data = await response.json();
73-
setUserStatus(data);
85+
setUserStatus(experienceData);
7486
setPoint({
75-
speedPoint: data.speedPoint,
76-
similarityPoint: data.similarityPoint,
77-
totalPoint: data.totalPoint,
87+
speedPoint: experienceData.speedPoint,
88+
similarityPoint: experienceData.similarityPoint,
89+
totalPoint: experienceData.totalPoint,
7890
id: Number(userData.id),
7991
});
92+
setUserRate(rateData);
8093
} catch (error) {
81-
console.error("エラーが発生しました", error);
94+
console.error("データ取得でエラーが発生しました:", error);
8295
}
96+
8397
setIsLoading(false);
8498
};
8599

@@ -131,7 +145,10 @@ const UserPage = () => {
131145
<div className="ml-4 flex flex-col gap-1">
132146
<div className="flex items-center">
133147
{isEditing ? (
134-
<RenameDialog setIsEditing={setIsEditing} setUserData={setUserData} />
148+
<RenameDialog
149+
setIsEditing={setIsEditing}
150+
setUserData={setUserData}
151+
/>
135152
) : (
136153
<>
137154
<span className="text-xl font-bold text-[#333333]">
@@ -166,7 +183,7 @@ const UserPage = () => {
166183
<p className="text-xs text-muted-foreground">最高点</p>
167184
</Card>
168185
</div>
169-
<PlayerRankCard rankPoint={2800} />
186+
{userRate && <PlayerRankCard rate={userRate} />}
170187
<button type="button" onClick={() => handleOpenDialog()}>
171188
<StatusList
172189
speedPoint={userStatus?.speedPoint || 0}

app/src/components/view/user/PlayerRankCard.tsx

Lines changed: 29 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,44 @@
1-
"use client";
2-
3-
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
1+
import { Card } from "@/components/ui/card";
42
import { Progress } from "@/components/ui/progress";
5-
import { useEffect, useState } from "react";
6-
7-
type Rank = {
8-
min: number;
9-
max: number;
10-
color: string;
11-
bgColor: string;
12-
};
3+
import type { UserRate as Rate } from "@/types";
134

14-
const ranks: { [key: string]: Rank } = {
5+
const ranks: { [key: string]: { color: string; bgColor: string } } = {
156
ブロンズ: {
16-
min: 0,
17-
max: 499,
187
color: "text-orange-500",
198
bgColor: "bg-orange-100",
209
},
2110
シルバー: {
22-
min: 500,
23-
max: 999,
2411
color: "text-slate-500",
2512
bgColor: "bg-slate-100",
2613
},
2714
ゴールド: {
28-
min: 1000,
29-
max: 1499,
3015
color: "text-yellow-500",
3116
bgColor: "bg-yellow-100",
3217
},
3318
プラチナ: {
34-
min: 1500,
35-
max: 1999,
3619
color: "text-emerald-500",
3720
bgColor: "bg-emerald-100",
3821
},
3922
ダイヤモンド: {
40-
min: 2000,
41-
max: 2499,
4223
color: "text-blue-500",
4324
bgColor: "bg-blue-100",
4425
},
4526
マスター: {
46-
min: 2500,
47-
max: 2999,
4827
color: "text-purple-500",
4928
bgColor: "bg-purple-100",
5029
},
5130
プレデター: {
52-
min: 3000,
53-
max: 3499,
5431
color: "text-red-500",
5532
bgColor: "bg-red-100",
5633
},
5734
};
5835

59-
const getCurrentRank = (rating: number): string | undefined => {
60-
return Object.entries(ranks).find(
61-
([_, { min, max }]) => rating >= min && rating <= max,
62-
)?.[0];
36+
type RateProps = {
37+
rate: Rate;
6338
};
6439

65-
interface PlayerRankCardProps {
66-
rankPoint: number;
67-
}
68-
69-
export default function PlayerRankCard({ rankPoint }: PlayerRankCardProps) {
70-
const [currentRank, setCurrentRank] = useState<string | undefined>(
71-
getCurrentRank(rankPoint),
72-
);
73-
74-
useEffect(() => {
75-
setCurrentRank(getCurrentRank(rankPoint));
76-
}, [rankPoint]);
77-
78-
const nextRank =
79-
currentRank &&
80-
(Object.keys(ranks)[Object.keys(ranks).indexOf(currentRank) + 1] ||
81-
undefined);
82-
83-
if (!currentRank) {
40+
export default function PlayerRankCard({ rate }: RateProps) {
41+
if (!rate.rate) {
8442
return (
8543
<div className="w-[21rem]">
8644
<Card className="w-full max-w-md space-y-6 p-8">
@@ -90,11 +48,17 @@ export default function PlayerRankCard({ rankPoint }: PlayerRankCardProps) {
9048
);
9149
}
9250

51+
// 現在のランクに対応するスタイルを取得
52+
const rankStyles = ranks[rate.rate.name] || {
53+
color: "text-gray-500",
54+
bgColor: "bg-gray-100",
55+
};
56+
9357
const rankPositionPercentage =
9458
100 -
9559
Math.floor(
96-
((rankPoint - ranks[currentRank].min) /
97-
(ranks[currentRank].max - ranks[currentRank].min)) *
60+
((rate.ratePoint - rate.rate.minRange) /
61+
(rate.rate.maxRange - rate.rate.minRange)) *
9862
100,
9963
);
10064

@@ -103,23 +67,23 @@ export default function PlayerRankCard({ rankPoint }: PlayerRankCardProps) {
10367
<Card className="w-full max-w-md space-y-6 p-8">
10468
<div className="flex justify-between items-center">
10569
<div>
106-
<h3 className={`text-3xl font-bold ${ranks[currentRank].color}`}>
107-
{currentRank}
70+
<h3 className={`text-3xl font-bold ${rankStyles.color}`}>
71+
{rate.rate.name}
10872
</h3>
10973
<p className="text-sm text-muted-foreground">現在のランク</p>
11074
</div>
11175
<div
112-
className={`w-16 h-16 rounded-full ${ranks[currentRank].bgColor} flex items-center justify-center`}
76+
className={`w-16 h-16 rounded-full flex items-center justify-center ${rankStyles.bgColor}`}
11377
>
114-
<span className={`text-2xl font-bold ${ranks[currentRank].color}`}>
115-
{rankPoint}
78+
<span className={`text-2xl font-bold ${rankStyles.color}`}>
79+
{rate.ratePoint}
11680
</span>
11781
</div>
11882
</div>
11983
<Progress
12084
value={
121-
((rankPoint - ranks[currentRank].min) /
122-
(ranks[currentRank].max - ranks[currentRank].min)) *
85+
((rate.ratePoint - rate.rate.minRange) /
86+
(rate.rate.maxRange - rate.rate.minRange)) *
12387
100
12488
}
12589
className="h-2 bg-gray-200"
@@ -129,33 +93,33 @@ export default function PlayerRankCard({ rankPoint }: PlayerRankCardProps) {
12993
<div>
13094
<p className="text-muted-foreground">ランク範囲</p>
13195
<p className="font-semibold">
132-
{ranks[currentRank].min} - {ranks[currentRank].max} LP
96+
{rate.rate.minRange} - {rate.rate.maxRange} LP
13397
</p>
13498
</div>
135-
{nextRank && (
99+
{rate.nextRate && (
136100
<>
137101
<div>
138102
<p className="text-muted-foreground">次のランク</p>
139-
<p className="font-semibold">{nextRank}</p>
103+
<p className="font-semibold">{rate.nextRate.name}</p>
140104
</div>
141105
<div>
142106
<p className="text-muted-foreground">次のランクまで</p>
143107
<p className="font-semibold">
144-
{ranks[currentRank].max - rankPoint} LP
108+
{rate.rate.maxRange - rate.ratePoint + 1} LP
145109
</p>
146110
</div>
147111
</>
148112
)}
149113
<div>
150114
<p className="text-muted-foreground">現在のLP</p>
151-
<p className="font-semibold">{rankPoint} LP</p>
115+
<p className="font-semibold">{rate.ratePoint} LP</p>
152116
</div>
153117
</div>
154-
<div className={`p-4 rounded-lg ${ranks[currentRank].bgColor}`}>
118+
<div className={`p-4 rounded-lg ${rankStyles.bgColor}`}>
155119
<p className="text-center text-sm mb-1">ランク内での位置</p>
156120
<div className="flex gap-2 justify-center items-center">
157121
<p className="text-sm font-bold">上位</p>
158-
<p className="text-center text-2xl font-bold">
122+
<p className={`text-center text-2xl font-bold ${rankStyles.color}`}>
159123
{rankPositionPercentage}%
160124
</p>
161125
</div>

app/src/types/index.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,16 @@ export interface ChangeStatus {
144144
totalPoint: number;
145145
id: number;
146146
}
147+
148+
export interface UserRate {
149+
ratePoint: number;
150+
rate: {
151+
name: string;
152+
minRange: number;
153+
maxRange: number;
154+
};
155+
nextRate: {
156+
name: string;
157+
pointsToNextRate: number;
158+
};
159+
}

0 commit comments

Comments
 (0)