Skip to content

Commit

Permalink
Merge pull request #42 from jphacks/feat/hikahana/assignment-timer
Browse files Browse the repository at this point in the history
お題が出てからの経過時間を表示
  • Loading branch information
TkymHrt authored Nov 12, 2024
2 parents 006abbc + 7a75ce2 commit 5f366e6
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 85 deletions.
38 changes: 38 additions & 0 deletions app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@radix-ui/react-alert-dialog": "^1.1.2",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-progress": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
Expand Down
4 changes: 2 additions & 2 deletions app/src/app/api/assignment/latest/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { todayAssignment } from "@/types";
import type { latestAssignment } from "@/types";
import { prisma } from "@lib/prisma";

// 最新の課題を取得
Expand All @@ -17,7 +17,7 @@ export async function GET() {
});
}

const latestAssignment: todayAssignment = {
const latestAssignment: latestAssignment = {
assignmentId: assignment.id,
english: assignment.word.english,
};
Expand Down
20 changes: 8 additions & 12 deletions app/src/app/api/assignment/today/route.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,36 @@
;import { prisma } from "@lib/prisma";
import type { Assignment, todayAssignment } from "@/types";
import { prisma } from "@lib/prisma";

// 課題新規作成(ランダム)
export async function GET() {
const startOfToday = new Date();
startOfToday.setHours(0, 0, 0, 0); // 今日の開始時間を設定 (00:00:00)

const endOfToday = new Date();
endOfToday.setHours(23, 59, 59, 999); // 今日の終了時間を設定 (23:59:59)

const assignments = await prisma.assignment.findMany({
where: {
date: {
gte: startOfToday, // 今日の開始時間以上
lte: endOfToday, // 今日の終了時間以下
gte: startOfToday, // 今日の開始時間以上
lte: endOfToday, // 今日の終了時間以下
},
},
include: { word: true },
},
include: { word: true },
});
console.log(assignments);

const todayAssignments: todayAssignment[] = assignments.map((assignment) => {
const todayAssignment: todayAssignment = {
assignmentId: assignment.id,
english: assignment.word.english,
assignTime: assignment.date,
};
return todayAssignment;
})
});

return new Response(JSON.stringify(todayAssignments), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}





4 changes: 2 additions & 2 deletions app/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const notoSansJP = Noto_Sans_JP({
});

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "Let`s pics",
description: "Let`s pics",
};

export default function RootLayout({
Expand Down
51 changes: 46 additions & 5 deletions app/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@

import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import type { MyScoreDetail } from "@/types";
import { Progress } from "@/components/ui/progress";
import Timer from "@/components/view/Timer";
import type { MyScoreDetail, todayAssignment } from "@/types";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
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 [isLoading, setIsLoading] = useState(true);
const [progressCount, setProgressCount] = useState(0);
const router = useRouter();

useEffect(() => {
Expand All @@ -20,18 +25,37 @@ export default function Home() {
}

try {
// get api/score/me
const userData = JSON.parse(userIdString);
const uid = userData.uid;
if (!uid) {
throw new Error("User ID not found");
}
setProgressCount(33);

const response = await fetch(`/api/score/me/${uid}?limit=3`);
if (!response.ok) {
throw new Error("データの取得に失敗しました");
}
const data = await response.json();
setMyScore(data);
setProgressCount(66);

// get api/assignment/today
const resAssignment = await fetch("/api/assignment/today");
if (!resAssignment.ok) {
throw new Error("データの取得に失敗しました");
}
const resData: todayAssignment[] = await resAssignment.json();
if (!resData) {
throw new Error("無効なデータが返されました");
}
const formattedData = resData.map((item) => ({
...item,
assignTime: new Date(item.assignTime),
}));
setAssignment(formattedData);
setIsLoading(false);
} catch (error) {
console.error("エラーが発生しました:", error);
}
Expand All @@ -41,10 +65,25 @@ export default function Home() {
}, []);

return (
<div className="flex flex-col h-full px-4 py-10 bg-gradient-to-t from-gray-300 via-gray-200 to-gray-50">
<div className="flex flex-col h-full 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} />
</div>
</Card>
) : (
<div className="text-lg w-full">
{assignment && (
// fixme [0]番目を参照しているがお題ごとに可変的にする必要あり。
<Timer assignTime={assignment[0]?.assignTime} />
)}
</div>
)}
<Card
className="flex flex-col items-center justify-around aspect-square w-full max-w-72 p-6 backdrop-blur-sm"
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%)",
Expand All @@ -54,7 +93,9 @@ export default function Home() {
<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">Labyrinthine</h1>
<h1 className="text-3xl font-bold text-center mb-4">
{assignment[0]?.english}
</h1>
<div className="flex justify-center w-full">
<Button
variant="default"
Expand All @@ -68,7 +109,7 @@ export default function Home() {
</Button>
</div>
</Card>
<Card className="flex flex-col items-center aspect-square w-10/12 p-6 bg-white/80 backdrop-blur-sm">
<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 ? (
<div className="text-gray-500 text-center py-8">
Expand Down
25 changes: 25 additions & 0 deletions app/src/components/ui/progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use client";

import * as ProgressPrimitive from "@radix-ui/react-progress";
import * as React from "react";

import { cn } from "@/lib/utils";

const Progress = React.forwardRef<
React.ElementRef<typeof ProgressPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
>(({ className, value, ...props }, ref) => (
<ProgressPrimitive.Root
ref={ref}
className={cn("relative h-2 w-full overflow-hidden rounded-full bg-primary/20", className)}
{...props}
>
<ProgressPrimitive.Indicator
className="h-full w-full flex-1 bg-primary transition-all"
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
</ProgressPrimitive.Root>
));
Progress.displayName = ProgressPrimitive.Root.displayName;

export { Progress };
57 changes: 57 additions & 0 deletions app/src/components/view/Timer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Card } from "@/components/ui/card";
import { type FC, useEffect, useState } from "react";

interface TimerProps {
assignTime: Date;
}

const Timer: FC<TimerProps> = ({ assignTime }) => {
const [elapsedTime, setElapsedTime] = useState(0);
const startTime = new Date(assignTime).getTime();

useEffect(() => {
const interval = setInterval(() => {
const currentTime = new Date();
const timeElapsed = currentTime.getTime() - startTime;
setElapsedTime(timeElapsed);
}, 1000);

return () => {
clearInterval(interval);
};
}, [startTime]);

// 経過時間を時間、分、秒に変換
const formatTime = (ms: number) => {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);

return {
hh: hours % 24,
mm: minutes % 60,
ss: seconds % 60,
};
};

const { hh, mm, ss } = formatTime(elapsedTime);

const formattedHours = String(hh).padStart(2, "0");
const formattedMinutes = String(mm).padStart(2, "0");
const formattedSeconds = String(ss).padStart(2, "0");

return (
<Card className="bg-white rounded-lg border-gray-300 w-full">
<div className="text-lg h-[6rem] w-full p-4 flex flex-col justify-center items-center text-gray-800">
<div className="mb-2 text-xl font-semibold">経過時間</div>
<div className="flex text-3xl font-bold font-mono">
<span className="mx-1">{formattedHours}</span>:
<span className="mx-1">{formattedMinutes}</span>:
<span className="mx-1">{formattedSeconds}</span>
</div>
</div>
</Card>
);
};

export default Timer;
Loading

0 comments on commit 5f366e6

Please sign in to comment.