Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions frontend/app/api/auth/dashboard/activities/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { getCurrentUser } from "@/lib/auth"
import prisma from "@/lib/prisma"
import { NextResponse } from "next/server"

export async function GET(request: Request) {
try {
const user = await getCurrentUser()

if (!user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 403 })
}

if (user.role === "APPLICANT") {
// Fetch recent applications (last 5)
const recentApplications = await prisma.internshipApplication.findMany({
where: { applicantId: user.id },
include: { internship: true },
orderBy: { createdAt: "desc" },
take: 5,
})

const activities = recentApplications.map((app) => ({
icon: getStatusIcon(app.status),
title: `Application ${getStatusText(app.status)}`,
description: app.internship.title,
date: new Date(app.createdAt).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
}),
}))

return NextResponse.json({ activities })
}

return NextResponse.json({ activities: [] })
} catch (error) {
console.error("[v0] Activities error:", error)
return NextResponse.json({ error: "Failed to fetch activities" }, { status: 500 })
}
}

function getStatusIcon(status: string): string {
switch (status) {
case "ACCEPTED":
return "✅"
case "REJECTED":
return "❌"
case "PENDING":
return "⏳"
case "REVIEWED":
return "👀"
default:
return "📝"
}
}

function getStatusText(status: string): string {
switch (status) {
case "ACCEPTED":
return "Accepted"
case "REJECTED":
return "Rejected"
case "PENDING":
return "Submitted"
case "REVIEWED":
return "Under Review"
default:
return "Created"
}
}
81 changes: 81 additions & 0 deletions frontend/app/api/auth/dashboard/activity-chart/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { getCurrentUser } from "@/lib/auth"
import prisma from "@/lib/prisma"
import { NextResponse } from "next/server"

export async function GET() {
try {
const user = await getCurrentUser()

if (!user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 403 })
}

if (user.role === "APPLICANT") {
// Get applications from the last 6 months
const sixMonthsAgo = new Date()
sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6)

const applications = await prisma.internshipApplication.findMany({
where: {
applicantId: user.id,
createdAt: {
gte: sixMonthsAgo,
},
},
select: {
createdAt: true,
},
orderBy: {
createdAt: "asc",
},
})

// Group by month
const monthlyData = new Map<string, number>()
const months = []

// Initialize last 6 months
for (let i = 5; i >= 0; i--) {
const date = new Date()
date.setMonth(date.getMonth() - i)
const monthKey = date.toLocaleDateString("en-US", { month: "short" })
months.push(monthKey)
monthlyData.set(monthKey, 0)
}

// Count applications per month
applications.forEach((app) => {
const monthKey = app.createdAt.toLocaleDateString("en-US", { month: "short" })
if (monthlyData.has(monthKey)) {
monthlyData.set(monthKey, (monthlyData.get(monthKey) || 0) + 1)
}
})

// Format for chart
const chartData = months.map((month) => ({
month,
applications: monthlyData.get(month) || 0,
}))

return NextResponse.json({ chartData })
}

const months = []
for (let i = 5; i >= 0; i--) {
const date = new Date()
date.setMonth(date.getMonth() - i)
const monthKey = date.toLocaleDateString("en-US", { month: "short" })
months.push(monthKey)
}

const chartData = months.map((month) => ({
month,
applications: 0,
}))

return NextResponse.json({ chartData })
} catch (error) {
console.error("[v0] Activity chart error:", error)
return NextResponse.json({ error: "Failed to fetch activity data" }, { status: 500 })
}
}
45 changes: 45 additions & 0 deletions frontend/app/api/auth/dashboard/recruiter-activities/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { getCurrentUser } from "@/lib/auth"
import { NextResponse } from "next/server"

export async function GET() {
try {
const user = await getCurrentUser()

if (!user || user.role !== "RECRUITER") {
return NextResponse.json({ error: "Unauthorized" }, { status: 403 })
}

// Mock recent activities for recruiters
const activities = [
{
icon: "✅",
title: "Candidate Hired",
description: "John Smith accepted offer for Frontend Developer position",
date: "2 hours ago",
},
{
icon: "📝",
title: "New Application",
description: "Sarah Johnson applied for Backend Engineer Intern",
date: "5 hours ago",
},
{
icon: "📅",
title: "Interview Scheduled",
description: "Interview with Michael Chen for UI/UX Design Intern",
date: "1 day ago",
},
{
icon: "📢",
title: "Listing Published",
description: "Full Stack Developer Intern position is now live",
date: "2 days ago",
},
]

return NextResponse.json({ activities })
} catch (error) {
console.error("[v0] Recruiter activities error:", error)
return NextResponse.json({ error: "Failed to fetch activities" }, { status: 500 })
}
}
28 changes: 28 additions & 0 deletions frontend/app/api/auth/dashboard/recruiter-activity-chart/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { getCurrentUser } from "@/lib/auth"
import { NextResponse } from "next/server"

