Compare commits
No commits in common. '43b82377e93ea4f05ac3e3fb8f2f20a553ae2677' and '7a5ff710101b3662e6d18c29a6f19aa63f5e7aab' have entirely different histories.
43b82377e9
...
7a5ff71010
@ -1 +0,0 @@ |
|||||||
declare module 'js-cookie'; |
|
File diff suppressed because it is too large
Load Diff
@ -1,34 +0,0 @@ |
|||||||
import CommunityImage from '@/assets/img/community-collboration.jpg' |
|
||||||
import Image from 'next/image' |
|
||||||
|
|
||||||
const CommunitySection = () => { |
|
||||||
return( |
|
||||||
<div className="bg-gray-50 border-t"> |
|
||||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-16"> |
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 items-center"> |
|
||||||
<div> |
|
||||||
<h2 className="text-3xl font-bold mb-6 text-purple-700">Join Our Growing Community</h2> |
|
||||||
<p className="text-gray-600 mb-8"> |
|
||||||
Connect with fellow researchers, educators, and learners. Share your knowledge, collaborate on courses, and participate in meaningful discussions. |
|
||||||
</p> |
|
||||||
<div className="grid grid-cols-2 gap-4 text-center"> |
|
||||||
<div className="bg-white p-4 rounded-lg shadow-sm border border-purple-700"> |
|
||||||
<p className="text-2xl font-bold text-purple-600">500+</p> |
|
||||||
<p className="text-gray-600">Expert Contributors</p> |
|
||||||
</div> |
|
||||||
<div className="bg-white p-4 rounded-lg shadow-sm border border-purple-700"> |
|
||||||
<p className="text-2xl font-bold text-purple-600">1000+</p> |
|
||||||
<p className="text-gray-600">Research-Based Courses</p> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<div className="relative overlay-purple"> |
|
||||||
<Image src={CommunityImage} alt="Community collaboration" className="rounded-lg shadow-lg" /> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default CommunitySection |
|
@ -1,104 +0,0 @@ |
|||||||
import React from 'react'; |
|
||||||
import CourseCard from '@/components/elements/CourseCard'; |
|
||||||
|
|
||||||
const FeaturedCourses = () => { |
|
||||||
const courses = [ |
|
||||||
{ |
|
||||||
id: 1, |
|
||||||
title: 'Foundation course to under stand about software', |
|
||||||
category: 'Data & Tech', |
|
||||||
lessons: 23, |
|
||||||
duration: '1hr 30 min', |
|
||||||
price: 32.00, |
|
||||||
originalPrice: 89.00, |
|
||||||
instructor: { |
|
||||||
name : 'Micie John', |
|
||||||
image: 'https://dummyimage.com/300' |
|
||||||
}, |
|
||||||
rating: 4.5, |
|
||||||
reviews: 44, |
|
||||||
image: 'https://dummyimage.com/300' |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 2, |
|
||||||
title: 'Nidhies course to under stand about softwere', |
|
||||||
category: 'Mechanical', |
|
||||||
lessons: 29, |
|
||||||
duration: '2hr 30 min', |
|
||||||
price: 32.00, |
|
||||||
originalPrice: 89.00, |
|
||||||
instructor: { |
|
||||||
name : 'Micie John', |
|
||||||
image: 'https://dummyimage.com/300' |
|
||||||
}, |
|
||||||
rating: 4.5, |
|
||||||
reviews: 44, |
|
||||||
image: 'https://dummyimage.com/300' |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 3, |
|
||||||
title: 'Minws course to under stand about solution', |
|
||||||
category: 'Development', |
|
||||||
lessons: 25, |
|
||||||
duration: '1hr 40 min', |
|
||||||
price: 40.00, |
|
||||||
originalPrice: 89.00, |
|
||||||
instructor: { |
|
||||||
name : 'Micie John', |
|
||||||
image: 'https://dummyimage.com/300' |
|
||||||
}, |
|
||||||
rating: 4.5, |
|
||||||
reviews: 44, |
|
||||||
image: 'https://dummyimage.com/300' |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 3, |
|
||||||
title: 'Minws course to under stand about solution', |
|
||||||
category: 'Development', |
|
||||||
lessons: 25, |
|
||||||
duration: '1hr 40 min', |
|
||||||
price: 40.00, |
|
||||||
originalPrice: 89.00, |
|
||||||
instructor: { |
|
||||||
name : 'Micie John', |
|
||||||
image: 'https://dummyimage.com/300' |
|
||||||
}, |
|
||||||
rating: 4.5, |
|
||||||
reviews: 44, |
|
||||||
image: 'https://dummyimage.com/300' |
|
||||||
} |
|
||||||
]; |
|
||||||
|
|
||||||
return ( |
|
||||||
<div className="max-w-7xl mx-auto p-6"> |
|
||||||
<div className="flex justify-between items-center my-12"> |
|
||||||
<div> |
|
||||||
<h1 className="text-3xl font-bold">Featured Courses</h1> |
|
||||||
<h2 className="text-xl text-purple-700">View all featured courses</h2> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> |
|
||||||
|
|
||||||
{ |
|
||||||
courses?.map((course : Record<string,any> , index) => { |
|
||||||
return( |
|
||||||
<CourseCard |
|
||||||
key={index} |
|
||||||
id={course.id} |
|
||||||
image ={course?.image} |
|
||||||
title ={course?.title} |
|
||||||
category = {course?.category} |
|
||||||
lessons = {course?.lessons} |
|
||||||
instructor = {course?.instructor} |
|
||||||
duration={course?.duration} |
|
||||||
/> |
|
||||||
) |
|
||||||
}) |
|
||||||
} |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
export default FeaturedCourses; |
|
@ -1,66 +0,0 @@ |
|||||||
|
|
||||||
type Feature = { |
|
||||||
title : string ,
|
|
||||||
description : string |
|
||||||
icon : React.ReactNode |
|
||||||
} |
|
||||||
const FeaturesSection = () => { |
|
||||||
|
|
||||||
const features: Feature[] = [ |
|
||||||
{ |
|
||||||
title: 'Research-Based Learning', |
|
||||||
description: 'Create and access courses developed by leading researchers and educators in their fields.', |
|
||||||
icon: ( |
|
||||||
<div className="w-12 h-12 rounded-lg bg-purple-100 flex items-center justify-center"> |
|
||||||
<svg className="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" /> |
|
||||||
</svg> |
|
||||||
</div> |
|
||||||
) |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: 'Knowledge Sharing', |
|
||||||
description: 'Join a vibrant community where educators and learners share insights and resources.', |
|
||||||
icon: ( |
|
||||||
<div className="w-12 h-12 rounded-lg bg-purple-100 flex items-center justify-center"> |
|
||||||
<svg className="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" /> |
|
||||||
</svg> |
|
||||||
</div> |
|
||||||
) |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: 'Interactive Assessments', |
|
||||||
description: 'Validate learning through comprehensive quizzes and assessments designed by experts.', |
|
||||||
icon: ( |
|
||||||
<div className="w-12 h-12 rounded-lg bg-purple-100 flex items-center justify-center"> |
|
||||||
<svg className="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /> |
|
||||||
</svg> |
|
||||||
</div> |
|
||||||
) |
|
||||||
} |
|
||||||
]; |
|
||||||
|
|
||||||
return( |
|
||||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-24"> |
|
||||||
<div className="text-center mb-16"> |
|
||||||
<h2 className="text-3xl font-bold text-gray-900 mb-4">Why Choose EduConnect?</h2> |
|
||||||
<p className=" max-w-2xl mx-auto"> |
|
||||||
Our platform connects researchers, educators, and learners in a dynamic environment focused on quality education and knowledge sharing. |
|
||||||
</p> |
|
||||||
</div> |
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8"> |
|
||||||
{features.map((feature, index) => ( |
|
||||||
<div key={index} className="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition-shadow border border-purple-700"> |
|
||||||
{feature.icon} |
|
||||||
<h3 className="text-xl font-semibold mt-4 mb-2">{feature.title}</h3> |
|
||||||
<p className="text-gray-600">{feature.description}</p> |
|
||||||
</div> |
|
||||||
))} |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default FeaturesSection |
|
@ -1,49 +0,0 @@ |
|||||||
import LearnWithUS from '@/assets/img/learn-with-us.jpg' |
|
||||||
import Image from 'next/image'; |
|
||||||
|
|
||||||
const HeroSection: React.FC = () => { |
|
||||||
return ( |
|
||||||
<div className="bg-gradient-to-br from-purple-900 to-indigo-900 text-white"> |
|
||||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-24"> |
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 items-center"> |
|
||||||
<div> |
|
||||||
<div className="text-purple-300 mb-4"> |
|
||||||
RESEARCH-POWERED LEARNING PLATFORM |
|
||||||
</div> |
|
||||||
<h1 className="text-4xl md:text-6xl font-bold mb-6"> |
|
||||||
Connect, Learn, and Grow Together |
|
||||||
</h1> |
|
||||||
<p className="mb-8 text-gray-300 text-lg"> |
|
||||||
Join a community where researchers and educators create engaging |
|
||||||
courses, share knowledge, and help learners validate their |
|
||||||
understanding through interactive assessments. |
|
||||||
</p> |
|
||||||
<div className="flex gap-4"> |
|
||||||
<button className="bg-white text-gray-900 px-6 py-3 rounded-md font-medium"> |
|
||||||
Explore Courses |
|
||||||
</button> |
|
||||||
<button className="text-white border border-white px-6 py-3 rounded-md font-medium"> |
|
||||||
Create Course → |
|
||||||
</button> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<div className="relative"> |
|
||||||
<div className='overlay-purple'> |
|
||||||
<Image |
|
||||||
src={LearnWithUS} |
|
||||||
alt="Collaborative learning" |
|
||||||
className="rounded-lg shadow-xl" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
<div className="absolute -bottom-4 -right-4 bg-purple-700 text-white p-4 rounded-lg shadow-lg"> |
|
||||||
<p className="font-bold">10,000+</p> |
|
||||||
<p className="text-sm">Active Learners</p> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
export default HeroSection |
|
@ -1,82 +0,0 @@ |
|||||||
import { useState } from 'react'; |
|
||||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card"; |
|
||||||
import { Label } from "@/components/ui/label"; |
|
||||||
import { Input } from "@/components/ui/input"; |
|
||||||
import { Button } from "@/components/ui/button"; |
|
||||||
import { EyeIcon, EyeOffIcon } from 'lucide-react'; |
|
||||||
|
|
||||||
export default function LoginForm() { |
|
||||||
const [showPassword, setShowPassword] = useState(false); |
|
||||||
|
|
||||||
return ( |
|
||||||
<div className="flex items-center justify-center min-h-[60vh]"> |
|
||||||
<Card className="w-full max-w-md shadow-lg border-0"> |
|
||||||
<CardHeader className="space-y-3"> |
|
||||||
<CardTitle className="text-2xl font-bold text-purple-600">Login</CardTitle> |
|
||||||
<CardDescription className="text-gray-600"> |
|
||||||
Enter your email and password to login to your account |
|
||||||
</CardDescription> |
|
||||||
</CardHeader> |
|
||||||
<CardContent> |
|
||||||
<form className="space-y-6"> |
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="email" className="text-gray-700">Email</Label> |
|
||||||
<Input
|
|
||||||
id="email"
|
|
||||||
type="email"
|
|
||||||
placeholder="Enter your email" |
|
||||||
className="h-11 px-4 bg-gray-50/50 border-gray-200 focus:border-purple-500 focus:ring-purple-500" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="password" className="text-gray-700">Password</Label> |
|
||||||
<div className="relative"> |
|
||||||
<Input
|
|
||||||
id="password"
|
|
||||||
type={showPassword ? "text" : "password"} |
|
||||||
placeholder="Enter your password" |
|
||||||
className="h-11 px-4 bg-gray-50/50 border-gray-200 focus:border-purple-500 focus:ring-purple-500 pr-10" |
|
||||||
/> |
|
||||||
<button |
|
||||||
type="button" |
|
||||||
onClick={() => setShowPassword(!showPassword)} |
|
||||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700" |
|
||||||
> |
|
||||||
{showPassword ? ( |
|
||||||
<EyeOffIcon className="h-5 w-5" /> |
|
||||||
) : ( |
|
||||||
<EyeIcon className="h-5 w-5" /> |
|
||||||
)} |
|
||||||
</button> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="flex items-center justify-between text-sm"> |
|
||||||
<label className="flex items-center space-x-2 text-gray-600"> |
|
||||||
<input type="checkbox" className="rounded border-gray-300 text-purple-600 focus:ring-purple-500" /> |
|
||||||
<span>Remember me</span> |
|
||||||
</label> |
|
||||||
<a href="#" className="text-purple-600 hover:text-purple-700"> |
|
||||||
Forgot password? |
|
||||||
</a> |
|
||||||
</div> |
|
||||||
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
className="w-full h-11 bg-purple-600 hover:bg-purple-700 text-white font-semibold" |
|
||||||
> |
|
||||||
Login |
|
||||||
</Button> |
|
||||||
|
|
||||||
<div className="text-center text-sm text-gray-600"> |
|
||||||
Don't have an account?{' '} |
|
||||||
<a href="#" className="text-purple-600 hover:text-purple-700 font-semibold"> |
|
||||||
Register |
|
||||||
</a> |
|
||||||
</div> |
|
||||||
</form> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
</div> |
|
||||||
); |
|
||||||
} |
|
@ -1,20 +0,0 @@ |
|||||||
'use client' |
|
||||||
import AppContextProvider from "@/helpers/context/AppContextProvider" |
|
||||||
import LoginForm from "./_partials/LoginForm" |
|
||||||
import CommonView from "@/views/CommonView" |
|
||||||
|
|
||||||
const LoginPage : React.FC = () => { |
|
||||||
return( |
|
||||||
<> |
|
||||||
<AppContextProvider> |
|
||||||
<CommonView> |
|
||||||
<div className="py-16 bg-gray-50"> |
|
||||||
<LoginForm /> |
|
||||||
</div> |
|
||||||
</CommonView> |
|
||||||
</AppContextProvider> |
|
||||||
</> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default LoginPage |
|
@ -1,186 +0,0 @@ |
|||||||
import { ChangeEvent, FormEvent, useState } from 'react'; |
|
||||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card"; |
|
||||||
import { Label } from "@/components/ui/label"; |
|
||||||
import { Input } from "@/components/ui/input"; |
|
||||||
import { Button } from "@/components/ui/button"; |
|
||||||
import { EyeIcon, EyeOffIcon, Upload } from 'lucide-react'; |
|
||||||
|
|
||||||
export default function SignupForm() { |
|
||||||
const [showPassword, setShowPassword] = useState(false); |
|
||||||
const [formData, setFormData] = useState({ |
|
||||||
email: '', |
|
||||||
firstName: '', |
|
||||||
lastName: '', |
|
||||||
username: '', |
|
||||||
password: '', |
|
||||||
bio: '', |
|
||||||
dob: '', |
|
||||||
profile_picture: null |
|
||||||
}); |
|
||||||
const [error , setError] = useState<Record<string,any>>({}) |
|
||||||
|
|
||||||
const handleInputChange = (e : ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => { |
|
||||||
const { id, value } = e.target; |
|
||||||
setFormData(prev => ({ |
|
||||||
...prev, |
|
||||||
[id]: value |
|
||||||
})); |
|
||||||
}; |
|
||||||
|
|
||||||
const handleSubmit = (e : FormEvent<HTMLFormElement>) => { |
|
||||||
e.preventDefault(); |
|
||||||
console.log('Form submitted:', formData); |
|
||||||
}; |
|
||||||
|
|
||||||
return ( |
|
||||||
<div className="flex items-center justify-center min-h-[80vh]"> |
|
||||||
<Card className="w-full max-w-lg shadow-lg border border-purple-700"> |
|
||||||
<CardHeader className="space-y-3"> |
|
||||||
<CardTitle className="text-2xl font-bold text-purple-600">Create Account</CardTitle> |
|
||||||
<CardDescription className="text-gray-600"> |
|
||||||
Fill in your details to create your account |
|
||||||
</CardDescription> |
|
||||||
</CardHeader> |
|
||||||
<CardContent> |
|
||||||
<form onSubmit={handleSubmit} className="space-y-6"> |
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> |
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="firstName" className="text-gray-700">First Name</Label> |
|
||||||
<Input
|
|
||||||
id="firstName" |
|
||||||
value={formData.firstName} |
|
||||||
onChange={handleInputChange} |
|
||||||
className="h-11 px-4 bg-gray-50/50 border-gray-200 focus:border-purple-500 focus:ring-purple-500" |
|
||||||
placeholder="Enter your first name" |
|
||||||
error={error?.firstName} |
|
||||||
/> |
|
||||||
</div> |
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="lastName" className="text-gray-700">Last Name</Label> |
|
||||||
<Input
|
|
||||||
id="lastName" |
|
||||||
value={formData.lastName} |
|
||||||
onChange={handleInputChange} |
|
||||||
className="h-11 px-4 bg-gray-50/50 border-gray-200 focus:border-purple-500 focus:ring-purple-500" |
|
||||||
placeholder="Enter your last name" |
|
||||||
error={error?.lastName} |
|
||||||
/> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="email" className="text-gray-700">Email</Label> |
|
||||||
<Input
|
|
||||||
id="email" |
|
||||||
type="email" |
|
||||||
value={formData.email} |
|
||||||
onChange={handleInputChange} |
|
||||||
className="h-11 px-4 bg-gray-50/50 border-gray-200 focus:border-purple-500 focus:ring-purple-500" |
|
||||||
placeholder="Enter your email" |
|
||||||
error={error?.email} |
|
||||||
/> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="username" className="text-gray-700">Username</Label> |
|
||||||
<Input
|
|
||||||
id="username" |
|
||||||
value={formData.username} |
|
||||||
onChange={handleInputChange} |
|
||||||
className="h-11 px-4 bg-gray-50/50 border-gray-200 focus:border-purple-500 focus:ring-purple-500" |
|
||||||
placeholder="Choose a username" |
|
||||||
error={error?.username} |
|
||||||
/> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="password" className="text-gray-700">Password</Label> |
|
||||||
<div className="relative"> |
|
||||||
<Input
|
|
||||||
id="password" |
|
||||||
type={showPassword ? "text" : "password"} |
|
||||||
value={formData.password} |
|
||||||
onChange={handleInputChange} |
|
||||||
className="h-11 px-4 bg-gray-50/50 border-gray-200 focus:border-purple-500 focus:ring-purple-500 pr-10" |
|
||||||
placeholder="Create a strong password" |
|
||||||
error={error?.password} |
|
||||||
/> |
|
||||||
<button |
|
||||||
type="button" |
|
||||||
onClick={() => setShowPassword(!showPassword)} |
|
||||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700" |
|
||||||
> |
|
||||||
{showPassword ? ( |
|
||||||
<EyeOffIcon className="h-5 w-5" /> |
|
||||||
) : ( |
|
||||||
<EyeIcon className="h-5 w-5" /> |
|
||||||
)} |
|
||||||
</button> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="dob" className="text-gray-700">Date of Birth</Label> |
|
||||||
<Input
|
|
||||||
id="dob" |
|
||||||
type="date" |
|
||||||
value={formData.dob} |
|
||||||
onChange={handleInputChange} |
|
||||||
error={error?.dob} |
|
||||||
className="h-11 px-4 bg-gray-50/50 border-gray-200 focus:border-purple-500 focus:ring-purple-500" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="bio" className="text-gray-700">Bio</Label> |
|
||||||
<textarea
|
|
||||||
id="bio" |
|
||||||
value={formData.bio} |
|
||||||
onChange={handleInputChange} |
|
||||||
className="w-full px-4 py-2 bg-gray-50/50 border-gray-200 rounded-md focus:border-purple-500 focus:ring-purple-500" |
|
||||||
rows={3} |
|
||||||
placeholder="Tell us about yourself" |
|
||||||
/> |
|
||||||
{ |
|
||||||
error?.bio && error?.bio.map((err : any) => { |
|
||||||
return( |
|
||||||
<span className='text-red-500'>{err}</span> |
|
||||||
) |
|
||||||
}) |
|
||||||
} |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="profile_picture" className="text-gray-700">Profile Picture</Label> |
|
||||||
<div className="flex items-center space-x-2"> |
|
||||||
<Button |
|
||||||
type="button" |
|
||||||
variant="outline" |
|
||||||
className="h-11 px-4 border-gray-200 hover:bg-gray-50" |
|
||||||
> |
|
||||||
<Upload className="h-5 w-5 mr-2" /> |
|
||||||
Upload Photo |
|
||||||
</Button> |
|
||||||
<span className="text-sm text-gray-500">No file chosen</span> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
className="w-full h-11 bg-purple-600 hover:bg-purple-700 text-white font-semibold" |
|
||||||
> |
|
||||||
Create Account |
|
||||||
</Button> |
|
||||||
|
|
||||||
<div className="text-center text-sm text-gray-600"> |
|
||||||
Already have an account?{' '} |
|
||||||
<a href="#" className="text-purple-600 hover:text-purple-700 font-semibold"> |
|
||||||
Login |
|
||||||
</a> |
|
||||||
</div> |
|
||||||
</form> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
</div> |
|
||||||
); |
|
||||||
} |
|
@ -1,17 +0,0 @@ |
|||||||
'use client' |
|
||||||
import AppContextProvider from "@/helpers/context/AppContextProvider" |
|
||||||
import CommonView from "@/views/CommonView" |
|
||||||
import RegisterForm from "./_partials/registerForm" |
|
||||||
|
|
||||||
export default function Component() { |
|
||||||
return ( |
|
||||||
<AppContextProvider> |
|
||||||
<CommonView> |
|
||||||
<div className="py-6"> |
|
||||||
<RegisterForm /> |
|
||||||
</div> |
|
||||||
</CommonView> |
|
||||||
</AppContextProvider> |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
@ -1,119 +0,0 @@ |
|||||||
'use client'; |
|
||||||
import React from 'react'; |
|
||||||
import { Input } from "@/components/ui/input"; |
|
||||||
import { Button } from "@/components/ui/button"; |
|
||||||
import { Label } from "@/components/ui/label"; |
|
||||||
import { Textarea } from "@/components/ui/textarea"; |
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; |
|
||||||
import { |
|
||||||
Select, |
|
||||||
SelectContent, |
|
||||||
SelectItem, |
|
||||||
SelectTrigger, |
|
||||||
SelectValue, |
|
||||||
} from "@/components/ui/select"; |
|
||||||
import { TabsContent } from '@/components/ui/tabs'; |
|
||||||
|
|
||||||
const CourseActionFormTabContent :React.FC = () => { |
|
||||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { |
|
||||||
e.preventDefault(); |
|
||||||
// Handle form submission
|
|
||||||
const formData = new FormData(e.currentTarget); |
|
||||||
console.log('Form submitted:', Object.fromEntries(formData)); |
|
||||||
}; |
|
||||||
|
|
||||||
return ( |
|
||||||
<Card> |
|
||||||
<CardHeader> |
|
||||||
<CardTitle className="text-2xl">Create New Course</CardTitle> |
|
||||||
</CardHeader> |
|
||||||
<CardContent> |
|
||||||
<form onSubmit={handleSubmit} className="space-y-6"> |
|
||||||
{/* Course Title */} |
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="title">Course Title</Label> |
|
||||||
<Input |
|
||||||
id="title" |
|
||||||
name="title" |
|
||||||
placeholder="Enter course title" |
|
||||||
required |
|
||||||
className="w-full" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
|
|
||||||
{/* Course Category */} |
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="category">Category</Label> |
|
||||||
<Select name="category"> |
|
||||||
<SelectTrigger> |
|
||||||
<SelectValue placeholder="Select a category" /> |
|
||||||
</SelectTrigger> |
|
||||||
<SelectContent> |
|
||||||
<SelectItem value="programming">Programming</SelectItem> |
|
||||||
<SelectItem value="design">Design</SelectItem> |
|
||||||
<SelectItem value="business">Business</SelectItem> |
|
||||||
<SelectItem value="marketing">Marketing</SelectItem> |
|
||||||
</SelectContent> |
|
||||||
</Select> |
|
||||||
</div> |
|
||||||
|
|
||||||
{/* Course Description */} |
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="description">Description</Label> |
|
||||||
<Textarea |
|
||||||
id="description" |
|
||||||
name="description" |
|
||||||
placeholder="Enter course description" |
|
||||||
className="min-h-32" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
|
|
||||||
{/* Estimated Learning Hours */} |
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="estimatedHours">Estimated Learning Hours</Label> |
|
||||||
<Input |
|
||||||
id="estimatedHours" |
|
||||||
name="estimatedHours" |
|
||||||
type="number" |
|
||||||
min="1" |
|
||||||
placeholder="Enter estimated hours" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
|
|
||||||
{/* Required Pages */} |
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="requiredPages">Required Pages</Label> |
|
||||||
<Input |
|
||||||
id="requiredPages" |
|
||||||
name="requiredPages" |
|
||||||
type="number" |
|
||||||
min="1" |
|
||||||
placeholder="Enter number of required pages" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
|
|
||||||
{/* PDF Upload */} |
|
||||||
<div className="space-y-2"> |
|
||||||
<Label htmlFor="coursePdf">Course PDF</Label> |
|
||||||
<Input |
|
||||||
id="coursePdf" |
|
||||||
name="coursePdf" |
|
||||||
type="file" |
|
||||||
accept=".pdf" |
|
||||||
className="cursor-pointer" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
|
|
||||||
{/* Submit Button */} |
|
||||||
<div className="pt-4"> |
|
||||||
<Button type="submit" className="w-full"> |
|
||||||
Create Course |
|
||||||
</Button> |
|
||||||
</div> |
|
||||||
</form> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
export default CourseActionFormTabContent; |
|
@ -1,9 +0,0 @@ |
|||||||
const MyCoursesTabContent : React.FC = () => { |
|
||||||
return( |
|
||||||
<> |
|
||||||
|
|
||||||
</> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default MyCoursesTabContent |
|
@ -1,46 +0,0 @@ |
|||||||
import React from 'react'; |
|
||||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; |
|
||||||
import MyCoursesActionContent from './MyCoursesTabContent'; |
|
||||||
import CourseActionFormTabContent from './CoursesActionModal'; |
|
||||||
|
|
||||||
const MyCoursesWrapper = () => { |
|
||||||
return ( |
|
||||||
<div className="container mx-auto py-8"> |
|
||||||
<Tabs defaultValue="general" className="flex gap-6 min-h-[50vh]"> |
|
||||||
<div className="min-w-[240px]"> |
|
||||||
<TabsList className="flex flex-col h-auto bg-transparent p-0"> |
|
||||||
<TabsTrigger
|
|
||||||
value="generali" |
|
||||||
className="justify-start w-full px-3 py-2 text-left data-[state=active]:bg-gray-50 data-[state=active]:border data-[state=active]:border-purple-700/50 rounded-md " |
|
||||||
> |
|
||||||
Profile |
|
||||||
</TabsTrigger> |
|
||||||
<TabsTrigger
|
|
||||||
value="email"
|
|
||||||
className="justify-start w-full px-3 py-2 text-left data-[state=active]:bg-gray-50 data-[state=active]:border data-[state=active]:border-purple-700/50 rounded-md" |
|
||||||
> |
|
||||||
Account |
|
||||||
</TabsTrigger> |
|
||||||
<TabsTrigger
|
|
||||||
value="password"
|
|
||||||
className="justify-start w-full px-3 py-2 text-left data-[state=active]:bg-gray-50 data-[state=active]:border data-[state=active]:border-purple-700/50 rounded-md" |
|
||||||
> |
|
||||||
Security |
|
||||||
</TabsTrigger> |
|
||||||
</TabsList> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="flex-1"> |
|
||||||
<TabsContent value="general" className="mt-0"> |
|
||||||
{/* <MyCoursesActionContent /> */} |
|
||||||
<CourseActionFormTabContent /> |
|
||||||
</TabsContent> |
|
||||||
{/* <UserEmailUpdateTabContent /> |
|
||||||
<UserPasswordUpdateTabContent /> */} |
|
||||||
</div> |
|
||||||
</Tabs> |
|
||||||
</div> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
export default MyCoursesWrapper; |
|
@ -1,19 +0,0 @@ |
|||||||
'use client' |
|
||||||
import AppContextProvider from "@/helpers/context/AppContextProvider" |
|
||||||
import MyCoursesWrapper from "./_partials/myCoursesTabWrapper" |
|
||||||
import CommonView from "@/views/CommonView" |
|
||||||
|
|
||||||
|
|
||||||
const MyCourses : React.FC = () => { |
|
||||||
return( |
|
||||||
<> |
|
||||||
<AppContextProvider> |
|
||||||
<CommonView> |
|
||||||
<MyCoursesWrapper /> |
|
||||||
</CommonView> |
|
||||||
</AppContextProvider> |
|
||||||
</> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default MyCourses |
|
@ -1,21 +1,101 @@ |
|||||||
'use client' |
import Image from "next/image"; |
||||||
|
|
||||||
import AppContextProvider from "@/helpers/context/AppContextProvider"; |
|
||||||
import CommonView from "@/views/CommonView"; |
|
||||||
import HeroSection from "./_partials/HeroSection"; |
|
||||||
import FeaturesSection from "./_partials/FeaturesSection"; |
|
||||||
import CommunitySection from "./_partials/CommunitySection"; |
|
||||||
import FeaturedCourses from "./_partials/FeaturedCourses"; |
|
||||||
|
|
||||||
export default function Home() { |
export default function Home() { |
||||||
return ( |
return ( |
||||||
<AppContextProvider> |
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]"> |
||||||
<CommonView> |
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start"> |
||||||
<HeroSection /> |
<Image |
||||||
<FeaturedCourses /> |
className="dark:invert" |
||||||
<FeaturesSection /> |
src="https://nextjs.org/icons/next.svg" |
||||||
<CommunitySection /> |
alt="Next.js logo" |
||||||
</CommonView> |
width={180} |
||||||
</AppContextProvider> |
height={38} |
||||||
|
priority |
||||||
|
/> |
||||||
|
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]"> |
||||||
|
<li className="mb-2"> |
||||||
|
Get started by editing{" "} |
||||||
|
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold"> |
||||||
|
src/app/page.tsx |
||||||
|
</code> |
||||||
|
. |
||||||
|
</li> |
||||||
|
<li>Save and see your changes instantly.</li> |
||||||
|
</ol> |
||||||
|
|
||||||
|
<div className="flex gap-4 items-center flex-col sm:flex-row"> |
||||||
|
<a |
||||||
|
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5" |
||||||
|
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" |
||||||
|
target="_blank" |
||||||
|
rel="noopener noreferrer" |
||||||
|
> |
||||||
|
<Image |
||||||
|
className="dark:invert" |
||||||
|
src="https://nextjs.org/icons/vercel.svg" |
||||||
|
alt="Vercel logomark" |
||||||
|
width={20} |
||||||
|
height={20} |
||||||
|
/> |
||||||
|
Deploy now |
||||||
|
</a> |
||||||
|
<a |
||||||
|
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44" |
||||||
|
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" |
||||||
|
target="_blank" |
||||||
|
rel="noopener noreferrer" |
||||||
|
> |
||||||
|
Read our docs |
||||||
|
</a> |
||||||
|
</div> |
||||||
|
</main> |
||||||
|
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center"> |
||||||
|
<a |
||||||
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4" |
||||||
|
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" |
||||||
|
target="_blank" |
||||||
|
rel="noopener noreferrer" |
||||||
|
> |
||||||
|
<Image |
||||||
|
aria-hidden |
||||||
|
src="https://nextjs.org/icons/file.svg" |
||||||
|
alt="File icon" |
||||||
|
width={16} |
||||||
|
height={16} |
||||||
|
/> |
||||||
|
Learn |
||||||
|
</a> |
||||||
|
<a |
||||||
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4" |
||||||
|
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" |
||||||
|
target="_blank" |
||||||
|
rel="noopener noreferrer" |
||||||
|
> |
||||||
|
<Image |
||||||
|
aria-hidden |
||||||
|
src="https://nextjs.org/icons/window.svg" |
||||||
|
alt="Window icon" |
||||||
|
width={16} |
||||||
|
height={16} |
||||||
|
/> |
||||||
|
Examples |
||||||
|
</a> |
||||||
|
<a |
||||||
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4" |
||||||
|
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" |
||||||
|
target="_blank" |
||||||
|
rel="noopener noreferrer" |
||||||
|
> |
||||||
|
<Image |
||||||
|
aria-hidden |
||||||
|
src="https://nextjs.org/icons/globe.svg" |
||||||
|
alt="Globe icon" |
||||||
|
width={16} |
||||||
|
height={16} |
||||||
|
/> |
||||||
|
Go to nextjs.org → |
||||||
|
</a> |
||||||
|
</footer> |
||||||
|
</div> |
||||||
); |
); |
||||||
} |
} |
||||||
|
@ -1,47 +0,0 @@ |
|||||||
import { Button } from "@/components/ui/button"; |
|
||||||
import { |
|
||||||
Card, |
|
||||||
CardContent, |
|
||||||
CardHeader, |
|
||||||
CardTitle, |
|
||||||
} from "@/components/ui/card"; |
|
||||||
import { Input } from "@/components/ui/input"; |
|
||||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; |
|
||||||
|
|
||||||
const UserEmailUpdateTabContent = () => { |
|
||||||
return( |
|
||||||
<> |
|
||||||
<TabsContent value="email" className="mt-0"> |
|
||||||
<Card> |
|
||||||
<CardHeader> |
|
||||||
<CardTitle>Email Settings</CardTitle> |
|
||||||
<p className="text-sm text-gray-500"> |
|
||||||
Manage your email addresses and verification status. |
|
||||||
</p> |
|
||||||
</CardHeader> |
|
||||||
<CardContent className="space-y-6"> |
|
||||||
|
|
||||||
|
|
||||||
<div className="space-y-2"> |
|
||||||
<label className="text-sm font-medium">Primary Email Address</label> |
|
||||||
<div className="p-4 border rounded-lg space-y-4"> |
|
||||||
<div className="flex items-center justify-between"> |
|
||||||
<span>your@email.com</span> |
|
||||||
<span className="text-sm text-green-600">✓ Verified</span> |
|
||||||
{ |
|
||||||
false &&
|
|
||||||
<Button>Add & Verify</Button> |
|
||||||
} |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
|
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
</TabsContent> |
|
||||||
</> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default UserEmailUpdateTabContent |
|
@ -1,46 +0,0 @@ |
|||||||
import { Button } from "@/components/ui/button"; |
|
||||||
import { |
|
||||||
Card, |
|
||||||
CardContent, |
|
||||||
CardHeader, |
|
||||||
CardTitle, |
|
||||||
} from "@/components/ui/card"; |
|
||||||
import { Input } from "@/components/ui/input"; |
|
||||||
import { TabsContent } from "@/components/ui/tabs"; |
|
||||||
|
|
||||||
const UserPasswordUpdateTabContent = () => { |
|
||||||
return( |
|
||||||
<TabsContent value="password" className="mt-0"> |
|
||||||
<Card> |
|
||||||
<CardHeader> |
|
||||||
<CardTitle>Update Password</CardTitle> |
|
||||||
<p className="text-sm text-gray-500"> |
|
||||||
Change your password to keep your account secure. |
|
||||||
</p> |
|
||||||
</CardHeader> |
|
||||||
<CardContent className="space-y-6"> |
|
||||||
<div className="space-y-2"> |
|
||||||
<label className="text-sm font-medium">Current Password</label> |
|
||||||
<Input type="password" required /> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="space-y-2"> |
|
||||||
<label className="text-sm font-medium">New Password</label> |
|
||||||
<Input type="password" required/> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="space-y-2"> |
|
||||||
<label className="text-sm font-medium">Confirm New Password</label> |
|
||||||
<Input type="password" required/> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="mx-auto w-fit"> |
|
||||||
<Button className="mt-6 w-full md:min-w-[600px] min-w-[300px] bg-purple-700">Save Changes</Button> |
|
||||||
</div> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
</TabsContent> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default UserPasswordUpdateTabContent |
|
@ -1,83 +0,0 @@ |
|||||||
import { Button } from "@/components/ui/button" |
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" |
|
||||||
import { Input } from "@/components/ui/input" |
|
||||||
import { Textarea } from "@/components/ui/textarea" |
|
||||||
|
|
||||||
const UserTabContent = () => { |
|
||||||
return( |
|
||||||
<Card> |
|
||||||
<CardHeader> |
|
||||||
<CardTitle>Profile</CardTitle> |
|
||||||
<p className="text-sm text-gray-500"> |
|
||||||
Manage your personal information and profile settings. |
|
||||||
</p> |
|
||||||
</CardHeader> |
|
||||||
<CardContent className="space-y-6"> |
|
||||||
|
|
||||||
{/* Profile Picture */} |
|
||||||
<div className="space-y-2"> |
|
||||||
<label className="text-sm font-medium">Profile Picture</label> |
|
||||||
<div className="flex items-center gap-4"> |
|
||||||
<div className="h-16 w-16 rounded-full bg-gray-100 flex items-center justify-center"> |
|
||||||
<span className="text-gray-500 text-sm">No image</span> |
|
||||||
</div> |
|
||||||
<Button variant="outline">Upload Image</Button> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
{/* Email */} |
|
||||||
|
|
||||||
{/* Name */} |
|
||||||
<div className="grid grid-cols-2 gap-4"> |
|
||||||
<div className="space-y-2"> |
|
||||||
<label className="text-sm font-medium">First Name</label> |
|
||||||
<Input defaultValue="John" /> |
|
||||||
</div> |
|
||||||
<div className="space-y-2"> |
|
||||||
<label className="text-sm font-medium">Last Name</label> |
|
||||||
<Input defaultValue="Doe" /> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
{/* Username */} |
|
||||||
<div className="grid grid-cols-2 gap-4"> |
|
||||||
<div className="space-y-2"> |
|
||||||
<label className="text-sm font-medium">Username</label> |
|
||||||
<Input defaultValue="johndoe123" /> |
|
||||||
<p className="text-sm text-gray-500"> |
|
||||||
This is your public display name. You can only change this once every 30 days. |
|
||||||
</p> |
|
||||||
</div> |
|
||||||
<div className="space-y-2"> |
|
||||||
<label className="text-sm font-medium">Date of Birth</label> |
|
||||||
<Input
|
|
||||||
type="date"
|
|
||||||
defaultValue="1990-01-01" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* Bio */} |
|
||||||
<div className="space-y-2"> |
|
||||||
<label className="text-sm font-medium">Bio</label> |
|
||||||
<Textarea
|
|
||||||
defaultValue="This is a test user." |
|
||||||
placeholder="Tell us about yourself" |
|
||||||
/> |
|
||||||
<p className="text-sm text-gray-500"> |
|
||||||
You can @mention other users and organizations to link to them. |
|
||||||
</p> |
|
||||||
</div> |
|
||||||
|
|
||||||
{/* Update Button */} |
|
||||||
<div className="mx-auto w-fit"> |
|
||||||
<Button className="mt-6 w-full md:min-w-[600px] min-w-[300px] bg-purple-700">Save Changes</Button> |
|
||||||
</div> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default UserTabContent |
|
@ -1,96 +0,0 @@ |
|||||||
import React from 'react'; |
|
||||||
import { |
|
||||||
Card, |
|
||||||
CardContent, |
|
||||||
CardHeader, |
|
||||||
CardTitle, |
|
||||||
} from "@/components/ui/card"; |
|
||||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; |
|
||||||
import UserTabContent from './UserTabContent'; |
|
||||||
import UserEmailUpdateTabContent from './UserEmailUpdateTabContent'; |
|
||||||
import UserPasswordUpdateTabContent from './UserPasswordUpdateTabContent'; |
|
||||||
|
|
||||||
const ProfileSettings = () => { |
|
||||||
return ( |
|
||||||
<div className="container mx-auto py-8"> |
|
||||||
<Tabs defaultValue="general" className="flex gap-6 min-h-[50vh]"> |
|
||||||
<div className="min-w-[240px]"> |
|
||||||
<TabsList className="flex flex-col h-auto bg-transparent p-0"> |
|
||||||
<TabsTrigger
|
|
||||||
value="general"
|
|
||||||
className="justify-start w-full px-3 py-2 text-left data-[state=active]:bg-gray-50 data-[state=active]:border data-[state=active]:border-purple-700/50 rounded-md " |
|
||||||
> |
|
||||||
Profile |
|
||||||
</TabsTrigger> |
|
||||||
<TabsTrigger
|
|
||||||
value="email"
|
|
||||||
className="justify-start w-full px-3 py-2 text-left data-[state=active]:bg-gray-50 data-[state=active]:border data-[state=active]:border-purple-700/50 rounded-md" |
|
||||||
> |
|
||||||
Account |
|
||||||
</TabsTrigger> |
|
||||||
<TabsTrigger
|
|
||||||
value="password"
|
|
||||||
className="justify-start w-full px-3 py-2 text-left data-[state=active]:bg-gray-50 data-[state=active]:border data-[state=active]:border-purple-700/50 rounded-md" |
|
||||||
> |
|
||||||
Security |
|
||||||
</TabsTrigger> |
|
||||||
</TabsList> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div className="flex-1"> |
|
||||||
<TabsContent value="general" className="mt-0"> |
|
||||||
<UserTabContent /> |
|
||||||
</TabsContent> |
|
||||||
<UserEmailUpdateTabContent /> |
|
||||||
<UserPasswordUpdateTabContent /> |
|
||||||
|
|
||||||
<TabsContent value="account" className="mt-0"> |
|
||||||
<Card> |
|
||||||
<CardHeader> |
|
||||||
<CardTitle>Account</CardTitle> |
|
||||||
</CardHeader> |
|
||||||
<CardContent> |
|
||||||
<p>Account settings coming soon...</p> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
</TabsContent> |
|
||||||
|
|
||||||
<TabsContent value="appearance" className="mt-0"> |
|
||||||
<Card> |
|
||||||
<CardHeader> |
|
||||||
<CardTitle>Appearance</CardTitle> |
|
||||||
</CardHeader> |
|
||||||
<CardContent> |
|
||||||
<p>Appearance settings coming soon...</p> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
</TabsContent> |
|
||||||
|
|
||||||
<TabsContent value="notifications" className="mt-0"> |
|
||||||
<Card> |
|
||||||
<CardHeader> |
|
||||||
<CardTitle>Notifications</CardTitle> |
|
||||||
</CardHeader> |
|
||||||
<CardContent> |
|
||||||
<p>Notification settings coming soon...</p> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
</TabsContent> |
|
||||||
|
|
||||||
<TabsContent value="display" className="mt-0"> |
|
||||||
<Card> |
|
||||||
<CardHeader> |
|
||||||
<CardTitle>Display</CardTitle> |
|
||||||
</CardHeader> |
|
||||||
<CardContent> |
|
||||||
<p>Display settings coming soon...</p> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
</TabsContent> |
|
||||||
</div> |
|
||||||
</Tabs> |
|
||||||
</div> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
export default ProfileSettings; |
|
@ -1,19 +0,0 @@ |
|||||||
'use client' |
|
||||||
|
|
||||||
import AppContextProvider from "@/helpers/context/AppContextProvider" |
|
||||||
import ProfileSettings from "./_partials/profile" |
|
||||||
import CommonView from "@/views/CommonView" |
|
||||||
|
|
||||||
const UserProfileIndex = () => { |
|
||||||
return( |
|
||||||
<> |
|
||||||
<AppContextProvider> |
|
||||||
<CommonView> |
|
||||||
<ProfileSettings /> |
|
||||||
</CommonView> |
|
||||||
</AppContextProvider> |
|
||||||
</> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default UserProfileIndex |
|
Before Width: | Height: | Size: 522 KiB |
Before Width: | Height: | Size: 301 KiB |
@ -1,13 +0,0 @@ |
|||||||
import { ElementType } from 'react'; |
|
||||||
|
|
||||||
export interface NavItem { |
|
||||||
title: string; |
|
||||||
href: string; |
|
||||||
description: string; |
|
||||||
icon: ElementType; |
|
||||||
} |
|
||||||
|
|
||||||
export interface ListItemProps extends React.ComponentPropsWithoutRef<"a"> { |
|
||||||
icon?: ElementType; |
|
||||||
title?: string; |
|
||||||
} |
|
@ -1,13 +0,0 @@ |
|||||||
import { Button } from "@/components/ui/button" |
|
||||||
|
|
||||||
const HeaderFeatureSection : React.FC = () => { |
|
||||||
return( |
|
||||||
<div className="flex"> |
|
||||||
<Button> |
|
||||||
Login |
|
||||||
</Button> |
|
||||||
</div> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default HeaderFeatureSection |
|
@ -1,7 +0,0 @@ |
|||||||
const Login : React.FC = () => { |
|
||||||
return( |
|
||||||
<> |
|
||||||
|
|
||||||
</> |
|
||||||
) |
|
||||||
} |
|
@ -1,49 +0,0 @@ |
|||||||
import { Input } from "@/components/ui/input" |
|
||||||
import { Search } from "lucide-react"; |
|
||||||
import { useState } from "react"; |
|
||||||
|
|
||||||
const SearchBar = () => { |
|
||||||
|
|
||||||
const [searchQuery, setSearchQuery] = useState<string>(''); |
|
||||||
|
|
||||||
const handleSearch = (e: React.FormEvent) => { |
|
||||||
e.preventDefault(); |
|
||||||
// Handle search logic here
|
|
||||||
console.log('Searching for:', searchQuery); |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
return( |
|
||||||
<> |
|
||||||
<form
|
|
||||||
onSubmit={handleSearch} |
|
||||||
className="hidden sm:flex flex-1 mx-4 max-w-md relative" |
|
||||||
> |
|
||||||
<div className="relative w-full"> |
|
||||||
<Input |
|
||||||
type="search" |
|
||||||
placeholder="Search courses..." |
|
||||||
className="w-full pl-10 bg-purple-700/10 border-white/20 text-white placeholder:text-white/50 focus:ring-[#9333EA] focus:border-[#9333EA]" |
|
||||||
value={searchQuery} |
|
||||||
onChange={(e) => setSearchQuery(e.target.value)} |
|
||||||
/> |
|
||||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-white/50" /> |
|
||||||
</div> |
|
||||||
</form> |
|
||||||
<div className="sm:hidden px-4 pb-4"> |
|
||||||
<form onSubmit={handleSearch} className="relative"> |
|
||||||
<Input |
|
||||||
type="search" |
|
||||||
placeholder="Search courses..." |
|
||||||
className="w-full pl-10 bg-white/10 border-white/20 text-white placeholder:text-white/50 focus:ring-[#9333EA] focus:border-[#9333EA]" |
|
||||||
value={searchQuery} |
|
||||||
onChange={(e) => setSearchQuery(e.target.value)} |
|
||||||
/> |
|
||||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-white/50" /> |
|
||||||
</form> |
|
||||||
</div> |
|
||||||
</> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default SearchBar |
|
@ -1,34 +0,0 @@ |
|||||||
|
|
||||||
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from "@/components/ui/dropdown-menu" |
|
||||||
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar" |
|
||||||
import Link from "next/link" |
|
||||||
import { Button } from "@/components/ui/button" |
|
||||||
|
|
||||||
export default function Component() { |
|
||||||
return ( |
|
||||||
<DropdownMenu> |
|
||||||
<DropdownMenuTrigger asChild> |
|
||||||
<Avatar className="h-9 w-9"> |
|
||||||
<AvatarImage src="/placeholder-user.jpg" alt="@shadcn" /> |
|
||||||
<AvatarFallback>JP</AvatarFallback> |
|
||||||
<span className="sr-only">Toggle user menu</span> |
|
||||||
</Avatar> |
|
||||||
</DropdownMenuTrigger> |
|
||||||
<DropdownMenuContent className="w-56"> |
|
||||||
<DropdownMenuItem className="font-bold text-lg">John Doe</DropdownMenuItem> |
|
||||||
<DropdownMenuSeparator /> |
|
||||||
<DropdownMenuItem asChild> |
|
||||||
<Link href="#" className="block w-full text-left" prefetch={false}> |
|
||||||
Profile |
|
||||||
</Link> |
|
||||||
</DropdownMenuItem> |
|
||||||
<DropdownMenuSeparator /> |
|
||||||
<DropdownMenuItem asChild> |
|
||||||
<Button variant="outline" className="block w-full text-left"> |
|
||||||
Logout |
|
||||||
</Button> |
|
||||||
</DropdownMenuItem> |
|
||||||
</DropdownMenuContent> |
|
||||||
</DropdownMenu> |
|
||||||
) |
|
||||||
} |
|
@ -1,56 +0,0 @@ |
|||||||
import React, { useState } from 'react'; |
|
||||||
import { Button } from "@/components/ui/button"; |
|
||||||
import { Menu, X } from "lucide-react"; |
|
||||||
import { DesktopNav } from '../Navbar/desktopNav'; |
|
||||||
import { MobileNav } from '../Navbar/mobileNav'; |
|
||||||
import SearchBar from './_partials/searchBar'; |
|
||||||
|
|
||||||
const Header = () => { |
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState(false); |
|
||||||
|
|
||||||
const toggleMenu = () => { |
|
||||||
setIsMenuOpen(!isMenuOpen); |
|
||||||
}; |
|
||||||
|
|
||||||
return ( |
|
||||||
<header className="relative bg-zinc-900"> |
|
||||||
<div className="container mx-auto px-4"> |
|
||||||
<div className="flex items-center justify-between py-4"> |
|
||||||
{/* Logo */} |
|
||||||
<h1 className="brand-logo text-purple-700 font-bold text-2xl">EDU CONNECT</h1> |
|
||||||
<SearchBar /> |
|
||||||
<div className='flex gap-8'> |
|
||||||
<DesktopNav /> |
|
||||||
<div className="hidden md:block space-x-4"> |
|
||||||
<Button className='bg-purple-700'> |
|
||||||
Login |
|
||||||
</Button> |
|
||||||
<Button className='bg-purple-700'> |
|
||||||
Register |
|
||||||
</Button> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* Hamburger Menu Button */} |
|
||||||
<button |
|
||||||
onClick={toggleMenu} |
|
||||||
className="md:hidden p-2 rounded-md hover:bg-gray-100" |
|
||||||
> |
|
||||||
{isMenuOpen ? ( |
|
||||||
<X className="h-6 w-6" /> |
|
||||||
) : ( |
|
||||||
<Menu className="h-6 w-6" /> |
|
||||||
)} |
|
||||||
</button> |
|
||||||
</div> |
|
||||||
|
|
||||||
{/* Mobile Navigation */} |
|
||||||
<MobileNav isOpen={isMenuOpen} /> |
|
||||||
</div> |
|
||||||
</header> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
export default Header; |
|
@ -1,53 +0,0 @@ |
|||||||
import React from 'react'; |
|
||||||
import Link from "next/link"; |
|
||||||
import { NavigationMenu,NavigationMenuItem, NavigationMenuLink, NavigationMenuList, navigationMenuTriggerStyle } from "@/components/ui/navigation-menu"; |
|
||||||
import { Book, Home, User } from "lucide-react"; |
|
||||||
|
|
||||||
export const DesktopNav = () => { |
|
||||||
return ( |
|
||||||
<div className="hidden md:block"> |
|
||||||
<NavigationMenu> |
|
||||||
<NavigationMenuList> |
|
||||||
{/* <NavigationMenuItem> |
|
||||||
<NavigationMenuTrigger className='bg-zinc-900 text-white hover:bg-zinc-600'> |
|
||||||
<Home className="mr-2 h-4 w-4" /> |
|
||||||
Menu |
|
||||||
</NavigationMenuTrigger> |
|
||||||
<NavigationMenuContent> |
|
||||||
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]"> |
|
||||||
{navigationItems.map((item : Record<string,any> , index : number) => ( |
|
||||||
<ListItem |
|
||||||
key={item.title} |
|
||||||
title={item.title} |
|
||||||
href={item.href} |
|
||||||
icon={item.icon} |
|
||||||
> |
|
||||||
{item.description} |
|
||||||
</ListItem> |
|
||||||
))} |
|
||||||
</ul> |
|
||||||
</NavigationMenuContent> |
|
||||||
</NavigationMenuItem> */} |
|
||||||
|
|
||||||
<NavigationMenuItem> |
|
||||||
<Link href="/docs" legacyBehavior passHref> |
|
||||||
<NavigationMenuLink className={navigationMenuTriggerStyle()}> |
|
||||||
<Home className="mr-2 h-4 w-4" /> |
|
||||||
Home |
|
||||||
</NavigationMenuLink> |
|
||||||
</Link> |
|
||||||
</NavigationMenuItem> |
|
||||||
|
|
||||||
<NavigationMenuItem> |
|
||||||
<Link href="/profile" legacyBehavior passHref> |
|
||||||
<NavigationMenuLink className={navigationMenuTriggerStyle()}> |
|
||||||
<Book className="mr-2 h-4 w-4" /> |
|
||||||
All Courses |
|
||||||
</NavigationMenuLink> |
|
||||||
</Link> |
|
||||||
</NavigationMenuItem> |
|
||||||
</NavigationMenuList> |
|
||||||
</NavigationMenu> |
|
||||||
</div> |
|
||||||
); |
|
||||||
}; |
|
@ -1,32 +0,0 @@ |
|||||||
import React from 'react'; |
|
||||||
import { NavigationMenuLink } from "@/components/ui/navigation-menu"; |
|
||||||
import { cn } from "@/lib/utils"; |
|
||||||
import { ListItemProps } from '../Header/_partials/header.type'; |
|
||||||
|
|
||||||
export const ListItem = React.forwardRef<React.ElementRef<"a">, ListItemProps>( |
|
||||||
({ className, title, children, icon: Icon, ...props }, ref) => { |
|
||||||
return ( |
|
||||||
<li> |
|
||||||
<NavigationMenuLink asChild> |
|
||||||
<a |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-zinc-500 hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground bg-zinc-900 text-white", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
<div className="flex items-center text-sm font-medium leading-none"> |
|
||||||
{Icon && <Icon className="mr-2 h-4 w-4" />} |
|
||||||
{title} |
|
||||||
</div> |
|
||||||
<p className="line-clamp-2 text-sm leading-snug text-muted-foreground mt-2"> |
|
||||||
{children} |
|
||||||
</p> |
|
||||||
</a> |
|
||||||
</NavigationMenuLink> |
|
||||||
</li> |
|
||||||
); |
|
||||||
} |
|
||||||
); |
|
||||||
ListItem.displayName = "ListItem"; |
|
@ -1,34 +0,0 @@ |
|||||||
import React from 'react'; |
|
||||||
import Link from "next/link"; |
|
||||||
import { Button } from "@/components/ui/button"; |
|
||||||
import { navigationItems } from './navRoutes'; |
|
||||||
|
|
||||||
interface MobileNavProps { |
|
||||||
isOpen: boolean; |
|
||||||
} |
|
||||||
|
|
||||||
export const MobileNav: React.FC<MobileNavProps> = ({ isOpen }) => { |
|
||||||
if (!isOpen) return null; |
|
||||||
|
|
||||||
return ( |
|
||||||
<div className="md:hidden absolute top-full left-0 right-0 bg-white border-t shadow-lg"> |
|
||||||
<nav className="px-4 py-2"> |
|
||||||
{navigationItems.map((item :Record<string,any> , index : number) => ( |
|
||||||
<Link |
|
||||||
key={item.title} |
|
||||||
href={item.href} |
|
||||||
className="flex items-center px-4 py-3 hover:bg-gray-100 rounded-md" |
|
||||||
> |
|
||||||
<item.icon className="mr-3 h-5 w-5" /> |
|
||||||
<span>{item.title}</span> |
|
||||||
</Link> |
|
||||||
))} |
|
||||||
<div className="px-4 py-3"> |
|
||||||
<Button className="w-full"> |
|
||||||
Login |
|
||||||
</Button> |
|
||||||
</div> |
|
||||||
</nav> |
|
||||||
</div> |
|
||||||
); |
|
||||||
}; |
|
@ -1,41 +0,0 @@ |
|||||||
import { Home, Settings, Book, FileText, Bell, User } from "lucide-react"; |
|
||||||
import { NavItem } from "../Header/_partials/header.type"; |
|
||||||
|
|
||||||
export const navigationItems: NavItem[] = [ |
|
||||||
{ |
|
||||||
title: "Dashboard", |
|
||||||
href: "/dashboard", |
|
||||||
description: "Overview of your account and key metrics", |
|
||||||
icon: Home |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: "Settings", |
|
||||||
href: "/settings", |
|
||||||
description: "Manage your account preferences and configuration", |
|
||||||
icon: Settings |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: "Documentation", |
|
||||||
href: "/docs", |
|
||||||
description: "Detailed guides and API references", |
|
||||||
icon: Book |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: "Reports", |
|
||||||
href: "/reports", |
|
||||||
description: "View and generate activity reports", |
|
||||||
icon: FileText |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: "Notifications", |
|
||||||
href: "/notifications", |
|
||||||
description: "Manage your alerts and notifications", |
|
||||||
icon: Bell |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: "Profile", |
|
||||||
href: "/profile", |
|
||||||
description: "View and edit your profile information", |
|
||||||
icon: User |
|
||||||
}, |
|
||||||
]; |
|
@ -1,19 +0,0 @@ |
|||||||
const CommonContainer = ({ |
|
||||||
children, |
|
||||||
title, |
|
||||||
className |
|
||||||
} : { |
|
||||||
children : React.ReactNode |
|
||||||
title? : string |
|
||||||
className? : string |
|
||||||
}) => { |
|
||||||
return( |
|
||||||
<> |
|
||||||
|
|
||||||
<title>{title ?? 'EDCUCONNECT'}</title> |
|
||||||
<div className={`container py-4 px-4 sm:px-8 mx-auto ${className}`}>{children}</div> |
|
||||||
</> |
|
||||||
) |
|
||||||
} |
|
||||||
export default CommonContainer |
|
||||||
|
|
@ -1,73 +0,0 @@ |
|||||||
import { BookOpen, Clock, Heart } from "lucide-react" |
|
||||||
import { Card, CardContent } from "../ui/card" |
|
||||||
|
|
||||||
|
|
||||||
interface CourseInterface { |
|
||||||
id : string , |
|
||||||
image :string | null
|
|
||||||
title : string |
|
||||||
category : string |
|
||||||
lessons : string |
|
||||||
duration : string |
|
||||||
instructor : { |
|
||||||
image : string |
|
||||||
name : string |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
const CourseCard : React.FC<CourseInterface> = ({ |
|
||||||
id, |
|
||||||
image, |
|
||||||
title, |
|
||||||
category, |
|
||||||
lessons , |
|
||||||
instructor, |
|
||||||
duration |
|
||||||
}) => { |
|
||||||
return( |
|
||||||
<Card key={id} className="overflow-hidden"> |
|
||||||
<div className="relative"> |
|
||||||
|
|
||||||
<img |
|
||||||
src={image!} |
|
||||||
alt={title} |
|
||||||
className="w-full h-48 object-cover" |
|
||||||
/> |
|
||||||
<span className="absolute top-4 left-4 bg-purple-700/90 text-white px-3 py-1 rounded-full text-sm"> |
|
||||||
{category} |
|
||||||
</span> |
|
||||||
<button className="absolute top-4 right-4 p-2 bg-white/90 rounded-full hover:bg-white"> |
|
||||||
<Heart className="w-4 h-4 fill-red-500 text-red-500" /> |
|
||||||
</button> |
|
||||||
</div> |
|
||||||
<CardContent className="p-6"> |
|
||||||
<div className="flex gap-4 text-sm text-gray-600 mb-3"> |
|
||||||
<div className="flex items-center gap-1"> |
|
||||||
<BookOpen className="w-4 h-4" /> |
|
||||||
<span>{lessons} Lesson</span> |
|
||||||
</div> |
|
||||||
<div className="flex items-center gap-1"> |
|
||||||
<Clock className="w-4 h-4" /> |
|
||||||
<span>{duration}</span> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<h3 className="text-lg font-semibold mb-4">{title}</h3> |
|
||||||
<div className="flex justify-between items-center"> |
|
||||||
<div className="flex items-center gap-2"> |
|
||||||
<img |
|
||||||
src={instructor?.image} |
|
||||||
alt={instructor?.name} |
|
||||||
className="w-8 h-8 rounded-full" |
|
||||||
/> |
|
||||||
<span className="text-sm">{instructor?.name}</span> |
|
||||||
</div> |
|
||||||
<div className="flex items-center gap-2"> |
|
||||||
<span className="text-purple-700 font-semibold text-sm px-4 py-1 bg-purple-200 rounded-2xl">Free</span> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default CourseCard |
|
@ -1,109 +0,0 @@ |
|||||||
import React, { useState } from 'react'; |
|
||||||
import { Card, CardContent } from "@/components/ui/card"; |
|
||||||
import { Button } from "@/components/ui/button"; |
|
||||||
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; |
|
||||||
import { Textarea } from "@/components/ui/textarea"; |
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area"; |
|
||||||
import { MessageCircle, ThumbsUp, Reply } from "lucide-react"; |
|
||||||
|
|
||||||
const DiscussionSection = () => { |
|
||||||
const [comment, setComment] = useState(''); |
|
||||||
const [discussions, setDiscussions] = useState([ |
|
||||||
{ |
|
||||||
id: 1, |
|
||||||
user: 'Sarah Chen', |
|
||||||
avatar: '/api/placeholder/32/32', |
|
||||||
content: 'This is really interesting! I particularly liked the section about state management.', |
|
||||||
likes: 12, |
|
||||||
replies: 2, |
|
||||||
timestamp: '2 hours ago' |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: 2, |
|
||||||
user: 'Alex Kim', |
|
||||||
avatar: '/api/placeholder/32/32', |
|
||||||
content: 'Great explanation! Could you elaborate more on the useEffect implementation?', |
|
||||||
likes: 8, |
|
||||||
replies: 1, |
|
||||||
timestamp: '1 hour ago' |
|
||||||
} |
|
||||||
]); |
|
||||||
|
|
||||||
const handleSubmit = () => { |
|
||||||
if (comment.trim()) { |
|
||||||
const newComment = { |
|
||||||
id: discussions.length + 1, |
|
||||||
user: 'Current User', |
|
||||||
avatar: '/api/placeholder/32/32', |
|
||||||
content: comment, |
|
||||||
likes: 0, |
|
||||||
replies: 0, |
|
||||||
timestamp: 'Just now' |
|
||||||
}; |
|
||||||
setDiscussions([...discussions, newComment]); |
|
||||||
setComment(''); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
return ( |
|
||||||
<Card className="w-full max-w-2xl mx-auto"> |
|
||||||
<CardContent className="p-6"> |
|
||||||
<div className="mb-6"> |
|
||||||
<div className="flex items-start gap-4"> |
|
||||||
<Avatar className="w-8 h-8"> |
|
||||||
<AvatarImage src="/api/placeholder/32/32" alt="User" /> |
|
||||||
<AvatarFallback>U</AvatarFallback> |
|
||||||
</Avatar> |
|
||||||
<div className="flex-1"> |
|
||||||
<Textarea |
|
||||||
placeholder="Add to the discussion..." |
|
||||||
value={comment} |
|
||||||
onChange={(e) => setComment(e.target.value)} |
|
||||||
className="min-h-24 mb-2" |
|
||||||
/> |
|
||||||
<Button onClick={handleSubmit} className="float-right"> |
|
||||||
Post Comment |
|
||||||
</Button> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
<ScrollArea className="h-96"> |
|
||||||
<div className="space-y-6"> |
|
||||||
{discussions.map((discussion) => ( |
|
||||||
<div key={discussion.id} className="flex gap-4"> |
|
||||||
<Avatar className="w-8 h-8"> |
|
||||||
<AvatarImage src={discussion.avatar} alt={discussion.user} /> |
|
||||||
<AvatarFallback>{discussion.user[0]}</AvatarFallback> |
|
||||||
</Avatar> |
|
||||||
<div className="flex-1"> |
|
||||||
<div className="flex items-center gap-2 mb-1"> |
|
||||||
<span className="font-medium">{discussion.user}</span> |
|
||||||
<span className="text-sm text-gray-500">{discussion.timestamp}</span> |
|
||||||
</div> |
|
||||||
<p className="text-gray-700 mb-2">{discussion.content}</p> |
|
||||||
<div className="flex items-center gap-4"> |
|
||||||
<button className="flex items-center gap-1 text-sm text-gray-500 hover:text-gray-700"> |
|
||||||
<ThumbsUp className="w-4 h-4" /> |
|
||||||
{discussion.likes} |
|
||||||
</button> |
|
||||||
<button className="flex items-center gap-1 text-sm text-gray-500 hover:text-gray-700"> |
|
||||||
<Reply className="w-4 h-4" /> |
|
||||||
Reply |
|
||||||
</button> |
|
||||||
<button className="flex items-center gap-1 text-sm text-gray-500 hover:text-gray-700"> |
|
||||||
<MessageCircle className="w-4 h-4" /> |
|
||||||
{discussion.replies} replies |
|
||||||
</button> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
))} |
|
||||||
</div> |
|
||||||
</ScrollArea> |
|
||||||
</CardContent> |
|
||||||
</Card> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
export default DiscussionSection; |
|
@ -1,50 +0,0 @@ |
|||||||
"use client" |
|
||||||
|
|
||||||
import * as React from "react" |
|
||||||
import * as AvatarPrimitive from "@radix-ui/react-avatar" |
|
||||||
|
|
||||||
import { cn } from "@/lib/utils" |
|
||||||
|
|
||||||
const Avatar = React.forwardRef< |
|
||||||
React.ElementRef<typeof AvatarPrimitive.Root>, |
|
||||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<AvatarPrimitive.Root |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
Avatar.displayName = AvatarPrimitive.Root.displayName |
|
||||||
|
|
||||||
const AvatarImage = React.forwardRef< |
|
||||||
React.ElementRef<typeof AvatarPrimitive.Image>, |
|
||||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<AvatarPrimitive.Image |
|
||||||
ref={ref} |
|
||||||
className={cn("aspect-square h-full w-full", className)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName |
|
||||||
|
|
||||||
const AvatarFallback = React.forwardRef< |
|
||||||
React.ElementRef<typeof AvatarPrimitive.Fallback>, |
|
||||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<AvatarPrimitive.Fallback |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"flex h-full w-full items-center justify-center rounded-full bg-muted", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName |
|
||||||
|
|
||||||
export { Avatar, AvatarImage, AvatarFallback } |
|
@ -1,36 +0,0 @@ |
|||||||
import * as React from "react" |
|
||||||
import { cva, type VariantProps } from "class-variance-authority" |
|
||||||
|
|
||||||
import { cn } from "@/lib/utils" |
|
||||||
|
|
||||||
const badgeVariants = cva( |
|
||||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", |
|
||||||
{ |
|
||||||
variants: { |
|
||||||
variant: { |
|
||||||
default: |
|
||||||
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80", |
|
||||||
secondary: |
|
||||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", |
|
||||||
destructive: |
|
||||||
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80", |
|
||||||
outline: "text-foreground", |
|
||||||
}, |
|
||||||
}, |
|
||||||
defaultVariants: { |
|
||||||
variant: "default", |
|
||||||
}, |
|
||||||
} |
|
||||||
) |
|
||||||
|
|
||||||
export interface BadgeProps |
|
||||||
extends React.HTMLAttributes<HTMLDivElement>, |
|
||||||
VariantProps<typeof badgeVariants> {} |
|
||||||
|
|
||||||
function Badge({ className, variant, ...props }: BadgeProps) { |
|
||||||
return ( |
|
||||||
<div className={cn(badgeVariants({ variant }), className)} {...props} /> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export { Badge, badgeVariants } |
|
@ -1,76 +0,0 @@ |
|||||||
import * as React from "react" |
|
||||||
|
|
||||||
import { cn } from "@/lib/utils" |
|
||||||
|
|
||||||
const Card = React.forwardRef< |
|
||||||
HTMLDivElement, |
|
||||||
React.HTMLAttributes<HTMLDivElement> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<div |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"rounded-xl border bg-card text-card-foreground shadow", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
Card.displayName = "Card" |
|
||||||
|
|
||||||
const CardHeader = React.forwardRef< |
|
||||||
HTMLDivElement, |
|
||||||
React.HTMLAttributes<HTMLDivElement> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<div |
|
||||||
ref={ref} |
|
||||||
className={cn("flex flex-col space-y-1.5 p-6", className)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
CardHeader.displayName = "CardHeader" |
|
||||||
|
|
||||||
const CardTitle = React.forwardRef< |
|
||||||
HTMLDivElement, |
|
||||||
React.HTMLAttributes<HTMLDivElement> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<div |
|
||||||
ref={ref} |
|
||||||
className={cn("font-semibold leading-none tracking-tight", className)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
CardTitle.displayName = "CardTitle" |
|
||||||
|
|
||||||
const CardDescription = React.forwardRef< |
|
||||||
HTMLDivElement, |
|
||||||
React.HTMLAttributes<HTMLDivElement> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<div |
|
||||||
ref={ref} |
|
||||||
className={cn("text-sm text-muted-foreground", className)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
CardDescription.displayName = "CardDescription" |
|
||||||
|
|
||||||
const CardContent = React.forwardRef< |
|
||||||
HTMLDivElement, |
|
||||||
React.HTMLAttributes<HTMLDivElement> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} /> |
|
||||||
)) |
|
||||||
CardContent.displayName = "CardContent" |
|
||||||
|
|
||||||
const CardFooter = React.forwardRef< |
|
||||||
HTMLDivElement, |
|
||||||
React.HTMLAttributes<HTMLDivElement> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<div |
|
||||||
ref={ref} |
|
||||||
className={cn("flex items-center p-6 pt-0", className)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
CardFooter.displayName = "CardFooter" |
|
||||||
|
|
||||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } |
|
@ -1,201 +0,0 @@ |
|||||||
"use client" |
|
||||||
|
|
||||||
import * as React from "react" |
|
||||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" |
|
||||||
import { Check, ChevronRight, Circle } from "lucide-react" |
|
||||||
|
|
||||||
import { cn } from "@/lib/utils" |
|
||||||
|
|
||||||
const DropdownMenu = DropdownMenuPrimitive.Root |
|
||||||
|
|
||||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger |
|
||||||
|
|
||||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group |
|
||||||
|
|
||||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal |
|
||||||
|
|
||||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub |
|
||||||
|
|
||||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup |
|
||||||
|
|
||||||
const DropdownMenuSubTrigger = React.forwardRef< |
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>, |
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { |
|
||||||
inset?: boolean |
|
||||||
} |
|
||||||
>(({ className, inset, children, ...props }, ref) => ( |
|
||||||
<DropdownMenuPrimitive.SubTrigger |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", |
|
||||||
inset && "pl-8", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
{children} |
|
||||||
<ChevronRight className="ml-auto" /> |
|
||||||
</DropdownMenuPrimitive.SubTrigger> |
|
||||||
)) |
|
||||||
DropdownMenuSubTrigger.displayName = |
|
||||||
DropdownMenuPrimitive.SubTrigger.displayName |
|
||||||
|
|
||||||
const DropdownMenuSubContent = React.forwardRef< |
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>, |
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<DropdownMenuPrimitive.SubContent |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
DropdownMenuSubContent.displayName = |
|
||||||
DropdownMenuPrimitive.SubContent.displayName |
|
||||||
|
|
||||||
const DropdownMenuContent = React.forwardRef< |
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>, |
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> |
|
||||||
>(({ className, sideOffset = 4, ...props }, ref) => ( |
|
||||||
<DropdownMenuPrimitive.Portal> |
|
||||||
<DropdownMenuPrimitive.Content |
|
||||||
ref={ref} |
|
||||||
sideOffset={sideOffset} |
|
||||||
className={cn( |
|
||||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md", |
|
||||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
</DropdownMenuPrimitive.Portal> |
|
||||||
)) |
|
||||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName |
|
||||||
|
|
||||||
const DropdownMenuItem = React.forwardRef< |
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>, |
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { |
|
||||||
inset?: boolean |
|
||||||
} |
|
||||||
>(({ className, inset, ...props }, ref) => ( |
|
||||||
<DropdownMenuPrimitive.Item |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0", |
|
||||||
inset && "pl-8", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName |
|
||||||
|
|
||||||
const DropdownMenuCheckboxItem = React.forwardRef< |
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>, |
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> |
|
||||||
>(({ className, children, checked, ...props }, ref) => ( |
|
||||||
<DropdownMenuPrimitive.CheckboxItem |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", |
|
||||||
className |
|
||||||
)} |
|
||||||
checked={checked} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> |
|
||||||
<DropdownMenuPrimitive.ItemIndicator> |
|
||||||
<Check className="h-4 w-4" /> |
|
||||||
</DropdownMenuPrimitive.ItemIndicator> |
|
||||||
</span> |
|
||||||
{children} |
|
||||||
</DropdownMenuPrimitive.CheckboxItem> |
|
||||||
)) |
|
||||||
DropdownMenuCheckboxItem.displayName = |
|
||||||
DropdownMenuPrimitive.CheckboxItem.displayName |
|
||||||
|
|
||||||
const DropdownMenuRadioItem = React.forwardRef< |
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>, |
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> |
|
||||||
>(({ className, children, ...props }, ref) => ( |
|
||||||
<DropdownMenuPrimitive.RadioItem |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> |
|
||||||
<DropdownMenuPrimitive.ItemIndicator> |
|
||||||
<Circle className="h-2 w-2 fill-current" /> |
|
||||||
</DropdownMenuPrimitive.ItemIndicator> |
|
||||||
</span> |
|
||||||
{children} |
|
||||||
</DropdownMenuPrimitive.RadioItem> |
|
||||||
)) |
|
||||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName |
|
||||||
|
|
||||||
const DropdownMenuLabel = React.forwardRef< |
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>, |
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { |
|
||||||
inset?: boolean |
|
||||||
} |
|
||||||
>(({ className, inset, ...props }, ref) => ( |
|
||||||
<DropdownMenuPrimitive.Label |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"px-2 py-1.5 text-sm font-semibold", |
|
||||||
inset && "pl-8", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName |
|
||||||
|
|
||||||
const DropdownMenuSeparator = React.forwardRef< |
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>, |
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<DropdownMenuPrimitive.Separator |
|
||||||
ref={ref} |
|
||||||
className={cn("-mx-1 my-1 h-px bg-muted", className)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName |
|
||||||
|
|
||||||
const DropdownMenuShortcut = ({ |
|
||||||
className, |
|
||||||
...props |
|
||||||
}: React.HTMLAttributes<HTMLSpanElement>) => { |
|
||||||
return ( |
|
||||||
<span |
|
||||||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
) |
|
||||||
} |
|
||||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut" |
|
||||||
|
|
||||||
export { |
|
||||||
DropdownMenu, |
|
||||||
DropdownMenuTrigger, |
|
||||||
DropdownMenuContent, |
|
||||||
DropdownMenuItem, |
|
||||||
DropdownMenuCheckboxItem, |
|
||||||
DropdownMenuRadioItem, |
|
||||||
DropdownMenuLabel, |
|
||||||
DropdownMenuSeparator, |
|
||||||
DropdownMenuShortcut, |
|
||||||
DropdownMenuGroup, |
|
||||||
DropdownMenuPortal, |
|
||||||
DropdownMenuSub, |
|
||||||
DropdownMenuSubContent, |
|
||||||
DropdownMenuSubTrigger, |
|
||||||
DropdownMenuRadioGroup, |
|
||||||
} |
|
@ -1,48 +1,22 @@ |
|||||||
import * as React from "react"; |
import * as React from "react" |
||||||
import { cn } from "@/lib/utils"; |
|
||||||
|
|
||||||
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> { |
import { cn } from "@/lib/utils" |
||||||
error?: string[]; |
|
||||||
label?: string; |
|
||||||
helperText?: string; |
|
||||||
required?: boolean; |
|
||||||
} |
|
||||||
|
|
||||||
const Input = React.forwardRef<HTMLInputElement, InputProps>( |
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>( |
||||||
({ className, type, error, label, helperText, required = false, ...props }, ref) => { |
({ className, type, ...props }, ref) => { |
||||||
return ( |
return ( |
||||||
<div className="w-full space-y-2"> |
<input |
||||||
{label && ( |
type={type} |
||||||
<div className="flex text-sm font-medium text-gray-700"> |
className={cn( |
||||||
{label} |
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", |
||||||
{required && <span className="text-red-500 ml-1">*</span>} |
className |
||||||
</div> |
|
||||||
)} |
)} |
||||||
<input |
ref={ref} |
||||||
type={type} |
{...props} |
||||||
className={cn( |
/> |
||||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", |
|
||||||
error && error.length > 0 && "border-red-500 focus-visible:ring-red-500", |
|
||||||
className |
|
||||||
)} |
|
||||||
ref={ref} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
{helperText && ( |
|
||||||
<p className="text-sm text-muted-foreground"> |
|
||||||
{helperText} |
|
||||||
</p> |
|
||||||
)} |
|
||||||
{error && error.map((message, index) => ( |
|
||||||
<p key={index} className="text-sm font-medium text-red-500"> |
|
||||||
{message} |
|
||||||
</p> |
|
||||||
))} |
|
||||||
</div> |
|
||||||
) |
) |
||||||
} |
} |
||||||
) |
) |
||||||
|
|
||||||
Input.displayName = "Input" |
Input.displayName = "Input" |
||||||
|
|
||||||
export { Input } |
export { Input } |
||||||
|
@ -1,26 +0,0 @@ |
|||||||
"use client" |
|
||||||
|
|
||||||
import * as React from "react" |
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label" |
|
||||||
import { cva, type VariantProps } from "class-variance-authority" |
|
||||||
|
|
||||||
import { cn } from "@/lib/utils" |
|
||||||
|
|
||||||
const labelVariants = cva( |
|
||||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" |
|
||||||
) |
|
||||||
|
|
||||||
const Label = React.forwardRef< |
|
||||||
React.ElementRef<typeof LabelPrimitive.Root>, |
|
||||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & |
|
||||||
VariantProps<typeof labelVariants> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<LabelPrimitive.Root |
|
||||||
ref={ref} |
|
||||||
className={cn(labelVariants(), className)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
Label.displayName = LabelPrimitive.Root.displayName |
|
||||||
|
|
||||||
export { Label } |
|
@ -1,28 +0,0 @@ |
|||||||
"use client" |
|
||||||
|
|
||||||
import * as React from "react" |
|
||||||
import * as ProgressPrimitive from "@radix-ui/react-progress" |
|
||||||
|
|
||||||
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 } |
|
@ -1,48 +0,0 @@ |
|||||||
"use client" |
|
||||||
|
|
||||||
import * as React from "react" |
|
||||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" |
|
||||||
|
|
||||||
import { cn } from "@/lib/utils" |
|
||||||
|
|
||||||
const ScrollArea = React.forwardRef< |
|
||||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>, |
|
||||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> |
|
||||||
>(({ className, children, ...props }, ref) => ( |
|
||||||
<ScrollAreaPrimitive.Root |
|
||||||
ref={ref} |
|
||||||
className={cn("relative overflow-hidden", className)} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]"> |
|
||||||
{children} |
|
||||||
</ScrollAreaPrimitive.Viewport> |
|
||||||
<ScrollBar /> |
|
||||||
<ScrollAreaPrimitive.Corner /> |
|
||||||
</ScrollAreaPrimitive.Root> |
|
||||||
)) |
|
||||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName |
|
||||||
|
|
||||||
const ScrollBar = React.forwardRef< |
|
||||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>, |
|
||||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar> |
|
||||||
>(({ className, orientation = "vertical", ...props }, ref) => ( |
|
||||||
<ScrollAreaPrimitive.ScrollAreaScrollbar |
|
||||||
ref={ref} |
|
||||||
orientation={orientation} |
|
||||||
className={cn( |
|
||||||
"flex touch-none select-none transition-colors", |
|
||||||
orientation === "vertical" && |
|
||||||
"h-full w-2.5 border-l border-l-transparent p-[1px]", |
|
||||||
orientation === "horizontal" && |
|
||||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" /> |
|
||||||
</ScrollAreaPrimitive.ScrollAreaScrollbar> |
|
||||||
)) |
|
||||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName |
|
||||||
|
|
||||||
export { ScrollArea, ScrollBar } |
|
@ -1,159 +0,0 @@ |
|||||||
"use client" |
|
||||||
|
|
||||||
import * as React from "react" |
|
||||||
import * as SelectPrimitive from "@radix-ui/react-select" |
|
||||||
import { Check, ChevronDown, ChevronUp } from "lucide-react" |
|
||||||
|
|
||||||
import { cn } from "@/lib/utils" |
|
||||||
|
|
||||||
const Select = SelectPrimitive.Root |
|
||||||
|
|
||||||
const SelectGroup = SelectPrimitive.Group |
|
||||||
|
|
||||||
const SelectValue = SelectPrimitive.Value |
|
||||||
|
|
||||||
const SelectTrigger = React.forwardRef< |
|
||||||
React.ElementRef<typeof SelectPrimitive.Trigger>, |
|
||||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> |
|
||||||
>(({ className, children, ...props }, ref) => ( |
|
||||||
<SelectPrimitive.Trigger |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
{children} |
|
||||||
<SelectPrimitive.Icon asChild> |
|
||||||
<ChevronDown className="h-4 w-4 opacity-50" /> |
|
||||||
</SelectPrimitive.Icon> |
|
||||||
</SelectPrimitive.Trigger> |
|
||||||
)) |
|
||||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName |
|
||||||
|
|
||||||
const SelectScrollUpButton = React.forwardRef< |
|
||||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>, |
|
||||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<SelectPrimitive.ScrollUpButton |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"flex cursor-default items-center justify-center py-1", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
<ChevronUp className="h-4 w-4" /> |
|
||||||
</SelectPrimitive.ScrollUpButton> |
|
||||||
)) |
|
||||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName |
|
||||||
|
|
||||||
const SelectScrollDownButton = React.forwardRef< |
|
||||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>, |
|
||||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<SelectPrimitive.ScrollDownButton |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"flex cursor-default items-center justify-center py-1", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
<ChevronDown className="h-4 w-4" /> |
|
||||||
</SelectPrimitive.ScrollDownButton> |
|
||||||
)) |
|
||||||
SelectScrollDownButton.displayName = |
|
||||||
SelectPrimitive.ScrollDownButton.displayName |
|
||||||
|
|
||||||
const SelectContent = React.forwardRef< |
|
||||||
React.ElementRef<typeof SelectPrimitive.Content>, |
|
||||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> |
|
||||||
>(({ className, children, position = "popper", ...props }, ref) => ( |
|
||||||
<SelectPrimitive.Portal> |
|
||||||
<SelectPrimitive.Content |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", |
|
||||||
position === "popper" && |
|
||||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", |
|
||||||
className |
|
||||||
)} |
|
||||||
position={position} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
<SelectScrollUpButton /> |
|
||||||
<SelectPrimitive.Viewport |
|
||||||
className={cn( |
|
||||||
"p-1", |
|
||||||
position === "popper" && |
|
||||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]" |
|
||||||
)} |
|
||||||
> |
|
||||||
{children} |
|
||||||
</SelectPrimitive.Viewport> |
|
||||||
<SelectScrollDownButton /> |
|
||||||
</SelectPrimitive.Content> |
|
||||||
</SelectPrimitive.Portal> |
|
||||||
)) |
|
||||||
SelectContent.displayName = SelectPrimitive.Content.displayName |
|
||||||
|
|
||||||
const SelectLabel = React.forwardRef< |
|
||||||
React.ElementRef<typeof SelectPrimitive.Label>, |
|
||||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<SelectPrimitive.Label |
|
||||||
ref={ref} |
|
||||||
className={cn("px-2 py-1.5 text-sm font-semibold", className)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
SelectLabel.displayName = SelectPrimitive.Label.displayName |
|
||||||
|
|
||||||
const SelectItem = React.forwardRef< |
|
||||||
React.ElementRef<typeof SelectPrimitive.Item>, |
|
||||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item> |
|
||||||
>(({ className, children, ...props }, ref) => ( |
|
||||||
<SelectPrimitive.Item |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
> |
|
||||||
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center"> |
|
||||||
<SelectPrimitive.ItemIndicator> |
|
||||||
<Check className="h-4 w-4" /> |
|
||||||
</SelectPrimitive.ItemIndicator> |
|
||||||
</span> |
|
||||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText> |
|
||||||
</SelectPrimitive.Item> |
|
||||||
)) |
|
||||||
SelectItem.displayName = SelectPrimitive.Item.displayName |
|
||||||
|
|
||||||
const SelectSeparator = React.forwardRef< |
|
||||||
React.ElementRef<typeof SelectPrimitive.Separator>, |
|
||||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<SelectPrimitive.Separator |
|
||||||
ref={ref} |
|
||||||
className={cn("-mx-1 my-1 h-px bg-muted", className)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName |
|
||||||
|
|
||||||
export { |
|
||||||
Select, |
|
||||||
SelectGroup, |
|
||||||
SelectValue, |
|
||||||
SelectTrigger, |
|
||||||
SelectContent, |
|
||||||
SelectLabel, |
|
||||||
SelectItem, |
|
||||||
SelectSeparator, |
|
||||||
SelectScrollUpButton, |
|
||||||
SelectScrollDownButton, |
|
||||||
} |
|
@ -1,55 +0,0 @@ |
|||||||
"use client" |
|
||||||
|
|
||||||
import * as React from "react" |
|
||||||
import * as TabsPrimitive from "@radix-ui/react-tabs" |
|
||||||
|
|
||||||
import { cn } from "@/lib/utils" |
|
||||||
|
|
||||||
const Tabs = TabsPrimitive.Root |
|
||||||
|
|
||||||
const TabsList = React.forwardRef< |
|
||||||
React.ElementRef<typeof TabsPrimitive.List>, |
|
||||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<TabsPrimitive.List |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
TabsList.displayName = TabsPrimitive.List.displayName |
|
||||||
|
|
||||||
const TabsTrigger = React.forwardRef< |
|
||||||
React.ElementRef<typeof TabsPrimitive.Trigger>, |
|
||||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<TabsPrimitive.Trigger |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName |
|
||||||
|
|
||||||
const TabsContent = React.forwardRef< |
|
||||||
React.ElementRef<typeof TabsPrimitive.Content>, |
|
||||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content> |
|
||||||
>(({ className, ...props }, ref) => ( |
|
||||||
<TabsPrimitive.Content |
|
||||||
ref={ref} |
|
||||||
className={cn( |
|
||||||
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", |
|
||||||
className |
|
||||||
)} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
)) |
|
||||||
TabsContent.displayName = TabsPrimitive.Content.displayName |
|
||||||
|
|
||||||
export { Tabs, TabsList, TabsTrigger, TabsContent } |
|
@ -1,22 +0,0 @@ |
|||||||
import * as React from "react" |
|
||||||
|
|
||||||
import { cn } from "@/lib/utils" |
|
||||||
|
|
||||||
const Textarea = React.forwardRef< |
|
||||||
HTMLTextAreaElement, |
|
||||||
React.ComponentProps<"textarea"> |
|
||||||
>(({ className, ...props }, ref) => { |
|
||||||
return ( |
|
||||||
<textarea |
|
||||||
className={cn( |
|
||||||
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", |
|
||||||
className |
|
||||||
)} |
|
||||||
ref={ref} |
|
||||||
{...props} |
|
||||||
/> |
|
||||||
) |
|
||||||
}) |
|
||||||
Textarea.displayName = "Textarea" |
|
||||||
|
|
||||||
export { Textarea } |
|
@ -1,14 +0,0 @@ |
|||||||
export interface User { |
|
||||||
firstName: string; |
|
||||||
lastName: string; |
|
||||||
email: string; |
|
||||||
id: string; |
|
||||||
pfpName: string; |
|
||||||
bio: string; |
|
||||||
date_of_birth: string; |
|
||||||
} |
|
||||||
|
|
||||||
export interface Admin extends User { |
|
||||||
role: string; |
|
||||||
permissions: string[]; |
|
||||||
} |
|
@ -1,15 +0,0 @@ |
|||||||
import { AuthProvider } from "./AuthProvider" |
|
||||||
|
|
||||||
const AppContextProvider = ({ |
|
||||||
children |
|
||||||
} : { |
|
||||||
children : React.ReactNode |
|
||||||
}) => { |
|
||||||
return( |
|
||||||
<AuthProvider> |
|
||||||
{children} |
|
||||||
</AuthProvider> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default AppContextProvider |
|
@ -1,93 +0,0 @@ |
|||||||
"use client"; |
|
||||||
|
|
||||||
import React, { ReactNode, createContext, useEffect, useState } from "react"; |
|
||||||
import Cookies from "js-cookie"; |
|
||||||
import { User } from "../apiSchema/User"; |
|
||||||
import { getEduConnectAccessToken } from "../token.helper"; |
|
||||||
|
|
||||||
interface AuthContextProps { |
|
||||||
user: User | null; |
|
||||||
loading: boolean; |
|
||||||
fetchUser: (token: string) => void; |
|
||||||
logout: () => void; |
|
||||||
} |
|
||||||
|
|
||||||
interface AuthProviderProps { |
|
||||||
children: ReactNode; |
|
||||||
} |
|
||||||
|
|
||||||
const AuthContext = createContext<AuthContextProps>({ |
|
||||||
user: null, |
|
||||||
loading: true, |
|
||||||
fetchUser: () => {}, |
|
||||||
logout: () => {}, |
|
||||||
}); |
|
||||||
|
|
||||||
const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => { |
|
||||||
|
|
||||||
|
|
||||||
const [user, setUser] = useState<User | null>(null); |
|
||||||
const [loading, setLoading] = useState(true); |
|
||||||
|
|
||||||
const fetchUser = async () => { |
|
||||||
|
|
||||||
|
|
||||||
try { |
|
||||||
// Fetch user data
|
|
||||||
const userResponse = await fetch(`${process.env.NEXT_PUBLIC_EDU_CONNECT_HOST}/api/get-user-by-token`, { |
|
||||||
method: "POST", |
|
||||||
headers: { |
|
||||||
Authorization: `Bearer ${getEduConnectAccessToken()}`, |
|
||||||
Accept: "Application/json", |
|
||||||
}, |
|
||||||
}); |
|
||||||
|
|
||||||
const userData = await userResponse.json(); |
|
||||||
setUser(userData.data); |
|
||||||
// router.replace(routes.SELECT_COMPANY_INDEX)
|
|
||||||
} catch (error) { |
|
||||||
console.error("Fetch error:", error); |
|
||||||
// router.replace(routes.ADMIN_LOGIN);
|
|
||||||
} finally { |
|
||||||
setLoading(false); // Only set loading to false on initial load
|
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
useEffect(() => { |
|
||||||
if (!user) { |
|
||||||
fetchUser(); |
|
||||||
} |
|
||||||
}, []); |
|
||||||
|
|
||||||
|
|
||||||
const logout = async () => { |
|
||||||
try { |
|
||||||
await fetch(`${process.env.NEXT_PUBLIC_IDP_HOST}/api/logout`, { |
|
||||||
method: "POST", |
|
||||||
headers: { |
|
||||||
Authorization: `Bearer ${getEduConnectAccessToken()}`, |
|
||||||
}, |
|
||||||
}); |
|
||||||
} catch (error) { |
|
||||||
console.error("Logout error:", error); |
|
||||||
} finally { |
|
||||||
Cookies.remove("HRMS_ACCESS_TOKEN", { domain: process.env.APP_DOMAIN }); |
|
||||||
setUser(null); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
return ( |
|
||||||
<AuthContext.Provider |
|
||||||
value={{ |
|
||||||
user, |
|
||||||
loading: !user && loading, |
|
||||||
fetchUser: fetchUser, |
|
||||||
logout, |
|
||||||
}} |
|
||||||
> |
|
||||||
{children} |
|
||||||
</AuthContext.Provider> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
export { AuthContext, AuthProvider }; |
|
@ -1,16 +0,0 @@ |
|||||||
import Cookie from 'js-cookie' |
|
||||||
|
|
||||||
export const getEduConnectAccessToken = () : string | null => { |
|
||||||
return Cookie.get('EDU_CONNECT_ACCESS_TOKEN') |
|
||||||
} |
|
||||||
|
|
||||||
export const setEduConnectAccessToken = (token : string) : void => { |
|
||||||
Cookie.set('EDU_CONNECT_ACCESS_TOKEN' , token) |
|
||||||
} |
|
||||||
|
|
||||||
export const removeEduConnectAccessToken = () : void => { |
|
||||||
Cookie.remove('EDU_CONNECT_ACCESS_TOKEN') |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@ |
|||||||
export const routes = { |
|
||||||
INDEX_PAGE : '/' ,
|
|
||||||
LOGIN_ROUTES : '/login' |
|
||||||
} |
|
@ -1,20 +0,0 @@ |
|||||||
import Footer from "@/components/common/Footer/footer" |
|
||||||
import Header from "@/components/common/Header/header" |
|
||||||
|
|
||||||
const CommonView = ({ |
|
||||||
children |
|
||||||
} : { |
|
||||||
children : React.ReactNode |
|
||||||
}) => { |
|
||||||
return( |
|
||||||
<div className="min-h-screen flex flex-col justify-between"> |
|
||||||
<Header /> |
|
||||||
<main> |
|
||||||
{children} |
|
||||||
</main> |
|
||||||
<Footer /> |
|
||||||
</div> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default CommonView |
|
Loading…
Reference in new issue