+
@@ -571,16 +571,20 @@ export default function LearningStyleQuiz() {
{renderQuestion()}
{/* Navigation Buttons */}
-
+
-
);
-}
+}
\ No newline at end of file
diff --git a/app/student/onboarding/page.tsx b/app/student/onboarding/page.tsx
index f29f867..94e2fa5 100644
--- a/app/student/onboarding/page.tsx
+++ b/app/student/onboarding/page.tsx
@@ -1,37 +1,297 @@
-import { createClient } from "@/lib/supabase/server";
-import { redirect } from "next/navigation";
-import StudentOnboardingForm from "./StudentOnboardingForm";
-
-export default async function StudentOnboardingPage() {
- const supabase = await createClient();
-
- const { data: { user }, error: authError } = await supabase.auth.getUser();
-
- // If not authenticated, redirect to login
- if (authError || !user) {
- redirect('/auth/login');
- }
-
- // Check if user already completed onboarding
- const { data: existingRole } = await supabase
- .from('user_role')
- .select('role')
- .eq('user_id', user.id)
- .single();
-
- if (existingRole) {
- // User already onboarded, redirect to dashboard
- redirect(existingRole.role === 'student' ? '/student/dashboard' : '/educator/dashboard');
- }
-
- // Check role from metadata - make sure they should be here
- const role = user.user_metadata?.role;
-
- if (role !== 'student') {
- // Wrong onboarding page, redirect to correct one or home
- redirect(role === 'educator' ? '/educator/onboarding' : '/');
- }
-
- // User is authenticated, has student role, and hasn't completed onboarding
- return
;
+"use client";
+
+import { useState } from "react";
+import { useRouter } from "next/navigation";
+import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { Textarea } from "@/components/ui/textarea";
+import Image from "next/image";
+
+export default function StudentOnboardingForm() {
+ const router = useRouter();
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState
(null);
+ const [step, setStep] = useState(1);
+ const [formData, setFormData] = useState({
+ firstname: "",
+ lastname: "",
+ plan: "",
+ grade_reading: "",
+ grade_math: "",
+ current_level: "",
+ career_interests: "",
+ goals: "",
+ });
+
+ const stepOneValid =
+ formData.firstname.trim() !== "" && formData.lastname.trim() !== "";
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+ setError(null);
+
+ try {
+ const response = await fetch("/api/student/onboarding", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(formData),
+ });
+
+ const data = await response.json();
+
+ if (!response.ok) {
+ throw new Error(data.error || "Failed to create profile");
+ }
+
+ // Redirect to dashboard
+ router.push(data.redirectTo || "/student/dashboard");
+ router.refresh(); // Refresh to update any server components
+ } catch (error) {
+ console.error("Error:", error);
+ setError(error instanceof Error ? error.message : "An error occurred");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+ {/* Progress Bar */}
+
+
+
+
Create your profile
+ Step {step} of 3
+
+
+
+
+
+
+
+
+
+ Ready to ace the GED?
+
+
+ Let's start with the basics.
+
+
+
+ {error && (
+
+ )}
+
+
+
+
+
+
+ );
+}
+
+function StepOne({ formData, setFormData }: any) {
+ return (
+
+ {/* Profile photo */}
+
+
+
+
+ {/* Avatar */}
+
+ {/* add uploaded image here */}
+ {/* */}
+
+
+ {formData.firstname || formData.lastname
+ ? `${formData.firstname?.[0]?.toUpperCase() ?? ""}${
+ formData.lastname?.[0]?.toUpperCase() ?? ""
+ }`
+ : "?"}
+
+
+
+ {/* Camera badge */}
+
document.getElementById("photo-upload")?.click()}
+ className="
+ absolute
+ bottom-0
+ right-0
+ sm:bottom-1
+ sm:right-1
+ h-8
+ w-8
+ sm:h-10
+ sm:w-10
+ rounded-full
+ bg-lime-300
+ flex
+ items-center
+ justify-center
+ shadow
+ hover:bg-lime-400
+ transition
+ "
+ >
+
+
+
+ {/* File input */}
+
{
+ const file = e.target.files?.[0];
+ if (file) {
+ // TODO: handle upload later
+ console.log(file);
+ }
+ }}
+ />
+
+
+
Help instructors recognize you.
+
+
+
+ setFormData({ ...formData, firstname: e.target.value })
+ }
+ required
+ />
+
+
setFormData({ ...formData, lastname: e.target.value })}
+ required
+ />
+
+ );
+}
+
+function StepTwo({ formData, setFormData }: any) {
+ return (
+
+
What are your career interests?
+
+ Select areas you're curious about or want to explore.
+
+
+
+ );
+}
+
+function StepThree({ formData, setFormData }: any) {
+ return (
+
+
What are your goals?
+
+ What do you hope to achieve with Eight Million Stories?
+
+
+
+
Think about:
+
+ - Education milestones
+ - Skills you want to learn
+ - Jobs you're interested in
+
+
+
+
+ );
}
\ No newline at end of file
diff --git a/domains/auth/LoginForm.tsx b/domains/auth/LoginForm.tsx
index 59a45f5..8649a68 100644
--- a/domains/auth/LoginForm.tsx
+++ b/domains/auth/LoginForm.tsx
@@ -1,5 +1,4 @@
"use client";
-
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { useState } from "react";
@@ -25,34 +24,27 @@ export default function LoginForm() {
toast.error("Password is required");
return;
}
-
setLoading(true);
-
try {
const supabase = await createClient();
-
// Sign in
const { data: signInData, error: signInError } =
await supabase.auth.signInWithPassword({
email: email,
password: password,
});
-
if (signInError) {
console.error(signInError);
toast.error(signInError.message || "Invalid email or password");
return;
}
-
// Check if user is in Students table
const { data: studentData } = await supabase
.from("Students")
.select("*")
.eq("email", email)
.single();
-
toast.success("Login successful!");
-
// Route based on whether they're in Students table
if (studentData) {
router.push("/student/onboarding");
@@ -68,45 +60,42 @@ export default function LoginForm() {
};
return (
-
- {/* Left Column */}
-
-
+
+ {/* Left Column - Form */}
+
+
{/* Header */}
-
+
Log In
{/* Form */}
-
- {/* Right Column */}
-
-
-
-
+ {/* Right Column - Logo */}
+
+
);
-}
+}
\ No newline at end of file
diff --git a/domains/auth/SignupForm.tsx b/domains/auth/SignupForm.tsx
index ba0ab21..8f5e128 100644
--- a/domains/auth/SignupForm.tsx
+++ b/domains/auth/SignupForm.tsx
@@ -94,57 +94,68 @@ export default function SignupForm() {
if (signupComplete) {
return (
-
-
Check your email
-
-
We've sent a confirmation email to:
-
{email}
-
- Click the link in the email to complete your signup and you'll be
- automatically redirected to the onboarding page.
-
+
+
+
Check your email
+
+
+ We've sent a confirmation email to:
+
+
+ {email}
+
+
+ Click the link in the email to complete your signup and you'll be
+ automatically redirected to the onboarding page.
+
+
+
+ {loading ? "Signing up..." : "Resend Email"}
+
-
- {loading ? "Signing up..." : "Resend Email"}
-
);
}
return (
-
- {/* Left Column */}
-
+
+ {/* Left Column - Form */}
+
-
+
Sign Up
-
+
-
+
{loading ? "Signing up..." : "Sign Up"}
-
+
Already have an account?{" "}
Log in
@@ -177,17 +188,15 @@ export default function SignupForm() {
- {/* Right Column */}
-
-
-
-
+ {/* Right Column - Logo */}
+
+
);
@@ -210,7 +219,7 @@ const FormItem = ({
value={input}
onChange={(e) => setInput(e.target.value)}
required
- className="border border-black h-11 bg-gray-100 text-black placeholder:text-black"
+ className="border border-black h-10 sm:h-11 bg-gray-100 text-black placeholder:text-black text-sm sm:text-base"
/>
);
};
@@ -232,7 +241,7 @@ const FormPassword = ({
value={input}
onChange={(e) => setInput(e.target.value)}
required
- className="border border-black h-11 bg-gray-100 text-black placeholder:text-black"
+ className="border border-black h-10 sm:h-11 bg-gray-100 text-black placeholder:text-black text-sm sm:text-base"
/>
);
};
@@ -247,16 +256,16 @@ const RoleSelect = ({
const roles = Object.values(UserRole);
return (
);
-};
+};
\ No newline at end of file
diff --git a/domains/educator/onboarding/OnboardingForm.tsx b/domains/educator/onboarding/OnboardingForm.tsx
index fc00efe..1a6232a 100644
--- a/domains/educator/onboarding/OnboardingForm.tsx
+++ b/domains/educator/onboarding/OnboardingForm.tsx
@@ -1,13 +1,12 @@
"use client";
-
-import {Button} from "@/components/ui/button";
-import {useRouter} from "next/navigation";
-import {toast} from "sonner";
-import {useEducatorOnboarding} from "./hooks/useEducatorOnboarding";
+import { Button } from "@/components/ui/button";
+import { useRouter } from "next/navigation";
+import { toast } from "sonner";
+import { useEducatorOnboarding } from "./hooks/useEducatorOnboarding";
export default function OnboardingForm() {
const router = useRouter();
- const {mutate: insertEducator, isPending} = useEducatorOnboarding();
+ const { mutate: insertEducator, isPending } = useEducatorOnboarding();
const handleFinishOnboarding = () => {
insertEducator(undefined, {
@@ -16,18 +15,29 @@ export default function OnboardingForm() {
router.push("/educator/dashboard");
router.refresh();
},
- onError: error => {
+ onError: (error) => {
toast.error(error.message || "Failed to complete onboarding");
},
});
};
return (
-
-
Educator Onboarding
-
- {isPending ? "Processing..." : "Finish Onboarding"}
-
+
+
+
+ Educator Onboarding
+
+
+ Complete your setup to start managing your students and courses.
+
+
+ {isPending ? "Processing..." : "Finish Onboarding"}
+
+
);
-}
+}
\ No newline at end of file
diff --git a/domains/student/dashboard/GreetingCard.tsx b/domains/student/dashboard/GreetingCard.tsx
index 3d68a4a..8d8430f 100644
--- a/domains/student/dashboard/GreetingCard.tsx
+++ b/domains/student/dashboard/GreetingCard.tsx
@@ -1,4 +1,7 @@
+import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
+import { Badge } from "@/components/ui/badge";
import { Card, CardContent } from "@/components/ui/card";
+import { Progress } from "@/components/ui/progress";
interface GreetingCardProps {
student: string | null;
@@ -6,39 +9,24 @@ interface GreetingCardProps {
export default function GreetingCard({ student }: GreetingCardProps) {
return (
-
-
- {/* Avatar Section */}
-
-

-
-
- {/* Text & Progress Section */}
-
-
- Hello {student || 'Student'}!
+
+
+
+
+
+
+ {student?.charAt(0).toUpperCase() || "S"}
+
+
+
+ Hello {student || "Student"}!
-
-
-
-
- Course Progress
-
-
- 33%
-
-
-
- {/* The Green Progress Bar */}
-
-
+
+
COURSE PROGRESS
+ 33%
+
+
);
diff --git a/domains/student/dashboard/PromptDiagnosticCard.tsx b/domains/student/dashboard/PromptDiagnosticCard.tsx
index 9101bc4..ef6707f 100644
--- a/domains/student/dashboard/PromptDiagnosticCard.tsx
+++ b/domains/student/dashboard/PromptDiagnosticCard.tsx
@@ -1,23 +1,24 @@
-"use client";
-
+import Link from "next/link";
import { Button } from "@/components/ui/button";
-import { useRouter } from "next/navigation";
+import { Card, CardContent } from "@/components/ui/card";
export default function PromptDiagnosticCard() {
- const router = useRouter();
-
return (
-
-
Start Your Diagnostic Assessment
-
- Complete this one-time quiz to unlock lessons, feedback, and progress tracking.
-
-
router.push('/student/diagnostic')}
- className="bg-black text-white px-10 py-6 rounded-xl font-bold hover:bg-zinc-800 transition-all mt-2"
- >
- Start Quiz
-
-
+
+
+
+ Start Your Diagnostic Assessment
+
+
+ Complete this one-time quiz to unlock lessons, feedback, and progress
+ tracking.
+
+
+
+ Start Quiz
+
+
+
+
);
}
\ No newline at end of file
diff --git a/domains/student/dashboard/RecentQuizCompletions.tsx b/domains/student/dashboard/RecentQuizCompletions.tsx
index 83eeb3e..bc362f6 100644
--- a/domains/student/dashboard/RecentQuizCompletions.tsx
+++ b/domains/student/dashboard/RecentQuizCompletions.tsx
@@ -1,40 +1,36 @@
+import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { CheckCircle2, Clock } from "lucide-react";
+import QuizCompletionCard from "@/components/quiz-completion";
interface RecentQuizCompletionsProps {
// defaulting to empty array to prevent crash
completedQuizzes?: any[];
}
-export default function RecentQuizCompletions({ completedQuizzes = [] }: RecentQuizCompletionsProps) {
+export default function RecentQuizCompletions({
+ completedQuizzes,
+}: RecentQuizCompletionsProps) {
return (
-
-
- Recent Activity
+
+
+
+ Recent Quiz Completions
+
-
- {/* Safety check: ensure completedQuizzes exists and has length */}
- {!completedQuizzes || completedQuizzes.length === 0 ? (
- No recent activity found.
- ) : (
-
+
+ {completedQuizzes.length > 0 ? (
+
{completedQuizzes.map((quiz) => (
-
-
-
-
Quiz Completed
-
-
-
- {quiz.end_time
- ? new Date(quiz.end_time).toLocaleDateString()
- : "Unknown Date"}
-
-
-
-
+
))}
+
+ View All
+
+ ) : (
+
+ No completed quizzes yet
+
)}
diff --git a/domains/student/dashboard/RecommendedQuizzes.tsx b/domains/student/dashboard/RecommendedQuizzes.tsx
index 74e9d1c..70905db 100644
--- a/domains/student/dashboard/RecommendedQuizzes.tsx
+++ b/domains/student/dashboard/RecommendedQuizzes.tsx
@@ -1,62 +1,48 @@
-"use client";
-
-import { Card, CardContent } from "@/components/ui/card";
+import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
-import { useRouter } from "next/navigation";
-
-interface Quiz {
- id: string;
- subject: string;
- questions: string[];
-}
+import { Card, CardContent, CardHeader } from "@/components/ui/card";
interface RecommendedQuizzesProps {
assignedQuizzes: Quiz[];
hasCompletedDiagnostic: boolean;
}
-export default function RecommendedQuizzes({ assignedQuizzes }: RecommendedQuizzesProps) {
- const router = useRouter();
-
+export default function RecommendedQuizzes({
+ hasCompletedDiagnostic,
+}: RecommendedQuizzesProps) {
return (
-
-
Recommended Quizzes
-
- {(!assignedQuizzes || assignedQuizzes.length === 0) ? (
-
- No quizzes assigned at the moment.
+
+ {!hasCompletedDiagnostic && (
+
+
+ Complete the diagnostic quiz to unlock this section
+
- ) : (
-
- {assignedQuizzes.map((quiz) => (
-
-
- {/* Green Header Area */}
-
-
- {quiz.subject || 'General'}
-
-
-
- {/* Card Body */}
-
-
-
-
- Quiz Assignment
-
-
- {quiz.questions?.length || 0} QUESTIONS
-
-
-
-
router.push(`/student/quiz/${quiz.id}`)}
- className="bg-black text-white rounded-xl px-6 h-10 font-bold text-sm hover:bg-zinc-800 transition-colors shadow-lg shadow-zinc-200"
- >
- Start
-
+ )}
+
+
+ Recommended Quizzes
+
+
+ {[1, 2, 3].map((i) => (
+
+
+
+ Subject
+
+
+
+
+
+ Lesson Name
+
+
+ Duration XXX
+
+
+ Start
+
))}
diff --git a/domains/student/dashboard/StudentDashboardClient.tsx b/domains/student/dashboard/StudentDashboardClient.tsx
index 7ab7c08..f150205 100644
--- a/domains/student/dashboard/StudentDashboardClient.tsx
+++ b/domains/student/dashboard/StudentDashboardClient.tsx
@@ -1,5 +1,4 @@
"use client";
-
import GreetingCard from "./GreetingCard";
import PromptDiagnosticCard from "./PromptDiagnosticCard";
import RecentQuizCompletions from "./RecentQuizCompletions";
@@ -15,18 +14,17 @@ interface Props {
}
export default function StudentDashboardClient({
- studentName,
+ student,
completedQuizzes,
- assignedQuizzes,
hasCompletedDiagnostic,
}: Props) {
return (
-
-
-
+
+ {/* Greeting / Progress */}
+
{/* LOGIC: Only show this card if diagnostic is NOT complete */}
{!hasCompletedDiagnostic && }
@@ -36,13 +34,13 @@ export default function StudentDashboardClient({
hasCompletedDiagnostic={hasCompletedDiagnostic}
/>
-
-
-
-
-
-
-
+ {/* Writing Feedback + Quiz Completions */}
+
+ {/* Writing Feedback */}
+
+
+ {/* Recent Quiz Completions */}
+
diff --git a/domains/student/dashboard/StudentDashboardHeader.tsx b/domains/student/dashboard/StudentDashboardHeader.tsx
index 06708a8..3fdfc53 100644
--- a/domains/student/dashboard/StudentDashboardHeader.tsx
+++ b/domains/student/dashboard/StudentDashboardHeader.tsx
@@ -1,9 +1,61 @@
-import Navbar from "@/components/ui/navbar";
+import Image from "next/image";
+import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
+import { Input } from "@/components/ui/input";
+import { BellIcon, Search } from "lucide-react";
+import logo from "../../../assets/logo.webp";
interface StudentDashboardHeaderProps {
student: string | null;
}
-export default function StudentDashboardHeader({ student }: StudentDashboardHeaderProps) {
- return ;
+export default function StudentDashboardHeader({
+ student,
+}: StudentDashboardHeaderProps) {
+ return (
+
+ );
}
diff --git a/domains/student/dashboard/WritingFeedback.tsx b/domains/student/dashboard/WritingFeedback.tsx
index 68561d1..56c420e 100644
--- a/domains/student/dashboard/WritingFeedback.tsx
+++ b/domains/student/dashboard/WritingFeedback.tsx
@@ -1,21 +1,32 @@
"use client";
-
-import {useState} from "react";
-
-import {Button} from "@/components/ui/button";
-import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card";
-import {Select, SelectTrigger, SelectValue, SelectContent, SelectItem} from "@/components/ui/select";
-import {Table, TableHeader, TableRow, TableHead, TableBody, TableCell} from "@/components/ui/table";
+import { useState } from "react";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import {
+ Select,
+ SelectTrigger,
+ SelectValue,
+ SelectContent,
+ SelectItem,
+} from "@/components/ui/select";
+import {
+ Table,
+ TableHeader,
+ TableRow,
+ TableHead,
+ TableBody,
+ TableCell,
+} from "@/components/ui/table";
export default function WritingFeedback() {
const [timeRange, setTimeRange] = useState<"all" | "week" | "month">("all");
return (
-
-
- Writing Feedback
-
-
View All
+
+ View All
+
);
@@ -66,6 +105,7 @@ const feedbacks = [
{
date: "Mar 9, 2025",
assignment: "Persuasive Essay",
- feedback: "Strong argument and supporting points. Really great work overall",
+ feedback:
+ "Strong argument and supporting points. Really great work overall",
},
-];
+];
\ No newline at end of file