diff --git a/apps/admin/package.json b/apps/admin/package.json index 0b5283e..aeafbdd 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -16,6 +16,7 @@ "@heroicons/react": "^2.2.0", "@hookform/resolvers": "^5.1.1", "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-switch": "^1.2.5", "@tailwindcss/postcss": "^4.0.8", "@tanstack/react-table": "^8.21.3", "@workspace/db": "workspace:*", diff --git a/apps/student/README.md b/apps/student/README.md new file mode 100644 index 0000000..2f62a60 --- /dev/null +++ b/apps/student/README.md @@ -0,0 +1,172 @@ +# Student Dashboard - NextPlacement + +A modern, student-focused dashboard for job discovery and application management. + +## 🎨 Design Philosophy + +The student dashboard has been completely redesigned with a different UI/UX approach compared to the admin dashboard: + +- **Student-Centric**: Focused on job discovery and career opportunities +- **Modern & Engaging**: Gradient backgrounds, interactive cards, and smooth animations +- **Mobile-First**: Responsive design that works perfectly on all devices +- **Intuitive Navigation**: Clear, student-focused navigation structure + +## 🚀 Features + +### 1. **Hero Section** +- Inspirational messaging focused on career discovery +- Call-to-action buttons for job browsing and saved jobs +- Gradient background with engaging visuals + +### 2. **Statistics Dashboard** +- Real-time stats showing active companies, open positions, student count +- Visual indicators with icons and color-coded metrics +- Success rate tracking + +### 3. **Featured Companies** +- Showcase of top companies with active job postings +- Company cards with job previews +- Quick access to company-specific job listings + +### 4. **Recent Job Opportunities** +- Latest job postings from all companies +- Detailed job cards with company information +- Quick apply functionality with resume selection + +### 5. **Job Applications Tracking** +- Comprehensive view of all submitted applications +- Status tracking (Pending, Under Review, Accepted, Rejected) +- Application history with company and job details + +### 6. **Student Profile Management** +- Complete profile information management +- Academic details and skills showcase +- Resume upload and management +- Social media links integration + +## 🛠 Technical Implementation + +### Backend Integration +- **Database Schema**: Uses the existing schema with `students`, `jobs`, `companies`, `applications`, and `resumes` tables +- **Server Actions**: New actions for job applications, profile management, and data fetching +- **Real-time Data**: Dynamic data fetching with proper error handling + +### Key Components + +#### 1. **Layout (`layout.tsx`)** +- Student-specific navigation with blue color scheme +- Responsive design with mobile menu +- Profile dropdown with student information + +#### 2. **Dashboard (`page.tsx`)** +- Hero section with career-focused messaging +- Statistics cards with real data +- Featured companies showcase +- Recent job opportunities grid + +#### 3. **Applications (`applications/page.tsx`)** +- Application status tracking +- Detailed application history +- Export functionality +- Status-based filtering + +#### 4. **Profile (`profile/page.tsx`)** +- Comprehensive profile management +- Academic information display +- Skills showcase +- Resume management + +#### 5. **Jobs (`jobs/page.tsx`)** +- Job browsing with search and filters +- Detailed job cards +- Application modal integration +- Company information display + +#### 6. **Job Application Modal (`components/job-application-modal.tsx`)** +- Interactive application form +- Resume selection +- Real-time validation +- Success/error messaging + +## 🎯 Key Differences from Admin Dashboard + +| Aspect | Admin Dashboard | Student Dashboard | +|--------|----------------|-------------------| +| **Color Scheme** | Red/Pink gradients | Blue/Indigo gradients | +| **Navigation** | Admin-focused (Dashboard, Students, Jobs) | Student-focused (Home, Applications, Profile) | +| **Layout** | Data-heavy, management-focused | Career-focused, opportunity-driven | +| **Interactions** | CRUD operations, data management | Job discovery, applications, profile management | +| **Visual Style** | Professional, corporate | Modern, engaging, student-friendly | + +## 🔧 Backend Actions + +### New Server Actions Added: + +1. **`applyForJob(jobId, studentId, resumeId)`** + - Handles job application submission + - Prevents duplicate applications + - Updates application status + +2. **`getStudentApplications(studentId)`** + - Fetches all applications for a student + - Includes job and company details + - Status tracking + +3. **`getStudentProfile(studentId)`** + - Retrieves complete student profile + - Includes grades, resumes, internships + +4. **`updateStudentProfile(studentId, data)`** + - Updates student profile information + - Handles validation and error cases + +5. **`getAvailableJobs()`** + - Fetches all active job postings + - Includes company information + +6. **`getFeaturedCompanies()`** + - Gets top companies with active jobs + - Sorted by job count + +## 🎨 UI Components Used + +- **Cards**: For job listings, company showcases, and profile sections +- **Buttons**: Various styles for different actions +- **Badges**: Status indicators and skill tags +- **Dialogs**: Application modals and confirmations +- **Forms**: Profile editing and application submission +- **Icons**: Lucide React icons for visual consistency + +## 🚀 Getting Started + +1. **Installation**: The dashboard is part of the monorepo structure +2. **Database**: Ensure the database schema is up to date +3. **Authentication**: Student authentication should be configured +4. **Development**: Run the student app with `pnpm dev` in the student directory + +## 📱 Responsive Design + +The dashboard is fully responsive with: +- Mobile-first approach +- Tablet-optimized layouts +- Desktop-enhanced features +- Touch-friendly interactions + +## 🔮 Future Enhancements + +- **Real-time Notifications**: WebSocket integration for application updates +- **Advanced Filtering**: More sophisticated job search and filtering +- **Resume Builder**: Integrated resume creation tool +- **Interview Scheduling**: Calendar integration for interviews +- **Analytics Dashboard**: Personal application analytics +- **Social Features**: Student networking and recommendations + +## 🎯 User Experience Goals + +1. **Easy Job Discovery**: Students can quickly find relevant opportunities +2. **Simple Application Process**: Streamlined job application workflow +3. **Clear Status Tracking**: Transparent application status updates +4. **Profile Management**: Easy profile updates and maintenance +5. **Mobile Accessibility**: Full functionality on mobile devices + +This student dashboard provides a modern, engaging experience that helps students discover career opportunities and manage their job applications effectively. \ No newline at end of file diff --git a/apps/student/app/(main)/actions.ts b/apps/student/app/(main)/actions.ts index 9ef1e5e..9cd2194 100644 --- a/apps/student/app/(main)/actions.ts +++ b/apps/student/app/(main)/actions.ts @@ -1,6 +1,134 @@ 'use server' import { signOut } from "@/auth"; +import { db, applications, jobs, students, resumes } from "@workspace/db"; +import { eq, and } from "@workspace/db/drizzle"; +import { revalidatePath } from "next/cache"; export async function signOutAction() { await signOut(); +} + +export async function applyForJob(jobId: number, studentId: number, resumeId: number) { + try { + // Check if student has already applied for this job + const existingApplication = await db.query.applications.findFirst({ + where: and( + eq(applications.jobId, jobId), + eq(applications.studentId, studentId) + ) + }); + + if (existingApplication) { + return { success: false, error: "You have already applied for this job" }; + } + + // Create new application + await db.insert(applications).values({ + jobId, + studentId, + resumeId, + status: 'pending' + }); + + revalidatePath('/applications'); + return { success: true }; + } catch (error) { + console.error("Error applying for job:", error); + return { success: false, error: "Failed to apply for job" }; + } +} + +export async function getStudentApplications(studentId: number) { + try { + const studentApplications = await db.query.applications.findMany({ + where: eq(applications.studentId, studentId), + with: { + job: { + with: { + company: true + } + }, + resume: true + } + }); + + return { success: true, applications: studentApplications }; + } catch (error) { + console.error("Error fetching student applications:", error); + return { success: false, error: "Failed to fetch applications" }; + } +} + +export async function getStudentProfile(studentId: number) { + try { + const student = await db.query.students.findFirst({ + where: eq(students.id, studentId), + with: { + grades: true, + resumes: true, + internships: true + } + }); + + return { success: true, student }; + } catch (error) { + console.error("Error fetching student profile:", error); + return { success: false, error: "Failed to fetch student profile" }; + } +} + +export async function updateStudentProfile(studentId: number, data: any) { + try { + await db.update(students) + .set({ + ...data, + updatedAt: new Date() + }) + .where(eq(students.id, studentId)); + + revalidatePath('/profile'); + return { success: true }; + } catch (error) { + console.error("Error updating student profile:", error); + return { success: false, error: "Failed to update profile" }; + } +} + +export async function getAvailableJobs() { + try { + const availableJobs = await db.query.jobs.findMany({ + where: eq(jobs.active, true), + with: { + company: true + } + }); + + return { success: true, jobs: availableJobs }; + } catch (error) { + console.error("Error fetching available jobs:", error); + return { success: false, error: "Failed to fetch jobs" }; + } +} + +export async function getFeaturedCompanies() { + try { + const companies = await db.query.companies.findMany({ + with: { + jobs: { + where: eq(jobs.active, true) + } + } + }); + + // Filter companies with active jobs and sort by number of jobs + const companiesWithJobs = companies + .filter(company => company.jobs.length > 0) + .sort((a, b) => b.jobs.length - a.jobs.length) + .slice(0, 6); // Top 6 companies + + return { success: true, companies: companiesWithJobs }; + } catch (error) { + console.error("Error fetching featured companies:", error); + return { success: false, error: "Failed to fetch companies" }; + } } \ No newline at end of file diff --git a/apps/student/app/(main)/applications/page.tsx b/apps/student/app/(main)/applications/page.tsx new file mode 100644 index 0000000..a00c785 --- /dev/null +++ b/apps/student/app/(main)/applications/page.tsx @@ -0,0 +1,271 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@workspace/ui/components/card" +import { Button } from "@workspace/ui/components/button" +import { Badge } from "@workspace/ui/components/badge" +import { Separator } from "@workspace/ui/components/separator" +import { + FileText, + Clock, + CheckCircle, + XCircle, + AlertCircle, + Building2, + Calendar, + MapPin, + DollarSign, + Eye, + Download, + Share2 +} from "lucide-react" + +// Mock data for applications - in real app this would come from database +const mockApplications = [ + { + id: 1, + jobTitle: "Software Engineer Intern", + company: "TechCorp Solutions", + status: "pending", + appliedDate: "2024-01-15", + deadline: "2024-02-15", + location: "San Francisco, CA", + salary: "$25/hour", + resume: "Resume_v2.pdf" + }, + { + id: 2, + jobTitle: "Data Analyst", + company: "DataFlow Inc", + status: "reviewed", + appliedDate: "2024-01-10", + deadline: "2024-02-10", + location: "New York, NY", + salary: "$30/hour", + resume: "Resume_v2.pdf" + }, + { + id: 3, + jobTitle: "Frontend Developer", + company: "WebSolutions", + status: "accepted", + appliedDate: "2024-01-05", + deadline: "2024-02-05", + location: "Remote", + salary: "$28/hour", + resume: "Resume_v2.pdf" + }, + { + id: 4, + jobTitle: "Product Manager Intern", + company: "InnovateTech", + status: "rejected", + appliedDate: "2024-01-01", + deadline: "2024-02-01", + location: "Seattle, WA", + salary: "$32/hour", + resume: "Resume_v2.pdf" + } +] + +const getStatusConfig = (status: string) => { + switch (status) { + case 'pending': + return { + icon: Clock, + color: 'bg-yellow-100 text-yellow-700', + text: 'Pending Review' + } + case 'reviewed': + return { + icon: Eye, + color: 'bg-blue-100 text-blue-700', + text: 'Under Review' + } + case 'accepted': + return { + icon: CheckCircle, + color: 'bg-green-100 text-green-700', + text: 'Accepted' + } + case 'rejected': + return { + icon: XCircle, + color: 'bg-red-100 text-red-700', + text: 'Rejected' + } + default: + return { + icon: AlertCircle, + color: 'bg-gray-100 text-gray-700', + text: 'Unknown' + } + } +} + +export default function ApplicationsPage() { + const statusConfig = getStatusConfig('pending') + const StatusIcon = statusConfig.icon + + // Calculate stats + const totalApplications = mockApplications.length + const pendingApplications = mockApplications.filter(app => app.status === 'pending').length + const acceptedApplications = mockApplications.filter(app => app.status === 'accepted').length + const rejectedApplications = mockApplications.filter(app => app.status === 'rejected').length + + return ( +
+
+ {/* Header */} +
+

