diff --git a/.env.example b/.env.example index e1e9179..7856e55 100644 --- a/.env.example +++ b/.env.example @@ -50,4 +50,5 @@ PINECONE_API_KEY=changethis OPENAI_API_KEY=changethis -NEXT_PUBLIC_BACKEND_BASE_URL=http://localhost:8000 \ No newline at end of file +NEXT_PUBLIC_BACKEND_BASE_URL=http://localhost:8000 +NEXT_INTERNAL_BACKEND_BASE_URL=http://backend:8000 diff --git a/backend/app/alembic/versions/10368f38610b_fix_delete_document_error.py b/backend/app/alembic/versions/10368f38610b_fix_delete_document_error.py index a1e3163..e226874 100644 --- a/backend/app/alembic/versions/10368f38610b_fix_delete_document_error.py +++ b/backend/app/alembic/versions/10368f38610b_fix_delete_document_error.py @@ -19,16 +19,6 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.create_table('chat', - sa.Column('message', sqlmodel.sql.sqltypes.AutoString(length=1024), nullable=True), - sa.Column('is_system', sa.Boolean(), nullable=False), - sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), - sa.Column('updated_at', sa.DateTime(), nullable=False), - sa.Column('id', sa.Uuid(), nullable=False), - sa.Column('course_id', sa.Uuid(), nullable=False), - sa.ForeignKeyConstraint(['course_id'], ['course.id'], ondelete='CASCADE'), - sa.PrimaryKeyConstraint('id') - ) op.drop_constraint(op.f('quizattempt_quiz_id_fkey'), 'quizattempt', type_='foreignkey') op.create_foreign_key(None, 'quizattempt', 'quiz', ['quiz_id'], ['id'], ondelete='CASCADE') # ### end Alembic commands ### @@ -38,5 +28,4 @@ def downgrade(): # ### commands auto generated by Alembic - please adjust! ### op.drop_constraint(None, 'quizattempt', type_='foreignkey') op.create_foreign_key(op.f('quizattempt_quiz_id_fkey'), 'quizattempt', 'quiz', ['quiz_id'], ['id']) - op.drop_table('chat') # ### end Alembic commands ### diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 871d206..bf6ce3e 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -96,6 +96,7 @@ services: - "3000:3000" environment: NODE_ENV: development + NEXT_INTERNAL_BACKEND_BASE_URL: http://backend:8000 NEXT_PUBLIC_BACKEND_BASE_URL: http://localhost:8000 depends_on: - backend diff --git a/frontend/src/app/(routes)/(auth)/login/page.tsx b/frontend/src/app/(routes)/(auth)/login/page.tsx index b8e96e9..0200534 100644 --- a/frontend/src/app/(routes)/(auth)/login/page.tsx +++ b/frontend/src/app/(routes)/(auth)/login/page.tsx @@ -2,20 +2,16 @@ import {useActionState, useState} from 'react' import Link from 'next/link' -import dynamic from 'next/dynamic' +import {Zap} from 'react-feather' import {authenticate} from '@/actions/auth' import {IAuthState} from '@/types/auth' import {validateField} from '@/lib/form' -import PasswordInput from '@/components/ui/auth/PasswordInput' - -const AuthBackground = dynamic( - () => import('@/components/ui/auth/AuthBackground'), - {ssr: true}, -) export default function Login() { const [errors, setErrors] = useState>({}) + const [rememberMe, setRememberMe] = useState(false) + const [showPassword, setShowPassword] = useState(false) const [state, formAction, isPending] = useActionState< IAuthState | undefined, @@ -32,76 +28,159 @@ export default function Login() { } return ( -
- {/* Left side - Form */} -
-
-

Welcome Back

-
-
- - - {errors.email && ( -

{errors.email}

- )} -
+
+ {/* Header */} +
+
+
+ +
+ StudyBuddy +
+ + Sign up + +
-
- - {state && !state?.ok && ( -
{state?.error?.message}
- )} -
+ {/* Main Content */} +
+
+ {/* Title and Subtitle - Outside the card */} +
+

+ Welcome back +

+

+ Sign in to continue to your study space. +

+
-
- - Forgot your password? - -
+ {/* Login Card */} +
+ {/* Form */} + + {/* Email Field */} +
+ +
+
+ + + +
+ +
+ {errors.email && ( +

{errors.email}

+ )} +
- - -
- Or + {/* Password Field */} +
+ +
+
+ + + +
+ + +
+ {errors.password && ( +

{errors.password}

+ )} + {state && !state?.ok && ( +
{state?.error?.message}
+ )} +
+ + {/* Remember Me and Forgot Password */} +
+
+ setRememberMe(e.target.checked)} + className='h-4 w-4 text-sb-primary focus:ring-sb-primary border-sb-border rounded' + /> + +
+ + Forgot your password? + +
+ + {/* Login Button */} + +
-
-

