Skip to content

Commit 9beb66c

Browse files
authored
Merge pull request #129 from Logannford/dashboard/todays-question-dashboard-card-component
Dashboard/todays question dashboard card component
2 parents 952caa4 + 73e149f commit 9beb66c

File tree

25 files changed

+468
-63
lines changed

25 files changed

+468
-63
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- CreateEnum
2+
CREATE TYPE "QuestionDifficulty" AS ENUM ('EASY', 'MEDIUM', 'HARD');
3+
4+
-- AlterTable
5+
ALTER TABLE "Questions" ADD COLUMN "QuestionDifficulty" "QuestionDifficulty" NOT NULL DEFAULT 'EASY';
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
Warnings:
3+
4+
- You are about to drop the column `QuestionDifficulty` on the `Questions` table. All the data in the column will be lost.
5+
6+
*/
7+
-- AlterTable
8+
ALTER TABLE "Questions" DROP COLUMN "QuestionDifficulty",
9+
ADD COLUMN "difficulty" "QuestionDifficulty" NOT NULL DEFAULT 'EASY';

prisma/schema.prisma

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ enum userLevel {
1616
PREMIUM
1717
}
1818

19+
enum QuestionDifficulty {
20+
EASY
21+
MEDIUM
22+
HARD
23+
}
24+
1925
model Users {
2026
uid String @id()
2127
email String @unique
@@ -80,6 +86,8 @@ model Questions {
8086
dailyQuestion Boolean @default(false)
8187
8288
tags QuestionTags[]
89+
90+
difficulty QuestionDifficulty @default(EASY)
8391
}
8492

8593
model Tag {

src/actions/questions/get-today.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,37 @@
11
'use server';
22
import { Question } from '@/types/Questions';
33
import { prisma } from '@/utils/prisma';
4+
import { getTagsFromQuestion } from '../utils/get-tags-from-question';
45

56
export const getTodaysQuestion = async (): Promise<Question | null> => {
67
try {
78
// Get the current date at 00:00:00 and the end of the day 23:59:59
89
const todayStart = new Date().toISOString().split('T')[0];
910

1011
// Find a question where `questionDate` is today
11-
return await prisma.questions.findFirst({
12+
const res = await prisma.questions.findFirst({
1213
where: {
13-
questionDate: todayStart
14+
questionDate: todayStart,
1415
},
1516
include: {
1617
answers: true,
18+
tags: {
19+
include: {
20+
tag: true,
21+
},
22+
},
1723
},
1824
});
25+
26+
if (!res) {
27+
console.error('Question not found');
28+
return null;
29+
}
30+
31+
// get the tags from out the question
32+
const question = getTagsFromQuestion(res) as unknown as Question;
33+
34+
return question;
1935
} catch (error) {
2036
console.error("Failed to get today's question:", error);
2137
return null;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use server';
2+
import { Question } from '@/types/Questions';
3+
import { prisma } from '@/utils/prisma';
4+
import { getTagsFromQuestion } from '../utils/get-tags-from-question';
5+
6+
export const getYesterdaysQuestion = async (): Promise<Question | null> => {
7+
try {
8+
// Get yesterday's date at midnight UTC
9+
const yesterday = new Date();
10+
yesterday.setDate(yesterday.getDate() - 1);
11+
yesterday.setHours(0, 0, 0, 0);
12+
const yesterdayISOString = yesterday.toISOString().split('T')[0];
13+
14+
// Find a question where `questionDate` is yesterday
15+
const res = await prisma.questions.findFirst({
16+
where: {
17+
questionDate: yesterdayISOString,
18+
},
19+
include: {
20+
answers: true,
21+
tags: {
22+
include: {
23+
tag: true,
24+
},
25+
},
26+
},
27+
});
28+
29+
console.log({
30+
res,
31+
});
32+
33+
if (!res) {
34+
console.error('No question found for yesterday');
35+
return null;
36+
}
37+
38+
// Get the tags from the question
39+
const question = getTagsFromQuestion(res) as unknown as Question;
40+
41+
return question;
42+
} catch (error) {
43+
console.error("Failed to get yesterday's question:", error);
44+
return null;
45+
}
46+
};

src/app/(default_layout)/dashboard/page.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1+
import { getUserFromDb, getUserFromSession } from '@/actions/user/get-user';
12
import DashboardBentoGrid from '@/components/dashboard/dashboard-bento-grid';
23
import LanguageSwitcher from '@/components/global/language-dropdown';
34
import UserProfileDropdown from '@/components/global/user-profile-dropdown';
45
import { Separator } from '@/components/ui/separator';
6+
import { getUserDisplayName } from '@/utils/user';
57

68
export default async function Dashboard() {
9+
const user = await getUserFromSession();
10+
if (!user?.data?.user?.id) return null;
11+
const userData = await getUserFromDb(user?.data?.user?.id);
12+
if (!userData) return null;
13+
714
return (
815
<div className="text-white flex flex-col gap-y-4 h-full">
916
<div className="flex w-full justify-between">
1017
<h1 className="text-xl md:text-4xl font-satoshi font-semibold">
11-
Overview
18+
Welcome back, {getUserDisplayName(userData)}!
1219
</h1>
1320
<div className="flex item-center gap-x-3">
1421
<LanguageSwitcher />

src/app/(default_layout)/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default function Layout({
3030
{/* Scrollable content */}
3131
<AppSidebar />
3232
<main className="w-full pr-6 py-6 lg:pt-6 lg:pb-3">
33-
<div className="lg:pl-4 h-full">
33+
<div className="lg:pl-4 h-[95%]">
3434
{/* <SidebarTrigger className="size-4 h-full flex items-center my-auto -top-2.5 relative" /> */}
3535
{children}
3636
</div>

src/app/(default_layout)/leaderboard/today/page.client.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,15 @@ export default function TodaysLeaderboardPageClient(opts: {
4242

4343
return (
4444
<div className="h-full">
45-
{data?.fastestTimes.length === 0 && (
46-
<div className="w-full flex flex-col gap-y-1 justify-center items-center ">
47-
<p>No fastest times yet!</p>
48-
<Button variant="secondary" href={`/question/${questionUid}`}>
49-
Click here to be the first!
50-
</Button>
51-
</div>
52-
)}
45+
{data?.fastestTimes.length === 0 ||
46+
(!data && (
47+
<div className="w-full flex flex-col gap-y-1 justify-center items-center ">
48+
<p>No fastest times yet!</p>
49+
<Button variant="secondary" href={`/question/${questionUid}`}>
50+
Click here to be the first!
51+
</Button>
52+
</div>
53+
))}
5354
<div className="h-full flex flex-col justify-between">
5455
<div className="flex flex-col gap-y-1">
5556
{data?.fastestTimes.map((time, i) => {

src/app/globals.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ body {
5858
:root {
5959
--background: 0 0% 100%;
6060
--foreground: 240 10% 3.9%;
61-
--card: 0 0% 100%;
61+
--card: 0 0% 5% 1;
6262
--card-foreground: 240 10% 3.9%;
6363
--popover: 0 0% 100%;
6464
--popover-foreground: 240 10% 3.9%;

src/components/questions/dashboard/all-questions-bento-box.tsx renamed to src/components/dashboard/all-questions-bento-box.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
'use client';
22
import React, { useState } from 'react';
3-
import Chip from '../../global/chip';
3+
import Chip from '../global/chip';
44
import DashboardQuestionCard from './dashboard-question-card';
5-
import { Arrow } from '@radix-ui/react-tooltip';
65
import { ArrowRight } from 'lucide-react';
6+
import { Grid } from '../ui/grid';
77

88
export default function AllQuestionsDashboardBentoBox() {
99
const questions = [
@@ -19,18 +19,23 @@ export default function AllQuestionsDashboardBentoBox() {
1919
const [allQuestions] = useState([...questions, ...questions, ...questions]);
2020

2121
return (
22-
<section className="h-full flex flex-col gap-y-5 group">
22+
<section className="h-full flex flex-col gap-y-5 group p-4 relative overflow-hidden">
23+
<Grid size={20} position="top-right" />
2324
<div className="space-y-3">
2425
<Chip color="accent" text="Questions" />
2526
<h6 className="text-lg lg:text-xl flex items-center">
2627
View all Questions
27-
<ArrowRight className="w-4 h-4 inline-block ml-1 group-hover:ml-2 duration-300" />
28+
<ArrowRight className="size-4 inline-block ml-1 group-hover:ml-2 duration-300" />
2829
</h6>
2930
</div>
3031

31-
<div className="relative overflow-hidden mt-3 h-64">
32+
<div className="relative overflow-hidden mt-3 md:h-64 xl:h-[17rem]">
33+
{/* Top fade effect */}
34+
<div className="absolute top-0 left-0 right-0 h-12 bg-gradient-to-b from-black-75 to-transparent z-10" />
35+
36+
{/* Scrolling content */}
3237
<div
33-
className="animate-scroll hover:pause-animation"
38+
className="animate-scroll hover:pause-animation relative z-0"
3439
style={
3540
{ '--question-count': questions.length } as React.CSSProperties
3641
}
@@ -42,6 +47,9 @@ export default function AllQuestionsDashboardBentoBox() {
4247
/>
4348
))}
4449
</div>
50+
51+
{/* Bottom fade effect */}
52+
<div className="absolute bottom-0 left-0 right-0 h-12 bg-gradient-to-t from-black-75 to-transparent z-10" />
4553
</div>
4654
</section>
4755
);

0 commit comments

Comments
 (0)