My Applications

+

Track your job applications and their status

+
+ + {/* Stats Cards */} +
+ + +
+
+

Total Applications

+

{totalApplications}

+
+ +
+
+
+ + + +
+
+

Pending Review

+

{pendingApplications}

+
+ +
+
+
+ + + +
+
+

Accepted

+

{acceptedApplications}

+
+ +
+
+
+ + + +
+
+

Rejected

+

{rejectedApplications}

+
+ +
+
+
+
+ + {/* Applications List */} +
+
+

Recent Applications

+ +
+ + {mockApplications.map((application) => { + const appStatusConfig = getStatusConfig(application.status) + const AppStatusIcon = appStatusConfig.icon + + return ( + + +
+
+
+ +
+
+

{application.jobTitle}

+

{application.company}

+
+ + + Applied: {application.appliedDate} + + + + {application.location} + + + + {application.salary} + +
+
+
+
+ + + {appStatusConfig.text} + + +
+
+ + + +
+
+ + + Resume: {application.resume} + + + + Deadline: {application.deadline} + +
+
+ + +
+
+
+
+ ) + })} +
+ + {/* Empty State */} + {mockApplications.length === 0 && ( + + + +

No applications yet

+

Start applying to jobs to see your applications here

+ +
+
+ )} +
+
+ ) +} \ No newline at end of file diff --git a/apps/student/app/(main)/jobs/page.tsx b/apps/student/app/(main)/jobs/page.tsx new file mode 100644 index 0000000..7b364ab --- /dev/null +++ b/apps/student/app/(main)/jobs/page.tsx @@ -0,0 +1,358 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@workspace/ui/components/card" +import { Button } from "@workspace/ui/components/button" +import { Badge } from "@workspace/ui/components/badge" +import { Input } from "@workspace/ui/components/input" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@workspace/ui/components/select" +import { + Building2, + MapPin, + DollarSign, + Calendar, + Clock, + Search, + Filter, + Bookmark, + Share2, + Eye, + ArrowRight, + Briefcase, + Users, + Star, + CheckCircle, + ExternalLink +} from "lucide-react" +import { db, jobs, companies } from "@workspace/db" +import { eq } from "drizzle-orm" +import JobApplicationModal from "../../components/job-application-modal" + +async function getJobsData() { + try { + const availableJobs = await db.query.jobs.findMany({ + where: eq(jobs.active, true), + with: { + company: true + } + }); + + return availableJobs; + } catch (error) { + console.error("Error fetching jobs:", error); + return []; + } +} + +export default async function JobsPage() { + const jobs = await getJobsData(); + + // Mock data for demonstration + const mockJobs = [ + { + id: 1, + title: "Software Engineer Intern", + company: { + name: "TechCorp Solutions", + email: "careers@techcorp.com" + }, + location: "San Francisco, CA", + salary: "$25/hour", + description: "Join our dynamic team and work on cutting-edge projects. We're looking for passionate developers who love to learn and grow.", + applicationDeadline: new Date("2024-02-15"), + minCGPA: 7.5, + active: true, + link: "https://techcorp.com/careers" + }, + { + id: 2, + title: "Data Analyst", + company: { + name: "DataFlow Inc", + email: "hr@dataflow.com" + }, + location: "New York, NY", + salary: "$30/hour", + description: "Analyze large datasets and provide insights to drive business decisions. Experience with Python and SQL required.", + applicationDeadline: new Date("2024-02-10"), + minCGPA: 7.0, + active: true, + link: "https://dataflow.com/jobs" + }, + { + id: 3, + title: "Frontend Developer", + company: { + name: "WebSolutions", + email: "jobs@websolutions.com" + }, + location: "Remote", + salary: "$28/hour", + description: "Build beautiful and responsive user interfaces. Strong knowledge of React, TypeScript, and modern CSS required.", + applicationDeadline: new Date("2024-02-05"), + minCGPA: 7.2, + active: true, + link: "https://websolutions.com/careers" + }, + { + id: 4, + title: "Product Manager Intern", + company: { + name: "InnovateTech", + email: "careers@innovatetech.com" + }, + location: "Seattle, WA", + salary: "$32/hour", + description: "Work closely with cross-functional teams to define product requirements and drive product development.", + applicationDeadline: new Date("2024-02-01"), + minCGPA: 7.8, + active: true, + link: "https://innovatetech.com/jobs" + }, + { + id: 5, + title: "DevOps Engineer", + company: { + name: "CloudTech Systems", + email: "hr@cloudtech.com" + }, + location: "Austin, TX", + salary: "$35/hour", + description: "Manage cloud infrastructure and deployment pipelines. Experience with AWS, Docker, and Kubernetes preferred.", + applicationDeadline: new Date("2024-02-20"), + minCGPA: 7.0, + active: true, + link: "https://cloudtech.com/careers" + }, + { + id: 6, + title: "UX/UI Designer", + company: { + name: "DesignStudio", + email: "jobs@designstudio.com" + }, + location: "Los Angeles, CA", + salary: "$26/hour", + description: "Create intuitive and beautiful user experiences. Proficiency in Figma, Adobe Creative Suite, and user research methods.", + applicationDeadline: new Date("2024-02-12"), + minCGPA: 7.5, + active: true, + link: "https://designstudio.com/jobs" + } + ]; + + const allJobs = [...jobs, ...mockJobs]; + + return ( +
+
+ {/* Header */} +
+

Browse Jobs

+

Find the perfect opportunity that matches your skills and aspirations

+
+ + {/* Search and Filter Section */} + + +
+
+
+ + +
+
+
+ +
+
+ +
+
+
+
+ + {/* Stats */} +
+ + +
+
+

Total Jobs

+

{allJobs.length}

+
+ +
+
+
+ + + +
+
+

Active Companies

+

+ {new Set(allJobs.map(job => job.company.name)).size} +

+
+ +
+
+
+ + + +
+
+

Remote Jobs

+

+ {allJobs.filter(job => job.location.toLowerCase().includes('remote')).length} +

+
+ +
+
+
+ + + +
+
+

Avg Salary

+

$28/hr

+
+ +
+
+
+
+ + {/* Jobs Grid */} +
+ {allJobs.map((job) => ( + + +
+
+
+ +
+
+

+ {job.title} +

+

{job.company.name}

+
+ + + {job.location} + + + + {job.salary} + +
+
+
+
+ + + Active + + +
+
+ +

{job.description}

+ +
+
+ + Deadline: {job.applicationDeadline.toLocaleDateString()} +
+
+ + Min CGPA: {job.minCGPA} +
+
+ +
+
+ + {job.link && ( + + )} +
+
+ + +
+
+
+
+ ))} +
+ + {/* Load More */} +
+ +
+ + {/* Empty State */} + {allJobs.length === 0 && ( + + + +

No jobs found

+

Try adjusting your search criteria or check back later for new opportunities

+ +
+
+ )} +
+
+ ) +} \ No newline at end of file diff --git a/apps/student/app/(main)/layout.tsx b/apps/student/app/(main)/layout.tsx index 1259cf4..6f7445f 100644 --- a/apps/student/app/(main)/layout.tsx +++ b/apps/student/app/(main)/layout.tsx @@ -6,37 +6,40 @@ import { useState, useEffect } from 'react'; import { Button } from '@workspace/ui/components/button'; import { Badge } from '@workspace/ui/components/badge'; import { - LayoutDashboard, - Users, + Home, Briefcase, + User, + FileText, + Bell, + Search, Menu, X, LogOut, - Settings, - Bell, - Search, - ChevronDown + Settings, + GraduationCap, + TrendingUp, + BookOpen } from 'lucide-react'; import { signOutAction } from './actions'; const navLinks = [ { href: '/', - label: 'Dashboard', - icon: LayoutDashboard, - description: 'Overview and analytics' + label: 'Home', + icon: Home, + description: 'Discover opportunities' }, { - href: '/students', - label: 'Students', - icon: Users, - description: 'Manage student profiles' + href: '/applications', + label: 'My Applications', + icon: FileText, + description: 'Track your applications' }, { - href: '/jobs', - label: 'Jobs', - icon: Briefcase, - description: 'Job listings and applications' + href: '/profile', + label: 'Profile', + icon: User, + description: 'Manage your profile' }, ]; @@ -61,11 +64,11 @@ export default function MainLayout({ children }: { children: React.ReactNode }) }, [pathname]); return ( -
- {/* Enhanced Sticky Navbar */} +
+ {/* Modern Student Navbar */}
@@ -73,23 +76,20 @@ export default function MainLayout({ children }: { children: React.ReactNode }) {/* Logo Section */}
- Logo -
+
+ +
- + NextPlacement - Admin Portal + Student Portal
{/* Desktop Navigation */} -
{/* Main Content */} -
+
{children}
diff --git a/apps/student/app/(main)/page.tsx b/apps/student/app/(main)/page.tsx index d8218d7..2ba5fa1 100644 --- a/apps/student/app/(main)/page.tsx +++ b/apps/student/app/(main)/page.tsx @@ -3,16 +3,34 @@ import { Button } from "@workspace/ui/components/button" import { Badge } from "@workspace/ui/components/badge" import { Separator } from "@workspace/ui/components/separator" import Link from "next/link" -import { db, companies } from "@workspace/db" -import { Plus, Building2, Briefcase, MapPin, DollarSign, Calendar, ExternalLink } from "lucide-react" +import { db, companies, jobs, students } from "@workspace/db" +import { + Building2, + Briefcase, + MapPin, + DollarSign, + Calendar, + ExternalLink, + TrendingUp, + Users, + Star, + Clock, + CheckCircle, + ArrowRight, + Search, + Filter, + Bookmark, + Share2, + Eye +} from "lucide-react" async function getDashboardData() { try { - // Get companies with their jobs + // Get companies with their active jobs const result = await db.query.companies.findMany({ with: { jobs: { - where: (job, {eq}) => eq(job.active, true), // Only include active jobs + where: (job, {eq}) => eq(job.active, true), } } }) @@ -20,201 +38,293 @@ async function getDashboardData() { // Filter to only include companies that have active jobs const companiesWithActiveJobs = result.filter((company) => company.jobs.length > 0) - console.log("Companies with active jobs:", companiesWithActiveJobs.length) - return companiesWithActiveJobs + // Get total student count for stats + const studentCount = await db.select().from(students) + + return { + companies: companiesWithActiveJobs, + totalStudents: studentCount.length + } } catch (error) { console.error("Database query error:", error) - // Fallback to companies only if the relation query fails - const companiesOnly = await db.select().from(companies) - return companiesOnly.map((company) => ({ ...company, jobs: [] })) + return { + companies: [], + totalStudents: 0 + } } } export default async function DashboardPage() { - const data = await getDashboardData() + const { companies: data, totalStudents } = await getDashboardData() - // Calculate stats for companies with active jobs only + // Calculate stats const totalActiveJobs = data.reduce((acc, company) => acc + company.jobs.filter((job) => job.active).length, 0) + const featuredCompanies = data.slice(0, 3) // Top 3 companies for featured section + const recentJobs = data.flatMap(company => + company.jobs.slice(0, 2).map(job => ({ ...job, company })) + ).slice(0, 6) return ( -
-
- {/* Header Section */} -
-
-
-

Companies Dashboard

-

Companies with active job listings

-
- - - + +
+
+
+ + + {/* Stats Section */} +
+
+
+
+
+ +
+

{data.length}

+

Active Companies

+
+
+
+ +
+

{totalActiveJobs}

+

Open Positions

+
+
+
+ +
+

{totalStudents}

+

Students

+
+
+
+ +
+

95%

+

Success Rate

+
+
+
+
+ + {/* Featured Companies Section */} +
+
+
+

Featured Companies

+

+ Top companies actively hiring talented students like you +

- {/* Stats Cards */} -
- - -
-
-

Companies with Active Jobs

-

{data.length}

+
+ {featuredCompanies.map((company) => ( + +
+
+
- -
- -
- - - -
-
-

Total Active Jobs

-

{totalActiveJobs}

-
- -
-
-
- - - -
-
-

Avg Jobs per Company

-

- {data.length > 0 ? Math.round((totalActiveJobs / data.length) * 10) / 10 : 0} -

-
-
-
+
+ + + Featured +
- - -
-
- - {/* Companies Section */} -
- {data.length === 0 ? ( - - - -

No companies with active jobs

-

Get started by adding your first job listing

- - - -
-
- ) : ( - data.map((company) => ( - - -
-
-
- -
-
- {company.name} -

{company.email}

-
-
-
- - {company.jobs.filter((job) => job.active).length} active job - {company.jobs.filter((job) => job.active).length !== 1 ? "s" : ""} - + + +
+
+

{company.name}

+

{company.email}

+ + {company.jobs.length} jobs +
+ {company.description && company.description !== "N/A" && ( -

{company.description}

+

{company.description}

)} - - - - - -
-

Active Job Listings

+ +
+ {company.jobs.slice(0, 2).map((job) => ( +
+
+

{job.title}

+
+ {job.location && job.location !== "N/A" && ( + + + {job.location} + + )} + {job.salary && job.salary !== "N/A" && ( + + + {job.salary} + + )} +
+
+ +
+ ))}
- -
- {company.jobs - .filter((job) => job.active) - .map((job) => ( - - -
-
-

- {job.title} -

- - Active - -
- -
- {job.location && job.location !== "N/A" && ( -
- - {job.location} -
- )} - {job.salary && job.salary !== "N/A" && ( -
- - {job.salary} -
- )} -
- - Deadline: {job.applicationDeadline.toLocaleDateString()} -
-
- - {job.link && ( - - )} -
-
-
- ))} + +
+ +
- )) - )} -
-
+ ))} +
+ + + + {/* Recent Job Opportunities */} +
+
+
+
+

Recent Opportunities

+

Latest job postings from top companies

+
+ +
+ +
+ {recentJobs.map((job) => ( + + +
+
+
+ +
+
+

{job.title}

+

{job.company.name}

+
+
+
+ + + Active + + +
+
+ +
+ {job.location && job.location !== "N/A" && ( +
+ + {job.location} +
+ )} + {job.salary && job.salary !== "N/A" && ( +
+ + {job.salary} +
+ )} +
+ + Deadline: {job.applicationDeadline.toLocaleDateString()} +
+
+ + Min CGPA: {job.minCGPA} +
+
+ + {job.description && job.description !== "N/A" && ( +

{job.description}

+ )} + +
+
+ + {job.link && ( + + )} +
+ +
+
+
+ ))} +
+ +
+ +
+
+
+ + {/* Call to Action */} +
+
+

Ready to Start Your Career Journey?

+

+ Join thousands of students who have found their dream jobs through NextPlacement +

+
+ + +
+
+
) } diff --git a/apps/student/app/(main)/profile/page.tsx b/apps/student/app/(main)/profile/page.tsx new file mode 100644 index 0000000..5f249fe --- /dev/null +++ b/apps/student/app/(main)/profile/page.tsx @@ -0,0 +1,314 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@workspace/ui/components/card" +import { Button } from "@workspace/ui/components/button" +import { Badge } from "@workspace/ui/components/badge" +import { Separator } from "@workspace/ui/components/separator" +import { Input } from "@workspace/ui/components/input" +import { Label } from "@workspace/ui/components/label" +import { Textarea } from "@workspace/ui/components/textarea" +import { + User, + Mail, + Phone, + MapPin, + Calendar, + GraduationCap, + BookOpen, + Award, + Edit, + Save, + Camera, + Linkedin, + Github, + FileText, + Download, + Upload, + CheckCircle, + AlertCircle +} from "lucide-react" + +// Mock student data - in real app this would come from database +const mockStudent = { + id: 1, + firstName: "John", + middleName: "Michael", + lastName: "Doe", + email: "john.doe@college.edu", + rollNumber: "2021CS001", + phoneNumber: "+91 98765 43210", + address: "123 College Street, Mumbai, Maharashtra", + gender: "Male", + dob: "2000-05-15", + degree: "Bachelor of Technology", + branch: "Computer Science", + year: "4th Year", + skills: ["JavaScript", "React", "Node.js", "Python", "SQL", "Git"], + linkedin: "https://linkedin.com/in/johndoe", + github: "https://github.com/johndoe", + ssc: 9.2, + hsc: 8.8, + isDiploma: false, + verified: true, + markedOut: false, + profilePicture: null +} + +export default function ProfilePage() { + return ( +
+
+ {/* Header */} +
+

My Profile

+

Manage your personal information and academic details

+
+ +
+ {/* Profile Overview */} +
+ + +
+
+
+ {mockStudent.firstName[0]}{mockStudent.lastName[0]} +
+ +
+

+ {mockStudent.firstName} {mockStudent.middleName} {mockStudent.lastName} +

+

{mockStudent.email}

+
+ + {mockStudent.verified ? ( + <> + + Verified + + ) : ( + <> + + Pending Verification + + )} + + {mockStudent.markedOut && ( + + Marked Out + + )} +
+
+ Roll Number: {mockStudent.rollNumber} +
+
+ + + + {/* Quick Stats */} +
+
+ Academic Year + {mockStudent.year} +
+
+ Branch + {mockStudent.branch} +
+
+ SSC Score + {mockStudent.ssc}/10 +
+
+ HSC Score + {mockStudent.hsc}/10 +
+
+ + + + {/* Social Links */} +
+

Social Links

+
+ + +
+
+
+
+
+ + {/* Main Content */} +
+ {/* Personal Information */} + + +
+ + + Personal Information + + +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +