Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

課題の表示変更 #55

Merged
merged 6 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 1 addition & 41 deletions app/src/app/api/score/imagelist/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,7 @@ import { prisma } from "@lib/prisma";

export async function GET() {
const allScores = await prisma.score.findMany({
select: {
id: true,
point: true,
answerTime: true,
similarity: true,
assignmentId: true,
userId: true,
imageUrl: true,
createdAt: true,
updatedAt: true,
user: {
select: {
id: true,
uid: true,
name: true,
email: true,
photoUrl: true,
createdAt: true,
updatedAt: true,
},
},
assignment: {
select: {
id: true,
wordId: true,
date: true,
createdAt: true,
updatedAt: true,
word: {
select: {
id: true,
english: true,
japanese: true,
difficulty: true,
createdAt: true,
updatedAt: true,
},
},
},
},
},
include: { assignment: { include: { word: true } }, user: true },
orderBy: { createdAt: "desc" },
});

Expand Down
146 changes: 104 additions & 42 deletions app/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@ import { Progress } from "@/components/ui/progress";
import { PointDialog } from "@/components/view/PointDialog";
import Timer from "@/components/view/Timer";
import { useHasShownOnce, usePointDialogOpen } from "@/lib/atom";
import type { MyScoreDetail, todayAssignment } from "@/types";
import type { MyScoreDetail, Score, todayAssignment } from "@/types";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { LuArrowRight, LuCheckCircle } from "react-icons/lu";
import ClockIcon from "../../public/icons/icon-clock.svg";
import PhotoCameraIcon from "../../public/icons/icon-photo-camera.svg";

export default function Home() {
const [myScore, setMyScore] = useState<MyScoreDetail[]>([]);
const [assignment, setAssignment] = useState<todayAssignment[]>([]);
const [todayAssignment, setTodayAssignment] = useState<todayAssignment>();
const [isLoading, setIsLoading] = useState(true);
const [progressCount, setProgressCount] = useState(0);
const router = useRouter();
const [isAnsweredAll, setIsAnsweredAll] = useState(false);
const [highestScore, setHighestScore] = useState(0);
const [_, setIsPointDialogOpen] = usePointDialogOpen();
const [hasShownOnce, setHasShownOnce] = useHasShownOnce();

Expand Down Expand Up @@ -45,10 +50,19 @@ export default function Home() {
}
const data = await response.json();
setMyScore(data);

const maxScore: number = data.reduce(
(max: number, score: Score) =>
score.point > max ? score.point : max,
0,
);
setHighestScore(maxScore);
setProgressCount(66);

// get api/assignment/today
const resAssignment = await fetch("/api/assignment/today");
const resAssignment = await fetch(
`/api/assignment/today?uid=${userData?.uid}`,
);
if (!resAssignment.ok) {
throw new Error("データの取得に失敗しました");
}
Expand All @@ -57,6 +71,17 @@ export default function Home() {
throw new Error("無効なデータが返されました");
}

const isNotAnsweredAssignment = resData.find(
(assignment) => assignment.isAnswered === false,
);

const isAnsweredAll =
resData.filter((assignment) => assignment.isAnswered).length ===
resData.length;
setIsAnsweredAll(isAnsweredAll);

setTodayAssignment(isNotAnsweredAssignment);

const formattedData = resData.map((item) => {
const date = item.assignTime ? new Date(item.assignTime) : new Date();
return {
Expand Down Expand Up @@ -89,51 +114,85 @@ export default function Home() {
.sort((a, b) => (b.assignTime?.getTime() ?? 0) - (a.assignTime?.getTime() ?? 0))[0];

return (
<div className="flex flex-col h-full px-10 py-10 bg-gradient-to-t from-gray-300 via-gray-200 to-gray-50">
<PointDialog type="login" />
<div className="flex flex-col min-h-screen px-10 py-10 bg-gradient-to-t from-gray-300 via-gray-200 to-gray-50">
<div className="flex flex-col items-center justify-center space-y-6">
{isLoading ? (
<Card className="w-full py-3 px-7">
<div className="h-[6rem] gap-2 font-bold #333 flex flex-col items-center justify-center">
Loading...
<Progress value={progressCount} />
{!isAnsweredAll &&
(isLoading ? (
<Card className="w-full py-3 px-7">
<div className="h-[6rem] gap-2 font-bold #333 flex flex-col items-center justify-center">
Loading...
<Progress value={progressCount} />
</div>
</Card>
) : (
<div className="text-lg w-full">
{assignment[0]?.assignTime && (
// fixme [0]番目を参照しているがお題ごとに可変的にする必要あり。
<Timer assignTime={assignment[0]?.assignTime} />
)}
</div>
))}
{!isAnsweredAll && todayAssignment && (
<Card
className="flex flex-col items-center justify-around aspect-square w-full p-6"
style={{
background:
"linear-gradient(90deg, rgba(255, 145, 109, 0.56) 0%, rgba(255, 90, 170, 0.44) 51%, rgba(139, 166, 255, 0.61) 100%)",
}}
>
<div className="text-center mb-4">
<h2 className="text-lg font-semibold mb-2">今日のお題</h2>
<p className="text-sm text-gray-600">撮影してスコアを競おう!</p>
</div>
<h1 className="text-3xl font-bold text-center mb-4">
{todayAssignment?.english}
</h1>
<div className="flex justify-center w-full">
<Button
variant="default"
className="flex items-center justify-center w-3/4 bg-gray-800 hover:bg-gray-700 text-white py-6 space-x-2"
asChild
>
<Link href="camera">
<div className="w-6 h-auto">
<PhotoCameraIcon />
</div>
<span className="text-lg font-semibold">写真を撮る</span>
</Link>
</Button>
</div>
</Card>
) : (
<div className="text-lg w-full">
{latestAssignment?.assignTime && (
// fixme [0]番目を参照しているがお題ごとに可変的にする必要あり。
<Timer assignTime={latestAssignment?.assignTime} />
)}
</div>
)}
<Card
className="flex flex-col items-center justify-around aspect-square w-full p-6 backdrop-blur-sm"
style={{
background:
"linear-gradient(90deg, rgba(255, 145, 109, 0.56) 0%, rgba(255, 90, 170, 0.44) 51%, rgba(139, 166, 255, 0.61) 100%)",
}}
>
<div className="text-center mb-4">
<h2 className="text-lg font-semibold mb-2">今日のお題</h2>
<p className="text-sm text-gray-600">撮影してスコアを競おう!</p>
</div>
<h1 className="text-3xl font-bold text-center mb-4">
{latestAssignment?.english}
</h1>
<div className="flex justify-center w-full">
<Button
variant="default"
className="flex items-center justify-center w-3/4 bg-gray-800 hover:bg-gray-700 text-white py-6 space-x-2"
onClick={() => router.push("/camera")}
>
<div className="w-6 h-auto">
<PhotoCameraIcon />
{isAnsweredAll && (
<Card className="w-full max-w-md bg-white overflow-hidden">
<div className="p-8 text-center">
<LuCheckCircle className="w-20 h-20 text-green-500 mx-auto mb-6" />
<h2 className="text-3xl font-bold mb-4 text-gray-800">
全課題完了
</h2>
<p className="text-gray-600 mb-8">
おめでとうございます。全ての課題をクリアしました!
</p>
<div className="bg-gray-100 rounded-2xl p-6 mb-8">
<h3 className="text-xl font-semibold text-gray-700 mb-2">
最終スコア
</h3>
<p className="text-4xl font-bold text-purple-600">
{highestScore}点
</p>
</div>
<span className="text-lg font-semibold">写真を撮る</span>
</Button>
</div>
</Card>
<Button
className="w-full bg-gradient-to-r from-pink-500 to-purple-500 text-white font-semibold py-3 px-6 rounded-full hover:from-pink-600 hover:to-purple-600 transition duration-300"
asChild
>
<Link href="ranking">
結果を確認する
<LuArrowRight className="ml-2 w-5 h-5" />
</Link>
</Button>
</div>
</Card>
)}
<Card className="flex flex-col items-center aspect-square w-full p-6 bg-white/80 backdrop-blur-sm">
<h2 className="text-lg font-semibold mb-4">過去のチャレンジ</h2>
{myScore.length === 0 ? (
Expand All @@ -142,6 +201,9 @@ export default function Home() {
<p className="text-sm mt-2">
新しいチャレンジに挑戦してみましょう!
</p>
<p className="text-sm mt-2">
新しいチャレンジに挑戦してみましょう!
</p>
</div>
) : (
myScore.map((score) => (
Expand Down
Loading