- Don’t have an account?{' '} - + + {/* Footer Link */} +

+

+ Don't have an account?{' '} + Sign up

- - {/* Right side - Image */} -
) } diff --git a/frontend/src/app/(routes)/(auth)/recover-password/page.tsx b/frontend/src/app/(routes)/(auth)/recover-password/page.tsx index 67f3cb0..cf70bf6 100644 --- a/frontend/src/app/(routes)/(auth)/recover-password/page.tsx +++ b/frontend/src/app/(routes)/(auth)/recover-password/page.tsx @@ -2,9 +2,9 @@ import {useState} from 'react' import Link from 'next/link' +import {Zap} from 'react-feather' import {emailPattern} from '@/lib/auth' -import AuthBackground from '@/components/ui/auth/AuthBackground' export default function RecoverPasswordPage() { const [error, _setError] = useState(null) @@ -70,38 +70,60 @@ export default function RecoverPasswordPage() { if (isSubmitted) { return ( -
-
-
-
- - - +
+ {/* Header */} +
+
+
+
-

- Check your email -

-

- We've sent a password recovery link to your email address. -

+ StudyBuddy
-
- - Back to Sign in - + + Sign In + +
+ + {/* Main Content */} +
+
+ {/* Title and Subtitle - Outside the card */} +
+

+ Check your email +

+

+ We've sent a password recovery link to your email address. +

+
+ + {/* Success Card */} +
+
+ + + +
+ + Back to Sign In + +
@@ -109,68 +131,103 @@ export default function RecoverPasswordPage() { } return ( -
- {/* Left side - Form */} -
-
-

Password Recovery

-

- A password recovery email will be sent to the registered account. -

- -
-
- - - {emailError && ( -

{emailError}

- )} -
+
+ {/* Header */} +
+
+
+ +
+ StudyBuddy +
+ + Sign In + +
+ + {/* Main Content */} +
+
+ {/* Title and Subtitle - Outside the card */} +
+

+ Password Recovery +

+

+ A password recovery email will be sent to the registered account. +

+
- {error && ( -
- {error} + {/* Recovery Card */} +
+ {/* Form */} + + {/* Email Field */} +
+ +
+
+ + + +
+ +
+ {emailError && ( +

{emailError}

+ )}
- )} - - + {error && ( +
+ {error} +
+ )} + + {/* Submit Button */} + + +
+ {/* Footer Link */}
- - Back to Sign in - +

+ Remember your password?{' '} + + Sign In + +

- - {/* Right side - Background */} -
) } diff --git a/frontend/src/app/(routes)/(auth)/signup/page.tsx b/frontend/src/app/(routes)/(auth)/signup/page.tsx index 1f1dc00..fc5f189 100644 --- a/frontend/src/app/(routes)/(auth)/signup/page.tsx +++ b/frontend/src/app/(routes)/(auth)/signup/page.tsx @@ -5,10 +5,10 @@ import {useForm} from 'react-hook-form' import {useRouter} from 'next/navigation' import {zodResolver} from '@hookform/resolvers/zod' import Link from 'next/link' +import {Zap} from 'react-feather' import {IAuthState} from '@/types/auth' import {register} from '@/actions/auth' -import AuthBackground from '@/components/ui/auth/AuthBackground' import { Form, FormField, @@ -18,12 +18,13 @@ import { FormMessage, PasswordFormInput, } from '@/components/ui/form' -import {Input} from '@/components/ui/input' import {signUpSchema, SignUpSchema} from '@/types/form' export default function SignUpPage() { const router = useRouter() const [isPending, setIsPending] = useState(false) + const [showPassword, setShowPassword] = useState(false) + const [showConfirmPassword, setShowConfirmPassword] = useState(false) const [state, setState] = useState({ error: undefined, ok: false, @@ -60,129 +61,219 @@ export default function SignUpPage() { } return ( -
-
-
-

Get Started Now

- - {/* ✅ Form with action-based submit */} -
- - {/* Full name */} - ( - - Name - - - - - - )} - /> - - {/* Email */} - ( - - Email address - - - - - - )} - /> +
+ {/* Header */} +
+
+
+ +
+ StudyBuddy +
+ + Log In + +
- ( - - )} - /> + {/* Main Content */} +
+
+ {/* Title and Subtitle - Outside the card */} +
+

+ Create your account +

+

+ Join our community of learners. +

+
- ( - - )} - /> + {/* Sign Up Card */} +
+ {/* Form */} + + + {/* Name */} + ( + + + Name + + +
+
+ + + +
+ +
+
+ +
+ )} + /> - {/* Terms */} - ( - -
+ {/* Email */} + ( + + + Email address + - field.onChange(e.target.checked)} - className='h-4 w-4 text-cyan-600 focus:ring-cyan-500 border-slate-300 rounded' - /> +
+
+ + + +
+ +
- - I agree to the terms & policy + +
+ )} + /> + + {/* Password */} + ( + + + Password -
- -
- )} - /> + +
+
+ + + +
+ + +
+
+ + + )} + /> - {/* Server error */} - {state && !state.ok && ( -
{state.error?.message}
- )} + {/* Confirm Password */} + ( + + + Confirm Password + + +
+
+ + + +
+ + +
+
+ +
+ )} + /> - {/* Submit Button */} - - - + {/* Server error */} + {state && !state.ok && ( +
{state.error?.message}
+ )} -
- Or + {/* Submit Button */} + + +
-
-

