From a7320ce8e2b07ba52c51f22be499131fd849b6e7 Mon Sep 17 00:00:00 2001 From: anelka777 <46974606+anelka777@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:48:52 -0800 Subject: [PATCH 1/2] feat(dashboard): implement Dashboard page with mock data and partial logic --- frontend/src/App.tsx | 8 +- frontend/src/assets/icons/CloseIcon.png | Bin 0 -> 503 bytes frontend/src/assets/icons/DocStatIcon.png | Bin 0 -> 11346 bytes .../src/assets/icons/DocumentStudyIcon.png | Bin 0 -> 944 bytes frontend/src/assets/icons/FlashStatIcon.png | Bin 0 -> 17170 bytes .../src/assets/icons/FlashcardStudyIcon.png | Bin 0 -> 751 bytes frontend/src/assets/icons/QuizStudyIcon.png | Bin 0 -> 794 bytes frontend/src/assets/icons/QuizzesStatIcon.png | Bin 0 -> 13177 bytes .../src/assets/icons/SummaryStudyIcon.png | Bin 0 -> 861 bytes .../src/components/dashboard/SetGoalModal.tsx | 105 ++++++++++ .../src/components/dashboard/StatCard.tsx | 50 +++++ .../components/dashboard/StudyHighlights.tsx | 197 ++++++++++++++++++ .../src/components/dashboard/StudyHistory.tsx | 180 ++++++++++++++++ frontend/src/pages/DashboardPage.tsx | 126 +++++++++++ 14 files changed, 662 insertions(+), 4 deletions(-) create mode 100644 frontend/src/assets/icons/CloseIcon.png create mode 100644 frontend/src/assets/icons/DocStatIcon.png create mode 100644 frontend/src/assets/icons/DocumentStudyIcon.png create mode 100644 frontend/src/assets/icons/FlashStatIcon.png create mode 100644 frontend/src/assets/icons/FlashcardStudyIcon.png create mode 100644 frontend/src/assets/icons/QuizStudyIcon.png create mode 100644 frontend/src/assets/icons/QuizzesStatIcon.png create mode 100644 frontend/src/assets/icons/SummaryStudyIcon.png create mode 100644 frontend/src/components/dashboard/SetGoalModal.tsx create mode 100644 frontend/src/components/dashboard/StatCard.tsx create mode 100644 frontend/src/components/dashboard/StudyHighlights.tsx create mode 100644 frontend/src/components/dashboard/StudyHistory.tsx create mode 100644 frontend/src/pages/DashboardPage.tsx diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6987fd6..689018c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3,6 +3,7 @@ import {Navigate, Route, Routes} from "react-router-dom"; import LandingPage from "./pages/LandingPage"; import SignUpPage from "./pages/SignUp"; import SignInPage from "./pages/SignIn"; +import DashboardPage from "./pages/DashboardPage.tsx"; import ResourcePage from "./pages/ResourcePage"; import LibraryPage from "./pages/LibraryPage"; import FlashcardsPage from "./pages/FlashcardsPage"; @@ -16,7 +17,6 @@ const RequireAuth = ({ children }: { children: ReactElement }) => { return children; }; - function App() { return ( @@ -24,6 +24,7 @@ function App() { } /> } /> } /> + }/> @@ -34,6 +35,7 @@ function App() { } /> + @@ -44,6 +46,4 @@ function App() { ); } -export default App; - - +export default App; \ No newline at end of file diff --git a/frontend/src/assets/icons/CloseIcon.png b/frontend/src/assets/icons/CloseIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..2d033aa2554e12b5c3a75ae6d9599d0a4aa323d5 GIT binary patch literal 503 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 UZx8(?7ytkO07*qoM6N<$f}4FBR{#J2 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/icons/DocumentStudyIcon.png b/frontend/src/assets/icons/DocumentStudyIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..a232c19e1579186a74ce94bfb12539320e8a1e0b GIT binary patch literal 944 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

9T8V+Hf91xP&LR^$!Gx;kLKh`Z!xixj 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 Z{y*7X9z<{&a(w^*002ovPDHLkV1jE2NT>h+ literal 0 HcmV?d00001 diff --git a/frontend/src/assets/icons/FlashcardStudyIcon.png b/frontend/src/assets/icons/FlashcardStudyIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..40cd14691fb2c8dcbb6c4ad408862ebcef8f4df7 GIT binary patch literal 751 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 literal 0 HcmV?d00001 diff --git a/frontend/src/components/dashboard/SetGoalModal.tsx b/frontend/src/components/dashboard/SetGoalModal.tsx new file mode 100644 index 0000000..5526232 --- /dev/null +++ b/frontend/src/components/dashboard/SetGoalModal.tsx @@ -0,0 +1,105 @@ +import { useState } from "react"; +import closeIcon from "../../assets/icons/CloseIcon.png"; + + +type Props = { + initialValue: number; + onUpdateGoal: (minutes: number) => void; + onClose: () => void; +}; + +export default function SetGoalModal({ initialValue, onUpdateGoal, onClose }: Props) { + const [value, setValue] = useState( + initialValue ? String(initialValue) : "" + ); + + const isValid: boolean = Number(value) > 0; + + function handleSave(): void { + if (!isValid) return; + onUpdateGoal(Number(value)); + onClose(); + } + + return ( +

+ {/* Overlay */} +
+ + {/* Modal */} +
+ {/* Close button */} + + + {/* Title */} +

+ Set Your Daily Study Goal +

+ + {/* Description */} +

+ How many minutes would you like to study each day? +

+ + {/* Input */} + setValue(e.target.value)} + className=" + mb-6 w-3/5 rounded-3xl border border-gray-200 + px-5 py-3 text-sm + outline-none + focus:border-[var(--color-primary)] + focus:ring-2 focus:ring-[var(--color-primary)]/20" + /> + + {/* Actions */} +
+ + + +
+ + {/* Helper text */} +

+ * You can update this goal anytime. +

+
+
+ ); +} \ No newline at end of file diff --git a/frontend/src/components/dashboard/StatCard.tsx b/frontend/src/components/dashboard/StatCard.tsx new file mode 100644 index 0000000..e3da59b --- /dev/null +++ b/frontend/src/components/dashboard/StatCard.tsx @@ -0,0 +1,50 @@ +import docIcon from "../../assets/icons/DocStatIcon.png"; +import flashcardsIcon from "../../assets/icons/FlashStatIcon.png"; +import quizzesIcon from "../../assets/icons/QuizzesStatIcon.png"; + + +interface StatCardProps { + type: "documents" | "flashcards" | "quizzes"; + value: number; +} + + +export default function StatCard({ type, value }: StatCardProps) { + const titleMap = { + documents: "Documents", + flashcards: "Flashcards", + quizzes: "Quizzes", + }; + + const colorMap = { + documents: "bg-[var(--color-primary)] text-white", + flashcards: "bg-[var(--color-primary-hover)] text-white", + quizzes: "bg-[var(--color-surface)] text-black", + }; + + const iconMap = { + documents: docIcon, + flashcards: flashcardsIcon, + quizzes: quizzesIcon, + }; + + + return ( +
+ {/*Left-side - Value */} +
+
{value}
+
{titleMap[type]}
+
+ + {/* Right-side - Icon */} + {titleMap[type]} +
+ ); +} diff --git a/frontend/src/components/dashboard/StudyHighlights.tsx b/frontend/src/components/dashboard/StudyHighlights.tsx new file mode 100644 index 0000000..99e70c4 --- /dev/null +++ b/frontend/src/components/dashboard/StudyHighlights.tsx @@ -0,0 +1,197 @@ +import SetGoalModal from "../../components/dashboard/SetGoalModal.tsx"; +import React, { useState } from "react"; + +type WeeklyActivity = { + flashcards: number; + summaries: number; + quizzes: number; +}; + +type TodayStats = { + studiedMinutes: number; + goalMinutes: number; + flashcardsReviewed: number; + quizzesCompleted: number; +}; + +type Props = { + weekly: WeeklyActivity; + today: TodayStats; + setTodayStats: React.Dispatch>; +}; + +type WeeklyItem = { + key: keyof WeeklyActivity; + label: string; + color: string; + value: number; + percent: number; +}; + + +export default function StudyHighlights({ weekly, today, setTodayStats }: Props) { + const weeklyTotal: number = + weekly.flashcards + weekly.summaries + weekly.quizzes; + + const flashcardsPct: number = + weeklyTotal > 0 ? (weekly.flashcards / weeklyTotal) * 100 : 0; + + const summariesPct: number = + weeklyTotal > 0 ? (weekly.summaries / weeklyTotal) * 100 : 0; + + const quizzesPct: number = + weeklyTotal > 0 ? (weekly.quizzes / weeklyTotal) * 100 : 0; + + const progressPercent: number = + today.goalMinutes > 0 + ? Math.min((today.studiedMinutes / today.goalMinutes) * 100, 100) + : 0; + + const weeklyItems: WeeklyItem[] = [ + { key: "flashcards", label: "Flashcards", color: "#6B53FF", value: weekly.flashcards, percent: flashcardsPct }, + { key: "summaries", label: "Summaries", color: "#9381FF", value: weekly.summaries, percent: summariesPct,}, + { key: "quizzes", label: "Quizzes", color: "#FFDD64", value: weekly.quizzes, percent: quizzesPct }, + ]; + + const GAP = 0.6; + const [isGoalOpen, setIsGoalOpen] = useState(false); + + + return ( +
+
+
+

Study Highlights

+ + {isGoalOpen && ( + { + setTodayStats((prev: TodayStats) => ({ + ...prev, + goalMinutes: minutes, + })); + }} + onClose={(): void => setIsGoalOpen(false)} + /> + )} + +
+ + {/* Weekly Activity */} +
+
+ Weekly Activity (last 7 days) +
+ +
+ + {/* Ring */} +
+ {/* Gray base ring */} +
+ + {/* Colored segments */} +
{ + const segments: string[] = []; + let startPercent: number = 0; + + weeklyItems.forEach((item: WeeklyItem): void => { + const endPercent: number = startPercent + item.percent; + segments.push(`${item.color} ${startPercent}% ${endPercent - GAP}%`); + segments.push(`transparent ${endPercent - GAP}% ${endPercent}%`); + startPercent = endPercent; + }); + + return `conic-gradient(${segments.join(",")})`; + })(), + WebkitMask: "radial-gradient(circle, transparent 62%, black 63%)", + mask: "radial-gradient(circle, transparent 62%, black 63%)", + }} + /> +
+ + {/* Legend */} +
+ {weeklyItems.map((item: WeeklyItem) => ( +
+ + + {Math.round(item.percent)}% {item.label} + +
+ ))} +
+
+
+ + {/* Today */} +
+
Today
+ + {/* Time Studied */} +
+ {/* Left text */} +
+ Time Studied +
+ + {/* Progress block */} +
+ {/* Min labels */} +
+ {today.studiedMinutes} min + {today.goalMinutes} min +
+ + {/* Progress bar */} +
+
+
+
+
+ + + {/* Stats */} +
+
Flashcards Reviewed {today.flashcardsReviewed} cards
+
Quizzes Completed {today.quizzesCompleted} quiz
+
+
+
+
+

Short study sessions improve retention

+
+
+ ); +} diff --git a/frontend/src/components/dashboard/StudyHistory.tsx b/frontend/src/components/dashboard/StudyHistory.tsx new file mode 100644 index 0000000..003a884 --- /dev/null +++ b/frontend/src/components/dashboard/StudyHistory.tsx @@ -0,0 +1,180 @@ +// import { useNavigate } from "react-router-dom"; +import documentStudyIcon from "../../assets/icons/DocumentStudyIcon.png" +import flashcardStudyIcon from "../../assets/icons/FlashcardStudyIcon.png" +import quizStudyIcon from "../../assets/icons/QuizStudyIcon.png" +import summaryStudyIcon from "../../assets/icons/SummaryStudyIcon.png" +// import { getActivityLog } from "../../api/apiClient.ts" + + + +export type ActivityLogItem = { + id: string; + type: "resource_uploaded" | "summary_created" | "flashcards_created" | "quiz_created"; + resourceId: string; + resourceTitle: string; + createdAt: string; +}; + +type HistoryItem = { + id: string; + type: ActivityLogItem["type"]; + title: string; + resourceTitle: string; + subtitle: string; + resourceId: string; + icon: string; +}; + + +type TabKey = "resource" | "summary" | "flashcards" | "quizzes"; + + +const activityConfig = { + resource_uploaded: { + title: "Document Uploaded", + icon: documentStudyIcon, + }, + summary_created: { + title: "Summary Created", + icon: summaryStudyIcon, + }, + flashcards_created: { + title: "Flashcards Created", + icon: flashcardStudyIcon, + }, + quiz_created: { + title: "Quiz Created", + icon: quizStudyIcon, + }, +} as const; + +const tabMap: Record = { + resource_uploaded: "resource", + summary_created: "summary", + flashcards_created: "flashcards", + quiz_created: "quizzes", +}; + + + +function mapActivityToHistory(item: ActivityLogItem): HistoryItem { + const config = activityConfig[item.type]; + + function pluralize(value: number, unit: string): string { + return value === 1 ? unit : `${unit}s`; + } + + function formatTimeAgo(date: string): string { + const diff: number = Math.floor( + (Date.now() - new Date(date).getTime()) / 1000 + ); + + if (diff < 60) { + const seconds: number = diff; + return `${seconds} ${pluralize(seconds, "second")} ago`; + } + + if (diff < 3600) { + const minutes: number = Math.floor(diff / 60); + return `${minutes} ${pluralize(minutes, "minute")} ago`; + } + + if (diff < 86400) { + const hours: number = Math.floor(diff / 3600); + return `${hours} ${pluralize(hours, "hour")} ago`; + } + + const days: number = Math.floor(diff / 86400); + return `${days} ${pluralize(days, "day")} ago`; + } + + return { + id: item.id, + type: item.type, + title: config.title, + resourceTitle: item.resourceTitle, + subtitle: formatTimeAgo(item.createdAt), + resourceId: item.resourceId, + icon: config.icon, + }; +} + +interface StudyHistoryProps { + data: ActivityLogItem[]; +} + +export default function StudyHistory({ data }: StudyHistoryProps) { + // const navigate = useNavigate(); + const items: HistoryItem[] = data.map(mapActivityToHistory); + + const handleClick = (item: HistoryItem): void => { + if (!item.resourceId) { + alert("No resourceId available!"); + return; + } + alert(`Navigate to resource: ${item.resourceId}\nTab: ${tabMap[item.type]}`); + }; + + /* Backend integration (when API is ready) + + const handleClick = (item: HistoryItem) => { + if (!item.resourceId) return; + navigate(`/resources/${item.resourceId}`, { state: { activeTab: tabMap[item.type] } }); + }; + + const [apiData, setApiData] = useState([]); + + useEffect(() => { + getActivityLog() + .then(setApiData) + .catch((err) => { + console.error("Failed to load activity log", err); + }); + }, []); + + const items = apiData.map(mapActivityToHistory); + */ + + return ( +
+

Study History

+
    + {items.map((item: HistoryItem) => ( +
  • handleClick(item)} + > +
    + +
    +
    + + {item.title} + {" "} + + {item.resourceTitle} + +
    +
    {item.subtitle}
    +
    +
    +
  • + ))} +
+
+ ); +} diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx new file mode 100644 index 0000000..59a3031 --- /dev/null +++ b/frontend/src/pages/DashboardPage.tsx @@ -0,0 +1,126 @@ +import StatCard from "../components/dashboard/StatCard"; +import StudyHighlights from "../components/dashboard/StudyHighlights.tsx"; +import StudyHistory from "../components/dashboard/StudyHistory"; +import type { ActivityLogItem } from "../components/dashboard/StudyHistory"; +import {useState} from "react"; + + +type User = { + firstName: string; + lastName: string; +}; + +type DashboardStats = { + documents: number; + flashcards: number; + quizzes: number; +}; + + +// Mocks +const mockUser: User = { firstName: "Alena", lastName: "Petrov"}; + +const mockStats: DashboardStats = { + documents: 32, + flashcards: 120, + quizzes: 8, +}; + +const mockActivity: ActivityLogItem[] = [ + { id: "1", type: "resource_uploaded", resourceId: "res1", resourceTitle: "UX Principles", createdAt: "2026-01-16T07:00:00Z" }, + { id: "2", type: "flashcards_created", resourceId: "res2", resourceTitle: "React Basics", createdAt: "2026-01-15T13:00:00Z" }, + { id: "3", type: "quiz_created", resourceId: "res1", resourceTitle: "UX Principles", createdAt: "2026-01-14T23:00:00Z" }, + { id: "4", type: "resource_uploaded", resourceId: "res1", resourceTitle: "UX Principles", createdAt: "2026-01-14T17:00:00Z" }, + { id: "5", type: "summary_created", resourceId: "res2", resourceTitle: "React Basics", createdAt: "2026-01-13T17:00:00Z" }, + +]; + +const mockWeeklyActivity = { + flashcards: 50, + summaries: 25, + quizzes: 25, +}; + + +type TodayStats = { + studiedMinutes: number; + goalMinutes: number; + flashcardsReviewed: number; + quizzesCompleted: number; +}; + + +export default function DashboardPage() { + /** + * Auth + * TODO: replace mock user with real auth once backend is ready + */ + // const { user } = useAuth(); + // if (!user) return null; + const user = mockUser; + + /** + * Dashboard stats + * TODO: replace mock data with API call + * Endpoint: GET /api/dashboard/stats + * Expected response: + * { + * documents: number; + * flashcards: number; + * quizzes: number; + * } + */ + // const { data: stats, isLoading, error } = useDashboardStats(); + + const stats: DashboardStats = mockStats; + + + // TEMP: will replace with: + // const { data: activity } = useActivityLog(); + const activity: ActivityLogItem[] = mockActivity; + + + const [todayStats, setTodayStats] = useState({ + studiedMinutes: 25, + goalMinutes: 60, + flashcardsReviewed: 10, + quizzesCompleted: 2, + }); + + return ( +
+
+
+
+
+

+ Hi, {user.firstName} {user.lastName?.charAt(0)}. +

+
+
+ + {/* Stats */} +
+ + + +
+ + {/* Bottom grid */} +
+ + +
+ +
+
+
+
+
+ ); +} + From 33bbeddac7ba325be3543f3a60a81484bced376d Mon Sep 17 00:00:00 2001 From: anelka777 <46974606+anelka777@users.noreply.github.com> Date: Wed, 28 Jan 2026 00:59:24 -0800 Subject: [PATCH 2/2] style(dashboard): fix invalid Tailwind classes in SetGoalModal, StatCard, StudyHighlights, StudyHistory --- frontend/src/components/dashboard/SetGoalModal.tsx | 6 +++--- frontend/src/components/dashboard/StatCard.tsx | 4 ++-- .../src/components/dashboard/StudyHighlights.tsx | 13 ++++++------- frontend/src/components/dashboard/StudyHistory.tsx | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/dashboard/SetGoalModal.tsx b/frontend/src/components/dashboard/SetGoalModal.tsx index 5526232..0943061 100644 --- a/frontend/src/components/dashboard/SetGoalModal.tsx +++ b/frontend/src/components/dashboard/SetGoalModal.tsx @@ -30,7 +30,7 @@ export default function SetGoalModal({ initialValue, onUpdateGoal, onClose }: Pr /> {/* Modal */} -
+
{/* Close button */}