🚀 UTAS Oman Portal Demo - Complete AI-Enhanced University Portal
✨ Features: • Real AI chatbot with OpenRouter API (bilingual Arabic/English) • Comprehensive UTAS Oman content with programs and admissions • Modern responsive design with Tailwind CSS • Student/Admin authentication and dashboards • Full course catalog with search and filtering • Contact forms and application processes 🤖 AI Capabilities: • Language detection (Arabic/English) • UTAS Oman knowledge base integration • Contextual responses about programs, admissions, scholarships • No mock data - all responses from real AI 🛠️ Technology Stack: • Next.js 14 + React 19 + TypeScript • OpenRouter API with Meta LLaMA 3.1 • Prisma ORM with SQLite • Tailwind CSS for styling 📋 Demo Ready: • Test users file included (TEST-USERS.md) • Navigation test checklist (NAVIGATION-TEST.md) • Clean codebase with proper gitignore • Production-ready configuration
This commit is contained in:
@@ -1,143 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { OpenAI } from 'openai'
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
})
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const formData = await request.formData()
|
||||
const file = formData.get('file') as File
|
||||
const url = formData.get('url') as string
|
||||
|
||||
if (!file && !url) {
|
||||
return NextResponse.json({ error: 'File or URL is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
let altText = ''
|
||||
let wcagScore = 0
|
||||
const issues: string[] = []
|
||||
const suggestions: string[] = []
|
||||
|
||||
if (file) {
|
||||
// Convert file to base64 for OpenAI Vision API
|
||||
const bytes = await file.arrayBuffer()
|
||||
const buffer = Buffer.from(bytes)
|
||||
const base64 = buffer.toString('base64')
|
||||
|
||||
// Generate alt text using OpenAI Vision
|
||||
const response = await openai.chat.completions.create({
|
||||
model: 'gpt-4o-mini',
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Generate concise, descriptive alt text for this image that would be useful for screen readers. Focus on the most important visual elements and context.',
|
||||
},
|
||||
{
|
||||
type: 'image_url',
|
||||
image_url: {
|
||||
url: `data:${file.type};base64,${base64}`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
max_tokens: 100,
|
||||
})
|
||||
|
||||
altText = response.choices[0]?.message?.content || 'Unable to generate alt text'
|
||||
}
|
||||
|
||||
// Simulate WCAG compliance checking
|
||||
if (!altText || altText.length < 10) {
|
||||
issues.push('Missing or inadequate alt text')
|
||||
suggestions.push('Add descriptive alt text for all images')
|
||||
wcagScore = 0.3
|
||||
} else if (altText.length > 125) {
|
||||
issues.push('Alt text is too long')
|
||||
suggestions.push('Keep alt text under 125 characters')
|
||||
wcagScore = 0.7
|
||||
} else {
|
||||
wcagScore = 0.95
|
||||
}
|
||||
|
||||
// Additional WCAG checks (simulated)
|
||||
if (url) {
|
||||
// Simulate checking color contrast, heading structure, etc.
|
||||
const randomFactor = Math.random()
|
||||
if (randomFactor < 0.3) {
|
||||
issues.push('Low color contrast detected')
|
||||
suggestions.push('Ensure color contrast ratio is at least 4.5:1')
|
||||
wcagScore = Math.min(wcagScore, 0.6)
|
||||
}
|
||||
if (randomFactor < 0.2) {
|
||||
issues.push('Missing heading structure')
|
||||
suggestions.push('Use proper heading hierarchy (h1, h2, h3, etc.)')
|
||||
wcagScore = Math.min(wcagScore, 0.5)
|
||||
}
|
||||
}
|
||||
|
||||
// Save audit to database
|
||||
const audit = await prisma.accessibilityAudit.create({
|
||||
data: {
|
||||
url: url || 'uploaded-image',
|
||||
imagePath: file ? file.name : null,
|
||||
altText,
|
||||
wcagScore,
|
||||
issues: JSON.stringify(issues),
|
||||
suggestions: JSON.stringify(suggestions),
|
||||
},
|
||||
})
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
audit: {
|
||||
id: audit.id,
|
||||
altText,
|
||||
wcagScore,
|
||||
issues,
|
||||
suggestions,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error in accessibility API:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to process accessibility audit' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const audits = await prisma.accessibilityAudit.findMany({
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
take: 50,
|
||||
})
|
||||
|
||||
const avgScore = audits.length > 0
|
||||
? audits.reduce((sum: number, audit: { wcagScore: number | null }) =>
|
||||
sum + (audit.wcagScore || 0), 0) / audits.length
|
||||
: 0
|
||||
|
||||
return NextResponse.json({
|
||||
audits,
|
||||
statistics: {
|
||||
totalAudits: audits.length,
|
||||
averageScore: Math.round(avgScore * 100) / 100,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error fetching accessibility audits:', error)
|
||||
return NextResponse.json({ error: 'Failed to fetch audits' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
+61
-100
@@ -1,109 +1,70 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import UTASChatBot from '@/lib/chatbot';
|
||||
|
||||
// Mock chat responses
|
||||
const mockResponses = [
|
||||
{
|
||||
trigger: ['library', 'hours', 'open'],
|
||||
response: {
|
||||
en: 'The library is open Monday-Friday 8:00 AM - 10:00 PM, Saturday 9:00 AM - 6:00 PM, and Sunday 12:00 PM - 8:00 PM. During exam periods, we have extended hours until midnight.',
|
||||
ar: 'المكتبة مفتوحة من الاثنين إلى الجمعة من 8:00 صباحاً حتى 10:00 مساءً، يوم السبت من 9:00 صباحاً حتى 6:00 مساءً، والأحد من 12:00 ظهراً حتى 8:00 مساءً. خلال فترات الامتحانات، لدينا ساعات ممتدة حتى منتصف الليل.'
|
||||
}
|
||||
},
|
||||
{
|
||||
trigger: ['password', 'change', 'reset'],
|
||||
response: {
|
||||
en: 'To change your password, go to Settings > Account > Change Password. You can also reset it using the "Forgot Password" link on the login page.',
|
||||
ar: 'لتغيير كلمة المرور الخاصة بك، اذهب إلى الإعدادات > الحساب > تغيير كلمة المرور. يمكنك أيضاً إعادة تعيينها باستخدام رابط "نسيت كلمة المرور" في صفحة تسجيل الدخول.'
|
||||
}
|
||||
},
|
||||
{
|
||||
trigger: ['registration', 'semester', 'enroll'],
|
||||
response: {
|
||||
en: 'Registration for the next semester opens on January 15th for continuing students and February 1st for new students. Please check your academic calendar for specific dates.',
|
||||
ar: 'التسجيل للفصل الدراسي القادم يفتح في 15 يناير للطلاب المستمرين و 1 فبراير للطلاب الجدد. يرجى مراجعة التقويم الأكاديمي للتواريخ المحددة.'
|
||||
}
|
||||
},
|
||||
{
|
||||
trigger: ['help', 'support', 'contact'],
|
||||
response: {
|
||||
en: 'For academic support, contact Student Services at support@university.edu or call (555) 123-4567. For technical issues, email IT help desk at it@university.edu.',
|
||||
ar: 'للدعم الأكاديمي، اتصل بخدمات الطلاب على support@university.edu أو اتصل بالرقم (555) 123-4567. للمشاكل التقنية، راسل مكتب المساعدة التقنية على it@university.edu.'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// Mental health keywords that trigger escalation
|
||||
const mentalHealthKeywords = [
|
||||
'depressed', 'depression', 'anxiety', 'anxious', 'stressed', 'stress',
|
||||
'overwhelmed', 'suicide', 'self-harm', 'hurt myself', 'kill myself',
|
||||
'hopeless', 'worthless', 'sad', 'crying', 'panic', 'fear',
|
||||
'مكتئب', 'اكتئاب', 'قلق', 'قلقان', 'متوتر', 'توتر',
|
||||
'مرهق', 'انتحار', 'إيذاء النفس', 'أؤذي نفسي', 'أقتل نفسي',
|
||||
'يائس', 'عديم القيمة', 'حزين', 'بكاء', 'هلع', 'خوف'
|
||||
];
|
||||
|
||||
function findBestResponse(message: string, language: string = 'en') {
|
||||
const lowerMessage = message.toLowerCase();
|
||||
|
||||
// Check for mental health keywords first
|
||||
const hasMentalHealthKeyword = mentalHealthKeywords.some(keyword =>
|
||||
lowerMessage.includes(keyword.toLowerCase())
|
||||
);
|
||||
|
||||
if (hasMentalHealthKeyword) {
|
||||
return {
|
||||
response: language === 'ar'
|
||||
? 'أفهم أنك تمر بوقت صعب. من المهم أن تطلب المساعدة من المختصين. يمكنك التواصل مع خدمة الاستشارة الجامعية على الرقم (555) 123-4567 أو زيارة مركز الصحة النفسية في الحرم الجامعي. في حالات الطوارئ، اتصل بالرقم 911 أو خط المساعدة الوطني للأزمات النفسية.'
|
||||
: 'I understand you\'re going through a difficult time. It\'s important to seek help from professionals. You can contact the university counseling service at (555) 123-4567 or visit the mental health center on campus. In emergencies, call 911 or the National Crisis Helpline.',
|
||||
escalate: true,
|
||||
category: 'mental_health'
|
||||
};
|
||||
}
|
||||
|
||||
// Look for FAQ matches
|
||||
for (const faq of mockResponses) {
|
||||
const hasMatch = faq.trigger.some(trigger =>
|
||||
lowerMessage.includes(trigger.toLowerCase())
|
||||
);
|
||||
|
||||
if (hasMatch) {
|
||||
return {
|
||||
response: faq.response[language as keyof typeof faq.response],
|
||||
escalate: false,
|
||||
category: 'faq'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Default response
|
||||
return {
|
||||
response: language === 'ar'
|
||||
? 'شكراً لك على سؤالك. يمكنني مساعدتك في العثور على المعلومات التي تحتاجها. جرب أن تسأل عن ساعات المكتبة، أو تغيير كلمة المرور، أو التسجيل للفصل الدراسي.'
|
||||
: 'Thank you for your question. I can help you find the information you need. Try asking about library hours, changing your password, or semester registration.',
|
||||
escalate: false,
|
||||
category: 'general'
|
||||
};
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { message, language = 'en' } = body;
|
||||
const {
|
||||
message,
|
||||
mode = 'general',
|
||||
history = [],
|
||||
conversationHistory = [],
|
||||
systemPrompt = null,
|
||||
language = 'en'
|
||||
} = await request.json();
|
||||
|
||||
if (!message) {
|
||||
return NextResponse.json({ error: 'Message is required' }, { status: 400 });
|
||||
if (!message || typeof message !== 'string') {
|
||||
return NextResponse.json({
|
||||
error: 'Message is required and must be a string'
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
const result = findBestResponse(message, language);
|
||||
// Initialize the chatbot with API key from environment
|
||||
const apiKey = process.env.OPENROUTER_API_KEY || '';
|
||||
const chatbot = new UTASChatBot(apiKey);
|
||||
|
||||
// Generate AI response using OpenRouter
|
||||
const response = await chatbot.generateResponse(message);
|
||||
|
||||
// Log the interaction for demo purposes
|
||||
console.log('UTAS Chat:', {
|
||||
timestamp: new Date().toISOString(),
|
||||
message: message.substring(0, 100),
|
||||
response: response.substring(0, 100)
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
message: response,
|
||||
response: response, // for backward compatibility
|
||||
timestamp: new Date().toISOString(),
|
||||
source: 'UTAS AI Assistant'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Chat API Error:', error);
|
||||
|
||||
return NextResponse.json({
|
||||
response: result.response,
|
||||
escalate: result.escalate,
|
||||
category: result.category,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error processing chat:', error);
|
||||
return NextResponse.json({ error: 'Failed to process message' }, { status: 500 });
|
||||
message: "I apologize, but I'm experiencing technical difficulties. Please try again or contact UTAS directly at +61 3 6226 6200 or info@utas.edu.au for immediate assistance.",
|
||||
timestamp: new Date().toISOString(),
|
||||
source: 'UTAS AI Assistant',
|
||||
error: true
|
||||
}, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({
|
||||
service: 'UTAS AI Chat Assistant',
|
||||
status: 'active',
|
||||
features: [
|
||||
'RAG-powered responses using UTAS knowledge base',
|
||||
'OpenRouter AI integration (when API key provided)',
|
||||
'Real-time course and program information',
|
||||
'Application guidance and support',
|
||||
'Campus and research information'
|
||||
],
|
||||
endpoints: {
|
||||
POST: 'Send message and conversation history',
|
||||
GET: 'Service status and information'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { OpenAI } from 'openai'
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
})
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
type Message = {
|
||||
sender: 'user' | 'bot'
|
||||
text: string
|
||||
timestamp: Date
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { message, mode = 'general', history = [] } = await request.json()
|
||||
|
||||
// Get FAQs from database
|
||||
const faqs = await prisma.fAQ.findMany({
|
||||
where: {
|
||||
language: 'en', // For demo, we'll use English FAQs
|
||||
},
|
||||
orderBy: {
|
||||
priority: 'asc',
|
||||
},
|
||||
})
|
||||
|
||||
// Create context from FAQs
|
||||
const faqContext = faqs.map((faq: { question: string; answer: string }) =>
|
||||
`Q: ${faq.question}\nA: ${faq.answer}`
|
||||
).join('\n\n')
|
||||
|
||||
// Check for mental health indicators if in mental health mode
|
||||
let shouldEscalate = false
|
||||
if (mode === 'mental_health') {
|
||||
// Simple trigger phrase detection
|
||||
const triggerPhrases = [
|
||||
'anxious', 'anxiety', 'depressed', 'depression', 'stressed', 'stress',
|
||||
'overwhelmed', 'panic', 'worried', 'fear', 'scared', 'sad', 'hopeless',
|
||||
'suicide', 'self-harm', 'hurt myself', 'end it all', 'giving up'
|
||||
]
|
||||
|
||||
const lowerMessage = message.toLowerCase()
|
||||
shouldEscalate = triggerPhrases.some(phrase => lowerMessage.includes(phrase))
|
||||
}
|
||||
|
||||
// Prepare system message based on mode
|
||||
let systemMessage = ''
|
||||
if (mode === 'mental_health') {
|
||||
systemMessage = `You are a compassionate mental health support assistant for a university.
|
||||
Provide empathetic, supportive responses. If the user mentions serious mental health concerns,
|
||||
gently encourage them to speak with a professional counselor. Keep responses warm and understanding.`
|
||||
} else {
|
||||
systemMessage = `You are a helpful university assistant. Answer questions based on the following FAQ database:
|
||||
|
||||
${faqContext}
|
||||
|
||||
If you cannot find the answer in the FAQs, provide a helpful general response and suggest contacting
|
||||
the appropriate university department. Keep responses concise and helpful.`
|
||||
}
|
||||
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: 'gpt-4o-mini',
|
||||
messages: [
|
||||
{ role: 'system', content: systemMessage },
|
||||
...history.map((msg: Message) => ({
|
||||
role: msg.sender === 'user' ? 'user' as const : 'assistant' as const,
|
||||
content: msg.text,
|
||||
})),
|
||||
{ role: 'user', content: message },
|
||||
],
|
||||
max_tokens: 500,
|
||||
temperature: 0.7,
|
||||
})
|
||||
|
||||
const response = completion.choices[0]?.message?.content || 'I apologize, but I cannot provide a response at this time.'
|
||||
|
||||
// Log the chat session
|
||||
await prisma.chatSession.create({
|
||||
data: {
|
||||
type: mode === 'mental_health' ? 'MENTAL_HEALTH' : 'GENERAL',
|
||||
messages: JSON.stringify([
|
||||
...history,
|
||||
{ sender: 'user', text: message, timestamp: new Date() },
|
||||
{ sender: 'bot', text: response, timestamp: new Date() },
|
||||
]),
|
||||
},
|
||||
})
|
||||
|
||||
return NextResponse.json({
|
||||
response,
|
||||
shouldEscalate,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error in chat API:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to process chat message' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
+17
-24
@@ -1,17 +1,9 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import UTASChatBot from '@/lib/chatbot';
|
||||
|
||||
// Initialize the chatbot (will use OpenRouter if API key is available)
|
||||
const chatbot = new UTASChatBot();
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const {
|
||||
message,
|
||||
conversationHistory = [],
|
||||
systemPrompt = null,
|
||||
language = 'en'
|
||||
} = await request.json();
|
||||
const { message } = await request.json();
|
||||
|
||||
if (!message || typeof message !== 'string') {
|
||||
return NextResponse.json({
|
||||
@@ -19,13 +11,12 @@ export async function POST(request: NextRequest) {
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
// Generate AI response using RAG and potentially OpenRouter with role-based context
|
||||
const response = await chatbot.generateResponse(
|
||||
message,
|
||||
conversationHistory,
|
||||
systemPrompt,
|
||||
language
|
||||
);
|
||||
// Initialize the chatbot with API key from environment
|
||||
const apiKey = process.env.OPENROUTER_API_KEY || '';
|
||||
const chatbot = new UTASChatBot(apiKey);
|
||||
|
||||
// Generate AI response using OpenRouter
|
||||
const response = await chatbot.generateResponse(message);
|
||||
|
||||
// Log the interaction for demo purposes
|
||||
console.log('UTAS Chat:', {
|
||||
@@ -34,19 +25,22 @@ export async function POST(request: NextRequest) {
|
||||
response: response.substring(0, 100)
|
||||
});
|
||||
|
||||
// Return both message and response for backward compatibility
|
||||
return NextResponse.json({
|
||||
message: response,
|
||||
response: response,
|
||||
timestamp: new Date().toISOString(),
|
||||
source: 'UTAS AI Assistant'
|
||||
source: 'UTAS Oman AI Assistant'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Chat API Error:', error);
|
||||
|
||||
return NextResponse.json({
|
||||
message: "I apologize, but I'm experiencing technical difficulties. Please try again or contact UTAS directly at +61 3 6226 6200 or info@utas.edu.au for immediate assistance.",
|
||||
message: "I apologize, but I'm experiencing technical difficulties. Please try again or contact UTAS Oman directly at +968 2414 3555 or admissions@utas.edu.om for immediate assistance.",
|
||||
response: "I apologize, but I'm experiencing technical difficulties. Please try again or contact UTAS Oman directly at +968 2414 3555 or admissions@utas.edu.om for immediate assistance.",
|
||||
timestamp: new Date().toISOString(),
|
||||
source: 'UTAS AI Assistant',
|
||||
source: 'UTAS Oman AI Assistant',
|
||||
error: true
|
||||
}, { status: 500 });
|
||||
}
|
||||
@@ -54,17 +48,16 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({
|
||||
service: 'UTAS AI Chat Assistant',
|
||||
service: 'UTAS Oman AI Chat Assistant',
|
||||
status: 'active',
|
||||
features: [
|
||||
'RAG-powered responses using UTAS knowledge base',
|
||||
'OpenRouter AI integration (when API key provided)',
|
||||
'OpenRouter AI integration with multilingual support',
|
||||
'Real-time course and program information',
|
||||
'Application guidance and support',
|
||||
'Campus and research information'
|
||||
'UTAS Oman specific information'
|
||||
],
|
||||
endpoints: {
|
||||
POST: 'Send message and conversation history',
|
||||
POST: 'Send message for AI response',
|
||||
GET: 'Service status and information'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { rating, type, feedback, sessionId, userId } = await request.json()
|
||||
|
||||
const survey = await prisma.survey.create({
|
||||
data: {
|
||||
rating,
|
||||
type,
|
||||
feedback,
|
||||
sessionId,
|
||||
userId,
|
||||
},
|
||||
})
|
||||
|
||||
return NextResponse.json({ success: true, survey })
|
||||
} catch (error) {
|
||||
console.error('Error creating survey:', error)
|
||||
return NextResponse.json({ error: 'Failed to submit survey' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const surveys = await prisma.survey.findMany({
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
take: 100,
|
||||
})
|
||||
|
||||
// Calculate statistics
|
||||
const totalSurveys = surveys.length
|
||||
const averageRating = totalSurveys > 0
|
||||
? surveys.reduce((sum: number, survey: { rating: number }) => sum + survey.rating, 0) / totalSurveys
|
||||
: 0
|
||||
const ratingDistribution = surveys.reduce((acc: Record<number, number>, survey: { rating: number }) => {
|
||||
acc[survey.rating] = (acc[survey.rating] || 0) + 1
|
||||
return acc
|
||||
}, {} as Record<number, number>)
|
||||
|
||||
return NextResponse.json({
|
||||
surveys,
|
||||
statistics: {
|
||||
totalSurveys,
|
||||
averageRating: Math.round(averageRating * 10) / 10,
|
||||
ratingDistribution,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error fetching surveys:', error)
|
||||
return NextResponse.json({ error: 'Failed to fetch surveys' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const email = searchParams.get('email')
|
||||
|
||||
if (!email) {
|
||||
return NextResponse.json({ error: 'Email is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { email },
|
||||
include: {
|
||||
enrollments: {
|
||||
include: {
|
||||
course: true,
|
||||
},
|
||||
},
|
||||
advisor: true,
|
||||
},
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
return NextResponse.json(user)
|
||||
} catch (error) {
|
||||
console.error('Error fetching user profile:', error)
|
||||
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user