- Have an account?{' '} + {/* Footer Link */} +

+

+ Already have an account?{' '} - Sign In + Log in

- - {/* Right side - Background */} -
) } diff --git a/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/layout.tsx b/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/layout.tsx index 6156695..ffba2f8 100644 --- a/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/layout.tsx +++ b/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/layout.tsx @@ -12,12 +12,15 @@ export default async function CourseLayout({ children: React.ReactNode }) { return ( -
-
-
{children}
-
- -
+
+ {/* Main Content - right padding for fixed sidebar */} +
+ {children} +
+ + {/* Fixed Project Settings Sidebar */} +
+
) diff --git a/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/page.tsx b/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/page.tsx index 3b56ed6..e887ed3 100644 --- a/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/page.tsx +++ b/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/page.tsx @@ -4,7 +4,7 @@ import {getCourse} from '@/actions/courses' import ErrorBox from '@/components/ui/ErrorBox' import {Tabs, TabsContent, TabsList, StyledTabList} from '@/components/ui/tabs' import PageLoader from '@/components/ui/page-loader' -import Flashcard from '@/components/flashcard'; +import Flashcard from '@/components/flashcard' const QuizComponent = dynamic(() => import('@/components/quiz/quiz'), { ssr: true, @@ -29,35 +29,37 @@ export default async function Page(props: {params: Promise<{id: string}>}) { const course = result.data return ( - <> +
- + - - - - - - - - - - - - - -
- Podcast content will be displayed here -
-
+
+ + + + + + + + + + + + + +
+ Podcast content will be displayed here +
+
+
- +
) } diff --git a/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/quiz-session/[sessionId]/page.tsx b/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/quiz-session/[sessionId]/page.tsx index e079465..582035d 100644 --- a/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/quiz-session/[sessionId]/page.tsx +++ b/frontend/src/app/(routes)/(dashboard)/dashboard/courses/[id]/quiz-session/[sessionId]/page.tsx @@ -1,6 +1,8 @@ import {getQuizSession} from '@/actions/quizzes' import ErrorBox from '@/components/ui/ErrorBox' import QuizForm from './QuizForm' +import {Tabs, TabsContent, TabsList, StyledTabList} from '@/components/ui/tabs' +import Link from 'next/link' export default async function Page(props: { params: {id: string; sessionId: string} @@ -10,7 +12,6 @@ export default async function Page(props: { const sessionId = params.sessionId const courseId = params.id - const result = await getQuizSession(sessionId) if (!result.ok) { @@ -18,10 +19,49 @@ export default async function Page(props: { } return ( -
-
- -
+
+ + + + + + + +
+ +
+ +
+
+ + +
+ + Go to Chat + +
+
+ + +
+ + Go to Flashcards + +
+
+ + +
+ + Go to Podcast + +
+
+
+
) } diff --git a/frontend/src/app/(routes)/(dashboard)/dashboard/courses/create/page.tsx b/frontend/src/app/(routes)/(dashboard)/dashboard/courses/create/page.tsx index 0cee8e1..117b942 100644 --- a/frontend/src/app/(routes)/(dashboard)/dashboard/courses/create/page.tsx +++ b/frontend/src/app/(routes)/(dashboard)/dashboard/courses/create/page.tsx @@ -1,12 +1,39 @@ 'use client' import CreateCourseForm from '@/components/create-course/create-course' +import ProjectSettings from '@/components/project-settings' +import { Settings } from 'react-feather' +import { useState } from 'react' export default function CreateCoursePage() { + const [selectedProjectId, setSelectedProjectId] = useState(null) + return ( -
-
+
+ {/* Main Content Area - right padding to account for fixed sidebar */} +
+
+
+
+ + {/* Right Sidebar - Project Settings - Fixed */} +
+ {selectedProjectId ? ( + + ) : ( +
+

Project Settings

+
+
+ +
+

+ Select a project to see its settings. +

+
+
+ )}
) diff --git a/frontend/src/app/(routes)/(dashboard)/dashboard/layout.tsx b/frontend/src/app/(routes)/(dashboard)/dashboard/layout.tsx index fe86467..60b11ed 100644 --- a/frontend/src/app/(routes)/(dashboard)/dashboard/layout.tsx +++ b/frontend/src/app/(routes)/(dashboard)/dashboard/layout.tsx @@ -8,6 +8,7 @@ import { client } from '@/client/client.gen' import { cookies } from 'next/headers' import { getMe } from '@/actions/users' +import UserAccountMenu from '@/components/user-account-menu' export default async function DashboardLayout({ children, @@ -33,14 +34,19 @@ import { getMe } from '@/actions/users' } return ( - - - -
- -
- {children} -
-
+
+ + + +
+ + +
+
+ {children} +
+
+
+
) } diff --git a/frontend/src/app/(routes)/(dashboard)/dashboard/user-settings/user-settings.tsx b/frontend/src/app/(routes)/(dashboard)/dashboard/user-settings/user-settings.tsx index bf8204c..5cde598 100644 --- a/frontend/src/app/(routes)/(dashboard)/dashboard/user-settings/user-settings.tsx +++ b/frontend/src/app/(routes)/(dashboard)/dashboard/user-settings/user-settings.tsx @@ -39,51 +39,71 @@ export default function UserSettingsClient() { }, []) return ( -
-

User Settings

+
+

User Settings

- - - My profile - Password + + + + My profile + + + Password +
-

User Information

+

User Information

-
- +
- -

{profileState.ok @@ -96,7 +116,7 @@ export default function UserSettingsClient() {

-

Reset password

+

Reset password

- -

{passwordState.ok diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 35aff61..d5f071a 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -41,44 +41,25 @@ --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); + + /* Miro Design Colors */ + --color-sb-background: #101827; + --color-sb-surface: #1f2937; + --color-sb-content: #182130; + --color-sb-surface-hover: #374151; + --color-sb-surface-active: #5A6578; + --color-sb-primary: #2563EB; + --color-sb-primary-hover: #1D4ED8; + --color-sb-primary-light: #60A5FA; + --color-sb-text-primary: #FFFFFF; + --color-sb-text-secondary: #A0AEC0; + --color-sb-border: #4A5568; + --color-sb-border-light: #2D3748; } :root { --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.141 0.005 285.823); - --card: oklch(1 0 0); - --card-foreground: oklch(0.141 0.005 285.823); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.141 0.005 285.823); - --primary: oklch(60.9% 0.126 221.723); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.967 0.001 286.375); - --secondary-foreground: oklch(60.9% 0.126 221.723); - --muted: oklch(0.967 0.001 286.375); - --muted-foreground: oklch(0.552 0.016 285.938); - --accent: oklch(0.967 0.001 286.375); - --accent-foreground: oklch(60.9% 0.126 221.723); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.92 0.004 286.32); - --input: oklch(0.92 0.004 286.32); - --ring: oklch(0.705 0.015 286.067); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.141 0.005 285.823); - --sidebar-primary: oklch(60.9% 0.126 221.723); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.967 0.001 286.375); - --sidebar-accent-foreground: oklch(60.9% 0.126 221.723); - --sidebar-border: oklch(0.92 0.004 286.32); - --sidebar-ring: oklch(0.705 0.015 286.067); -} - -.dark { + /* Dark theme only - no light mode */ --background: oklch(0.141 0.005 285.823); --foreground: oklch(0.985 0 0); --card: oklch(60.9% 0.126 221.723); @@ -106,10 +87,10 @@ --sidebar-foreground: oklch(0.985 0 0); --sidebar-primary: oklch(71.5% 0.143 215.221); --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.274 0.006 286.033); + --sidebar-accent: oklch(0.269 0 0); --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.552 0.016 285.938); + --sidebar-ring: oklch(0.439 0 0); } @layer base { @@ -120,27 +101,3 @@ @apply bg-background text-foreground; } } - -@layer base { - :root { - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); - } - - .dark { - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(71.5% 0.143 215.221); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.439 0 0); - } -} diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 96b1dc1..3e1b581 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -3,7 +3,7 @@ import './globals.css' import type {Metadata} from 'next' import {DM_Sans, DM_Mono} from 'next/font/google' import {Toaster} from '@/components/ui/sonner' -import {ThemeProvider} from 'next-themes' +// import {ThemeProvider} from 'next-themes' const dmSans = DM_Sans({ variable: '--font-dn-serif', @@ -30,10 +30,10 @@ export default async function RootLayout({ return ( - -

{children}
- - + {/* */} +
{children}
+ + {/*
*/} ) diff --git a/frontend/src/components/app-sidebar.tsx b/frontend/src/components/app-sidebar.tsx index 364ffb6..ec97d8b 100644 --- a/frontend/src/components/app-sidebar.tsx +++ b/frontend/src/components/app-sidebar.tsx @@ -1,14 +1,14 @@ 'use client' -import React from 'react' +import React, { useState, useEffect } from 'react' +import { usePathname } from 'next/navigation' -import { User, ChevronUp, Zap, Home, Plus } from 'react-feather' +import { Home, Plus, File, Zap } from 'react-feather' import { Button } from '@/components/ui/button' import { Sidebar, SidebarContent, - SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, @@ -17,110 +17,138 @@ import { SidebarMenuButton, SidebarMenuItem, } from '@/components/ui/sidebar' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu' -import { logout } from '@/actions/auth' +import { getCourses } from '@/actions/courses' +import { CourseWithOptionalDate } from '@/types/date' import Link from 'next/link' -import { ThemeToggle } from './theme-toggle' + export function AppSidebar({ displayName = 'User' }: { displayName?: string }) { + const [courses, setCourses] = useState([]) + const [isLoading, setIsLoading] = useState(true) + const pathname = usePathname() + + useEffect(() => { + const fetchCourses = async () => { + try { + const result = await getCourses() + if (result.ok) { + setCourses(result.data) + } + } catch (error) { + console.error('Failed to fetch courses:', error) + } finally { + setIsLoading(false) + } + } + + fetchCourses() + }, []) + + // Extract course ID from pathname for highlighting + const getCurrentCourseId = () => { + const courseMatch = pathname.match(/\/dashboard\/courses\/([^\/]+)/) + return courseMatch ? courseMatch[1] : null + } + + const currentCourseId = getCurrentCourseId() + return ( - - + + - - - - -
-
- -
-
- Study Companion -
-
- -
-
-
+ + +
+
+ +
+
+ StudyBuddy +
+
+ +
- + - Menu + Projects - + - - Dashboard - - - - - - - + + Dashboard + + {/* Project List */} + + + + {isLoading ? ( + + + Loading projects... + + + ) : courses.length === 0 ? ( + + + No projects yet + + + ) : ( + courses.map((course) => { + const isActive = currentCourseId === course.id + return ( + + + + + {course.name} + + + + ) + }) + )} + + + + - - - - - - - {displayName} - - - - - - - Account - - - - - - - - - - - - - - - + + {/* Fixed Add New Project Button at Bottom */} +
+ +
) } -export default AppSidebar +export default AppSidebar \ No newline at end of file diff --git a/frontend/src/components/courses-list.tsx b/frontend/src/components/courses-list.tsx index 9a7bb24..625d36f 100644 --- a/frontend/src/components/courses-list.tsx +++ b/frontend/src/components/courses-list.tsx @@ -47,17 +47,17 @@ export default function CoursesList({ return ( -
+
-

My Courses

+

My Courses

- + setQuery(e.target.value)} - className='pl-9' + className='pl-9 bg-sb-surface-hover border-sb-border text-sb-text-primary placeholder-sb-text-secondary focus:ring-sb-primary' />
@@ -65,23 +65,23 @@ export default function CoursesList({ value={datePreset} onValueChange={(val) => setDatePreset(val as DatePreset)} > - + - - All dates - Today - Last 7 days - Last 30 days - This year - On… + + All dates + Today + Last 7 days + Last 30 days + This year + On…
{datePreset === 'on' && ( -
+
- - Add Course + + Add Course -

+

No courses found.

diff --git a/frontend/src/components/create-course/course-form.tsx b/frontend/src/components/create-course/course-form.tsx index 00061e3..4bd26fe 100644 --- a/frontend/src/components/create-course/course-form.tsx +++ b/frontend/src/components/create-course/course-form.tsx @@ -1,5 +1,6 @@ import {useActionState} from 'react' import {useRouter} from 'next/navigation' +import {Cloud} from 'react-feather' import {Button} from '@/components/ui/button' import {Input} from '@/components/ui/input' @@ -23,38 +24,67 @@ export function CourseForm() { return (
- +
- +