export async function GET() {
try {
const user = await getCurrentUser()

if (!user || user.role !== "RECRUITER") {
return NextResponse.json({ error: "Unauthorized" }, { status: 403 })
}

// Mock data for recruiter activity chart
// In production, this would aggregate data from internship applications
const chartData = [
{ month: "Jul", applications: 45, hires: 2 },
{ month: "Aug", applications: 62, hires: 3 },
{ month: "Sep", applications: 78, hires: 5 },
{ month: "Oct", applications: 91, hires: 4 },
{ month: "Nov", applications: 103, hires: 6 },
{ month: "Dec", applications: 87, hires: 3 },
]

return NextResponse.json(chartData)
} catch (error) {
console.error("[v0] Recruiter activity chart error:", error)
return NextResponse.json({ error: "Failed to fetch chart data" }, { status: 500 })
}
}
33 changes: 33 additions & 0 deletions frontend/app/api/auth/dashboard/recruiter-stats/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { getCurrentUser } from "@/lib/auth"
import { NextResponse } from "next/server"

export async function GET() {
try {
const user = await getCurrentUser()

if (!user || user.role !== "RECRUITER") {
return NextResponse.json({ error: "Unauthorized" }, { status: 403 })
}

// Mock data for recruiter stats
// In production, these would query actual internship and application tables
const activeListings = 12
const totalApplicants = 247
const hiredCandidates = 8
const shortlistedCandidates = 23
const pendingReviews = 45
const upcomingInterviews = 15

return NextResponse.json({
activeListings,
totalApplicants,
hiredCandidates,
shortlistedCandidates,
pendingReviews,
upcomingInterviews,
})
} catch (error) {
console.error("[v0] Recruiter stats error:", error)
return NextResponse.json({ error: "Failed to fetch stats" }, { status: 500 })
}
}
74 changes: 74 additions & 0 deletions frontend/app/api/auth/dashboard/stats/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { getCurrentUser } from "@/lib/auth"
import prisma from "@/lib/prisma"
import { NextResponse } from "next/server"

export async function GET() {
try {
const user = await getCurrentUser()

if (!user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 403 })
}

if (user.role === "APPLICANT") {
// Total applications submitted
const totalApplications = await prisma.internshipApplication.count({
where: { applicantId: user.id },
})

// Applications by status
const applicationsByStatus = await prisma.internshipApplication.groupBy({
by: ["status"],
where: { applicantId: user.id },
_count: true,
})

const acceptedCount = applicationsByStatus.find((a) => a.status === "ACCEPTED")?._count || 0
const pendingCount = applicationsByStatus.find((a) => a.status === "PENDING")?._count || 0
const reviewedCount = applicationsByStatus.find((a) => a.status === "REVIEWED")?._count || 0

// Get last application created date
const lastApplication = await prisma.internshipApplication.findFirst({
where: { applicantId: user.id },
orderBy: { createdAt: "desc" },
select: { createdAt: true },
})

// Get applicant details
const applicant = await prisma.applicant.findUnique({
where: { userId: user.id },
select: {
linkedInLink: true,
portfolioLink: true,
githubLink: true,
},
})

const savedInternships = applicant?.linkedInLink ? 1 : 0
const upcomingInterviews = 0

return NextResponse.json({
totalApplications,
acceptedApplications: acceptedCount,
reviewedApplications: reviewedCount,
pendingApplications: pendingCount,
savedInternships,
upcomingInterviews,
lastActivityDate: lastApplication?.createdAt || user.emailVerified || new Date(),
})
}

return NextResponse.json({
totalApplications: 0,
acceptedApplications: 0,
reviewedApplications: 0,
pendingApplications: 0,
savedInternships: 0,
upcomingInterviews: 0,
lastActivityDate: new Date(),
})
} catch (error) {
console.error("[v0] Dashboard stats error:", error)
return NextResponse.json({ error: "Failed to fetch stats" }, { status: 500 })
}
}
Loading