This commit is contained in:
Krikorios
2025-07-12 22:36:47 +04:00
parent 7fbf089ec5
commit f83b27db61
73 changed files with 19053 additions and 189 deletions
+392
View File
@@ -0,0 +1,392 @@
'use client';
import React, { useState, useEffect } from 'react'
import { useAuth } from '@/components/providers/MockAuthProvider'
import { useLanguage } from '@/components/providers/LanguageProvider'
import { useRouter } from 'next/navigation'
import {
Upload,
Image as ImageIcon,
CheckCircle,
XCircle,
AlertCircle,
Eye,
LogOut,
Languages,
ArrowLeft
} from 'lucide-react'
import Link from 'next/link'
interface AccessibilityAudit {
id: string
altText: string
wcagScore: number
issues: string[]
suggestions: string[]
}
export default function AccessibilityPage() {
const { user, userProfile, logout } = useAuth()
const { t, language, setLanguage } = useLanguage()
const router = useRouter()
const [selectedFile, setSelectedFile] = useState<File | null>(null)
const [preview, setPreview] = useState<string | null>(null)
const [audit, setAudit] = useState<AccessibilityAudit | null>(null)
const [isAnalyzing, setIsAnalyzing] = useState(false)
const [recentAudits, setRecentAudits] = useState<AccessibilityAudit[]>([])
useEffect(() => {
if (!user) {
router.push('/')
}
}, [user, router])
useEffect(() => {
fetchRecentAudits()
}, [])
const fetchRecentAudits = async () => {
try {
const response = await fetch('/api/accessibility')
if (response.ok) {
const data = await response.json()
setRecentAudits(data.audits || [])
}
} catch (error) {
console.error('Error fetching audits:', error)
}
}
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]
if (file) {
setSelectedFile(file)
// Create preview
const reader = new FileReader()
reader.onload = (e) => {
setPreview(e.target?.result as string)
}
reader.readAsDataURL(file)
}
}
const handleAnalyze = async () => {
if (!selectedFile) return
setIsAnalyzing(true)
try {
const formData = new FormData()
formData.append('file', selectedFile)
const response = await fetch('/api/accessibility', {
method: 'POST',
body: formData,
})
if (response.ok) {
const data = await response.json()
setAudit(data.audit)
fetchRecentAudits()
} else {
console.error('Failed to analyze image')
}
} catch (error) {
console.error('Error analyzing image:', error)
} finally {
setIsAnalyzing(false)
}
}
const handleLogout = async () => {
await logout()
}
const toggleLanguage = () => {
setLanguage(language === 'en' ? 'ar' : 'en')
}
const getScoreColor = (score: number) => {
if (score >= 0.9) return 'text-green-600'
if (score >= 0.7) return 'text-yellow-600'
return 'text-red-600'
}
const getScoreBackground = (score: number) => {
if (score >= 0.9) return 'bg-green-50 border-green-200'
if (score >= 0.7) return 'bg-yellow-50 border-yellow-200'
return 'bg-red-50 border-red-200'
}
if (!user || !userProfile) {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
<p className="text-gray-600">Loading accessibility tools...</p>
</div>
</div>
)
}
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
<header className="bg-white shadow-sm border-b">
<div className="container mx-auto px-4 py-4">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
<Link href="/dashboard" className="flex items-center space-x-2 text-blue-600 hover:text-blue-800">
<ArrowLeft size={20} />
<span>Back to Dashboard</span>
</Link>
<div className="text-gray-300">|</div>
<h1 className="text-xl font-bold text-gray-900">
{t('accessibility')} Tools
</h1>
</div>
<div className="flex items-center space-x-4">
<button
onClick={toggleLanguage}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors"
>
<Languages size={16} />
<span className="text-sm font-medium">{language.toUpperCase()}</span>
</button>
<div className="flex items-center space-x-3">
<div className="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center">
<span className="text-white text-sm font-medium">
{userProfile.name.charAt(0)}
</span>
</div>
<div className="hidden md:block">
<p className="text-sm font-medium text-gray-900">{userProfile.name}</p>
<p className="text-xs text-gray-500">{userProfile.role}</p>
</div>
</div>
<button
onClick={handleLogout}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-red-100 hover:bg-red-200 transition-colors text-red-700"
>
<LogOut size={16} />
<span className="text-sm font-medium">{t('logout')}</span>
</button>
</div>
</div>
</div>
</header>
{/* Main Content */}
<main className="container mx-auto px-4 py-8">
<div className="max-w-4xl mx-auto">
{/* Upload Section */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
Image Accessibility Analyzer
</h2>
<p className="text-gray-600 mb-6">
Upload an image to automatically generate alt text and check WCAG 2.2 compliance.
Our AI-powered tool helps ensure your content is accessible to everyone.
</p>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{/* Upload Area */}
<div>
<div className="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center">
<input
type="file"
accept="image/*"
onChange={handleFileSelect}
className="hidden"
id="image-upload"
/>
<label
htmlFor="image-upload"
className="cursor-pointer flex flex-col items-center"
>
<Upload size={48} className="text-gray-400 mb-4" />
<p className="text-lg font-medium text-gray-900 mb-2">
{t('upload_image')}
</p>
<p className="text-sm text-gray-600">
PNG, JPG, GIF up to 10MB
</p>
</label>
</div>
{selectedFile && (
<div className="mt-4">
<p className="text-sm text-gray-600 mb-2">
Selected: {selectedFile.name}
</p>
<button
onClick={handleAnalyze}
disabled={isAnalyzing}
className="w-full bg-blue-600 text-white py-3 px-4 rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{isAnalyzing ? 'Analyzing...' : 'Analyze Image'}
</button>
</div>
)}
</div>
{/* Preview */}
{preview && (
<div>
<h3 className="text-lg font-semibold text-gray-900 mb-4">
Image Preview
</h3>
<div className="bg-gray-100 rounded-lg p-4">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={preview}
alt="Preview"
className="max-w-full h-auto rounded-lg"
/>
</div>
</div>
)}
</div>
</div>
{/* Analysis Results */}
{audit && (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
Analysis Results
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Alt Text */}
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
<h3 className="text-lg font-semibold text-blue-900 mb-2">
{t('alt_text_suggestion')}
</h3>
<p className="text-blue-800">{audit.altText}</p>
</div>
{/* WCAG Score */}
<div className={`border rounded-lg p-4 ${getScoreBackground(audit.wcagScore)}`}>
<h3 className="text-lg font-semibold mb-2">
{t('wcag_score')}
</h3>
<div className="flex items-center space-x-2">
<span className={`text-2xl font-bold ${getScoreColor(audit.wcagScore)}`}>
{Math.round(audit.wcagScore * 100)}%
</span>
{audit.wcagScore >= 0.9 ? (
<CheckCircle className="text-green-600" size={24} />
) : audit.wcagScore >= 0.7 ? (
<AlertCircle className="text-yellow-600" size={24} />
) : (
<XCircle className="text-red-600" size={24} />
)}
</div>
</div>
</div>
{/* Issues and Suggestions */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
{audit.issues.length > 0 && (
<div>
<h3 className="text-lg font-semibold text-gray-900 mb-3">
Issues Found
</h3>
<ul className="space-y-2">
{audit.issues.map((issue, index) => (
<li key={index} className="flex items-start space-x-2">
<XCircle className="text-red-500 mt-0.5" size={16} />
<span className="text-sm text-gray-700">{issue}</span>
</li>
))}
</ul>
</div>
)}
{audit.suggestions.length > 0 && (
<div>
<h3 className="text-lg font-semibold text-gray-900 mb-3">
Suggestions
</h3>
<ul className="space-y-2">
{audit.suggestions.map((suggestion, index) => (
<li key={index} className="flex items-start space-x-2">
<CheckCircle className="text-green-500 mt-0.5" size={16} />
<span className="text-sm text-gray-700">{suggestion}</span>
</li>
))}
</ul>
</div>
)}
</div>
</div>
)}
{/* Recent Audits */}
{recentAudits.length > 0 && (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
Recent Audits
</h2>
<div className="space-y-4">
{recentAudits.slice(0, 5).map((recentAudit, index) => (
<div key={index} className="flex items-center justify-between p-4 bg-gray-50 rounded-lg">
<div className="flex items-center space-x-3">
<ImageIcon className="text-gray-400" size={20} />
<div>
<p className="font-medium text-gray-900">
{recentAudit.altText.substring(0, 50)}...
</p>
<p className="text-sm text-gray-600">
Score: {Math.round(recentAudit.wcagScore * 100)}%
</p>
</div>
</div>
<div className="flex items-center space-x-2">
<Eye className="text-gray-400" size={16} />
<span className="text-sm text-gray-600">View Details</span>
</div>
</div>
))}
</div>
</div>
)}
{/* Guidelines */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mt-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
Accessibility Guidelines
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 className="text-lg font-semibold text-gray-900 mb-3">
Alt Text Best Practices
</h3>
<ul className="space-y-2 text-sm text-gray-700">
<li> Be concise but descriptive</li>
<li> Focus on important details</li>
<li> Avoid redundant phrases like &quot;image of&quot;</li>
<li> Keep under 125 characters when possible</li>
</ul>
</div>
<div>
<h3 className="text-lg font-semibold text-gray-900 mb-3">
WCAG 2.2 Compliance
</h3>
<ul className="space-y-2 text-sm text-gray-700">
<li> Color contrast ratio of 4.5:1 minimum</li>
<li> Keyboard navigation support</li>
<li> Screen reader compatibility</li>
<li> Clear focus indicators</li>
</ul>
</div>
</div>
</div>
</div>
</main>
</div>
)
}
+430
View File
@@ -0,0 +1,430 @@
'use client';
import React, { useState, useEffect } from 'react'
import { useAuth } from '@/components/providers/MockAuthProvider'
import { useLanguage } from '@/components/providers/LanguageProvider'
import { useRouter } from 'next/navigation'
import {
BarChart3,
Users,
MessageSquare,
Star,
TrendingUp,
Clock,
Shield,
Heart,
LogOut,
Languages,
ArrowLeft,
Eye,
CheckCircle,
AlertTriangle
} from 'lucide-react'
import Link from 'next/link'
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, BarChart, Bar } from 'recharts'
interface SurveyStats {
totalSurveys: number
averageRating: number
ratingDistribution: Record<number, number>
}
export default function AdminPage() {
const { user, userProfile, logout } = useAuth()
const { t, language, setLanguage } = useLanguage()
const router = useRouter()
const [surveyStats, setSurveyStats] = useState<SurveyStats | null>(null)
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
if (!user) {
router.push('/')
return
}
if (userProfile && userProfile.role !== 'ADMIN') {
router.push('/dashboard')
return
}
fetchDashboardData()
}, [user, userProfile, router])
const fetchDashboardData = async () => {
try {
const response = await fetch('/api/survey')
if (response.ok) {
const data = await response.json()
setSurveyStats(data.statistics)
}
} catch (error) {
console.error('Error fetching dashboard data:', error)
} finally {
setIsLoading(false)
}
}
const handleLogout = async () => {
await logout()
}
const toggleLanguage = () => {
setLanguage(language === 'en' ? 'ar' : 'en')
}
// Mock data for charts
const responseTimeData = [
{ name: 'Mon', time: 1.2 },
{ name: 'Tue', time: 0.8 },
{ name: 'Wed', time: 1.5 },
{ name: 'Thu', time: 1.1 },
{ name: 'Fri', time: 0.9 },
{ name: 'Sat', time: 1.3 },
{ name: 'Sun', time: 1.0 },
]
const satisfactionData = [
{ name: 'Week 1', satisfaction: 92 },
{ name: 'Week 2', satisfaction: 88 },
{ name: 'Week 3', satisfaction: 95 },
{ name: 'Week 4', satisfaction: 91 },
]
const ratingData = surveyStats ?
Object.entries(surveyStats.ratingDistribution).map(([rating, count]) => ({
rating: `${rating} Stars`,
count
})) : []
if (!user || !userProfile || isLoading) {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
<p className="text-gray-600">Loading admin dashboard...</p>
</div>
</div>
)
}
if (userProfile.role !== 'ADMIN') {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<AlertTriangle className="mx-auto h-12 w-12 text-red-500 mb-4" />
<h1 className="text-xl font-bold text-gray-900 mb-2">Access Denied</h1>
<p className="text-gray-600">You don&apos;t have permission to access this page.</p>
<Link href="/dashboard" className="mt-4 inline-block bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700">
Go to Dashboard
</Link>
</div>
</div>
)
}
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
<header className="bg-white shadow-sm border-b">
<div className="container mx-auto px-4 py-4">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
<Link href="/dashboard" className="flex items-center space-x-2 text-blue-600 hover:text-blue-800">
<ArrowLeft size={20} />
<span>Back to Dashboard</span>
</Link>
<div className="text-gray-300">|</div>
<div className="flex items-center space-x-2">
<BarChart3 className="text-blue-600" size={24} />
<h1 className="text-xl font-bold text-gray-900">
Admin Dashboard
</h1>
</div>
</div>
<div className="flex items-center space-x-4">
<button
onClick={toggleLanguage}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors"
>
<Languages size={16} />
<span className="text-sm font-medium">{language.toUpperCase()}</span>
</button>
<div className="flex items-center space-x-3">
<div className="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center">
<span className="text-white text-sm font-medium">
{userProfile.name.charAt(0)}
</span>
</div>
<div className="hidden md:block">
<p className="text-sm font-medium text-gray-900">{userProfile.name}</p>
<p className="text-xs text-gray-500">{userProfile.role}</p>
</div>
</div>
<button
onClick={handleLogout}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-red-100 hover:bg-red-200 transition-colors text-red-700"
>
<LogOut size={16} />
<span className="text-sm font-medium">{t('logout')}</span>
</button>
</div>
</div>
</div>
</header>
{/* Main Content */}
<main className="container mx-auto px-4 py-8">
{/* KPI Cards */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<KPICard
title="Active Users"
value="12,543"
change="+5.2%"
trend="up"
icon={<Users size={24} />}
color="blue"
/>
<KPICard
title="Avg Response Time"
value="1.2s"
change="-0.3s"
trend="down"
icon={<Clock size={24} />}
color="green"
/>
<KPICard
title="Satisfaction Rate"
value={surveyStats ? `${Math.round(surveyStats.averageRating * 20)}%` : '94%'}
change="+2.1%"
trend="up"
icon={<Star size={24} />}
color="yellow"
/>
<KPICard
title="Ticket Deflection"
value="87%"
change="+4.3%"
trend="up"
icon={<MessageSquare size={24} />}
color="purple"
/>
</div>
{/* Charts Section */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
{/* Response Time Chart */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
Average Response Time (This Week)
</h3>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={responseTimeData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Line type="monotone" dataKey="time" stroke="#3B82F6" strokeWidth={2} />
</LineChart>
</ResponsiveContainer>
</div>
{/* Satisfaction Trend */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
User Satisfaction Trend
</h3>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={satisfactionData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Line type="monotone" dataKey="satisfaction" stroke="#10B981" strokeWidth={2} />
</LineChart>
</ResponsiveContainer>
</div>
</div>
{/* Rating Distribution */}
{surveyStats && ratingData.length > 0 && (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-8">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
Rating Distribution ({surveyStats.totalSurveys} responses)
</h3>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={ratingData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="rating" />
<YAxis />
<Tooltip />
<Bar dataKey="count" fill="#F59E0B" />
</BarChart>
</ResponsiveContainer>
</div>
)}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{/* System Health */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
System Health
</h3>
<div className="space-y-4">
<HealthIndicator
label="Chat Service"
status="healthy"
value="99.8% uptime"
/>
<HealthIndicator
label="Database"
status="healthy"
value="Response time: 12ms"
/>
<HealthIndicator
label="AI Assistant"
status="healthy"
value="Processing normally"
/>
<HealthIndicator
label="Accessibility Scanner"
status="warning"
value="High load detected"
/>
</div>
</div>
{/* Recent Activity */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
Recent Activity
</h3>
<div className="space-y-4">
<ActivityItem
icon={<MessageSquare size={16} />}
title="New chat session started"
time="2 minutes ago"
type="chat"
/>
<ActivityItem
icon={<Star size={16} />}
title="Survey response: 5 stars"
time="5 minutes ago"
type="survey"
/>
<ActivityItem
icon={<Shield size={16} />}
title="Accessibility scan completed"
time="12 minutes ago"
type="accessibility"
/>
<ActivityItem
icon={<Heart size={16} />}
title="Mental health escalation"
time="25 minutes ago"
type="mental-health"
/>
<ActivityItem
icon={<Users size={16} />}
title="New user registration"
time="1 hour ago"
type="user"
/>
</div>
</div>
</div>
</main>
</div>
)
}
// Helper Components
const KPICard: React.FC<{
title: string
value: string
change: string
trend: 'up' | 'down'
icon: React.ReactNode
color: 'blue' | 'green' | 'yellow' | 'purple'
}> = ({ title, value, change, trend, icon, color }) => {
const colorClasses = {
blue: 'bg-blue-50 border-blue-200 text-blue-600',
green: 'bg-green-50 border-green-200 text-green-600',
yellow: 'bg-yellow-50 border-yellow-200 text-yellow-600',
purple: 'bg-purple-50 border-purple-200 text-purple-600',
}
return (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<div className="flex items-center justify-between mb-4">
<div className={`p-3 rounded-lg ${colorClasses[color]}`}>
{icon}
</div>
<div className={`flex items-center space-x-1 text-sm ${
trend === 'up' ? 'text-green-600' : 'text-red-600'
}`}>
<TrendingUp size={16} className={trend === 'down' ? 'rotate-180' : ''} />
<span>{change}</span>
</div>
</div>
<div>
<p className="text-2xl font-bold text-gray-900">{value}</p>
<p className="text-sm text-gray-600">{title}</p>
</div>
</div>
)
}
const HealthIndicator: React.FC<{
label: string
status: 'healthy' | 'warning' | 'error'
value: string
}> = ({ label, status, value }) => {
const statusColors = {
healthy: 'text-green-600 bg-green-50',
warning: 'text-yellow-600 bg-yellow-50',
error: 'text-red-600 bg-red-50',
}
const StatusIcon = status === 'healthy' ? CheckCircle : AlertTriangle
return (
<div className="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div className="flex items-center space-x-3">
<StatusIcon className={`${statusColors[status].split(' ')[0]}`} size={16} />
<span className="font-medium text-gray-900">{label}</span>
</div>
<span className="text-sm text-gray-600">{value}</span>
</div>
)
}
const ActivityItem: React.FC<{
icon: React.ReactNode
title: string
time: string
type: string
}> = ({ icon, title, time, type }) => {
const typeColors = {
chat: 'text-blue-600 bg-blue-50',
survey: 'text-yellow-600 bg-yellow-50',
accessibility: 'text-green-600 bg-green-50',
'mental-health': 'text-pink-600 bg-pink-50',
user: 'text-purple-600 bg-purple-50',
}
return (
<div className="flex items-center space-x-3 p-3 bg-gray-50 rounded-lg">
<div className={`p-2 rounded-lg ${typeColors[type as keyof typeof typeColors]}`}>
{icon}
</div>
<div className="flex-1">
<p className="text-sm font-medium text-gray-900">{title}</p>
<p className="text-xs text-gray-500">{time}</p>
</div>
<Eye className="text-gray-400" size={16} />
</div>
)
}
+545
View File
@@ -0,0 +1,545 @@
'use client';
import React, { useState } from 'react';
import { useLanguage } from '@/components/providers/LanguageProvider';
import {
GraduationCap,
Calendar,
Users,
CheckCircle,
Clock,
DollarSign,
Globe,
MapPin,
Mail,
Phone,
ExternalLink
} from 'lucide-react';
import { mockCourses } from '@/lib/mockData';
export default function AdmissionsPage() {
const { language, dir } = useLanguage();
const [activeTab, setActiveTab] = useState('requirements');
// Application process steps
const applicationSteps = [
{
step: 1,
titleEn: 'Choose Your Program',
titleAr: 'اختر برنامجك',
descriptionEn: 'Browse our extensive range of undergraduate and postgraduate programs.',
descriptionAr: 'تصفح مجموعتنا الواسعة من البرامج الجامعية والدراسات العليا.',
timelineEn: '1-2 weeks',
timelineAr: '1-2 أسابيع'
},
{
step: 2,
titleEn: 'Submit Application',
titleAr: 'تقديم الطلب',
descriptionEn: 'Complete your online application with all required documents.',
descriptionAr: 'أكمل طلبك عبر الإنترنت مع جميع الوثائق المطلوبة.',
timelineEn: '2-3 days',
timelineAr: '2-3 أيام'
},
{
step: 3,
titleEn: 'Application Review',
titleAr: 'مراجعة الطلب',
descriptionEn: 'Our admissions team reviews your application and documents.',
descriptionAr: 'يراجع فريق القبول لدينا طلبك ووثائقك.',
timelineEn: '2-4 weeks',
timelineAr: '2-4 أسابيع'
},
{
step: 4,
titleEn: 'Receive Offer',
titleAr: 'استلام العرض',
descriptionEn: 'If successful, you\'ll receive a conditional or unconditional offer.',
descriptionAr: 'في حالة النجاح، ستتلقى عرضاً مشروطاً أو غير مشروط.',
timelineEn: '1 week',
timelineAr: '1 أسبوع'
},
{
step: 5,
titleEn: 'Accept & Enroll',
titleAr: 'القبول والتسجيل',
descriptionEn: 'Accept your offer and complete enrollment procedures.',
descriptionAr: 'اقبل عرضك وأكمل إجراءات التسجيل.',
timelineEn: '1-2 weeks',
timelineAr: '1-2 أسابيع'
}
];
// Entry requirements by level
const entryRequirements = {
undergraduate: {
titleEn: 'Undergraduate Requirements',
titleAr: 'متطلبات البكالوريوس',
requirements: {
en: [
'Australian Year 12 or equivalent international qualification',
'English language proficiency (IELTS 6.0 or equivalent)',
'Prerequisites specific to chosen program',
'Personal statement (for some programs)',
'Portfolio (for creative programs)'
],
ar: [
'الصف الثاني عشر الأسترالي أو مؤهل دولي معادل',
'إجادة اللغة الإنجليزية (IELTS 6.0 أو ما يعادله)',
'المتطلبات المسبقة الخاصة بالبرنامج المختار',
'بيان شخصي (لبعض البرامج)',
'محفظة أعمال (للبرامج الإبداعية)'
]
}
},
postgraduate: {
titleEn: 'Postgraduate Requirements',
titleAr: 'متطلبات الدراسات العليا',
requirements: {
en: [
'Bachelor\'s degree or equivalent from recognized institution',
'English language proficiency (IELTS 6.5 or equivalent)',
'Academic transcripts and certificates',
'CV/Resume and personal statement',
'Letters of recommendation (for research degrees)',
'Research proposal (for PhD programs)'
],
ar: [
'درجة البكالوريوس أو ما يعادلها من مؤسسة معترف بها',
'إجادة اللغة الإنجليزية (IELTS 6.5 أو ما يعادله)',
'كشوف الدرجات والشهادات الأكاديمية',
'السيرة الذاتية والبيان الشخصي',
'خطابات التوصية (لدرجات البحث)',
'مقترح البحث (لبرامج الدكتوراه)'
]
}
},
international: {
titleEn: 'International Student Requirements',
titleAr: 'متطلبات الطلاب الدوليين',
requirements: {
en: [
'Valid passport and student visa',
'Academic credentials assessment',
'English language test results',
'Financial capacity evidence',
'Health insurance coverage',
'Overseas Student Health Cover (OSHC)'
],
ar: [
'جواز سفر صالح وتأشيرة طالب',
'تقييم الأوراق الأكاديمية',
'نتائج اختبار اللغة الإنجليزية',
'دليل القدرة المالية',
'تغطية التأمين الصحي',
'تغطية صحية للطلاب الأجانب (OSHC)'
]
}
}
};
// Important dates
const importantDates = [
{
dateEn: 'October 31, 2024',
dateAr: '31 أكتوبر 2024',
eventEn: 'Applications Open',
eventAr: 'فتح التطبيقات',
typeEn: 'Application',
typeAr: 'التطبيق'
},
{
dateEn: 'January 15, 2025',
dateAr: '15 يناير 2025',
eventEn: 'Semester 1 Applications Close',
eventAr: 'إغلاق طلبات الفصل الأول',
typeEn: 'Deadline',
typeAr: 'الموعد النهائي'
},
{
dateEn: 'February 24, 2025',
dateAr: '24 فبراير 2025',
eventEn: 'Semester 1 Commences',
eventAr: 'بداية الفصل الأول',
typeEn: 'Start Date',
typeAr: 'تاريخ البداية'
},
{
dateEn: 'June 15, 2025',
dateAr: '15 يونيو 2025',
eventEn: 'Semester 2 Applications Close',
eventAr: 'إغلاق طلبات الفصل الثاني',
typeEn: 'Deadline',
typeAr: 'الموعد النهائي'
},
{
dateEn: 'July 28, 2025',
dateAr: '28 يوليو 2025',
eventEn: 'Semester 2 Commences',
eventAr: 'بداية الفصل الثاني',
typeEn: 'Start Date',
typeAr: 'تاريخ البداية'
}
];
// Support services
const supportServices = [
{
titleEn: 'Academic Support',
titleAr: 'الدعم الأكاديمي',
descriptionEn: 'Tutoring, study groups, and academic skills workshops.',
descriptionAr: 'التدريس والمجموعات الدراسية وورش المهارات الأكاديمية.',
iconColor: 'text-blue-500'
},
{
titleEn: 'Student Accommodation',
titleAr: 'سكن الطلاب',
descriptionEn: 'On-campus and off-campus housing options with support.',
descriptionAr: 'خيارات السكن داخل وخارج الحرم الجامعي مع الدعم.',
iconColor: 'text-green-500'
},
{
titleEn: 'Career Services',
titleAr: 'خدمات الوظائف',
descriptionEn: 'Job placement, internships, and career development programs.',
descriptionAr: 'التوظيف والتدريب وبرامج تطوير المهنة.',
iconColor: 'text-purple-500'
},
{
titleEn: 'International Student Support',
titleAr: 'دعم الطلاب الدوليين',
descriptionEn: 'Visa assistance, orientation programs, and cultural integration.',
descriptionAr: 'مساعدة التأشيرة وبرامج التوجيه والاندماج الثقافي.',
iconColor: 'text-orange-500'
},
{
titleEn: 'Financial Aid',
titleAr: 'المساعدة المالية',
descriptionEn: 'Scholarships, grants, and financial planning assistance.',
descriptionAr: 'المنح الدراسية والمنح والمساعدة في التخطيط المالي.',
iconColor: 'text-green-600'
},
{
titleEn: 'Disability Services',
titleAr: 'خدمات الإعاقة',
descriptionEn: 'Accessibility support and reasonable adjustments.',
descriptionAr: 'دعم إمكانية الوصول والتعديلات المعقولة.',
iconColor: 'text-red-500'
}
];
// Filter popular courses
const popularCourses = mockCourses.slice(0, 6);
return (
<div className={`min-h-screen bg-gray-50 ${dir === 'rtl' ? 'font-arabic' : ''}`} dir={dir}>
{/* Hero Section */}
<div className="bg-gradient-to-r from-purple-600 to-blue-600 text-white py-16">
<div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">
{language === 'en' ? 'Admissions' : 'القبول'}
</h1>
<p className="text-xl opacity-90 mb-8">
{language === 'en'
? 'Join UTAS and embark on your educational journey. We\'re here to guide you through every step of the application process.'
: 'انضم إلى UTAS وابدأ رحلتك التعليمية. نحن هنا لإرشادك خلال كل خطوة من خطوات عملية التقديم.'
}
</p>
<div className="flex justify-center space-x-8 text-center">
<div>
<div className="text-3xl font-bold">150+</div>
<div className="opacity-80">{language === 'en' ? 'Programs' : 'برنامج'}</div>
</div>
<div>
<div className="text-3xl font-bold">95%</div>
<div className="opacity-80">{language === 'en' ? 'Graduate Employment' : 'توظيف الخريجين'}</div>
</div>
<div>
<div className="text-3xl font-bold">100+</div>
<div className="opacity-80">{language === 'en' ? 'Countries Represented' : 'دولة ممثلة'}</div>
</div>
</div>
</div>
</div>
</div>
<div className="container mx-auto px-4 py-8">
{/* Navigation Tabs */}
<div className="flex justify-center mb-8">
<div className="bg-white rounded-lg p-1 shadow-lg">
{[
{ id: 'requirements', labelEn: 'Requirements', labelAr: 'المتطلبات' },
{ id: 'process', labelEn: 'Application Process', labelAr: 'عملية التقديم' },
{ id: 'dates', labelEn: 'Important Dates', labelAr: 'تواريخ مهمة' },
{ id: 'support', labelEn: 'Student Support', labelAr: 'دعم الطلاب' }
].map(tab => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`px-6 py-3 rounded-md font-semibold transition-colors ${
activeTab === tab.id
? 'bg-purple-600 text-white'
: 'text-gray-600 hover:text-purple-600'
}`}
>
{language === 'en' ? tab.labelEn : tab.labelAr}
</button>
))}
</div>
</div>
{/* Requirements Tab */}
{activeTab === 'requirements' && (
<div className="space-y-8">
{Object.values(entryRequirements).map((category, index) => (
<div key={index} className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6 flex items-center">
<GraduationCap className="mr-3 text-purple-600" size={28} />
{language === 'en' ? category.titleEn : category.titleAr}
</h2>
<div className="grid lg:grid-cols-2 gap-6">
<div>
<ul className="space-y-4">
{(language === 'en' ? category.requirements.en : category.requirements.ar).map((requirement, reqIndex) => (
<li key={reqIndex} className="flex items-start">
<CheckCircle className="w-5 h-5 text-green-500 mr-3 mt-0.5 flex-shrink-0" />
<span className="text-gray-700">{requirement}</span>
</li>
))}
</ul>
</div>
<div className="bg-purple-50 rounded-lg p-6">
<h3 className="font-semibold text-purple-900 mb-3">
{language === 'en' ? 'Quick Tips' : 'نصائح سريعة'}
</h3>
<ul className="space-y-2 text-sm text-purple-700">
<li> {language === 'en' ? 'Apply early for better chances' : 'تقدم مبكراً لفرص أفضل'}</li>
<li> {language === 'en' ? 'Prepare documents in advance' : 'حضر الوثائق مسبقاً'}</li>
<li> {language === 'en' ? 'Contact our admissions team for help' : 'اتصل بفريق القبول للمساعدة'}</li>
</ul>
</div>
</div>
</div>
))}
</div>
)}
{/* Application Process Tab */}
{activeTab === 'process' && (
<div className="space-y-8">
<div className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-3xl font-bold text-gray-900 mb-8 text-center">
{language === 'en' ? 'Application Process' : 'عملية التقديم'}
</h2>
<div className="space-y-8">
{applicationSteps.map((step, index) => (
<div key={step.step} className="flex items-start">
<div className="flex-shrink-0 w-12 h-12 bg-purple-600 text-white rounded-full flex items-center justify-center font-bold text-lg mr-6">
{step.step}
</div>
<div className="flex-1">
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between mb-2">
<h3 className="text-xl font-bold text-gray-900">
{language === 'en' ? step.titleEn : step.titleAr}
</h3>
<div className="flex items-center text-sm text-purple-600 font-medium">
<Clock className="w-4 h-4 mr-1" />
{language === 'en' ? step.timelineEn : step.timelineAr}
</div>
</div>
<p className="text-gray-600">
{language === 'en' ? step.descriptionEn : step.descriptionAr}
</p>
{index < applicationSteps.length - 1 && (
<div className="w-px h-8 bg-gray-300 ml-6 mt-4"></div>
)}
</div>
</div>
))}
</div>
<div className="mt-8 text-center">
<button className="bg-purple-600 text-white px-8 py-3 rounded-lg font-semibold hover:bg-purple-700 transition-colors">
{language === 'en' ? 'Start Your Application' : 'ابدأ طلبك'}
</button>
</div>
</div>
{/* Popular Programs */}
<div className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
{language === 'en' ? 'Popular Programs' : 'البرامج الشائعة'}
</h2>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{popularCourses.map(course => (
<div key={course.id} className="border border-gray-200 rounded-lg p-6 hover:shadow-md transition-shadow">
<h3 className="text-lg font-bold text-gray-900 mb-2">
{language === 'en' ? course.title : course.titleAr}
</h3>
<div className="space-y-2 text-sm text-gray-600 mb-4">
<div className="flex items-center">
<Clock className="w-4 h-4 mr-2" />
<span>{course.duration}</span>
</div>
<div className="flex items-center">
<MapPin className="w-4 h-4 mr-2" />
<span>{language === 'en' ? course.campus : course.campusAr}</span>
</div>
<div className="flex items-center">
<DollarSign className="w-4 h-4 mr-2" />
<span>{course.fees}</span>
</div>
</div>
<button className="w-full bg-purple-50 text-purple-700 py-2 px-4 rounded-lg font-medium hover:bg-purple-100 transition-colors">
{language === 'en' ? 'Learn More' : 'تعلم المزيد'}
</button>
</div>
))}
</div>
</div>
</div>
)}
{/* Important Dates Tab */}
{activeTab === 'dates' && (
<div className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-3xl font-bold text-gray-900 mb-8 text-center">
{language === 'en' ? 'Important Dates 2024-2025' : 'تواريخ مهمة 2024-2025'}
</h2>
<div className="space-y-6">
{importantDates.map((date, index) => (
<div key={index} className="flex items-center justify-between p-6 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors">
<div className="flex items-center">
<div className="w-12 h-12 bg-purple-600 text-white rounded-full flex items-center justify-center mr-4">
<Calendar size={20} />
</div>
<div>
<h3 className="font-semibold text-gray-900">
{language === 'en' ? date.eventEn : date.eventAr}
</h3>
<p className="text-sm text-gray-600">
{language === 'en' ? date.typeEn : date.typeAr}
</p>
</div>
</div>
<div className="text-right">
<div className="font-semibold text-purple-600">
{language === 'en' ? date.dateEn : date.dateAr}
</div>
</div>
</div>
))}
</div>
<div className="mt-8 text-center">
<button className="bg-purple-600 text-white px-6 py-3 rounded-lg font-semibold hover:bg-purple-700 transition-colors mr-4">
{language === 'en' ? 'Download Academic Calendar' : 'تحميل التقويم الأكاديمي'}
</button>
<button className="bg-gray-200 text-gray-700 px-6 py-3 rounded-lg font-semibold hover:bg-gray-300 transition-colors">
{language === 'en' ? 'Set Reminders' : 'تعيين التذكيرات'}
</button>
</div>
</div>
)}
{/* Student Support Tab */}
{activeTab === 'support' && (
<div className="space-y-8">
<div className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-3xl font-bold text-gray-900 mb-8 text-center">
{language === 'en' ? 'Student Support Services' : 'خدمات دعم الطلاب'}
</h2>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
{supportServices.map((service, index) => (
<div key={index} className="text-center">
<div className={`w-16 h-16 rounded-full bg-gray-100 flex items-center justify-center mx-auto mb-4 ${service.iconColor}`}>
<Users size={32} />
</div>
<h3 className="text-lg font-bold text-gray-900 mb-3">
{language === 'en' ? service.titleEn : service.titleAr}
</h3>
<p className="text-gray-600 text-sm">
{language === 'en' ? service.descriptionEn : service.descriptionAr}
</p>
</div>
))}
</div>
</div>
{/* Contact Information */}
<div className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
{language === 'en' ? 'Contact Admissions' : 'اتصل بالقبول'}
</h2>
<div className="grid md:grid-cols-2 gap-8">
<div>
<h3 className="font-semibold text-gray-900 mb-4">
{language === 'en' ? 'General Inquiries' : 'الاستفسارات العامة'}
</h3>
<div className="space-y-3">
<div className="flex items-center">
<Mail className="w-5 h-5 text-purple-600 mr-3" />
<span>admissions@utas.edu.au</span>
</div>
<div className="flex items-center">
<Phone className="w-5 h-5 text-purple-600 mr-3" />
<span>+61 3 6226 2999</span>
</div>
<div className="flex items-center">
<Globe className="w-5 h-5 text-purple-600 mr-3" />
<span>www.utas.edu.au/admissions</span>
</div>
</div>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-4">
{language === 'en' ? 'International Students' : 'الطلاب الدوليون'}
</h3>
<div className="space-y-3">
<div className="flex items-center">
<Mail className="w-5 h-5 text-blue-600 mr-3" />
<span>international@utas.edu.au</span>
</div>
<div className="flex items-center">
<Phone className="w-5 h-5 text-blue-600 mr-3" />
<span>+61 3 6226 1800</span>
</div>
</div>
</div>
</div>
<div className="mt-6 flex gap-4">
<button className="flex-1 bg-purple-600 text-white py-3 px-4 rounded-lg font-semibold hover:bg-purple-700 transition-colors">
{language === 'en' ? 'Schedule a Call' : 'جدولة مكالمة'}
</button>
<button className="flex-1 bg-gray-200 text-gray-700 py-3 px-4 rounded-lg font-semibold hover:bg-gray-300 transition-colors flex items-center justify-center gap-2">
<ExternalLink size={16} />
{language === 'en' ? 'Live Chat' : 'الدردشة المباشرة'}
</button>
</div>
</div>
</div>
)}
{/* Call to Action */}
<div className="mt-16 bg-gradient-to-r from-purple-600 to-blue-600 rounded-xl p-8 text-white text-center">
<h2 className="text-3xl font-bold mb-4">
{language === 'en' ? 'Ready to Start Your Journey?' : 'هل أنت مستعد لبدء رحلتك؟'}
</h2>
<p className="text-xl opacity-90 mb-8 max-w-2xl mx-auto">
{language === 'en'
? 'Join thousands of students who have chosen UTAS for their education. Apply now and take the first step towards your future.'
: 'انضم إلى آلاف الطلاب الذين اختاروا UTAS لتعليمهم. تقدم الآن واتخذ الخطوة الأولى نحو مستقبلك.'
}
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<button className="bg-white text-purple-600 px-8 py-3 rounded-lg font-semibold hover:bg-gray-100 transition-colors">
{language === 'en' ? 'Apply Now' : 'تقدم الآن'}
</button>
<button className="bg-purple-700 text-white px-8 py-3 rounded-lg font-semibold hover:bg-purple-800 transition-colors">
{language === 'en' ? 'Book Information Session' : 'احجز جلسة معلومات'}
</button>
</div>
</div>
</div>
</div>
);
}
+266
View File
@@ -0,0 +1,266 @@
'use client';
import { useLanguage } from '@/components/providers/LanguageProvider';
import { Snowflake, Mountain, Ship, Microscope, Users } from 'lucide-react';
const AntarcticPage = () => {
const { language } = useLanguage();
const isRTL = language === 'ar';
const expeditions = [
{
year: "2024",
title: "Antarctic Climate Monitoring Mission",
description: "Deploying advanced sensors to track ice sheet changes and their global impact",
participants: 45,
duration: "6 months",
image: "🌨️"
},
{
year: "2023",
title: "Deep Sea Antarctic Exploration",
description: "Discovering new marine species in the Southern Ocean depths",
participants: 32,
duration: "4 months",
image: "🐟"
},
{
year: "2023",
title: "Ice Core Historical Analysis",
description: "Extracting 100,000 years of climate data from Antarctic ice cores",
participants: 28,
duration: "5 months",
image: "🧊"
}
];
const discoveries = [
{
title: "New Antarctic Fish Species",
description: "UTAS researchers discovered 15 new fish species adapted to extreme cold, revolutionizing our understanding of polar marine biodiversity.",
impact: "Published in Nature: Marine Biology",
year: "2024"
},
{
title: "Ice Sheet Stability Model",
description: "Breakthrough computer modeling predicting Antarctic ice sheet behavior over the next century, informing global sea level rise projections.",
impact: "Cited by IPCC Climate Reports",
year: "2023"
},
{
title: "Polar Microorganism Medicine",
description: "Antarctic bacteria showing promise for new antibiotics resistant to current drug-resistant infections.",
impact: "3 patents filed, clinical trials pending",
year: "2023"
}
];
const facilities = [
{
name: "Australian Antarctic Division HQ",
location: "Hobart, Tasmania",
description: "Australia's primary Antarctic research coordination center",
icon: <Mountain className="w-8 h-8" />
},
{
name: "Research Vessel Aurora Australis",
location: "Southern Ocean",
description: "State-of-the-art polar research vessel for Antarctic expeditions",
icon: <Ship className="w-8 h-8" />
},
{
name: "Casey Station Collaboration",
location: "Antarctic Territory",
description: "Year-round research station for climate and marine studies",
icon: <Snowflake className="w-8 h-8" />
},
{
name: "Polar Medicine Centre",
location: "UTAS Campus",
description: "World-leading research in polar medicine and extreme environment health",
icon: <Microscope className="w-8 h-8" />
}
];
const stats = [
{ value: "40+", label: "Years in Antarctica", description: "Continuous research presence" },
{ value: "200+", label: "Expeditions Led", description: "Scientific missions completed" },
{ value: "1,500+", label: "Research Papers", description: "Published Antarctic studies" },
{ value: "50+", label: "Countries Partnered", description: "International collaborations" }
];
return (
<div className={`min-h-screen bg-gradient-to-br from-blue-50 via-white to-cyan-50 ${isRTL ? 'rtl' : 'ltr'}`}>
{/* Hero Section */}
<div className="relative bg-gradient-to-r from-blue-900 via-cyan-900 to-blue-800 text-white overflow-hidden">
<div className="absolute inset-0 bg-black/20"></div>
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24">
<div className="text-center">
<div className="flex justify-center mb-6">
<div className="bg-white/10 backdrop-blur-sm rounded-full p-6">
<Snowflake className="w-16 h-16 text-cyan-300" />
</div>
</div>
<h1 className="text-5xl md:text-7xl font-bold mb-6 bg-gradient-to-r from-white to-cyan-200 bg-clip-text text-transparent">
Antarctic Excellence
</h1>
<p className="text-xl md:text-2xl mb-8 text-cyan-100 max-w-4xl mx-auto">
Leading the world in polar research, climate science, and Antarctic exploration
for over four decades
</p>
<div className="text-6xl mb-8">🇦🇶</div>
<p className="text-lg text-cyan-200">
Australia&apos;s Gateway to the Antarctic
</p>
</div>
</div>
</div>
{/* Stats Section */}
<div className="bg-white py-16">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
{stats.map((stat, index) => (
<div key={index} className="text-center">
<div className="text-4xl md:text-5xl font-bold text-blue-600 mb-2">
{stat.value}
</div>
<div className="text-lg font-semibold text-gray-900 mb-1">
{stat.label}
</div>
<div className="text-sm text-gray-600">
{stat.description}
</div>
</div>
))}
</div>
</div>
</div>
{/* Current Expeditions */}
<div className="py-16 bg-gradient-to-r from-blue-50 to-cyan-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-4xl font-bold text-center mb-12 text-gray-900">
Current Expeditions
</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{expeditions.map((expedition, index) => (
<div key={index} className="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition-shadow duration-300">
<div className="p-6">
<div className="text-6xl text-center mb-4">{expedition.image}</div>
<div className="bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-semibold inline-block mb-3">
{expedition.year}
</div>
<h3 className="text-xl font-bold mb-3 text-gray-900">
{expedition.title}
</h3>
<p className="text-gray-700 mb-4">
{expedition.description}
</p>
<div className="flex justify-between text-sm text-gray-600">
<div className="flex items-center gap-1">
<Users className="w-4 h-4" />
{expedition.participants} researchers
</div>
<div>
Duration: {expedition.duration}
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
{/* Major Discoveries */}
<div className="py-16 bg-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-4xl font-bold text-center mb-12 text-gray-900">
Groundbreaking Discoveries
</h2>
<div className="space-y-8">
{discoveries.map((discovery, index) => (
<div key={index} className="bg-gradient-to-r from-blue-50 to-cyan-50 rounded-xl p-8 hover:shadow-lg transition-shadow duration-300">
<div className="flex flex-col md:flex-row justify-between items-start gap-6">
<div className="flex-1">
<div className="flex items-center gap-3 mb-3">
<h3 className="text-2xl font-bold text-gray-900">
{discovery.title}
</h3>
<span className="bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-semibold">
{discovery.year}
</span>
</div>
<p className="text-gray-700 mb-4 text-lg">
{discovery.description}
</p>
<div className="bg-green-100 text-green-800 px-4 py-2 rounded-lg inline-block">
<strong>Impact:</strong> {discovery.impact}
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
{/* Research Facilities */}
<div className="py-16 bg-gradient-to-r from-cyan-50 to-blue-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-4xl font-bold text-center mb-12 text-gray-900">
World-Class Facilities
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{facilities.map((facility, index) => (
<div key={index} className="bg-white rounded-xl p-6 shadow-lg hover:shadow-xl transition-shadow duration-300">
<div className="flex items-start gap-4">
<div className="bg-blue-100 text-blue-600 p-3 rounded-lg">
{facility.icon}
</div>
<div className="flex-1">
<h3 className="text-xl font-bold mb-2 text-gray-900">
{facility.name}
</h3>
<div className="text-sm text-blue-600 mb-2 font-semibold">
📍 {facility.location}
</div>
<p className="text-gray-700">
{facility.description}
</p>
</div>
</div>
</div>
))}
</div>
</div>
</div>
{/* Call to Action */}
<div className="bg-gradient-to-r from-blue-600 to-cyan-600 py-16">
<div className="max-w-4xl mx-auto text-center px-4 sm:px-6 lg:px-8">
<h2 className="text-4xl font-bold text-white mb-6">
Join the Antarctic Adventure
</h2>
<p className="text-xl text-blue-100 mb-8">
Be part of the next generation of polar researchers shaping our understanding of climate change
</p>
<div className="flex flex-wrap justify-center gap-4">
<button className="bg-white text-blue-600 px-8 py-4 rounded-lg font-semibold hover:bg-blue-50 transition-colors text-lg">
Explore Antarctic Programs
</button>
<button className="border-2 border-white text-white px-8 py-4 rounded-lg font-semibold hover:bg-white hover:text-blue-600 transition-colors text-lg">
Research Opportunities
</button>
</div>
</div>
</div>
</div>
);
};
export default AntarcticPage;
+73
View File
@@ -0,0 +1,73 @@
import { NextResponse } from 'next/server';
// Mock data for demo purposes
const mockAudits = [
{
id: '1',
fileName: 'homepage-banner.jpg',
originalAltText: '',
suggestedAltText: 'University campus building with students walking in the foreground',
wcagScore: 85,
improvements: [
'Add descriptive alt text to improve accessibility',
'Ensure sufficient color contrast',
'Consider adding captions for better understanding'
],
createdAt: new Date('2024-12-01T10:00:00Z'),
userId: '1'
},
{
id: '2',
fileName: 'course-diagram.png',
originalAltText: 'diagram',
suggestedAltText: 'Flow chart showing course prerequisites with arrows connecting related subjects',
wcagScore: 92,
improvements: [
'Current alt text is good',
'Consider adding more descriptive details',
'Ensure text is readable at all zoom levels'
],
createdAt: new Date('2024-12-02T14:30:00Z'),
userId: '1'
}
];
export async function GET() {
try {
// Return mock data instead of database query
return NextResponse.json(mockAudits);
} catch (error) {
console.error('Error fetching accessibility audits:', error);
return NextResponse.json({ error: 'Failed to fetch audits' }, { status: 500 });
}
}
export async function POST(request: Request) {
try {
const formData = await request.formData();
const file = formData.get('file') as File;
if (!file) {
return NextResponse.json({ error: 'No file uploaded' }, { status: 400 });
}
// Mock AI analysis results
const mockAnalysis = {
fileName: file.name,
suggestedAltText: `Professional photograph showing ${file.name.replace(/\.[^/.]+$/, "").replace(/[-_]/g, ' ')} in a clear, well-lit environment`,
wcagScore: Math.floor(Math.random() * 20) + 80, // Random score between 80-100
improvements: [
'Add descriptive alt text for screen readers',
'Ensure image has sufficient color contrast',
'Consider adding captions for complex images',
'Verify image is meaningful and not decorative'
],
confidence: 0.95
};
return NextResponse.json(mockAnalysis);
} catch (error) {
console.error('Error processing accessibility audit:', error);
return NextResponse.json({ error: 'Failed to process audit' }, { status: 500 });
}
}
+143
View File
@@ -0,0 +1,143 @@
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 })
}
}
+73
View File
@@ -0,0 +1,73 @@
import { NextResponse } from 'next/server';
// Mock data for demo purposes
const mockAudits = [
{
id: '1',
fileName: 'homepage-banner.jpg',
originalAltText: '',
suggestedAltText: 'University campus building with students walking in the foreground',
wcagScore: 85,
improvements: [
'Add descriptive alt text to improve accessibility',
'Ensure sufficient color contrast',
'Consider adding captions for better understanding'
],
createdAt: new Date('2024-12-01T10:00:00Z'),
userId: '1'
},
{
id: '2',
fileName: 'course-diagram.png',
originalAltText: 'diagram',
suggestedAltText: 'Flow chart showing course prerequisites with arrows connecting related subjects',
wcagScore: 92,
improvements: [
'Current alt text is good',
'Consider adding more descriptive details',
'Ensure text is readable at all zoom levels'
],
createdAt: new Date('2024-12-02T14:30:00Z'),
userId: '1'
}
];
export async function GET() {
try {
// Return mock data instead of database query
return NextResponse.json(mockAudits);
} catch (error) {
console.error('Error fetching accessibility audits:', error);
return NextResponse.json({ error: 'Failed to fetch audits' }, { status: 500 });
}
}
export async function POST(request: Request) {
try {
const formData = await request.formData();
const file = formData.get('file') as File;
if (!file) {
return NextResponse.json({ error: 'No file uploaded' }, { status: 400 });
}
// Mock AI analysis results
const mockAnalysis = {
fileName: file.name,
suggestedAltText: `Professional photograph showing ${file.name.replace(/\.[^/.]+$/, "").replace(/[-_]/g, ' ')} in a clear, well-lit environment`,
wcagScore: Math.floor(Math.random() * 20) + 80, // Random score between 80-100
improvements: [
'Add descriptive alt text for screen readers',
'Ensure image has sufficient color contrast',
'Consider adding captions for complex images',
'Verify image is meaningful and not decorative'
],
confidence: 0.95
};
return NextResponse.json(mockAnalysis);
} catch (error) {
console.error('Error processing accessibility audit:', error);
return NextResponse.json({ error: 'Failed to process audit' }, { status: 500 });
}
}
+253
View File
@@ -0,0 +1,253 @@
import { NextResponse } from 'next/server';
interface ApplicationData {
type: 'undergraduate' | 'postgraduate' | 'research' | 'international';
personalInfo: {
firstName: string;
lastName: string;
email: string;
phone: string;
dateOfBirth: string;
citizenship: string;
address: string;
};
academicInfo: {
previousEducation: string;
atar?: number;
transcripts: string[];
englishProficiency?: string;
};
coursePreferences: {
firstChoice: string;
secondChoice?: string;
thirdChoice?: string;
campus: string;
startDate: string;
};
documents: string[];
scholarshipInterest: boolean;
}
// Mock application database
const applications: Array<ApplicationData & { id: string; status: string; submittedAt: string }> = [];
export async function POST(request: Request) {
try {
const { action, ...data } = await request.json();
switch (action) {
case 'submit':
const applicationId = `APP-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const newApplication = {
id: applicationId,
...data as ApplicationData,
status: 'submitted',
submittedAt: new Date().toISOString()
};
applications.push(newApplication);
// Send confirmation email (mock)
console.log('Application submitted:', {
id: applicationId,
email: data.personalInfo?.email,
course: data.coursePreferences?.firstChoice
});
return NextResponse.json({
success: true,
applicationId,
message: 'Application submitted successfully',
nextSteps: [
'Check your email for confirmation',
'Upload required documents if not already provided',
'Monitor application status in your portal',
'Await assessment (typically 2-4 weeks)',
'Respond to offer if successful'
],
estimatedProcessingTime: '2-4 weeks',
contactInfo: {
phone: '+61 3 6226 6200',
email: 'admissions@utas.edu.au',
hours: 'Monday-Friday 9:00 AM - 5:00 PM'
}
});
case 'getStatus':
const { applicationId: statusId } = data;
const application = applications.find(app => app.id === statusId);
if (!application) {
return NextResponse.json({
error: 'Application not found'
}, { status: 404 });
}
return NextResponse.json({
application: {
id: application.id,
status: application.status,
submittedAt: application.submittedAt,
course: application.coursePreferences.firstChoice,
campus: application.coursePreferences.campus
},
timeline: [
{ step: 'Application Submitted', completed: true, date: application.submittedAt },
{ step: 'Document Verification', completed: false, estimated: '1-2 weeks' },
{ step: 'Academic Assessment', completed: false, estimated: '2-3 weeks' },
{ step: 'Offer Decision', completed: false, estimated: '3-4 weeks' },
{ step: 'Enrollment', completed: false, estimated: 'Upon acceptance' }
]
});
case 'getRequirements':
const { courseType, citizenship } = data;
const requirements = {
undergraduate: {
domestic: [
'Completed Year 12 or equivalent',
'ATAR score or alternative entry pathway',
'Prerequisite subjects for specific courses',
'English language proficiency',
'Valid identification documents'
],
international: [
'Completed secondary education equivalent to Australian Year 12',
'Academic transcripts (officially translated)',
'English proficiency (IELTS 6.0+ or equivalent)',
'Student visa documentation',
'Financial capacity evidence',
'Health insurance (OSHC)'
]
},
postgraduate: {
domestic: [
'Completed bachelor degree or equivalent',
'Academic transcripts',
'Work experience (for some programs)',
'Professional references',
'English language proficiency'
],
international: [
'Completed bachelor degree equivalent to Australian standard',
'Academic transcripts (officially translated)',
'English proficiency (IELTS 6.5+ or equivalent)',
'Student visa documentation',
'Financial capacity evidence',
'Health insurance (OSHC)',
'Professional experience (where required)'
]
}
};
const citizenshipType = citizenship === 'australian' || citizenship === 'permanent_resident'
? 'domestic' : 'international';
return NextResponse.json({
requirements: requirements[courseType as keyof typeof requirements]?.[citizenshipType] || [],
deadlines: {
semester1: {
domestic: 'December 31, 2024',
international: 'October 31, 2024'
},
semester2: {
domestic: 'May 31, 2025',
international: 'March 31, 2025'
}
},
fees: {
undergraduate: {
domestic: 'Commonwealth Supported Places available',
international: '$32,000 - $45,000 per year'
},
postgraduate: {
domestic: '$25,000 - $40,000 per year',
international: '$35,000 - $50,000 per year'
}
}
});
default:
return NextResponse.json({
error: 'Invalid action'
}, { status: 400 });
}
} catch (error) {
console.error('Application API error:', error);
return NextResponse.json({
error: 'Failed to process application request'
}, { status: 500 });
}
}
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const type = searchParams.get('type') || 'info';
if (type === 'info') {
return NextResponse.json({
applicationTypes: [
{
type: 'undergraduate',
title: 'Undergraduate Applications',
description: 'Bachelor degrees, diplomas, and certificates',
eligibility: 'Year 12 completion or equivalent',
portal: 'UAC UTAS portal'
},
{
type: 'postgraduate',
title: 'Postgraduate Applications',
description: 'Masters, graduate certificates and diplomas',
eligibility: 'Bachelor degree or equivalent + work experience',
portal: 'Direct UTAS application'
},
{
type: 'research',
title: 'Research Degrees',
description: 'PhD, Masters by Research',
eligibility: 'Honours degree or masters + research proposal',
portal: 'Research degree portal'
},
{
type: 'international',
title: 'International Applications',
description: 'For students requiring a student visa',
eligibility: 'Varies by course + English proficiency',
portal: 'International student portal'
}
],
support: {
phone: '+61 3 6226 6200',
email: 'admissions@utas.edu.au',
chat: 'Available 24/7 through this portal',
hours: 'Monday-Friday 9:00 AM - 5:00 PM AEST'
},
scholarships: {
available: true,
types: [
'Merit-based scholarships up to $5,000/year',
'Tasmanian scholarships up to $15,000/year',
'International student scholarships',
'Program-specific scholarships',
'Indigenous student support',
'Rural and regional scholarships'
],
deadline: 'Apply early for best scholarship opportunities'
}
});
}
return NextResponse.json({
error: 'Invalid request type'
}, { status: 400 });
} catch (error) {
console.error('Application info error:', error);
return NextResponse.json({
error: 'Failed to get application information'
}, { status: 500 });
}
}
+109
View File
@@ -0,0 +1,109 @@
import { NextResponse } from 'next/server';
// 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) {
try {
const body = await request.json();
const { message, language = 'en' } = body;
if (!message) {
return NextResponse.json({ error: 'Message is required' }, { status: 400 });
}
const result = findBestResponse(message, language);
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 });
}
}
+61
View File
@@ -0,0 +1,61 @@
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 = [] } = await request.json();
if (!message || typeof message !== 'string') {
return NextResponse.json({
error: 'Message is required and must be a string'
}, { status: 400 });
}
// Generate AI response using RAG and potentially OpenRouter
const response = await chatbot.generateResponse(message, conversationHistory);
// 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,
timestamp: new Date().toISOString(),
source: 'UTAS 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.",
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'
}
});
}
+109
View File
@@ -0,0 +1,109 @@
import { NextResponse } from 'next/server';
// 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) {
try {
const body = await request.json();
const { message, language = 'en' } = body;
if (!message) {
return NextResponse.json({ error: 'Message is required' }, { status: 400 });
}
const result = findBestResponse(message, language);
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 });
}
}
+104
View File
@@ -0,0 +1,104 @@
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 }
)
}
}
+71
View File
@@ -0,0 +1,71 @@
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();
if (!message || typeof message !== 'string') {
return NextResponse.json({
error: 'Message is required and must be a string'
}, { status: 400 });
}
// Generate AI response using RAG and potentially OpenRouter with role-based context
const response = await chatbot.generateResponse(
message,
conversationHistory,
systemPrompt,
language
);
// 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,
timestamp: new Date().toISOString(),
source: 'UTAS 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.",
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'
}
});
}
+127
View File
@@ -0,0 +1,127 @@
import { NextRequest, NextResponse } from 'next/server';
import { mockCourses, searchCourses, studyAreas } from '@/lib/mockData';
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const query = searchParams.get('q') || '';
const area = searchParams.get('area') || '';
const level = searchParams.get('level') || '';
const campus = searchParams.get('campus') || '';
// Convert level filter to studyMode
let studyMode = '';
if (level) {
if (level.toLowerCase() === 'undergraduate') {
studyMode = 'undergraduate';
} else if (level.toLowerCase() === 'postgraduate') {
studyMode = 'postgraduate';
} else if (level.toLowerCase() === 'research') {
studyMode = 'research';
}
}
// Build filters object
const filters: { area?: string; studyMode?: string; availability?: string } = {};
if (area) filters.area = area;
if (studyMode) filters.studyMode = studyMode;
let results = searchCourses(query, filters);
// Filter by campus if specified
if (campus) {
results = results.filter(course =>
course.campus.some(c => c.toLowerCase() === campus.toLowerCase())
);
}
return NextResponse.json({
success: true,
courses: results,
total: results.length,
filters: {
query,
area,
level,
campus
},
areas: studyAreas.map(area => area.name),
campuses: ["Hobart", "Launceston", "Burnie", "Sydney"]
});
} catch (error) {
console.error('Courses API error:', error);
return NextResponse.json(
{
success: false,
error: 'Failed to fetch courses',
courses: mockCourses.slice(0, 5), // Return some courses as fallback
total: 5
},
{ status: 500 }
);
}
}
export async function POST(request: NextRequest) {
try {
const { courseId, action } = await request.json();
if (action === 'getDetails') {
const course = mockCourses.find(c => c.id === courseId);
if (!course) {
return NextResponse.json({
error: 'Course not found'
}, { status: 404 });
}
return NextResponse.json({
success: true,
course: course,
relatedCourses: mockCourses
.filter(c => c.area === course.area && c.id !== courseId)
.slice(0, 3),
applicationInfo: {
process: course.area.includes('Medicine')
? 'Competitive entry with UCAT and interview required'
: 'Standard application through UAC UTAS portal',
requirements: course.entry,
deadlines: {
semester1: 'December 31, 2024',
semester2: 'May 31, 2025'
},
scholarships: [
'UTAS Merit Scholarship - $5,000/year',
'Tasmanian Scholarship - $15,000/year (for mainland students)',
`${course.area} specific scholarships available`
]
}
});
}
if (action === 'apply') {
// Mock application process
return NextResponse.json({
success: true,
message: 'Application submitted successfully',
applicationId: `APP-${Date.now()}`,
nextSteps: [
'Check your email for confirmation',
'Complete required documents',
'Attend orientation session'
]
});
}
return NextResponse.json({
error: 'Invalid action'
}, { status: 400 });
} catch (error) {
console.error('Course action error:', error);
return NextResponse.json({
error: 'Failed to process request'
}, { status: 500 });
}
}
+58
View File
@@ -0,0 +1,58 @@
import { NextResponse } from 'next/server';
// Mock survey data
const mockSurveys = [
{
id: '1',
rating: 5,
feedback: 'Great chatbot experience!',
category: 'chatbot',
createdAt: new Date('2024-12-01T10:00:00Z'),
userId: '1'
},
{
id: '2',
rating: 4,
feedback: 'Dashboard is very helpful',
category: 'dashboard',
createdAt: new Date('2024-12-02T14:30:00Z'),
userId: '1'
}
];
export async function GET() {
try {
return NextResponse.json(mockSurveys);
} catch (error) {
console.error('Error fetching surveys:', error);
return NextResponse.json({ error: 'Failed to fetch surveys' }, { status: 500 });
}
}
export async function POST(request: Request) {
try {
const body = await request.json();
const { rating, feedback, category } = body;
if (!rating || !feedback || !category) {
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
}
// Mock survey creation
const newSurvey = {
id: Date.now().toString(),
rating,
feedback,
category,
createdAt: new Date(),
userId: '1'
};
mockSurveys.push(newSurvey);
return NextResponse.json(newSurvey);
} catch (error) {
console.error('Error creating survey:', error);
return NextResponse.json({ error: 'Failed to create survey' }, { status: 500 });
}
}
+58
View File
@@ -0,0 +1,58 @@
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 })
}
}
+58
View File
@@ -0,0 +1,58 @@
import { NextResponse } from 'next/server';
// Mock survey data
const mockSurveys = [
{
id: '1',
rating: 5,
feedback: 'Great chatbot experience!',
category: 'chatbot',
createdAt: new Date('2024-12-01T10:00:00Z'),
userId: '1'
},
{
id: '2',
rating: 4,
feedback: 'Dashboard is very helpful',
category: 'dashboard',
createdAt: new Date('2024-12-02T14:30:00Z'),
userId: '1'
}
];
export async function GET() {
try {
return NextResponse.json(mockSurveys);
} catch (error) {
console.error('Error fetching surveys:', error);
return NextResponse.json({ error: 'Failed to fetch surveys' }, { status: 500 });
}
}
export async function POST(request: Request) {
try {
const body = await request.json();
const { rating, feedback, category } = body;
if (!rating || !feedback || !category) {
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
}
// Mock survey creation
const newSurvey = {
id: Date.now().toString(),
rating,
feedback,
category,
createdAt: new Date(),
userId: '1'
};
mockSurveys.push(newSurvey);
return NextResponse.json(newSurvey);
} catch (error) {
console.error('Error creating survey:', error);
return NextResponse.json({ error: 'Failed to create survey' }, { status: 500 });
}
}
+52
View File
@@ -0,0 +1,52 @@
import { NextResponse } from 'next/server';
// Mock user profile data
const mockUserProfile = {
id: '1',
email: 'student@university.edu',
name: 'John Doe',
role: 'STUDENT',
studentId: 'ST001234',
faculty: 'Arts',
balance: 5420.50,
enrollments: [
{
id: '1',
course: {
id: '1',
code: 'CS101',
title: 'Introduction to Computer Science',
credits: 3,
instructor: 'Dr. Smith',
schedule: 'MWF 10:00-11:00'
},
grade: 'A',
semester: 'Fall 2024'
},
{
id: '2',
course: {
id: '2',
code: 'MATH201',
title: 'Calculus II',
credits: 4,
instructor: 'Prof. Johnson',
schedule: 'TTh 2:00-3:30'
},
grade: 'B+',
semester: 'Fall 2024'
}
],
createdAt: new Date('2024-09-01T00:00:00Z'),
updatedAt: new Date('2024-12-01T00:00:00Z')
};
export async function GET() {
try {
// Return mock user profile
return NextResponse.json(mockUserProfile);
} catch (error) {
console.error('Error fetching user profile:', error);
return NextResponse.json({ error: 'Failed to fetch user profile' }, { status: 500 });
}
}
@@ -0,0 +1,36 @@
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 })
}
}
+52
View File
@@ -0,0 +1,52 @@
import { NextResponse } from 'next/server';
// Mock user profile data
const mockUserProfile = {
id: '1',
email: 'student@university.edu',
name: 'John Doe',
role: 'STUDENT',
studentId: 'ST001234',
faculty: 'Arts',
balance: 5420.50,
enrollments: [
{
id: '1',
course: {
id: '1',
code: 'CS101',
title: 'Introduction to Computer Science',
credits: 3,
instructor: 'Dr. Smith',
schedule: 'MWF 10:00-11:00'
},
grade: 'A',
semester: 'Fall 2024'
},
{
id: '2',
course: {
id: '2',
code: 'MATH201',
title: 'Calculus II',
credits: 4,
instructor: 'Prof. Johnson',
schedule: 'TTh 2:00-3:30'
},
grade: 'B+',
semester: 'Fall 2024'
}
],
createdAt: new Date('2024-09-01T00:00:00Z'),
updatedAt: new Date('2024-12-01T00:00:00Z')
};
export async function GET() {
try {
// Return mock user profile
return NextResponse.json(mockUserProfile);
} catch (error) {
console.error('Error fetching user profile:', error);
return NextResponse.json({ error: 'Failed to fetch user profile' }, { status: 500 });
}
}
+299
View File
@@ -0,0 +1,299 @@
'use client';
import React, { useState, useEffect } from 'react';
import { Search, Filter, MapPin, Clock, DollarSign, BookOpen, Award, ChevronRight, X } from 'lucide-react';
import Link from 'next/link';
interface Course {
id: string;
title: string;
area: string;
duration: string;
description: string;
entry: string;
campus: string[];
fees: string;
pathways: string[];
}
export default function CoursesPage() {
const [courses, setCourses] = useState<Course[]>([]);
const [loading, setLoading] = useState(true);
const [searchQuery, setSearchQuery] = useState('');
const [selectedArea, setSelectedArea] = useState('');
const [selectedLevel, setSelectedLevel] = useState('');
const [selectedCampus, setSelectedCampus] = useState('');
const [showFilters, setShowFilters] = useState(false);
const areas = [
"Business and Law",
"Creative Arts and Design",
"Earth, Sea, Antarctic and Environment",
"Education, Humanities and Social Sciences",
"Health and Medicine",
"Science, Technology and Engineering"
];
const levels = ["Undergraduate", "Postgraduate"];
const campuses = ["Hobart", "Launceston", "Burnie", "Sydney"];
useEffect(() => {
fetchCourses();
}, [searchQuery, selectedArea, selectedLevel, selectedCampus]);
const fetchCourses = async () => {
try {
setLoading(true);
const params = new URLSearchParams();
if (searchQuery) params.append('q', searchQuery);
if (selectedArea) params.append('area', selectedArea);
if (selectedLevel) params.append('level', selectedLevel);
if (selectedCampus) params.append('campus', selectedCampus);
const response = await fetch(`/api/courses?${params}`);
const data = await response.json();
setCourses(data.courses || []);
} catch (error) {
console.error('Error fetching courses:', error);
} finally {
setLoading(false);
}
};
const clearFilters = () => {
setSearchQuery('');
setSelectedArea('');
setSelectedLevel('');
setSelectedCampus('');
};
const filteredCourses = courses.filter(course => {
if (searchQuery && !course.title.toLowerCase().includes(searchQuery.toLowerCase()) &&
!course.description.toLowerCase().includes(searchQuery.toLowerCase())) {
return false;
}
if (selectedArea && course.area !== selectedArea) return false;
if (selectedCampus && !course.campus.includes(selectedCampus)) return false;
return true;
});
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
<div className="bg-gradient-to-r from-blue-600 to-teal-600 text-white">
<div className="container mx-auto px-4 py-16">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-4">
Find Your Perfect Course
</h1>
<p className="text-xl opacity-90 mb-8">
Explore over 350 study programs at the world&apos;s #1 university for climate action
</p>
{/* Search Bar */}
<div className="relative max-w-2xl mx-auto">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400" size={20} />
<input
type="text"
placeholder="Search courses by name, area, or keyword..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full pl-12 pr-16 py-4 rounded-xl text-gray-800 text-lg focus:outline-none focus:ring-4 focus:ring-white/30"
/>
<button
onClick={() => setShowFilters(!showFilters)}
className="absolute right-2 top-1/2 transform -translate-y-1/2 bg-blue-600 text-white p-2 rounded-lg hover:bg-blue-700 transition-colors"
>
<Filter size={20} />
</button>
</div>
</div>
</div>
</div>
{/* Filters */}
{showFilters && (
<div className="bg-white border-b border-gray-200 shadow-sm">
<div className="container mx-auto px-4 py-6">
<div className="flex flex-wrap gap-4 items-center justify-between">
<div className="flex flex-wrap gap-4">
<select
value={selectedArea}
onChange={(e) => setSelectedArea(e.target.value)}
className="px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">All Study Areas</option>
{areas.map(area => (
<option key={area} value={area}>{area}</option>
))}
</select>
<select
value={selectedLevel}
onChange={(e) => setSelectedLevel(e.target.value)}
className="px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">All Levels</option>
{levels.map(level => (
<option key={level} value={level}>{level}</option>
))}
</select>
<select
value={selectedCampus}
onChange={(e) => setSelectedCampus(e.target.value)}
className="px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">All Campuses</option>
{campuses.map(campus => (
<option key={campus} value={campus}>{campus}</option>
))}
</select>
</div>
<div className="flex items-center space-x-4">
<button
onClick={clearFilters}
className="flex items-center space-x-2 px-4 py-2 text-gray-600 hover:text-gray-800 transition-colors"
>
<X size={16} />
<span>Clear Filters</span>
</button>
<button
onClick={() => setShowFilters(false)}
className="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors"
>
Hide Filters
</button>
</div>
</div>
</div>
</div>
)}
{/* Results */}
<div className="container mx-auto px-4 py-8">
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold text-gray-800">
{loading ? 'Loading...' : `${filteredCourses.length} courses found`}
</h2>
{(selectedArea || selectedLevel || selectedCampus || searchQuery) && (
<button
onClick={clearFilters}
className="text-blue-600 hover:text-blue-700 font-medium transition-colors"
>
Clear all filters
</button>
)}
</div>
{loading ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{[...Array(6)].map((_, i) => (
<div key={i} className="bg-white rounded-lg p-6 shadow-sm animate-pulse">
<div className="h-4 bg-gray-200 rounded mb-2"></div>
<div className="h-6 bg-gray-200 rounded mb-4"></div>
<div className="h-20 bg-gray-200 rounded mb-4"></div>
<div className="flex space-x-2 mb-4">
<div className="h-6 bg-gray-200 rounded flex-1"></div>
<div className="h-6 bg-gray-200 rounded flex-1"></div>
</div>
</div>
))}
</div>
) : filteredCourses.length === 0 ? (
<div className="text-center py-12">
<BookOpen size={64} className="mx-auto text-gray-400 mb-4" />
<h3 className="text-xl font-semibold text-gray-600 mb-2">No courses found</h3>
<p className="text-gray-500 mb-4">Try adjusting your search criteria or clearing filters</p>
<button
onClick={clearFilters}
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors"
>
Clear Filters
</button>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredCourses.map((course) => (
<div key={course.id} className="bg-white rounded-lg shadow-sm hover:shadow-md transition-shadow border border-gray-200">
<div className="p-6">
<div className="flex items-start justify-between mb-3">
<span className="inline-block px-3 py-1 bg-blue-100 text-blue-800 text-xs font-medium rounded-full">
{course.area}
</span>
<Award className="text-teal-600" size={20} />
</div>
<h3 className="text-xl font-semibold text-gray-900 mb-3 line-clamp-2">
{course.title}
</h3>
<p className="text-gray-600 text-sm mb-4 line-clamp-3">
{course.description}
</p>
<div className="space-y-2 mb-4">
<div className="flex items-center text-sm text-gray-500">
<Clock size={16} className="mr-2" />
<span>{course.duration}</span>
</div>
<div className="flex items-center text-sm text-gray-500">
<MapPin size={16} className="mr-2" />
<span>{course.campus.join(', ')}</span>
</div>
<div className="flex items-center text-sm text-gray-500">
<DollarSign size={16} className="mr-2" />
<span>{course.fees}</span>
</div>
</div>
<div className="flex items-center justify-between">
<div className="text-sm text-gray-600">
<span className="font-medium">Entry:</span> {course.entry}
</div>
<Link
href={`/courses/${course.id}`}
className="inline-flex items-center text-blue-600 hover:text-blue-700 font-medium text-sm transition-colors"
>
Learn More
<ChevronRight size={16} className="ml-1" />
</Link>
</div>
</div>
</div>
))}
</div>
)}
</div>
{/* Call to Action */}
<div className="bg-gradient-to-r from-teal-600 to-blue-600 text-white">
<div className="container mx-auto px-4 py-16">
<div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-4">Ready to Start Your Journey?</h2>
<p className="text-xl opacity-90 mb-8">
Join over 35,000 students at the world&apos;s #1 university for climate action
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link
href="/apply"
className="bg-white text-blue-600 px-8 py-3 rounded-xl font-semibold hover:bg-gray-100 transition-all duration-200"
>
Apply Now
</Link>
<Link
href="/contact"
className="border-2 border-white text-white px-8 py-3 rounded-xl font-semibold hover:bg-white hover:text-blue-600 transition-all duration-200"
>
Get Advice
</Link>
</div>
</div>
</div>
</div>
</div>
);
}
+303
View File
@@ -0,0 +1,303 @@
'use client';
import React, { useState, useEffect } from 'react';
import { Search, Filter, MapPin, Clock, DollarSign, BookOpen, Award, ChevronRight } from 'lucide-react';
import Link from 'next/link';
interface Course {
id: string;
title: string;
area: string;
duration: string;
description: string;
entry: string;
campus: string[];
fees: string;
pathways: string[];
}
export default function CoursesPage() {
const [courses, setCourses] = useState<Course[]>([]);
const [loading, setLoading] = useState(true);
const [searchQuery, setSearchQuery] = useState('');
const [selectedArea, setSelectedArea] = useState('');
const [selectedLevel, setSelectedLevel] = useState('');
const [selectedCampus, setSelectedCampus] = useState('');
const [showFilters, setShowFilters] = useState(false);
const areas = [
"Business and Law",
"Creative Arts and Design",
"Earth, Sea, Antarctic and Environment",
"Education, Humanities and Social Sciences",
"Health and Medicine",
"Science, Technology and Engineering"
];
const campuses = ["Hobart", "Launceston", "Burnie", "Sydney"];
useEffect(() => {
fetchCourses();
}, [searchQuery, selectedArea, selectedLevel, selectedCampus]);
const fetchCourses = async () => {
try {
setLoading(true);
const params = new URLSearchParams();
if (searchQuery) params.append('q', searchQuery);
if (selectedArea) params.append('area', selectedArea);
if (selectedLevel) params.append('level', selectedLevel);
if (selectedCampus) params.append('campus', selectedCampus);
const response = await fetch(`/api/courses?${params}`);
const data = await response.json();
setCourses(data.courses || []);
} catch (error) {
console.error('Error fetching courses:', error);
} finally {
setLoading(false);
}
}, [searchQuery, selectedArea, selectedLevel, selectedCampus]);
const clearFilters = () => {
setSearchQuery('');
setSelectedArea('');
setSelectedLevel('');
setSelectedCampus('');
};
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
<div className="bg-gradient-to-r from-blue-600 to-teal-600 text-white">
<div className="container mx-auto px-4 py-16">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-4">
Find Your Perfect Course
</h1>
<p className="text-xl opacity-90 mb-8">
Explore over 350 study programs at the world&apos;s #1 university for climate action
</p>
{/* Search Bar */}
<div className="relative max-w-2xl mx-auto">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400" size={20} />
<input
type="text"
placeholder="Search courses, keywords, or study areas..."
className="w-full pl-12 pr-4 py-4 rounded-xl text-gray-900 text-lg focus:outline-none focus:ring-2 focus:ring-white"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
</div>
</div>
</div>
{/* Filters */}
<div className="bg-white shadow-sm border-b">
<div className="container mx-auto px-4 py-4">
<div className="flex flex-wrap items-center gap-4">
<button
onClick={() => setShowFilters(!showFilters)}
className="flex items-center space-x-2 px-4 py-2 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors"
>
<Filter size={16} />
<span>Filters</span>
</button>
{/* Quick Filters */}
<select
value={selectedArea}
onChange={(e) => setSelectedArea(e.target.value)}
className="px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">All Study Areas</option>
{areas.map(area => (
<option key={area} value={area}>{area}</option>
))}
</select>
<select
value={selectedLevel}
onChange={(e) => setSelectedLevel(e.target.value)}
className="px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">All Levels</option>
<option value="undergraduate">Undergraduate</option>
<option value="postgraduate">Postgraduate</option>
</select>
<select
value={selectedCampus}
onChange={(e) => setSelectedCampus(e.target.value)}
className="px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">All Campuses</option>
{campuses.map(campus => (
<option key={campus} value={campus}>{campus}</option>
))}
</select>
{(searchQuery || selectedArea || selectedLevel || selectedCampus) && (
<button
onClick={clearFilters}
className="text-blue-600 hover:text-blue-700 text-sm font-medium"
>
Clear all filters
</button>
)}
</div>
</div>
</div>
{/* Results */}
<div className="container mx-auto px-4 py-8">
<div className="flex items-center justify-between mb-6">
<h2 className="text-2xl font-bold text-gray-900">
{loading ? 'Searching...' : `${courses.length} courses found`}
</h2>
<div className="flex items-center space-x-4">
<span className="text-gray-600">Sort by:</span>
<select className="px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<option>Relevance</option>
<option>Course Name A-Z</option>
<option>Study Area</option>
<option>Duration</option>
</select>
</div>
</div>
{loading ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{[...Array(6)].map((_, i) => (
<div key={i} className="bg-white rounded-xl shadow-sm p-6 animate-pulse">
<div className="h-4 bg-gray-200 rounded mb-3"></div>
<div className="h-6 bg-gray-200 rounded mb-4"></div>
<div className="h-16 bg-gray-200 rounded mb-4"></div>
<div className="space-y-2">
<div className="h-3 bg-gray-200 rounded"></div>
<div className="h-3 bg-gray-200 rounded w-3/4"></div>
</div>
</div>
))}
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{courses.map(course => (
<div key={course.id} className="bg-white rounded-xl shadow-sm hover:shadow-lg transition-all duration-300 overflow-hidden group">
<div className="p-6">
<div className="flex items-start justify-between mb-3">
<span className="px-3 py-1 bg-blue-100 text-blue-700 text-sm font-medium rounded-full">
{course.area}
</span>
<Award size={16} className="text-yellow-500" />
</div>
<h3 className="text-xl font-bold text-gray-900 mb-3 group-hover:text-blue-600 transition-colors">
{course.title}
</h3>
<p className="text-gray-600 mb-4 line-clamp-3">
{course.description}
</p>
<div className="space-y-2 mb-4">
<div className="flex items-center text-sm text-gray-500">
<Clock size={14} className="mr-2" />
<span>{course.duration}</span>
</div>
<div className="flex items-center text-sm text-gray-500">
<MapPin size={14} className="mr-2" />
<span>{course.campus.join(', ')}</span>
</div>
<div className="flex items-center text-sm text-gray-500">
<DollarSign size={14} className="mr-2" />
<span>{course.fees}</span>
</div>
<div className="flex items-center text-sm text-gray-500">
<BookOpen size={14} className="mr-2" />
<span>{course.entry}</span>
</div>
</div>
<div className="flex flex-wrap gap-2 mb-4">
{course.pathways.slice(0, 3).map(pathway => (
<span key={pathway} className="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded">
{pathway}
</span>
))}
{course.pathways.length > 3 && (
<span className="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded">
+{course.pathways.length - 3} more
</span>
)}
</div>
<div className="flex space-x-2">
<Link
href={`/courses/${course.id}`}
className="flex-1 bg-blue-600 text-white px-4 py-2 rounded-lg text-center hover:bg-blue-700 transition-colors text-sm font-medium"
>
Learn More
</Link>
<Link
href="/apply"
className="flex-1 border border-blue-600 text-blue-600 px-4 py-2 rounded-lg text-center hover:bg-blue-50 transition-colors text-sm font-medium"
>
Apply Now
</Link>
</div>
</div>
</div>
))}
</div>
)}
{!loading && courses.length === 0 && (
<div className="text-center py-16">
<div className="bg-gray-100 rounded-full w-24 h-24 flex items-center justify-center mx-auto mb-6">
<Search size={32} className="text-gray-400" />
</div>
<h3 className="text-xl font-bold text-gray-900 mb-2">No courses found</h3>
<p className="text-gray-600 mb-6">
Try adjusting your search criteria or browse all available courses.
</p>
<button
onClick={clearFilters}
className="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 transition-colors"
>
Show All Courses
</button>
</div>
)}
</div>
{/* Call to Action */}
<div className="bg-gradient-to-r from-teal-600 to-blue-600 text-white py-16">
<div className="container mx-auto px-4 text-center">
<h2 className="text-3xl font-bold mb-4">Ready to Apply?</h2>
<p className="text-xl opacity-90 mb-8">
Join thousands of students at Australia&apos;s most sustainable university
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link
href="/apply"
className="bg-white text-blue-600 px-8 py-3 rounded-xl font-semibold hover:bg-gray-100 transition-all duration-200 flex items-center justify-center"
>
Start Application
<ChevronRight size={20} className="ml-2" />
</Link>
<Link
href="/chat"
className="border-2 border-white text-white px-8 py-3 rounded-xl font-semibold hover:bg-white hover:text-blue-600 transition-all duration-200"
>
Chat with AI Assistant
</Link>
</div>
</div>
</div>
</div>
);
}
+299
View File
@@ -0,0 +1,299 @@
'use client';
import React, { useState, useEffect } from 'react';
import { Search, Filter, MapPin, Clock, DollarSign, BookOpen, Award, ChevronRight, X } from 'lucide-react';
import Link from 'next/link';
interface Course {
id: string;
title: string;
area: string;
duration: string;
description: string;
entry: string;
campus: string[];
fees: string;
pathways: string[];
}
export default function CoursesPage() {
const [courses, setCourses] = useState<Course[]>([]);
const [loading, setLoading] = useState(true);
const [searchQuery, setSearchQuery] = useState('');
const [selectedArea, setSelectedArea] = useState('');
const [selectedLevel, setSelectedLevel] = useState('');
const [selectedCampus, setSelectedCampus] = useState('');
const [showFilters, setShowFilters] = useState(false);
const areas = [
"Business and Law",
"Creative Arts and Design",
"Earth, Sea, Antarctic and Environment",
"Education, Humanities and Social Sciences",
"Health and Medicine",
"Science, Technology and Engineering"
];
const levels = ["Undergraduate", "Postgraduate"];
const campuses = ["Hobart", "Launceston", "Burnie", "Sydney"];
const fetchCourses = React.useCallback(async () => {
try {
setLoading(true);
const params = new URLSearchParams();
if (searchQuery) params.append('q', searchQuery);
if (selectedArea) params.append('area', selectedArea);
if (selectedLevel) params.append('level', selectedLevel);
if (selectedCampus) params.append('campus', selectedCampus);
const response = await fetch(`/api/courses?${params}`);
const data = await response.json();
setCourses(data.courses || []);
} catch (error) {
console.error('Error fetching courses:', error);
} finally {
setLoading(false);
}
}, [searchQuery, selectedArea, selectedLevel, selectedCampus]);
useEffect(() => {
fetchCourses();
}, [fetchCourses]);
const clearFilters = () => {
setSearchQuery('');
setSelectedArea('');
setSelectedLevel('');
setSelectedCampus('');
};
const filteredCourses = courses.filter(course => {
if (searchQuery && !course.title.toLowerCase().includes(searchQuery.toLowerCase()) &&
!course.description.toLowerCase().includes(searchQuery.toLowerCase())) {
return false;
}
if (selectedArea && course.area !== selectedArea) return false;
if (selectedCampus && !course.campus.includes(selectedCampus)) return false;
return true;
});
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
<div className="bg-gradient-to-r from-blue-600 to-teal-600 text-white">
<div className="container mx-auto px-4 py-16">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-4">
Find Your Perfect Course
</h1>
<p className="text-xl opacity-90 mb-8">
Explore over 350 study programs at the world&apos;s #1 university for climate action
</p>
{/* Search Bar */}
<div className="relative max-w-2xl mx-auto">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400" size={20} />
<input
type="text"
placeholder="Search courses by name, area, or keyword..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full pl-12 pr-16 py-4 rounded-xl text-gray-800 text-lg focus:outline-none focus:ring-4 focus:ring-white/30"
/>
<button
onClick={() => setShowFilters(!showFilters)}
className="absolute right-2 top-1/2 transform -translate-y-1/2 bg-blue-600 text-white p-2 rounded-lg hover:bg-blue-700 transition-colors"
>
<Filter size={20} />
</button>
</div>
</div>
</div>
</div>
{/* Filters */}
{showFilters && (
<div className="bg-white border-b border-gray-200 shadow-sm">
<div className="container mx-auto px-4 py-6">
<div className="flex flex-wrap gap-4 items-center justify-between">
<div className="flex flex-wrap gap-4">
<select
value={selectedArea}
onChange={(e) => setSelectedArea(e.target.value)}
className="px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">All Study Areas</option>
{areas.map(area => (
<option key={area} value={area}>{area}</option>
))}
</select>
<select
value={selectedLevel}
onChange={(e) => setSelectedLevel(e.target.value)}
className="px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">All Levels</option>
{levels.map(level => (
<option key={level} value={level}>{level}</option>
))}
</select>
<select
value={selectedCampus}
onChange={(e) => setSelectedCampus(e.target.value)}
className="px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">All Campuses</option>
{campuses.map(campus => (
<option key={campus} value={campus}>{campus}</option>
))}
</select>
</div>
<div className="flex items-center space-x-4">
<button
onClick={clearFilters}
className="flex items-center space-x-2 px-4 py-2 text-gray-600 hover:text-gray-800 transition-colors"
>
<X size={16} />
<span>Clear Filters</span>
</button>
<button
onClick={() => setShowFilters(false)}
className="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors"
>
Hide Filters
</button>
</div>
</div>
</div>
</div>
)}
{/* Results */}
<div className="container mx-auto px-4 py-8">
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold text-gray-800">
{loading ? 'Loading...' : `${filteredCourses.length} courses found`}
</h2>
{(selectedArea || selectedLevel || selectedCampus || searchQuery) && (
<button
onClick={clearFilters}
className="text-blue-600 hover:text-blue-700 font-medium transition-colors"
>
Clear all filters
</button>
)}
</div>
{loading ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{[...Array(6)].map((_, i) => (
<div key={i} className="bg-white rounded-lg p-6 shadow-sm animate-pulse">
<div className="h-4 bg-gray-200 rounded mb-2"></div>
<div className="h-6 bg-gray-200 rounded mb-4"></div>
<div className="h-20 bg-gray-200 rounded mb-4"></div>
<div className="flex space-x-2 mb-4">
<div className="h-6 bg-gray-200 rounded flex-1"></div>
<div className="h-6 bg-gray-200 rounded flex-1"></div>
</div>
</div>
))}
</div>
) : filteredCourses.length === 0 ? (
<div className="text-center py-12">
<BookOpen size={64} className="mx-auto text-gray-400 mb-4" />
<h3 className="text-xl font-semibold text-gray-600 mb-2">No courses found</h3>
<p className="text-gray-500 mb-4">Try adjusting your search criteria or clearing filters</p>
<button
onClick={clearFilters}
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors"
>
Clear Filters
</button>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredCourses.map((course) => (
<div key={course.id} className="bg-white rounded-lg shadow-sm hover:shadow-md transition-shadow border border-gray-200">
<div className="p-6">
<div className="flex items-start justify-between mb-3">
<span className="inline-block px-3 py-1 bg-blue-100 text-blue-800 text-xs font-medium rounded-full">
{course.area}
</span>
<Award className="text-teal-600" size={20} />
</div>
<h3 className="text-xl font-semibold text-gray-900 mb-3 line-clamp-2">
{course.title}
</h3>
<p className="text-gray-600 text-sm mb-4 line-clamp-3">
{course.description}
</p>
<div className="space-y-2 mb-4">
<div className="flex items-center text-sm text-gray-500">
<Clock size={16} className="mr-2" />
<span>{course.duration}</span>
</div>
<div className="flex items-center text-sm text-gray-500">
<MapPin size={16} className="mr-2" />
<span>{course.campus.join(', ')}</span>
</div>
<div className="flex items-center text-sm text-gray-500">
<DollarSign size={16} className="mr-2" />
<span>{course.fees}</span>
</div>
</div>
<div className="flex items-center justify-between">
<div className="text-sm text-gray-600">
<span className="font-medium">Entry:</span> {course.entry}
</div>
<Link
href={`/courses/${course.id}`}
className="inline-flex items-center text-blue-600 hover:text-blue-700 font-medium text-sm transition-colors"
>
Learn More
<ChevronRight size={16} className="ml-1" />
</Link>
</div>
</div>
</div>
))}
</div>
)}
</div>
{/* Call to Action */}
<div className="bg-gradient-to-r from-teal-600 to-blue-600 text-white">
<div className="container mx-auto px-4 py-16">
<div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-4">Ready to Start Your Journey?</h2>
<p className="text-xl opacity-90 mb-8">
Join over 35,000 students at the world&apos;s #1 university for climate action
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link
href="/apply"
className="bg-white text-blue-600 px-8 py-3 rounded-xl font-semibold hover:bg-gray-100 transition-all duration-200"
>
Apply Now
</Link>
<Link
href="/contact"
className="border-2 border-white text-white px-8 py-3 rounded-xl font-semibold hover:bg-white hover:text-blue-600 transition-all duration-200"
>
Get Advice
</Link>
</div>
</div>
</div>
</div>
</div>
);
}
+477
View File
@@ -0,0 +1,477 @@
'use client';
import React, { useEffect } from 'react'
import { useAuth } from '@/components/providers/MockAuthProvider'
import { useLanguage } from '@/components/providers/LanguageProvider'
import { useRouter } from 'next/navigation'
import {
Calendar,
DollarSign,
User,
BookOpen,
Clock,
AlertCircle,
LogOut,
Languages,
Heart,
Shield,
BarChart3,
Star
} from 'lucide-react'
import Link from 'next/link'
// Extended UserProfile type to include relationships
interface ExtendedUserProfile {
id: string
email: string
name: string
role: string
year?: number
faculty?: string
balance?: number
enrollments?: Array<{
id: string
grade?: string
course: {
id: string
name: string
code: string
schedule?: string
credits: number
}
}>
advisor?: {
id: string
name: string
email: string
}
}
export default function DashboardPage() {
const { user, userProfile, logout } = useAuth()
const { t, language, setLanguage } = useLanguage()
const router = useRouter()
// Type assertion for extended user profile
const extendedProfile = userProfile as ExtendedUserProfile
useEffect(() => {
if (!user) {
router.push('/')
}
}, [user, router])
const handleLogout = async () => {
await logout()
}
const toggleLanguage = () => {
setLanguage(language === 'en' ? 'ar' : 'en')
}
if (!user || !userProfile) {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
<p className="text-gray-600">Loading dashboard...</p>
</div>
</div>
)
}
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
<header className="bg-white shadow-sm border-b">
<div className="container mx-auto px-4 py-4">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
<Link href="/" className="flex items-center space-x-2">
<div className="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center">
<span className="text-white font-bold text-sm">UP</span>
</div>
<span className="text-xl font-bold text-gray-900">University Portal</span>
</Link>
<nav className="hidden md:flex space-x-6">
<Link href="/dashboard" className="text-blue-600 font-medium">
{t('dashboard')}
</Link>
<Link href="/accessibility" className="text-gray-600 hover:text-blue-600">
{t('accessibility')}
</Link>
<Link href="/wellbeing" className="text-gray-600 hover:text-blue-600">
{t('wellbeing')}
</Link>
{userProfile.role === 'ADMIN' && (
<Link href="/admin" className="text-gray-600 hover:text-blue-600">
{t('admin')}
</Link>
)}
</nav>
</div>
<div className="flex items-center space-x-4">
<button
onClick={toggleLanguage}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors"
>
<Languages size={16} />
<span className="text-sm font-medium">{language.toUpperCase()}</span>
</button>
<div className="flex items-center space-x-3">
<div className="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center">
<span className="text-white text-sm font-medium">
{userProfile.name.charAt(0)}
</span>
</div>
<div className="hidden md:block">
<p className="text-sm font-medium text-gray-900">{userProfile.name}</p>
<p className="text-xs text-gray-500">{userProfile.role}</p>
</div>
</div>
<button
onClick={handleLogout}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-red-100 hover:bg-red-200 transition-colors text-red-700"
>
<LogOut size={16} />
<span className="text-sm font-medium">{t('logout')}</span>
</button>
</div>
</div>
</div>
</header>
{/* Main Content */}
<main className="container mx-auto px-4 py-8">
{/* Welcome Section */}
<div className="mb-8">
<h1 className="text-3xl font-bold text-gray-900 mb-2">
Welcome back, {userProfile.name}!
</h1>
<p className="text-gray-600">
Here&apos;s your personalized dashboard with important updates and quick actions.
</p>
</div>
{/* Personalized Alert */}
{userProfile.role === 'STUDENT' && userProfile.faculty === 'Arts' && (
<div className="mb-8 p-4 bg-blue-50 border border-blue-200 rounded-lg">
<div className="flex items-center space-x-3">
<AlertCircle className="text-blue-600" size={20} />
<div>
<h3 className="font-medium text-blue-900">
{t('registration_opens')}
</h3>
<p className="text-sm text-blue-800">
Registration for spring semester opens on August 15th for Year 2 students.
</p>
</div>
</div>
</div>
)}
{/* Stats Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
{userProfile.role === 'STUDENT' && (
<>
<StatCard
title={t('tuition_balance')}
value={`$${userProfile.balance?.toLocaleString() || '0'}`}
icon={<DollarSign size={20} />}
color="green"
/>
<StatCard
title={t('my_courses')}
value={extendedProfile.enrollments?.length.toString() || '0'}
icon={<BookOpen size={20} />}
color="blue"
/>
<StatCard
title="GPA"
value="3.7"
icon={<Star size={20} />}
color="yellow"
/>
<StatCard
title="Credits"
value="45"
icon={<Clock size={20} />}
color="purple"
/>
</>
)}
{userProfile.role === 'ADMIN' && (
<>
<StatCard
title="Active Students"
value="12,543"
icon={<User size={20} />}
color="blue"
/>
<StatCard
title="Avg Response Time"
value="1.2s"
icon={<Clock size={20} />}
color="green"
/>
<StatCard
title="Satisfaction Rate"
value="94%"
icon={<Star size={20} />}
color="yellow"
/>
<StatCard
title="Tickets Resolved"
value="1,247"
icon={<BarChart3 size={20} />}
color="purple"
/>
</>
)}
</div>
{/* Main Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Left Column - Student specific */}
<div className="lg:col-span-2 space-y-6">
{userProfile.role === 'STUDENT' && (
<>
{/* Course Schedule */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200">
<div className="p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
Current Courses
</h3>
<div className="space-y-3">
{extendedProfile.enrollments?.map((enrollment) => (
<div key={enrollment.id} className="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div>
<h4 className="font-medium text-gray-900">
{enrollment.course.name}
</h4>
<p className="text-sm text-gray-600">
{enrollment.course.code} {enrollment.course.schedule}
</p>
</div>
<div className="text-right">
<span className="text-sm font-medium text-gray-900">
{enrollment.grade || 'In Progress'}
</span>
<p className="text-xs text-gray-500">
{enrollment.course.credits} credits
</p>
</div>
</div>
))}
</div>
</div>
</div>
{/* Upcoming Deadlines */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200">
<div className="p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
Upcoming Deadlines
</h3>
<div className="space-y-3">
<div className="flex items-center justify-between p-3 bg-yellow-50 rounded-lg border border-yellow-200">
<div>
<h4 className="font-medium text-yellow-900">
Art History Essay
</h4>
<p className="text-sm text-yellow-800">
Due in 3 days
</p>
</div>
<Calendar className="text-yellow-600" size={20} />
</div>
<div className="flex items-center justify-between p-3 bg-blue-50 rounded-lg border border-blue-200">
<div>
<h4 className="font-medium text-blue-900">
Course Registration
</h4>
<p className="text-sm text-blue-800">
Opens August 15th
</p>
</div>
<Calendar className="text-blue-600" size={20} />
</div>
</div>
</div>
</div>
</>
)}
{/* Quick Actions */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200">
<div className="p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
Quick Actions
</h3>
<div className="grid grid-cols-2 gap-4">
<Link
href="/accessibility"
className="flex items-center space-x-3 p-4 bg-green-50 rounded-lg hover:bg-green-100 transition-colors"
>
<Shield className="text-green-600" size={20} />
<span className="font-medium text-green-900">
{t('accessibility')}
</span>
</Link>
<Link
href="/wellbeing"
className="flex items-center space-x-3 p-4 bg-pink-50 rounded-lg hover:bg-pink-100 transition-colors"
>
<Heart className="text-pink-600" size={20} />
<span className="font-medium text-pink-900">
{t('wellbeing')}
</span>
</Link>
{userProfile.role === 'ADMIN' && (
<Link
href="/admin"
className="flex items-center space-x-3 p-4 bg-blue-50 rounded-lg hover:bg-blue-100 transition-colors"
>
<BarChart3 className="text-blue-600" size={20} />
<span className="font-medium text-blue-900">
{t('admin')}
</span>
</Link>
)}
</div>
</div>
</div>
</div>
{/* Right Column - Advisor & Support */}
<div className="space-y-6">
{/* Advisor Contact */}
{userProfile.role === 'STUDENT' && extendedProfile.advisor && (
<div className="bg-white rounded-lg shadow-sm border border-gray-200">
<div className="p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
{t('advisor_contact')}
</h3>
<div className="space-y-3">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-blue-600 rounded-full flex items-center justify-center">
<span className="text-white text-sm font-medium">
{extendedProfile.advisor.name.charAt(0)}
</span>
</div>
<div>
<p className="font-medium text-gray-900">
{extendedProfile.advisor.name}
</p>
<p className="text-sm text-gray-600">
{extendedProfile.advisor.email}
</p>
</div>
</div>
<button className="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 transition-colors">
Schedule Meeting
</button>
</div>
</div>
</div>
)}
{/* Recent Activity */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200">
<div className="p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
Recent Activity
</h3>
<div className="space-y-3">
<div className="flex items-center space-x-3 text-sm">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="text-gray-600">
Submitted Art History assignment
</span>
</div>
<div className="flex items-center space-x-3 text-sm">
<div className="w-2 h-2 bg-blue-500 rounded-full"></div>
<span className="text-gray-600">
Accessed course materials
</span>
</div>
<div className="flex items-center space-x-3 text-sm">
<div className="w-2 h-2 bg-yellow-500 rounded-full"></div>
<span className="text-gray-600">
Chatted with AI assistant
</span>
</div>
</div>
</div>
</div>
{/* Support Resources */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200">
<div className="p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
Support Resources
</h3>
<div className="space-y-3">
<a
href="#"
className="flex items-center justify-between p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors"
>
<span className="text-sm text-gray-700">Academic Support</span>
<span className="text-xs text-gray-500">24/7</span>
</a>
<a
href="#"
className="flex items-center justify-between p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors"
>
<span className="text-sm text-gray-700">Technical Help</span>
<span className="text-xs text-gray-500">Mon-Fri</span>
</a>
<a
href="#"
className="flex items-center justify-between p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors"
>
<span className="text-sm text-gray-700">Counseling Services</span>
<span className="text-xs text-gray-500">Available</span>
</a>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
)
}
// Helper Components
const StatCard: React.FC<{
title: string
value: string
icon: React.ReactNode
color: 'blue' | 'green' | 'yellow' | 'purple'
}> = ({ title, value, icon, color }) => {
const colorClasses = {
blue: 'bg-blue-50 border-blue-200 text-blue-600',
green: 'bg-green-50 border-green-200 text-green-600',
yellow: 'bg-yellow-50 border-yellow-200 text-yellow-600',
purple: 'bg-purple-50 border-purple-200 text-purple-600',
}
return (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<div className="flex items-center justify-between mb-4">
<div className={`p-2 rounded-lg ${colorClasses[color]}`}>
{icon}
</div>
</div>
<div>
<p className="text-2xl font-bold text-gray-900">{value}</p>
<p className="text-sm text-gray-600">{title}</p>
</div>
</div>
)
}
+185
View File
@@ -0,0 +1,185 @@
@import "tailwindcss";
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
:root {
--background: #ffffff;
--foreground: #171717;
--primary-blue: #1e3a8a;
--primary-teal: #0f766e;
--accent-gold: #f59e0b;
--text-primary: #111827;
--text-secondary: #6b7280;
--surface-light: #f8fafc;
--border-light: #e5e7eb;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
line-height: 1.6;
}
/* Custom animations */
@keyframes fade-in-up {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fade-in-up-delay {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fade-in-up-delay-2 {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes float {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
}
@keyframes pulse-glow {
0%, 100% {
box-shadow: 0 0 5px rgba(59, 130, 246, 0.5);
}
50% {
box-shadow: 0 0 20px rgba(59, 130, 246, 0.8);
}
}
.animate-fade-in-up {
animation: fade-in-up 0.8s ease-out;
}
.animate-fade-in-up-delay {
animation: fade-in-up-delay 0.8s ease-out 0.2s both;
}
.animate-fade-in-up-delay-2 {
animation: fade-in-up-delay-2 0.8s ease-out 0.4s both;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
.animate-pulse-glow {
animation: pulse-glow 2s ease-in-out infinite;
}
/* Professional gradients */
.gradient-primary {
background: linear-gradient(135deg, var(--primary-blue) 0%, var(--primary-teal) 100%);
}
.gradient-accent {
background: linear-gradient(135deg, var(--accent-gold) 0%, #f97316 100%);
}
.gradient-surface {
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
}
/* Glass morphism effects */
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.glass-dark {
background: rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* Typography improvements */
.text-hero {
font-size: clamp(2.5rem, 8vw, 5rem);
font-weight: 800;
line-height: 1.1;
letter-spacing: -0.02em;
}
.text-display {
font-size: clamp(1.875rem, 4vw, 3rem);
font-weight: 700;
line-height: 1.2;
letter-spacing: -0.01em;
}
.text-body-large {
font-size: 1.125rem;
line-height: 1.7;
}
/* Professional hover effects */
.hover-lift {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.hover-lift:hover {
transform: translateY(-8px);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
/* Loading states */
.skeleton {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: loading 1.5s infinite;
}
@keyframes loading {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
/* Responsive improvements */
@media (max-width: 768px) {
.text-hero {
line-height: 1.2;
}
.container {
padding-left: 1rem;
padding-right: 1rem;
}
}
+130
View File
@@ -0,0 +1,130 @@
@import "tailwindcss";
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
:root {
--background: #ffffff;
--foreground: #171717;
--primary-blue: #1e3a8a;
--primary-teal: #0f766e;
--accent-gold: #f59e0b;
--text-primary: #111827;
--text-secondary: #6b7280;
--surface-light: #f8fafc;
--border-light: #e5e7eb;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
line-height: 1.6;
}
/* Custom animations */
@keyframes fade-in-up {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes float {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
}
@keyframes pulse-glow {
0%, 100% {
box-shadow: 0 0 5px rgba(59, 130, 246, 0.5);
}
50% {
box-shadow: 0 0 20px rgba(59, 130, 246, 0.8);
}
}
.animate-fade-in-up {
animation: fade-in-up 0.8s ease-out;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
.animate-pulse-glow {
animation: pulse-glow 2s ease-in-out infinite;
}
/* Professional gradients */
.gradient-primary {
background: linear-gradient(135deg, var(--primary-blue) 0%, var(--primary-teal) 100%);
}
.gradient-accent {
background: linear-gradient(135deg, var(--accent-gold) 0%, #f97316 100%);
}
/* Glass morphism effects */
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.glass-dark {
background: rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* Typography improvements */
.text-hero {
font-size: clamp(2.5rem, 8vw, 5rem);
font-weight: 800;
line-height: 1.1;
letter-spacing: -0.02em;
}
.text-display {
font-size: clamp(1.875rem, 4vw, 3rem);
font-weight: 700;
line-height: 1.2;
letter-spacing: -0.01em;
}
/* Professional hover effects */
.hover-lift {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.hover-lift:hover {
transform: translateY(-8px);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
/* Responsive improvements */
@media (max-width: 768px) {
.text-hero {
line-height: 1.2;
}
.container {
padding-left: 1rem;
padding-right: 1rem;
}
}
+163 -12
View File
@@ -1,26 +1,177 @@
@import "tailwindcss";
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--background: #ffffff;
--foreground: #171717;
--primary-blue: #1e3a8a;
--primary-teal: #0f766e;
--accent-gold: #f59e0b;
--text-primary: #111827;
--text-secondary: #6b7280;
--surface-light: #f8fafc;
--border-light: #e5e7eb;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
/* RTL Support */
[dir="rtl"] {
text-align: right;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
[dir="rtl"] .ltr-only {
display: none;
}
[dir="ltr"] .rtl-only {
display: none;
}
/* Consistent Container Classes */
.page-container {
margin-left: auto;
margin-right: auto;
max-width: 80rem;
padding: 2rem 1rem;
}
.section-container {
margin-left: auto;
margin-right: auto;
max-width: 72rem;
padding: 1.5rem 1rem;
}
.content-container {
margin-left: auto;
margin-right: auto;
max-width: 64rem;
padding: 1rem;
}
/* RTL Specific Margins and Paddings */
[dir="rtl"] .ml-auto {
margin-left: unset;
margin-right: auto;
}
[dir="rtl"] .mr-auto {
margin-right: unset;
margin-left: auto;
}
[dir="rtl"] .space-x-4 > * + * {
margin-left: unset;
margin-right: 1rem;
}
/* Base styles */
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
line-height: 1.6;
}
/* Custom animations */
@keyframes fade-in-up {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes float {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
}
@keyframes pulse-glow {
0%, 100% {
box-shadow: 0 0 5px rgba(59, 130, 246, 0.5);
}
50% {
box-shadow: 0 0 20px rgba(59, 130, 246, 0.8);
}
}
.animate-fade-in-up {
animation: fade-in-up 0.8s ease-out;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
.animate-pulse-glow {
animation: pulse-glow 2s ease-in-out infinite;
}
/* Professional gradients */
.gradient-primary {
background: linear-gradient(135deg, var(--primary-blue) 0%, var(--primary-teal) 100%);
}
.gradient-accent {
background: linear-gradient(135deg, var(--accent-gold) 0%, #f97316 100%);
}
/* Glass morphism effects */
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.glass-dark {
background: rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* Typography improvements */
.text-hero {
font-size: clamp(2.5rem, 8vw, 5rem);
font-weight: 800;
line-height: 1.1;
letter-spacing: -0.02em;
}
.text-display {
font-size: clamp(1.875rem, 4vw, 3rem);
font-weight: 700;
line-height: 1.2;
letter-spacing: -0.01em;
}
/* Professional hover effects */
.hover-lift {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.hover-lift:hover {
transform: translateY(-8px);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
/* Responsive improvements */
@media (max-width: 768px) {
.text-hero {
line-height: 1.2;
}
.container {
padding-left: 1rem;
padding-right: 1rem;
}
}
+302
View File
@@ -0,0 +1,302 @@
'use client';
import { useLanguage } from '@/components/providers/LanguageProvider';
import { Lightbulb, Rocket, Brain, Zap, Target, Globe, Award, TrendingUp } from 'lucide-react';
const InnovationPage = () => {
const { language } = useLanguage();
const isRTL = language === 'ar';
const innovations = [
{
title: "Ocean Intelligence Platform",
category: "Marine Technology",
description: "AI-powered ocean monitoring system providing real-time data on marine ecosystems, helping predict and prevent environmental disasters.",
impact: "$50M+ in marine conservation funding secured",
status: "Deployed globally",
icon: <Brain className="w-8 h-8" />,
color: "text-blue-600",
bgColor: "bg-blue-50"
},
{
title: "Antarctic Climate Predictive Models",
category: "Climate Science",
description: "Revolutionary machine learning models that predict ice sheet behavior with 95% accuracy, informing global climate policy.",
impact: "Used by 15+ government climate agencies",
status: "Active research",
icon: <Zap className="w-8 h-8" />,
color: "text-cyan-600",
bgColor: "bg-cyan-50"
},
{
title: "Sustainable Aquaculture Systems",
category: "Food Security",
description: "Breakthrough closed-loop aquaculture technology reducing environmental impact while tripling fish production efficiency.",
impact: "Licensed to 200+ global fish farms",
status: "Commercial deployment",
icon: <Target className="w-8 h-8" />,
color: "text-green-600",
bgColor: "bg-green-50"
},
{
title: "Polar Medicine Innovations",
category: "Healthcare",
description: "Medical devices and treatments adapted for extreme environments, revolutionizing remote healthcare delivery.",
impact: "Saving lives in 40+ remote locations",
status: "Medical trials",
icon: <Rocket className="w-8 h-8" />,
color: "text-purple-600",
bgColor: "bg-purple-50"
}
];
const partnerships = [
{
name: "Antarctic Treaty System",
type: "International Treaty",
role: "Research Coordinator",
impact: "Leading climate research for 54 nations"
},
{
name: "Commonwealth Scientific Research",
type: "Government Partnership",
role: "Strategic Research Partner",
impact: "£100M+ joint research funding"
},
{
name: "International Ocean Discovery",
type: "Global Consortium",
role: "Core Institution",
impact: "20+ breakthrough marine discoveries"
},
{
name: "World Climate Research Programme",
type: "UN Partnership",
role: "Lead Research Institution",
impact: "Informing global climate policy"
}
];
const startups = [
{
name: "OceanMind Analytics",
founded: "2022",
sector: "Marine AI",
valuation: "$15M",
description: "AI platform predicting fish migration patterns for sustainable fishing"
},
{
name: "Antarctic Genomics",
founded: "2023",
sector: "Biotechnology",
valuation: "$8M",
description: "Developing new medicines from Antarctic microorganisms"
},
{
name: "Climate Futures Tech",
founded: "2021",
sector: "Climate Tech",
valuation: "$25M",
description: "Software solutions for climate adaptation planning"
},
{
name: "Polar Healthcare Solutions",
founded: "2023",
sector: "HealthTech",
valuation: "$12M",
description: "Medical devices for extreme environment healthcare"
}
];
const metrics = [
{ value: "150+", label: "Patents Filed", description: "Active intellectual property portfolio" },
{ value: "$500M+", label: "Research Impact", description: "Annual economic impact of research" },
{ value: "40+", label: "Spin-off Companies", description: "Successful research commercialization" },
{ value: "85%", label: "Industry Adoption", description: "Research translated to real-world applications" }
];
return (
<div className={`min-h-screen bg-gradient-to-br from-purple-50 to-blue-50 ${isRTL ? 'rtl' : 'ltr'}`}>
{/* Hero Section */}
<div className="bg-gradient-to-r from-purple-900 via-blue-900 to-indigo-900 text-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
<div className="text-center">
<div className="flex justify-center mb-6">
<div className="bg-white/10 backdrop-blur-sm rounded-full p-6">
<Lightbulb className="w-16 h-16 text-yellow-300" />
</div>
</div>
<h1 className="text-5xl md:text-7xl font-bold mb-6">
Innovation Hub
</h1>
<p className="text-xl md:text-2xl mb-8 text-purple-100 max-w-4xl mx-auto">
Where breakthrough research meets real-world impact. Discover how UTAS
innovations are solving global challenges and creating tomorrow&apos;s solutions.
</p>
<div className="flex flex-wrap justify-center gap-6">
<div className="bg-white/10 backdrop-blur-sm rounded-lg px-6 py-4">
<div className="text-3xl font-bold text-yellow-300">150+</div>
<div className="text-sm text-purple-100">Patents</div>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-lg px-6 py-4">
<div className="text-3xl font-bold text-yellow-300">40+</div>
<div className="text-sm text-purple-100">Startups</div>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-lg px-6 py-4">
<div className="text-3xl font-bold text-yellow-300">$500M+</div>
<div className="text-sm text-purple-100">Impact</div>
</div>
</div>
</div>
</div>
</div>
{/* Key Metrics */}
<div className="bg-white py-16">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-center mb-12 text-gray-900">
Innovation Impact
</h2>
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
{metrics.map((metric, index) => (
<div key={index} className="text-center">
<div className="text-4xl md:text-5xl font-bold text-purple-600 mb-2">
{metric.value}
</div>
<div className="text-lg font-semibold text-gray-900 mb-1">
{metric.label}
</div>
<div className="text-sm text-gray-600">
{metric.description}
</div>
</div>
))}
</div>
</div>
</div>
{/* Breakthrough Innovations */}
<div className="py-16 bg-gradient-to-r from-purple-50 to-blue-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-4xl font-bold text-center mb-12 text-gray-900">
Breakthrough Innovations
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{innovations.map((innovation, index) => (
<div key={index} className="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow duration-300">
<div className="flex items-start gap-4 mb-4">
<div className={`${innovation.bgColor} ${innovation.color} p-3 rounded-lg`}>
{innovation.icon}
</div>
<div className="flex-1">
<div className="bg-purple-100 text-purple-800 px-3 py-1 rounded-full text-sm font-semibold inline-block mb-2">
{innovation.category}
</div>
<h3 className="text-xl font-bold text-gray-900 mb-2">
{innovation.title}
</h3>
<div className="bg-green-100 text-green-800 px-2 py-1 rounded text-sm font-medium inline-block">
{innovation.status}
</div>
</div>
</div>
<p className="text-gray-700 mb-4">
{innovation.description}
</p>
<div className="bg-gradient-to-r from-blue-500 to-purple-500 text-white px-4 py-2 rounded-lg text-sm font-semibold">
<TrendingUp className="w-4 h-4 inline mr-2" />
{innovation.impact}
</div>
</div>
))}
</div>
</div>
</div>
{/* Global Partnerships */}
<div className="py-16 bg-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-4xl font-bold text-center mb-12 text-gray-900">
Global Research Partnerships
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{partnerships.map((partnership, index) => (
<div key={index} className="bg-gradient-to-r from-blue-50 to-purple-50 rounded-xl p-6">
<div className="flex items-center gap-3 mb-3">
<Globe className="w-6 h-6 text-blue-600" />
<h3 className="text-xl font-bold text-gray-900">
{partnership.name}
</h3>
</div>
<div className="text-sm text-blue-600 font-semibold mb-2">
{partnership.type} {partnership.role}
</div>
<p className="text-gray-700">
{partnership.impact}
</p>
</div>
))}
</div>
</div>
</div>
{/* UTAS Spin-offs */}
<div className="py-16 bg-gradient-to-r from-blue-50 to-purple-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-4xl font-bold text-center mb-12 text-gray-900">
UTAS-Born Startups
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{startups.map((startup, index) => (
<div key={index} className="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow duration-300">
<div className="flex justify-between items-start mb-4">
<div>
<h3 className="text-xl font-bold text-gray-900 mb-1">
{startup.name}
</h3>
<div className="text-sm text-gray-600">
Founded {startup.founded} {startup.sector}
</div>
</div>
<div className="bg-green-100 text-green-800 px-3 py-1 rounded-full text-sm font-semibold">
{startup.valuation}
</div>
</div>
<p className="text-gray-700">
{startup.description}
</p>
</div>
))}
</div>
</div>
</div>
{/* Call to Action */}
<div className="bg-gradient-to-r from-purple-600 to-blue-600 py-16">
<div className="max-w-4xl mx-auto text-center px-4 sm:px-6 lg:px-8">
<Award className="w-16 h-16 text-yellow-300 mx-auto mb-6" />
<h2 className="text-4xl font-bold text-white mb-6">
Join the Innovation Revolution
</h2>
<p className="text-xl text-purple-100 mb-8">
Be part of the next generation of innovators solving global challenges
through cutting-edge research and real-world applications.
</p>
<div className="flex flex-wrap justify-center gap-4">
<button className="bg-white text-purple-600 px-8 py-4 rounded-lg font-semibold hover:bg-purple-50 transition-colors text-lg">
Research Programs
</button>
<button className="border-2 border-white text-white px-8 py-4 rounded-lg font-semibold hover:bg-white hover:text-purple-600 transition-colors text-lg">
Innovation Partnerships
</button>
</div>
</div>
</div>
</div>
);
};
export default InnovationPage;
+41 -12
View File
@@ -1,6 +1,13 @@
'use client';
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { AuthProvider } from "@/components/providers/MockAuthProvider";
import { LanguageProvider, useLanguage } from "@/components/providers/LanguageProvider";
import FloatingChatbot from "@/components/Chat/FloatingChatbot";
import { GDPRBanner } from "@/components/GDPRBanner";
import SimplifiedNavigation from "@/components/Navigation/SimplifiedNavigation";
const geistSans = Geist({
variable: "--font-geist-sans",
@@ -13,22 +20,44 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "University Portal - Next Generation Student Experience",
description: "AI-enabled university portal with personalized content and 24/7 support",
keywords: "university, portal, student, AI, education",
authors: [{ name: "University IT Department" }],
viewport: "width=device-width, initial-scale=1",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
function RootLayoutContent({ children }: { children: React.ReactNode }) {
const { language } = useLanguage();
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{children}
<html lang={language} dir={language === 'ar' ? 'rtl' : 'ltr'} className="scroll-smooth">
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
<AuthProvider>
<SimplifiedNavigation />
<main className="min-h-screen bg-gray-50">
<div className="page-container">
{children}
</div>
</main>
<FloatingChatbot position={language === 'ar' ? 'bottom-left' : 'bottom-right'} theme="blue" />
<GDPRBanner />
</AuthProvider>
</body>
</html>
);
}
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<LanguageProvider>
<RootLayoutContent>
{children}
</RootLayoutContent>
</LanguageProvider>
);
}
+414
View File
@@ -0,0 +1,414 @@
'use client';
import React, { useState } from 'react'
import { useAuth } from '@/components/providers/MockAuthProvider'
import { useLanguage } from '@/components/providers/LanguageProvider'
import {
Globe,
BookOpen,
Users,
MessageSquare,
Heart,
Shield,
BarChart3,
Languages,
LogIn,
GraduationCap,
Star,
Clock,
MapPin
} from 'lucide-react'
import Link from 'next/link'
export default function HomePage() {
const { user, login, loading } = useAuth()
const { t, language, setLanguage } = useLanguage()
const [loginForm, setLoginForm] = useState({ email: '', password: '' })
const [showLogin, setShowLogin] = useState(false)
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault()
try {
await login(loginForm.email, loginForm.password)
} catch (error) {
console.error('Login failed:', error)
}
}
const toggleLanguage = () => {
setLanguage(language === 'en' ? 'ar' : 'en')
}
if (user) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
{/* Header */}
<header className="bg-white shadow-sm">
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
<div className="flex items-center space-x-3">
<GraduationCap size={32} className="text-blue-600" />
<h1 className="text-2xl font-bold text-gray-900">University Portal</h1>
</div>
<div className="flex items-center space-x-4">
<button
onClick={toggleLanguage}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors"
>
<Languages size={16} />
<span className="text-sm font-medium">{language.toUpperCase()}</span>
</button>
<Link
href="/dashboard"
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
>
{t('dashboard')}
</Link>
</div>
</div>
</header>
{/* Welcome Section */}
<section className="py-20">
<div className="container mx-auto px-4 text-center">
<h2 className="text-4xl font-bold text-gray-900 mb-6">
{t('welcome')}
</h2>
<p className="text-xl text-gray-600 mb-8 max-w-2xl mx-auto">
Experience the future of university services with AI-powered assistance,
personalized content, and comprehensive support.
</p>
<div className="flex justify-center space-x-4">
<Link
href="/dashboard"
className="bg-blue-600 text-white px-8 py-3 rounded-lg text-lg hover:bg-blue-700 transition-colors"
>
Go to Dashboard
</Link>
<Link
href="/wellbeing"
className="bg-pink-600 text-white px-8 py-3 rounded-lg text-lg hover:bg-pink-700 transition-colors flex items-center space-x-2"
>
<Heart size={20} />
<span>{t('wellbeing')}</span>
</Link>
</div>
</div>
</section>
{/* Features Grid */}
<section className="py-16 bg-white">
<div className="container mx-auto px-4">
<h3 className="text-3xl font-bold text-center text-gray-900 mb-12">
Flagship Features
</h3>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
<FeatureCard
icon={<MessageSquare size={24} />}
title="24/7 AI Assistant"
description="Get instant answers to your questions in English or Arabic with our GPT-powered chatbot."
/>
<FeatureCard
icon={<Users size={24} />}
title="Personalized Dashboard"
description="View your timetable, tuition balance, and advisor contact in one place."
/>
<FeatureCard
icon={<Shield size={24} />}
title="Accessibility First"
description="Automated WCAG compliance checking with AI-generated alt text suggestions."
/>
<FeatureCard
icon={<Heart size={24} />}
title="Mental Health Support"
description="Dedicated wellbeing chat with professional counselor referrals."
/>
<FeatureCard
icon={<BarChart3 size={24} />}
title="Smart Feedback"
description="Real-time satisfaction surveys with live dashboard updates."
/>
<FeatureCard
icon={<Globe size={24} />}
title="Multilingual Support"
description="Full interface available in English and Arabic with RTL support."
/>
</div>
</div>
</section>
{/* Quick Actions */}
<section className="py-16 bg-gray-50">
<div className="container mx-auto px-4">
<h3 className="text-3xl font-bold text-center text-gray-900 mb-12">
Quick Actions
</h3>
<div className="grid md:grid-cols-4 gap-6">
<QuickAction
icon={<BookOpen size={20} />}
title="Course Registration"
description="Register for fall courses"
href="/courses"
/>
<QuickAction
icon={<Star size={20} />}
title="Scholarships"
description="View available scholarships"
href="/scholarships"
/>
<QuickAction
icon={<Clock size={20} />}
title="Academic Calendar"
description="Important dates & deadlines"
href="/calendar"
/>
<QuickAction
icon={<MapPin size={20} />}
title="Campus Map"
description="Find buildings & facilities"
href="/map"
/>
</div>
</div>
</section>
</div>
)
}
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
{/* Header */}
<header className="bg-white shadow-sm">
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
<div className="flex items-center space-x-3">
<GraduationCap size={32} className="text-blue-600" />
<h1 className="text-2xl font-bold text-gray-900">University Portal</h1>
</div>
<div className="flex items-center space-x-4">
<button
onClick={toggleLanguage}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors"
>
<Languages size={16} />
<span className="text-sm font-medium">{language.toUpperCase()}</span>
</button>
<button
onClick={() => setShowLogin(true)}
className="flex items-center space-x-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
>
<LogIn size={16} />
<span>{t('login')}</span>
</button>
</div>
</div>
</header>
{/* Hero Section */}
<section className="py-20">
<div className="container mx-auto px-4 text-center">
<h2 className="text-5xl font-bold text-gray-900 mb-6">
{t('welcome')}
</h2>
<p className="text-xl text-gray-600 mb-8 max-w-3xl mx-auto">
Experience the future of university services with AI-powered assistance,
personalized content, comprehensive accessibility features, and 24/7 support.
</p>
<div className="flex justify-center space-x-4">
<button
onClick={() => setShowLogin(true)}
className="bg-blue-600 text-white px-8 py-3 rounded-lg text-lg hover:bg-blue-700 transition-colors"
>
{t('login')}
</button>
<Link
href="/wellbeing"
className="bg-pink-600 text-white px-8 py-3 rounded-lg text-lg hover:bg-pink-700 transition-colors flex items-center space-x-2"
>
<Heart size={20} />
<span>{t('wellbeing')}</span>
</Link>
</div>
</div>
</section>
{/* Features Section */}
<section className="py-16 bg-white">
<div className="container mx-auto px-4">
<h3 className="text-3xl font-bold text-center text-gray-900 mb-12">
Flagship Capabilities
</h3>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
<FeatureCard
icon={<MessageSquare size={24} />}
title="24/7 Conversational Assistant"
description="Multilingual GPT-4 powered chatbot answering 20+ FAQs with human escalation support."
/>
<FeatureCard
icon={<Users size={24} />}
title="Personalized Dashboard"
description="Login-based content showing timetable, tuition balance, and advisor contact from mock DB."
/>
<FeatureCard
icon={<Shield size={24} />}
title="Automated Accessibility"
description="WCAG 2.2 compliance checking with AI-generated alt text suggestions via Vision API."
/>
<FeatureCard
icon={<Heart size={24} />}
title="Mental Health Triage"
description="Empathic chat flow with trigger phrase detection and counselor calendar integration."
/>
<FeatureCard
icon={<BarChart3 size={24} />}
title="Smart Feedback Surveys"
description="One-click CSAT with real-time dashboard updates in under 5 seconds."
/>
<FeatureCard
icon={<Globe size={24} />}
title="Multilingual Interface"
description="Full English/Arabic support with RTL layout and cultural adaptations."
/>
</div>
</div>
</section>
{/* Demo Accounts */}
<section className="py-16 bg-gray-50">
<div className="container mx-auto px-4">
<h3 className="text-3xl font-bold text-center text-gray-900 mb-12">
Demo Accounts
</h3>
<div className="grid md:grid-cols-3 gap-6 max-w-4xl mx-auto">
<DemoAccount
name="Sara Johnson"
role="Year 2 Arts Student"
email="sara.year2@university.edu"
password="sara123"
features={['Registration opens Aug 15', 'Tuition balance: $2,500', 'Advisor: Dr. Smith']}
/>
<DemoAccount
name="John Smith"
role="Postgraduate Engineering"
email="john.postgrad@university.edu"
password="john123"
features={['Research project status', 'Tuition balance: $1,200', 'Advisor: Dr. Johnson']}
/>
<DemoAccount
name="Admin User"
role="System Administrator"
email="admin@university.edu"
password="admin123"
features={['Full system access', 'Analytics dashboard', 'User management']}
/>
</div>
</div>
</section>
{/* Login Modal */}
{showLogin && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg p-8 w-full max-w-md">
<h3 className="text-2xl font-bold mb-6 text-center">{t('login')}</h3>
<form onSubmit={handleLogin} className="space-y-4">
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-2">
Email
</label>
<input
type="email"
id="email"
value={loginForm.email}
onChange={(e) => setLoginForm({ ...loginForm, email: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-gray-700 mb-2">
Password
</label>
<input
type="password"
id="password"
value={loginForm.password}
onChange={(e) => setLoginForm({ ...loginForm, password: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
</div>
<div className="flex space-x-4">
<button
type="submit"
disabled={loading}
className="flex-1 bg-blue-600 text-white py-2 rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50"
>
{loading ? 'Signing in...' : t('login')}
</button>
<button
type="button"
onClick={() => setShowLogin(false)}
className="flex-1 bg-gray-300 text-gray-700 py-2 rounded-lg hover:bg-gray-400 transition-colors"
>
Cancel
</button>
</div>
</form>
</div>
</div>
)}
</div>
)
}
// Helper Components
const FeatureCard: React.FC<{ icon: React.ReactNode; title: string; description: string }> = ({
icon,
title,
description,
}) => (
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<div className="text-blue-600 mb-4">{icon}</div>
<h4 className="text-lg font-semibold text-gray-900 mb-2">{title}</h4>
<p className="text-gray-600">{description}</p>
</div>
)
const QuickAction: React.FC<{
icon: React.ReactNode
title: string
description: string
href: string
}> = ({ icon, title, description, href }) => (
<Link
href={href}
className="bg-white p-6 rounded-lg shadow-sm border border-gray-200 hover:shadow-md transition-shadow"
>
<div className="text-blue-600 mb-3">{icon}</div>
<h4 className="font-semibold text-gray-900 mb-1">{title}</h4>
<p className="text-sm text-gray-600">{description}</p>
</Link>
)
const DemoAccount: React.FC<{
name: string
role: string
email: string
password: string
features: string[]
}> = ({ name, role, email, password, features }) => (
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
<h4 className="font-semibold text-gray-900 mb-1">{name}</h4>
<p className="text-sm text-gray-600 mb-4">{role}</p>
<div className="space-y-2 mb-4">
<p className="text-sm"><span className="font-medium">Email:</span> {email}</p>
<p className="text-sm"><span className="font-medium">Password:</span> {password}</p>
</div>
<ul className="text-sm text-gray-600 space-y-1">
{features.map((feature, index) => (
<li key={index} className="flex items-center space-x-2">
<span className="w-1.5 h-1.5 bg-blue-600 rounded-full"></span>
<span>{feature}</span>
</li>
))}
</ul>
</div>
)
+647
View File
@@ -0,0 +1,647 @@
'use client';
import React, { useState, useEffect } from 'react';
import { useAuth } from '@/components/providers/MockAuthProvider';
import { useLanguage } from '@/components/providers/LanguageProvider';
import {
Globe,
BookOpen,
Users,
MessageSquare,
Heart,
Shield,
BarChart3,
Languages,
LogIn,
GraduationCap,
Star,
MapPin,
Trophy,
Waves,
Leaf,
ChevronRight,
Award,
Zap,
MapIcon,
Phone,
Mail,
ExternalLink
} from 'lucide-react';
import Link from 'next/link';
import Image from 'next/image';
import { useRouter } from 'next/navigation';
export default function HomePage() {
const { user, login, loading } = useAuth();
const { language, setLanguage } = useLanguage();
const router = useRouter();
const [loginForm, setLoginForm] = useState({ email: '', password: '' });
const [showLogin, setShowLogin] = useState(false);
const [currentSlide, setCurrentSlide] = useState(0);
const [animatedStats, setAnimatedStats] = useState({ students: 0, programs: 0, satisfaction: 0 });
// Auto-slide for hero banner
useEffect(() => {
const timer = setInterval(() => {
setCurrentSlide((prev) => (prev + 1) % 3);
}, 5000);
return () => clearInterval(timer);
}, []);
// Animate statistics
useEffect(() => {
const timer = setTimeout(() => {
const interval = setInterval(() => {
setAnimatedStats(prev => ({
students: prev.students < 35000 ? prev.students + 500 : 35000,
programs: prev.programs < 350 ? prev.programs + 5 : 350,
satisfaction: prev.satisfaction < 92 ? prev.satisfaction + 1 : 92
}));
}, 50);
setTimeout(() => clearInterval(interval), 2000);
}, 1000);
return () => clearTimeout(timer);
}, []);
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
try {
const success = await login(loginForm.email, loginForm.password);
if (success) {
router.push('/dashboard');
} else {
alert('Invalid credentials. Use: student@university.edu / password123 or admin@university.edu / admin123');
}
} catch (error) {
console.error('Login failed:', error);
}
};
const toggleLanguage = () => {
setLanguage(language === 'en' ? 'ar' : 'en');
};
const heroSlides = [
{
title: language === 'en' ? "#1 in Climate Action Globally" : "#1 عالمياً في العمل المناخي",
subtitle: language === 'en' ? "Leading the world in sustainability and environmental innovation" : "رائدة عالمياً في الاستدامة والابتكار البيئي",
image: "https://images.unsplash.com/photo-1569163139394-de4e4f43e4e3?w=1200&h=600&fit=crop",
cta: language === 'en' ? "Discover Our Impact" : "اكتشف تأثيرنا"
},
{
title: language === 'en' ? "World-Class Marine & Antarctic Science" : "علوم بحرية وقطبية عالمية المستوى",
subtitle: language === 'en' ? "Pioneering research in marine ecosystems and climate science" : "أبحاث رائدة في النظم البيئية البحرية وعلوم المناخ",
image: "https://images.unsplash.com/photo-1583212292454-1fe6229603b7?w=1200&h=600&fit=crop",
cta: language === 'en' ? "Explore Research" : "اكتشف البحوث"
},
{
title: language === 'en' ? "Transform Your Future with UTAS" : "حوّل مستقبلك مع جامعة تاسمانيا",
subtitle: language === 'en' ? "Join Australia's most sustainable university" : "انضم إلى أكثر الجامعات الأسترالية استدامة",
image: "https://images.unsplash.com/photo-1523050854058-8df90110c9f1?w=1200&h=600&fit=crop",
cta: language === 'en' ? "Start Your Journey" : "ابدأ رحلتك"
}
];
const studyAreas = [
{
title: language === 'en' ? "Business and Law" : "الأعمال والقانون",
description: language === 'en' ? "Leading programs in commerce, law, and business innovation" : "برامج رائدة في التجارة والقانون وابتكار الأعمال",
icon: <Users className="w-8 h-8" />,
color: "from-blue-500 to-blue-600"
},
{
title: language === 'en' ? "Earth, Sea, Antarctic & Environment" : "الأرض والبحار والقطب الجنوبي والبيئة",
description: language === 'en' ? "World-renowned research in climate and environmental sciences" : "أبحاث مشهورة عالمياً في علوم المناخ والبيئة",
icon: <Waves className="w-8 h-8" />,
color: "from-teal-500 to-cyan-600"
},
{
title: language === 'en' ? "Health and Medicine" : "الصحة والطب",
description: language === 'en' ? "Innovative health programs with real-world impact" : "برامج صحية مبتكرة ذات تأثير حقيقي",
icon: <Heart className="w-8 h-8" />,
color: "from-red-500 to-pink-600"
},
{
title: language === 'en' ? "Science, Technology & Engineering" : "العلوم والتكنولوجيا والهندسة",
description: language === 'en' ? "Cutting-edge programs in STEM fields" : "برامج متطورة في مجالات العلوم والتكنولوجيا",
icon: <Zap className="w-8 h-8" />,
color: "from-purple-500 to-indigo-600"
},
{
title: language === 'en' ? "Creative Arts and Design" : "الفنون الإبداعية والتصميم",
description: language === 'en' ? "Inspiring creativity and artistic excellence" : "إلهام الإبداع والتميز الفني",
icon: <Star className="w-8 h-8" />,
color: "from-orange-500 to-yellow-600"
},
{
title: language === 'en' ? "Education, Humanities & Social Sciences" : "التعليم والعلوم الإنسانية والاجتماعية",
description: language === 'en' ? "Shaping the future of education and society" : "تشكيل مستقبل التعليم والمجتمع",
icon: <BookOpen className="w-8 h-8" />,
color: "from-green-500 to-emerald-600"
}
];
const achievements = [
{
rank: "#1",
title: language === 'en' ? "Climate Action Globally" : "العمل المناخي عالمياً",
subtitle: language === 'en' ? "THE Impact Rankings 2025" : "تصنيف التأثير 2025",
icon: <Trophy className="w-6 h-6" />
},
{
rank: "5★",
title: language === 'en' ? "QS Overall Rating" : "التقييم العام QS",
subtitle: language === 'en' ? "Excellence in Education" : "التميز في التعليم",
icon: <Award className="w-6 h-6" />
},
{
rank: "Top 1%",
title: language === 'en' ? "Global Universities" : "الجامعات العالمية",
subtitle: language === 'en' ? "World University Rankings" : "تصنيف الجامعات العالمية",
icon: <Globe className="w-6 h-6" />
}
];
if (user) {
router.push('/dashboard');
return null;
}
return (
<div className={`min-h-screen ${language === 'ar' ? 'rtl' : 'ltr'}`}>
{/* Header */}
<header className="bg-white/95 backdrop-blur-sm shadow-lg border-b border-gray-200 sticky top-0 z-50">
<div className="container mx-auto px-4">
<div className="flex items-center justify-between h-20">
{/* Logo */}
<div className="flex items-center space-x-4">
<div className="bg-gradient-to-br from-blue-600 to-teal-600 p-2 rounded-xl">
<GraduationCap size={32} className="text-white" />
</div>
<div>
<h1 className="text-2xl font-bold bg-gradient-to-r from-blue-600 to-teal-600 bg-clip-text text-transparent">
UTAS Portal
</h1>
<p className="text-xs text-gray-500">University of Tasmania</p>
</div>
</div>
{/* Navigation */}
<nav className="hidden md:flex items-center space-x-8">
<Link href="#study" className="text-gray-700 hover:text-blue-600 font-medium transition-colors">
{language === 'en' ? 'Study' : 'الدراسة'}
</Link>
<Link href="#research" className="text-gray-700 hover:text-blue-600 font-medium transition-colors">
{language === 'en' ? 'Research' : 'البحث'}
</Link>
<Link href="#campus" className="text-gray-700 hover:text-blue-600 font-medium transition-colors">
{language === 'en' ? 'Campus Life' : 'الحياة الجامعية'}
</Link>
<Link href="#about" className="text-gray-700 hover:text-blue-600 font-medium transition-colors">
{language === 'en' ? 'About' : 'حول'}
</Link>
</nav>
{/* Language & Login */}
<div className="flex items-center space-x-4">
<button
onClick={toggleLanguage}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors"
>
<Languages size={18} />
<span className="font-medium">{language === 'en' ? 'ع' : 'EN'}</span>
</button>
<button
onClick={() => setShowLogin(true)}
className="bg-gradient-to-r from-blue-600 to-teal-600 text-white px-6 py-2 rounded-xl hover:shadow-lg transition-all duration-200 font-medium flex items-center space-x-2"
>
<LogIn size={18} />
<span>{language === 'en' ? 'Portal Login' : 'دخول البوابة'}</span>
</button>
</div>
</div>
</div>
</header>
{/* Hero Section */}
<section className="relative h-screen overflow-hidden">
{heroSlides.map((slide, index) => (
<div
key={index}
className={`absolute inset-0 transition-transform duration-1000 ease-in-out ${
index === currentSlide ? 'translate-x-0' :
index < currentSlide ? '-translate-x-full' : 'translate-x-full'
}`}
style={{
backgroundImage: `linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.6)), url(${slide.image})`,
backgroundSize: 'cover',
backgroundPosition: 'center'
}}
>
<div className="absolute inset-0 flex items-center justify-center">
<div className="text-center text-white max-w-4xl px-4">
<h1 className="text-5xl md:text-7xl font-bold mb-6 animate-fade-in-up">
{slide.title}
</h1>
<p className="text-xl md:text-2xl mb-8 opacity-90 animate-fade-in-up-delay">
{slide.subtitle}
</p>
<button className="bg-gradient-to-r from-teal-500 to-blue-600 text-white px-8 py-4 rounded-xl text-lg font-semibold hover:shadow-2xl transition-all duration-300 transform hover:scale-105 animate-fade-in-up-delay-2">
{slide.cta} <ChevronRight className="inline ml-2" size={20} />
</button>
</div>
</div>
</div>
))}
{/* Slide Indicators */}
<div className="absolute bottom-8 left-1/2 transform -translate-x-1/2 flex space-x-3">
{heroSlides.map((_, index) => (
<button
key={index}
onClick={() => setCurrentSlide(index)}
className={`w-3 h-3 rounded-full transition-all duration-300 ${
index === currentSlide ? 'bg-white scale-125' : 'bg-white/50'
}`}
/>
))}
</div>
{/* Scroll Indicator */}
<div className="absolute bottom-20 left-1/2 transform -translate-x-1/2 animate-bounce">
<div className="w-1 h-16 bg-white/30 rounded-full">
<div className="w-1 h-4 bg-white rounded-full animate-pulse"></div>
</div>
</div>
</section>
{/* Statistics Section */}
<section className="py-20 bg-gradient-to-r from-blue-600 to-teal-600 text-white">
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 text-center">
<div className="space-y-4">
<div className="text-5xl font-bold">{animatedStats.students.toLocaleString()}+</div>
<div className="text-xl opacity-90">{language === 'en' ? 'Students Worldwide' : 'طالب حول العالم'}</div>
</div>
<div className="space-y-4">
<div className="text-5xl font-bold">{animatedStats.programs}+</div>
<div className="text-xl opacity-90">{language === 'en' ? 'Study Programs' : 'برنامج دراسي'}</div>
</div>
<div className="space-y-4">
<div className="text-5xl font-bold">{animatedStats.satisfaction}%</div>
<div className="text-xl opacity-90">{language === 'en' ? 'Student Satisfaction' : 'رضا الطلاب'}</div>
</div>
</div>
</div>
</section>
{/* Achievements Banner */}
<section className="py-16 bg-gradient-to-r from-gray-900 to-blue-900 text-white">
<div className="container mx-auto px-4">
<div className="text-center mb-12">
<h2 className="text-4xl font-bold mb-4">
{language === 'en' ? 'Globally Recognized Excellence' : 'تميز معترف به عالمياً'}
</h2>
<p className="text-xl opacity-90">
{language === 'en' ? 'Leading the world in sustainability and innovation' : 'رائدة عالمياً في الاستدامة والابتكار'}
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{achievements.map((achievement, index) => (
<div key={index} className="bg-white/10 backdrop-blur-sm rounded-2xl p-8 text-center hover:bg-white/15 transition-all duration-300">
<div className="flex justify-center mb-4 text-teal-400">
{achievement.icon}
</div>
<div className="text-3xl font-bold text-teal-400 mb-2">{achievement.rank}</div>
<div className="text-xl font-semibold mb-2">{achievement.title}</div>
<div className="text-sm opacity-75">{achievement.subtitle}</div>
</div>
))}
</div>
</div>
</section>
{/* Study Areas */}
<section id="study" className="py-20 bg-gray-50">
<div className="container mx-auto px-4">
<div className="text-center mb-16">
<h2 className="text-4xl md:text-5xl font-bold text-gray-900 mb-4">
{language === 'en' ? 'Discover Your Pathway' : 'اكتشف مسارك'}
</h2>
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
{language === 'en'
? 'Choose from world-class programs designed to prepare you for the future'
: 'اختر من بين البرامج عالمية المستوى المصممة لإعدادك للمستقبل'
}
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{studyAreas.map((area, index) => (
<div
key={index}
className="group bg-white rounded-2xl shadow-lg hover:shadow-2xl transition-all duration-500 overflow-hidden transform hover:-translate-y-2"
>
<div className={`h-2 bg-gradient-to-r ${area.color}`}></div>
<div className="p-8">
<div className={`inline-flex p-4 rounded-2xl bg-gradient-to-r ${area.color} text-white mb-6 group-hover:scale-110 transition-transform duration-300`}>
{area.icon}
</div>
<h3 className="text-xl font-bold text-gray-900 mb-4 group-hover:text-blue-600 transition-colors">
{area.title}
</h3>
<p className="text-gray-600 mb-6">
{area.description}
</p>
<button className="text-blue-600 font-semibold hover:text-blue-800 transition-colors flex items-center">
{language === 'en' ? 'Learn More' : 'اعرف أكثر'}
<ChevronRight size={16} className="ml-1 group-hover:translate-x-1 transition-transform" />
</button>
</div>
</div>
))}
</div>
</div>
</section>
{/* AI Features Showcase */}
<section className="py-20 bg-gradient-to-br from-blue-900 via-purple-900 to-teal-900 text-white relative overflow-hidden">
<div className="absolute inset-0 opacity-10">
<div className="absolute inset-0 bg-repeat" style={{
backgroundImage: `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.4'%3E%3Ccircle cx='30' cy='30' r='1'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`,
backgroundSize: '60px 60px'
}}></div>
</div>
<div className="container mx-auto px-4 relative z-10">
<div className="text-center mb-16">
<h2 className="text-4xl md:text-5xl font-bold mb-4">
{language === 'en' ? 'AI-Powered Student Experience' : 'تجربة طلابية مدعومة بالذكاء الاصطناعي'}
</h2>
<p className="text-xl opacity-90 max-w-3xl mx-auto">
{language === 'en'
? 'Experience the future of education with our intelligent portal features'
: 'اختبر مستقبل التعليم مع ميزات البوابة الذكية'
}
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
<div className="bg-white/10 backdrop-blur-sm rounded-2xl p-6 hover:bg-white/20 transition-all duration-300">
<MessageSquare size={40} className="text-teal-400 mb-4" />
<h3 className="text-xl font-bold mb-3">
{language === 'en' ? '24/7 AI Assistant' : 'مساعد ذكي 24/7'}
</h3>
<p className="text-sm opacity-90">
{language === 'en'
? 'Multilingual support in English and Arabic with smart FAQ responses'
: 'دعم متعدد اللغات بالإنجليزية والعربية مع ردود ذكية'
}
</p>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-2xl p-6 hover:bg-white/20 transition-all duration-300">
<Shield size={40} className="text-blue-400 mb-4" />
<h3 className="text-xl font-bold mb-3">
{language === 'en' ? 'Smart Accessibility' : 'إمكانية وصول ذكية'}
</h3>
<p className="text-sm opacity-90">
{language === 'en'
? 'AI-powered alt-text generation and WCAG compliance checking'
: 'توليد نص بديل بالذكاء الاصطناعي وفحص التوافق مع معايير الوصول'
}
</p>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-2xl p-6 hover:bg-white/20 transition-all duration-300">
<Heart size={40} className="text-pink-400 mb-4" />
<h3 className="text-xl font-bold mb-3">
{language === 'en' ? 'Mental Health Support' : 'دعم الصحة النفسية'}
</h3>
<p className="text-sm opacity-90">
{language === 'en'
? 'AI-powered mental health triage with crisis detection and escalation'
: 'فرز الصحة النفسية بالذكاء الاصطناعي مع كشف الأزمات'
}
</p>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-2xl p-6 hover:bg-white/20 transition-all duration-300">
<BarChart3 size={40} className="text-green-400 mb-4" />
<h3 className="text-xl font-bold mb-3">
{language === 'en' ? 'Smart Analytics' : 'تحليلات ذكية'}
</h3>
<p className="text-sm opacity-90">
{language === 'en'
? 'Real-time dashboards with predictive insights and personalized recommendations'
: 'لوحات معلومات فورية مع رؤى تنبؤية وتوصيات شخصية'
}
</p>
</div>
</div>
</div>
</section>
{/* Campus Locations */}
<section id="campus" className="py-20 bg-white">
<div className="container mx-auto px-4">
<div className="text-center mb-16">
<h2 className="text-4xl md:text-5xl font-bold text-gray-900 mb-4">
{language === 'en' ? 'Our Campuses' : 'حرمنا الجامعي'}
</h2>
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
{language === 'en'
? 'Study at world-class facilities across Australia'
: 'ادرس في مرافق عالمية المستوى عبر أستراليا'
}
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
{[
{ name: 'Hobart', location: 'Tasmania, Australia', image: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&h=300&fit=crop' },
{ name: 'Launceston', location: 'Tasmania, Australia', image: 'https://images.unsplash.com/photo-1523050854058-8df90110c9f1?w=400&h=300&fit=crop' },
{ name: 'Burnie', location: 'Tasmania, Australia', image: 'https://images.unsplash.com/photo-1541339907198-e08756dedf3f?w=400&h=300&fit=crop' },
{ name: 'Sydney', location: 'NSW, Australia', image: 'https://images.unsplash.com/photo-1506973035872-a4ec16b8e8d9?w=400&h=300&fit=crop' }
].map((campus, index) => (
<div key={index} className="group relative overflow-hidden rounded-2xl shadow-lg hover:shadow-2xl transition-all duration-500">
<Image
src={campus.image}
alt={campus.name}
width={400}
height={300}
className="w-full h-64 object-cover group-hover:scale-110 transition-transform duration-500"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent">
<div className="absolute bottom-6 left-6 text-white">
<h3 className="text-2xl font-bold mb-2">{campus.name}</h3>
<p className="flex items-center opacity-90">
<MapPin size={16} className="mr-1" />
{campus.location}
</p>
</div>
</div>
<div className="absolute top-4 right-4 bg-white/20 backdrop-blur-sm rounded-full p-2 opacity-0 group-hover:opacity-100 transition-opacity duration-300">
<ExternalLink size={16} className="text-white" />
</div>
</div>
))}
</div>
</div>
</section>
{/* Footer */}
<footer className="bg-gray-900 text-white py-16">
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 md:grid-cols-4 gap-12">
<div className="col-span-1 md:col-span-2">
<div className="flex items-center space-x-4 mb-6">
<div className="bg-gradient-to-br from-blue-600 to-teal-600 p-2 rounded-xl">
<GraduationCap size={32} className="text-white" />
</div>
<div>
<h3 className="text-2xl font-bold">University of Tasmania</h3>
<p className="text-gray-400">{language === 'en' ? '#1 in Climate Action Globally' : '#1 عالمياً في العمل المناخي'}</p>
</div>
</div>
<p className="text-gray-400 mb-6 max-w-md">
{language === 'en'
? 'Leading the world in sustainability research and education. Join us in creating a better future for all.'
: 'رائدة عالمياً في أبحاث وتعليم الاستدامة. انضم إلينا في خلق مستقبل أفضل للجميع.'
}
</p>
<div className="flex space-x-4">
<div className="bg-blue-600 p-2 rounded-lg">
<Award size={20} />
</div>
<div className="bg-teal-600 p-2 rounded-lg">
<Leaf size={20} />
</div>
<div className="bg-green-600 p-2 rounded-lg">
<Globe size={20} />
</div>
</div>
</div>
<div>
<h4 className="text-lg font-semibold mb-6">{language === 'en' ? 'Quick Links' : 'روابط سريعة'}</h4>
<ul className="space-y-3">
<li><Link href="#study" className="text-gray-400 hover:text-white transition-colors">{language === 'en' ? 'Study Areas' : 'مجالات الدراسة'}</Link></li>
<li><Link href="#research" className="text-gray-400 hover:text-white transition-colors">{language === 'en' ? 'Research' : 'البحث'}</Link></li>
<li><Link href="#campus" className="text-gray-400 hover:text-white transition-colors">{language === 'en' ? 'Campus Life' : 'الحياة الجامعية'}</Link></li>
<li><Link href="/privacy" className="text-gray-400 hover:text-white transition-colors">{language === 'en' ? 'Privacy Policy' : 'سياسة الخصوصية'}</Link></li>
</ul>
</div>
<div>
<h4 className="text-lg font-semibold mb-6">{language === 'en' ? 'Contact Us' : 'اتصل بنا'}</h4>
<div className="space-y-3">
<div className="flex items-center space-x-3">
<Phone size={16} className="text-teal-400" />
<span className="text-gray-400">+61 3 6226 6200</span>
</div>
<div className="flex items-center space-x-3">
<Mail size={16} className="text-teal-400" />
<span className="text-gray-400">info@utas.edu.au</span>
</div>
<div className="flex items-center space-x-3">
<MapIcon size={16} className="text-teal-400" />
<span className="text-gray-400">Hobart, Tasmania</span>
</div>
</div>
</div>
</div>
<div className="border-t border-gray-800 mt-12 pt-8 text-center">
<p className="text-gray-400">
{language === 'en'
? '© 2025 University of Tasmania. All rights reserved. CRICOS Provider Code 00586B'
: '© 2025 جامعة تاسمانيا. جميع الحقوق محفوظة. رمز مقدم CRICOS 00586B'
}
</p>
</div>
</div>
</footer>
{/* Login Modal */}
{showLogin && (
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-2xl shadow-2xl max-w-md w-full p-8 transform transition-all duration-300 scale-100">
<div className="text-center mb-8">
<div className="bg-gradient-to-br from-blue-600 to-teal-600 p-3 rounded-2xl inline-block mb-4">
<LogIn size={32} className="text-white" />
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2">
{language === 'en' ? 'Welcome Back' : 'مرحباً بعودتك'}
</h2>
<p className="text-gray-600">
{language === 'en' ? 'Sign in to access your portal' : 'سجل الدخول للوصول إلى بوابتك'}
</p>
</div>
<form onSubmit={handleLogin} className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
{language === 'en' ? 'Email Address' : 'عنوان البريد الإلكتروني'}
</label>
<input
type="email"
value={loginForm.email}
onChange={(e) => setLoginForm({...loginForm, email: e.target.value})}
className="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200"
placeholder={language === 'en' ? 'Enter your email' : 'أدخل بريدك الإلكتروني'}
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
{language === 'en' ? 'Password' : 'كلمة المرور'}
</label>
<input
type="password"
value={loginForm.password}
onChange={(e) => setLoginForm({...loginForm, password: e.target.value})}
className="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200"
placeholder={language === 'en' ? 'Enter your password' : 'أدخل كلمة المرور'}
required
/>
</div>
<div className="bg-blue-50 border border-blue-200 rounded-xl p-4">
<p className="text-sm text-blue-800 mb-2 font-medium">
{language === 'en' ? 'Demo Accounts:' : 'حسابات تجريبية:'}
</p>
<div className="text-xs text-blue-700 space-y-1">
<div>Student: student@university.edu / password123</div>
<div>Admin: admin@university.edu / admin123</div>
</div>
</div>
<div className="flex space-x-4">
<button
type="button"
onClick={() => setShowLogin(false)}
className="flex-1 px-6 py-3 border border-gray-300 text-gray-700 rounded-xl hover:bg-gray-50 transition-all duration-200 font-medium"
>
{language === 'en' ? 'Cancel' : 'إلغاء'}
</button>
<button
type="submit"
disabled={loading}
className="flex-1 bg-gradient-to-r from-blue-600 to-teal-600 text-white px-6 py-3 rounded-xl hover:shadow-lg transition-all duration-200 font-medium disabled:opacity-50"
>
{loading ? (language === 'en' ? 'Signing in...' : 'جارٍ تسجيل الدخول...') : (language === 'en' ? 'Sign In' : 'تسجيل الدخول')}
</button>
</div>
</form>
</div>
</div>
)}
</div>
);
}
+1299 -95
View File
File diff suppressed because it is too large Load Diff
+216
View File
@@ -0,0 +1,216 @@
'use client';
import { useLanguage } from '@/components/providers/LanguageProvider';
import { ArrowLeftIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
export default function PrivacyPage() {
const { language, t } = useLanguage();
const content = {
en: {
title: 'Privacy Policy',
lastUpdated: 'Last updated: December 2024',
sections: [
{
title: 'Information We Collect',
content: [
'Personal identification information (name, email, student ID)',
'Academic information (courses, grades, enrollment status)',
'Chat conversations with our AI assistant',
'Survey responses and feedback',
'Accessibility audit data',
'Usage analytics and performance data'
]
},
{
title: 'How We Use Your Information',
content: [
'Provide personalized educational services',
'Improve our AI assistant and chatbot responses',
'Generate analytics and insights for better services',
'Ensure accessibility compliance',
'Communicate important updates and notifications',
'Comply with legal and regulatory requirements'
]
},
{
title: 'Data Security',
content: [
'We implement industry-standard security measures',
'All data is encrypted in transit and at rest',
'Access to personal data is restricted to authorized personnel',
'Regular security audits and assessments',
'Incident response procedures for data breaches'
]
},
{
title: 'Your Rights',
content: [
'Access your personal data',
'Correct inaccurate information',
'Request deletion of your data',
'Object to processing of your data',
'Data portability',
'Withdraw consent at any time'
]
},
{
title: 'Third-Party Services',
content: [
'OpenAI for AI chat functionality',
'Supabase for authentication and database',
'Azure Computer Vision for accessibility features',
'Analytics providers for usage insights'
]
},
{
title: 'Contact Us',
content: [
'For privacy-related questions or concerns:',
'Email: privacy@university.edu',
'Phone: +1 (555) 123-4567',
'Office: Student Services Building, Room 101'
]
}
]
},
ar: {
title: 'سياسة الخصوصية',
lastUpdated: 'آخر تحديث: ديسمبر 2024',
sections: [
{
title: 'المعلومات التي نجمعها',
content: [
'معلومات الهوية الشخصية (الاسم، البريد الإلكتروني، رقم الطالب)',
'المعلومات الأكاديمية (المقررات، الدرجات، حالة التسجيل)',
'محادثات الدردشة مع المساعد الذكي',
'ردود الاستبيانات والتعليقات',
'بيانات تدقيق إمكانية الوصول',
'تحليلات الاستخدام وبيانات الأداء'
]
},
{
title: 'كيف نستخدم معلوماتك',
content: [
'تقديم خدمات تعليمية مخصصة',
'تحسين المساعد الذكي وردود الدردشة',
'إنشاء تحليلات ورؤى لخدمات أفضل',
'ضمان امتثال إمكانية الوصول',
'التواصل بشأن التحديثات والإشعارات المهمة',
'الامتثال للمتطلبات القانونية والتنظيمية'
]
},
{
title: 'أمان البيانات',
content: [
'نطبق تدابير أمنية معيارية في الصناعة',
'جميع البيانات مشفرة أثناء النقل والتخزين',
'الوصول إلى البيانات الشخصية مقيد للموظفين المخولين',
'عمليات تدقيق وتقييم أمنية منتظمة',
'إجراءات الاستجابة للحوادث لخروق البيانات'
]
},
{
title: 'حقوقك',
content: [
'الوصول إلى بياناتك الشخصية',
'تصحيح المعلومات غير الدقيقة',
'طلب حذف بياناتك',
'الاعتراض على معالجة بياناتك',
'قابلية نقل البيانات',
'سحب الموافقة في أي وقت'
]
},
{
title: 'خدمات الطرف الثالث',
content: [
'OpenAI لوظائف الدردشة الذكية',
'Supabase للمصادقة وقاعدة البيانات',
'Azure Computer Vision لميزات إمكانية الوصول',
'موفرو التحليلات لرؤى الاستخدام'
]
},
{
title: 'اتصل بنا',
content: [
'للأسئلة أو المخاوف المتعلقة بالخصوصية:',
'البريد الإلكتروني: privacy@university.edu',
'الهاتف: +1 (555) 123-4567',
'المكتب: مبنى خدمات الطلاب، الغرفة 101'
]
}
]
}
};
const currentContent = content[language];
return (
<div className="min-h-screen bg-gray-50 py-8">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="bg-white rounded-lg shadow-lg p-6 md:p-8">
<div className="flex items-center mb-6">
<Link
href="/"
className="flex items-center text-blue-600 hover:text-blue-800 mr-4"
>
<ArrowLeftIcon className="h-5 w-5 mr-2" />
{t('back')}
</Link>
</div>
<div className="mb-8">
<h1 className="text-3xl font-bold text-gray-900 mb-2">
{currentContent.title}
</h1>
<p className="text-gray-600">{currentContent.lastUpdated}</p>
</div>
<div className="space-y-8">
{currentContent.sections.map((section, index) => (
<div key={index} className="border-l-4 border-blue-500 pl-6">
<h2 className="text-xl font-semibold text-gray-900 mb-4">
{section.title}
</h2>
<ul className="space-y-2">
{section.content.map((item, itemIndex) => (
<li key={itemIndex} className="text-gray-700 leading-relaxed">
{item.includes('@') || item.includes('+') ? (
<span className="font-medium">{item}</span>
) : (
<> {item}</>
)}
</li>
))}
</ul>
</div>
))}
</div>
<div className="mt-12 p-6 bg-blue-50 rounded-lg">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center">
<span className="text-white font-bold">i</span>
</div>
</div>
<div className="ml-4">
<p className="text-blue-800 font-medium">
{language === 'en'
? 'Questions about this privacy policy?'
: 'أسئلة حول سياسة الخصوصية؟'}
</p>
<p className="text-blue-700 mt-1">
{language === 'en'
? 'Contact our privacy team at privacy@university.edu'
: 'اتصل بفريق الخصوصية على privacy@university.edu'}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
+224
View File
@@ -0,0 +1,224 @@
'use client';
import { useLanguage } from '@/components/providers/LanguageProvider';
import { Award, Trophy, Globe, Star, BarChart3 } from 'lucide-react';
const RankingsPage = () => {
const { language, t } = useLanguage();
const isRTL = language === 'ar';
const rankings = [
{
rank: "#1",
title: "Climate Action Research",
organization: "Times Higher Education Impact Rankings 2024",
description: "Leading the world in climate change research and solutions",
icon: <Globe className="w-8 h-8" />,
color: "text-green-600",
bgColor: "bg-green-50"
},
{
rank: "#1",
title: "Antarctic & Marine Science",
organization: "Shanghai Ranking Global Ranking of Academic Subjects",
description: "World's premier institution for polar and marine research",
icon: <Award className="w-8 h-8" />,
color: "text-blue-600",
bgColor: "bg-blue-50"
},
{
rank: "Top 10",
title: "Small University Rankings",
organization: "Times Higher Education World University Rankings",
description: "Excellence in education and research at intimate scale",
icon: <Trophy className="w-8 h-8" />,
color: "text-yellow-600",
bgColor: "bg-yellow-50"
},
{
rank: "Top 2%",
title: "Global University Rankings",
organization: "QS World University Rankings 2024",
description: "Among the world's top universities for quality education",
icon: <Star className="w-8 h-8" />,
color: "text-purple-600",
bgColor: "bg-purple-50"
}
];
const achievements = [
{
metric: "40+",
label: "Years in Antarctica",
description: "Continuous research presence since 1983"
},
{
metric: "95%",
label: "Graduate Employment",
description: "Employment rate within 6 months of graduation"
},
{
metric: "300+",
label: "Research Partners",
description: "Global collaborations across 6 continents"
},
{
metric: "$200M+",
label: "Research Income",
description: "Annual research funding and grants"
}
];
const impacts = [
{
title: "Antarctic Gateway Strategy",
description: "UTAS serves as Australia's primary gateway to Antarctic research, hosting the Australian Antarctic Division headquarters and leading international polar science initiatives.",
impact: "50% of Australia's Antarctic research"
},
{
title: "Climate Solutions Hub",
description: "Our Climate Futures research centre develops cutting-edge solutions for climate adaptation and mitigation, directly informing global policy.",
impact: "Advising 30+ governments worldwide"
},
{
title: "Marine Innovation",
description: "IMAS leads breakthrough research in sustainable fisheries, ocean conservation, and marine biotechnology with real-world applications.",
impact: "$500M+ industry impact annually"
}
];
return (
<div className={`min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 ${isRTL ? 'rtl' : 'ltr'}`}>
{/* Hero Section */}
<div className="bg-gradient-to-r from-blue-900 via-blue-800 to-teal-700 text-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20">
<div className="text-center">
<h1 className="text-4xl md:text-6xl font-bold mb-6">
World-Class Excellence
</h1>
<p className="text-xl md:text-2xl mb-8 text-blue-100 max-w-4xl mx-auto">
Discover why UTAS ranks among the world's leading universities for research impact,
student satisfaction, and global influence
</p>
<div className="flex flex-wrap justify-center gap-4">
<div className="bg-white/10 backdrop-blur-sm rounded-lg px-6 py-3">
<div className="text-3xl font-bold text-yellow-300">#1</div>
<div className="text-sm text-blue-100">Climate Research</div>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-lg px-6 py-3">
<div className="text-3xl font-bold text-yellow-300">#1</div>
<div className="text-sm text-blue-100">Antarctic Science</div>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-lg px-6 py-3">
<div className="text-3xl font-bold text-yellow-300">Top 2%</div>
<div className="text-sm text-blue-100">Globally</div>
</div>
</div>
</div>
</div>
</div>
{/* Rankings Grid */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
<h2 className="text-3xl font-bold text-center mb-12 text-gray-900">
International Recognition
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-16">
{rankings.map((ranking, index) => (
<div key={index} className="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow duration-300">
<div className="flex items-start gap-4">
<div className={`${ranking.bgColor} ${ranking.color} p-3 rounded-lg`}>
{ranking.icon}
</div>
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<span className={`text-3xl font-bold ${ranking.color}`}>
{ranking.rank}
</span>
<h3 className="text-xl font-semibold text-gray-900">
{ranking.title}
</h3>
</div>
<p className="text-sm text-gray-600 mb-2 font-medium">
{ranking.organization}
</p>
<p className="text-gray-700">
{ranking.description}
</p>
</div>
</div>
</div>
))}
</div>
{/* Key Metrics */}
<div className="bg-gradient-to-r from-blue-600 to-teal-600 rounded-2xl p-8 mb-16">
<h2 className="text-3xl font-bold text-center mb-12 text-white">
By the Numbers
</h2>
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
{achievements.map((achievement, index) => (
<div key={index} className="text-center">
<div className="text-4xl md:text-5xl font-bold text-yellow-300 mb-2">
{achievement.metric}
</div>
<div className="text-lg font-semibold text-white mb-1">
{achievement.label}
</div>
<div className="text-sm text-blue-100">
{achievement.description}
</div>
</div>
))}
</div>
</div>
{/* Research Impact */}
<div className="mb-16">
<h2 className="text-3xl font-bold text-center mb-12 text-gray-900">
Global Research Impact
</h2>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{impacts.map((impact, index) => (
<div key={index} className="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow duration-300">
<h3 className="text-xl font-bold mb-4 text-gray-900">
{impact.title}
</h3>
<p className="text-gray-700 mb-4">
{impact.description}
</p>
<div className="bg-gradient-to-r from-blue-500 to-teal-500 text-white px-4 py-2 rounded-lg text-sm font-semibold">
<BarChart3 className="w-4 h-4 inline mr-2" />
{impact.impact}
</div>
</div>
))}
</div>
</div>
{/* Call to Action */}
<div className="bg-gradient-to-r from-teal-500 to-blue-600 rounded-2xl p-8 text-center text-white">
<h2 className="text-3xl font-bold mb-4">
Join the World's Leading Voices
</h2>
<p className="text-xl mb-6 text-blue-100">
Be part of groundbreaking research that shapes our planet's future
</p>
<div className="flex flex-wrap justify-center gap-4">
<button className="bg-white text-blue-600 px-8 py-3 rounded-lg font-semibold hover:bg-blue-50 transition-colors">
Explore Programs
</button>
<button className="border-2 border-white text-white px-8 py-3 rounded-lg font-semibold hover:bg-white hover:text-blue-600 transition-colors">
Research Opportunities
</button>
</div>
</div>
</div>
</div>
);
};
export default RankingsPage;
+440
View File
@@ -0,0 +1,440 @@
'use client';
import React, { useState } from 'react';
import { useLanguage } from '@/components/providers/LanguageProvider';
import { Waves, Snowflake, Fish, ThermometerSun, Globe, MapPin, ExternalLink } from 'lucide-react';
import { mockResearch } from '@/lib/mockData';
export default function MarineAntarcticResearchPage() {
const { language, dir } = useLanguage();
const [activeSection, setActiveSection] = useState('overview');
// Filter for marine and climate research
const marineResearch = mockResearch.filter(research =>
research.institute === 'Institute for Marine and Antarctic Studies (IMAS)' ||
research.tags.some(tag => tag.toLowerCase().includes('marine') || tag.toLowerCase().includes('climate') || tag.toLowerCase().includes('antarctic'))
);
const researchHighlights = [
{
id: 'southern-ocean',
titleEn: 'Southern Ocean Research',
titleAr: 'أبحاث المحيط الجنوبي',
descriptionEn: 'Monitoring and understanding the Southern Ocean\'s role in global climate systems.',
descriptionAr: 'مراقبة وفهم دور المحيط الجنوبي في أنظمة المناخ العالمية.',
icon: <Waves className="text-blue-500" size={48} />,
funding: 'A$25M',
duration: '2020-2025',
keyFindings: {
en: ['Ocean warming accelerating', 'Carbon absorption declining', 'Marine ecosystem shifts'],
ar: ['تسارع الاحترار البحري', 'انخفاض امتصاص الكربون', 'تغيرات النظام البيئي البحري']
}
},
{
id: 'ice-sheet-dynamics',
titleEn: 'Antarctic Ice Sheet Dynamics',
titleAr: 'ديناميكيات الغطاء الجليدي القطبي',
descriptionEn: 'Advanced monitoring of ice sheet changes and their global sea level implications.',
descriptionAr: 'المراقبة المتقدمة لتغيرات الغطاء الجليدي وآثارها على مستوى سطح البحر العالمي.',
icon: <Snowflake className="text-cyan-500" size={48} />,
funding: 'A$18M',
duration: '2019-2024',
keyFindings: {
en: ['Accelerated ice loss', 'Unstable ice shelf behavior', 'Sea level rise contributions'],
ar: ['تسارع فقدان الجليد', 'سلوك غير مستقر للرف الجليدي', 'مساهمات ارتفاع مستوى سطح البحر']
}
},
{
id: 'marine-biodiversity',
titleEn: 'Marine Biodiversity Conservation',
titleAr: 'حفظ التنوع البيولوجي البحري',
descriptionEn: 'Protecting marine species and ecosystems in a changing climate.',
descriptionAr: 'حماية الأنواع البحرية والنظم البيئية في مناخ متغير.',
icon: <Fish className="text-green-500" size={48} />,
funding: 'A$12M',
duration: '2021-2026',
keyFindings: {
en: ['Species migration patterns', 'Ecosystem resilience factors', 'Conservation strategies'],
ar: ['أنماط هجرة الأنواع', 'عوامل مرونة النظام البيئي', 'استراتيجيات الحفظ']
}
}
];
const expeditions = [
{
id: 'aurora-australis',
nameEn: 'Aurora Australis Expedition 2024',
nameAr: 'رحلة أورورا أوستراليس 2024',
descriptionEn: 'Multi-disciplinary research voyage to the Antarctic Peninsula focusing on climate change impacts.',
descriptionAr: 'رحلة بحثية متعددة التخصصات إلى شبه الجزيرة القطبية الجنوبية تركز على تأثيرات تغير المناخ.',
duration: '45 days',
participants: 32,
objectives: {
en: ['Ice core sampling', 'Marine ecosystem surveys', 'Climate monitoring station deployment'],
ar: ['أخذ عينات من النواة الجليدية', 'مسوحات النظام البيئي البحري', 'نشر محطة مراقبة المناخ']
}
},
{
id: 'deep-sea-exploration',
nameEn: 'Deep Sea Exploration Initiative',
nameAr: 'مبادرة استكشاف أعماق البحار',
descriptionEn: 'Advanced submersible research exploring deep ocean ecosystems and geological features.',
descriptionAr: 'بحث متقدم بالغواصات لاستكشاف النظم البيئية في أعماق المحيطات والميزات الجيولوجية.',
duration: '6 months',
participants: 28,
objectives: {
en: ['Deep sea biodiversity mapping', 'Hydrothermal vent studies', 'Ocean floor geological surveys'],
ar: ['رسم خرائط التنوع البيولوجي في أعماق البحار', 'دراسات الفتحات الحرارية المائية', 'المسوحات الجيولوجية لقاع المحيط']
}
}
];
const facilities = [
{
nameEn: 'IMAS Research Vessels',
nameAr: 'سفن البحث IMAS',
descriptionEn: 'State-of-the-art research vessels equipped for polar and marine research.',
descriptionAr: 'سفن بحثية حديثة مجهزة للبحوث القطبية والبحرية.',
capabilities: {
en: ['Ice-breaking capability', 'Advanced laboratory facilities', 'Remote sensing equipment'],
ar: ['قدرة كسر الجليد', 'مرافق مختبرية متقدمة', 'معدات الاستشعار عن بعد']
}
},
{
nameEn: 'Antarctic Research Station',
nameAr: 'محطة البحوث القطبية',
descriptionEn: 'Year-round research facility in Antarctica for continuous climate monitoring.',
descriptionAr: 'مرفق بحثي على مدار السنة في القطب الجنوبي للمراقبة المستمرة للمناخ.',
capabilities: {
en: ['Meteorological monitoring', 'Ice core drilling', 'Wildlife observation'],
ar: ['المراقبة الأرصادية', 'حفر النواة الجليدية', 'مراقبة الحياة البرية']
}
}
];
return (
<div className={`min-h-screen bg-gray-50 ${dir === 'rtl' ? 'font-arabic' : ''}`} dir={dir}>
{/* Hero Section */}
<div className="bg-gradient-to-r from-blue-600 via-cyan-500 to-blue-800 text-white py-20">
<div className="container mx-auto px-4">
<div className="max-w-5xl mx-auto text-center">
<h1 className="text-5xl md:text-6xl font-bold mb-6">
{language === 'en' ? 'Marine & Antarctic Studies' : 'دراسات البحرية والقطب الجنوبي'}
</h1>
<p className="text-xl opacity-90 mb-8 max-w-3xl mx-auto">
{language === 'en'
? 'World-leading research at IMAS, tackling climate change through polar and marine science. From Antarctica to Tasmania\'s waters, we\'re understanding our changing planet.'
: 'الأبحاث الرائدة عالمياً في IMAS، مواجهة تغير المناخ من خلال علوم القطبين والبحار. من القطب الجنوبي إلى مياه تسمانيا، نحن نفهم كوكبنا المتغير.'
}
</p>
<div className="grid grid-cols-2 md:grid-cols-4 gap-6 max-w-4xl mx-auto">
<div className="text-center">
<div className="text-3xl font-bold">#1</div>
<div className="opacity-80">{language === 'en' ? 'Climate Research' : 'بحوث المناخ'}</div>
</div>
<div className="text-center">
<div className="text-3xl font-bold">50+</div>
<div className="opacity-80">{language === 'en' ? 'Expeditions/Year' : 'رحلة/سنة'}</div>
</div>
<div className="text-center">
<div className="text-3xl font-bold">200+</div>
<div className="opacity-80">{language === 'en' ? 'Researchers' : 'باحث'}</div>
</div>
<div className="text-center">
<div className="text-3xl font-bold">A$80M</div>
<div className="opacity-80">{language === 'en' ? 'Annual Funding' : 'التمويل السنوي'}</div>
</div>
</div>
</div>
</div>
</div>
<div className="container mx-auto px-4 py-12">
{/* Navigation */}
<div className="flex justify-center mb-12">
<div className="bg-white rounded-xl p-2 shadow-lg">
{[
{ id: 'overview', labelEn: 'Research Overview', labelAr: 'نظرة عامة على البحث' },
{ id: 'expeditions', labelEn: 'Expeditions', labelAr: 'الرحلات الاستكشافية' },
{ id: 'facilities', labelEn: 'Facilities', labelAr: 'المرافق' }
].map(section => (
<button
key={section.id}
onClick={() => setActiveSection(section.id)}
className={`px-6 py-3 mx-1 rounded-lg font-semibold transition-colors ${
activeSection === section.id
? 'bg-blue-600 text-white'
: 'text-gray-600 hover:text-blue-600 hover:bg-blue-50'
}`}
>
{language === 'en' ? section.labelEn : section.labelAr}
</button>
))}
</div>
</div>
{/* Research Overview */}
{activeSection === 'overview' && (
<div className="space-y-12">
{/* Research Highlights */}
<div className="grid lg:grid-cols-3 gap-8">
{researchHighlights.map(highlight => (
<div key={highlight.id} className="bg-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden">
<div className="p-8">
<div className="flex items-center justify-center mb-6">
{highlight.icon}
</div>
<h3 className="text-xl font-bold text-gray-900 mb-4 text-center">
{language === 'en' ? highlight.titleEn : highlight.titleAr}
</h3>
<p className="text-gray-600 mb-6 text-center">
{language === 'en' ? highlight.descriptionEn : highlight.descriptionAr}
</p>
<div className="space-y-4 mb-6">
<div className="flex justify-between items-center text-sm">
<span className="font-medium text-gray-700">{language === 'en' ? 'Funding:' : 'التمويل:'}</span>
<span className="text-blue-600 font-semibold">{highlight.funding}</span>
</div>
<div className="flex justify-between items-center text-sm">
<span className="font-medium text-gray-700">{language === 'en' ? 'Duration:' : 'المدة:'}</span>
<span className="text-green-600 font-semibold">{highlight.duration}</span>
</div>
</div>
<div className="mb-6">
<h4 className="font-semibold text-gray-900 mb-3">
{language === 'en' ? 'Key Findings' : 'النتائج الرئيسية'}
</h4>
<ul className="space-y-2">
{(language === 'en' ? highlight.keyFindings.en : highlight.keyFindings.ar).map((finding, index) => (
<li key={index} className="text-sm text-gray-600 flex items-start">
<span className="w-2 h-2 bg-blue-500 rounded-full mt-2 mr-3 flex-shrink-0"></span>
{finding}
</li>
))}
</ul>
</div>
<button className="w-full bg-blue-600 text-white py-3 px-4 rounded-lg font-semibold hover:bg-blue-700 transition-colors">
{language === 'en' ? 'Learn More' : 'تعلم المزيد'}
</button>
</div>
</div>
))}
</div>
{/* Current Research Projects */}
<div className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-3xl font-bold text-gray-900 mb-8 text-center">
{language === 'en' ? 'Current Research Projects' : 'مشاريع البحث الحالية'}
</h2>
<div className="grid lg:grid-cols-2 gap-8">
{marineResearch.slice(0, 4).map(research => (
<div key={research.id} className="border border-gray-200 rounded-lg p-6 hover:shadow-md transition-shadow">
<h3 className="text-lg font-bold text-gray-900 mb-3">
{language === 'en' ? research.title : research.titleAr}
</h3>
<p className="text-gray-600 mb-4 text-sm">
{language === 'en' ? research.description : research.descriptionAr}
</p>
<div className="flex items-center justify-between text-sm text-gray-500 mb-4">
<span>{language === 'en' ? research.institute : research.instituteAr}</span>
<span>{research.publications} {language === 'en' ? 'publications' : 'منشورات'}</span>
</div>
<div className="flex gap-2">
<button className="flex-1 bg-blue-50 text-blue-700 py-2 px-4 rounded-lg font-medium hover:bg-blue-100 transition-colors">
{language === 'en' ? 'Details' : 'التفاصيل'}
</button>
<button className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg font-medium hover:bg-gray-50 transition-colors">
<ExternalLink size={16} />
</button>
</div>
</div>
))}
</div>
</div>
</div>
)}
{/* Expeditions */}
{activeSection === 'expeditions' && (
<div className="space-y-8">
<div className="text-center mb-12">
<h2 className="text-3xl font-bold text-gray-900 mb-4">
{language === 'en' ? 'Research Expeditions' : 'الرحلات الاستكشافية البحثية'}
</h2>
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
{language === 'en'
? 'Leading scientific expeditions to the world\'s most remote and challenging environments to advance our understanding of climate change.'
: 'قيادة البعثات العلمية إلى البيئات الأكثر نائية وتحدياً في العالم لتطوير فهمنا لتغير المناخ.'
}
</p>
</div>
<div className="grid lg:grid-cols-2 gap-8">
{expeditions.map(expedition => (
<div key={expedition.id} className="bg-white rounded-xl shadow-lg overflow-hidden">
<div className="h-48 bg-gradient-to-br from-cyan-500 to-blue-600 flex items-center justify-center">
<div className="text-center text-white">
<Globe size={64} className="mx-auto mb-4 opacity-80" />
<div className="text-lg font-semibold">
{language === 'en' ? 'Scientific Expedition' : 'رحلة علمية'}
</div>
</div>
</div>
<div className="p-8">
<h3 className="text-xl font-bold text-gray-900 mb-4">
{language === 'en' ? expedition.nameEn : expedition.nameAr}
</h3>
<p className="text-gray-600 mb-6">
{language === 'en' ? expedition.descriptionEn : expedition.descriptionAr}
</p>
<div className="grid grid-cols-2 gap-4 mb-6">
<div className="text-center p-3 bg-gray-50 rounded-lg">
<div className="text-2xl font-bold text-blue-600">{expedition.duration}</div>
<div className="text-sm text-gray-600">{language === 'en' ? 'Duration' : 'المدة'}</div>
</div>
<div className="text-center p-3 bg-gray-50 rounded-lg">
<div className="text-2xl font-bold text-green-600">{expedition.participants}</div>
<div className="text-sm text-gray-600">{language === 'en' ? 'Researchers' : 'باحثين'}</div>
</div>
</div>
<div className="mb-6">
<h4 className="font-semibold text-gray-900 mb-3">
{language === 'en' ? 'Research Objectives' : 'أهداف البحث'}
</h4>
<ul className="space-y-2">
{(language === 'en' ? expedition.objectives.en : expedition.objectives.ar).map((objective, index) => (
<li key={index} className="text-sm text-gray-600 flex items-start">
<span className="w-2 h-2 bg-cyan-500 rounded-full mt-2 mr-3 flex-shrink-0"></span>
{objective}
</li>
))}
</ul>
</div>
<button className="w-full bg-cyan-600 text-white py-3 px-4 rounded-lg font-semibold hover:bg-cyan-700 transition-colors">
{language === 'en' ? 'Expedition Details' : 'تفاصيل الرحلة'}
</button>
</div>
</div>
))}
</div>
</div>
)}
{/* Facilities */}
{activeSection === 'facilities' && (
<div className="space-y-8">
<div className="text-center mb-12">
<h2 className="text-3xl font-bold text-gray-900 mb-4">
{language === 'en' ? 'Research Facilities' : 'مرافق البحث'}
</h2>
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
{language === 'en'
? 'World-class facilities supporting cutting-edge marine and Antarctic research.'
: 'مرافق عالمية المستوى تدعم البحوث الرائدة في المجالين البحري والقطب الجنوبي.'
}
</p>
</div>
<div className="grid lg:grid-cols-2 gap-8">
{facilities.map((facility, index) => (
<div key={index} className="bg-white rounded-xl shadow-lg p-8">
<div className="flex items-center mb-6">
<div className="w-16 h-16 bg-gradient-to-br from-blue-500 to-cyan-500 rounded-full flex items-center justify-center text-white mr-4">
<MapPin size={32} />
</div>
<div>
<h3 className="text-xl font-bold text-gray-900">
{language === 'en' ? facility.nameEn : facility.nameAr}
</h3>
</div>
</div>
<p className="text-gray-600 mb-6">
{language === 'en' ? facility.descriptionEn : facility.descriptionAr}
</p>
<div className="mb-6">
<h4 className="font-semibold text-gray-900 mb-3">
{language === 'en' ? 'Capabilities' : 'القدرات'}
</h4>
<ul className="space-y-2">
{(language === 'en' ? facility.capabilities.en : facility.capabilities.ar).map((capability, capIndex) => (
<li key={capIndex} className="text-sm text-gray-600 flex items-start">
<span className="w-2 h-2 bg-blue-500 rounded-full mt-2 mr-3 flex-shrink-0"></span>
{capability}
</li>
))}
</ul>
</div>
<button className="w-full bg-blue-600 text-white py-3 px-4 rounded-lg font-semibold hover:bg-blue-700 transition-colors">
{language === 'en' ? 'Facility Details' : 'تفاصيل المرفق'}
</button>
</div>
))}
</div>
</div>
)}
{/* Global Impact */}
<div className="mt-16 bg-gradient-to-r from-blue-600 to-cyan-600 rounded-xl p-8 text-white">
<h2 className="text-3xl font-bold mb-8 text-center">
{language === 'en' ? 'Global Climate Impact' : 'التأثير المناخي العالمي'}
</h2>
<div className="grid md:grid-cols-3 gap-8">
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<ThermometerSun size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Climate Monitoring' : 'مراقبة المناخ'}
</h3>
<p className="opacity-90 text-sm">
{language === 'en'
? 'Real-time monitoring of Southern Ocean and Antarctic climate systems.'
: 'المراقبة في الوقت الفعلي لأنظمة المناخ في المحيط الجنوبي والقطب الجنوبي.'
}
</p>
</div>
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<Waves size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Ocean Science' : 'علوم المحيطات'}
</h3>
<p className="opacity-90 text-sm">
{language === 'en'
? 'Understanding ocean circulation and its role in global climate regulation.'
: 'فهم دوران المحيطات ودورها في تنظيم المناخ العالمي.'
}
</p>
</div>
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<Fish size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Marine Conservation' : 'حفظ البحرية'}
</h3>
<p className="opacity-90 text-sm">
{language === 'en'
? 'Protecting marine biodiversity and sustainable fishing practices.'
: 'حماية التنوع البيولوجي البحري وممارسات الصيد المستدامة.'
}
</p>
</div>
</div>
</div>
</div>
</div>
);
}
View File
+341
View File
@@ -0,0 +1,341 @@
'use client';
import React, { useState, useMemo } from 'react';
import { useLanguage } from '@/components/providers/LanguageProvider';
import { Award, DollarSign, Users, Globe, CheckCircle, Clock, Search, Filter, ExternalLink, ArrowRight, CalendarDays, GraduationCap } from 'lucide-react';
import { mockScholarships, getOpenScholarships, getScholarshipsByCategory, Scholarship } from '@/lib/mockData';
export default function ScholarshipsPage() {
const { language, t, dir } = useLanguage();
const [searchQuery, setSearchQuery] = useState('');
const [selectedCategory, setSelectedCategory] = useState('');
const [selectedStatus, setSelectedStatus] = useState('');
const [showFilters, setShowFilters] = useState(false);
// Filter scholarships based on search and filters
const filteredScholarships = useMemo(() => {
let results = mockScholarships;
// Text search
if (searchQuery) {
const query = searchQuery.toLowerCase();
results = results.filter(scholarship =>
(language === 'en' ? scholarship.title : scholarship.titleAr).toLowerCase().includes(query) ||
(language === 'en' ? scholarship.description : scholarship.descriptionAr).toLowerCase().includes(query) ||
(language === 'en' ? scholarship.value : scholarship.valueAr).toLowerCase().includes(query)
);
}
// Category filter
if (selectedCategory) {
results = results.filter(scholarship => scholarship.category === selectedCategory);
}
// Status filter
if (selectedStatus) {
results = results.filter(scholarship => scholarship.status === selectedStatus);
}
return results;
}, [searchQuery, selectedCategory, selectedStatus, language]);
const ScholarshipCard = ({ scholarship }: { scholarship: Scholarship }) => (
<div className="group bg-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden border border-gray-100">
<div className="p-6">
<div className="flex items-start justify-between mb-4">
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<div className={`p-2 rounded-lg ${
scholarship.category === 'merit' ? 'bg-blue-100 text-blue-600' :
scholarship.category === 'need' ? 'bg-green-100 text-green-600' :
scholarship.category === 'research' ? 'bg-purple-100 text-purple-600' :
'bg-orange-100 text-orange-600'
}`}>
<Award size={20} />
</div>
<div className="flex-1">
<h3 className="text-xl font-bold text-gray-900">
{language === 'en' ? scholarship.title : scholarship.titleAr}
</h3>
<div className="flex items-center gap-2 mt-1">
<span className={`px-3 py-1 rounded-full text-xs font-semibold ${
scholarship.status === 'open' ? 'bg-green-500 text-white' :
scholarship.status === 'closing' ? 'bg-yellow-500 text-white' :
'bg-red-500 text-white'
}`}>
{scholarship.status === 'open' ? (language === 'en' ? 'Open' : 'مفتوح') :
scholarship.status === 'closing' ? (language === 'en' ? 'Closing Soon' : 'يغلق قريباً') :
(language === 'en' ? 'Closed' : 'مغلق')}
</span>
<span className="text-sm text-gray-500 capitalize">
{scholarship.category === 'merit' ? (language === 'en' ? 'Merit-based' : 'على أساس الجدارة') :
scholarship.category === 'need' ? (language === 'en' ? 'Need-based' : 'على أساس الحاجة') :
scholarship.category === 'research' ? (language === 'en' ? 'Research' : 'بحثي') :
(language === 'en' ? 'International' : 'دولي')}
</span>
</div>
</div>
</div>
</div>
</div>
<p className="text-gray-600 mb-4 leading-relaxed">
{language === 'en' ? scholarship.description : scholarship.descriptionAr}
</p>
<div className="grid grid-cols-2 gap-4 mb-6">
<div className="flex items-center gap-2">
<DollarSign className="w-4 h-4 text-green-500" />
<div>
<div className="text-sm text-gray-500">{language === 'en' ? 'Value' : 'القيمة'}</div>
<div className="font-semibold text-gray-900">
{language === 'en' ? scholarship.value : scholarship.valueAr}
</div>
</div>
</div>
<div className="flex items-center gap-2">
<Clock className="w-4 h-4 text-blue-500" />
<div>
<div className="text-sm text-gray-500">{language === 'en' ? 'Duration' : 'المدة'}</div>
<div className="font-semibold text-gray-900">
{language === 'en' ? scholarship.duration : scholarship.durationAr}
</div>
</div>
</div>
</div>
<div className="mb-6">
<h4 className="font-semibold text-gray-900 mb-3 flex items-center gap-2">
<Users className="w-4 h-4" />
{language === 'en' ? 'Eligibility Requirements' : 'متطلبات الأهلية'}
</h4>
<ul className="space-y-2">
{(language === 'en' ? scholarship.eligibility : scholarship.eligibilityAr).slice(0, 3).map((requirement, index) => (
<li key={index} className="flex items-start gap-2 text-sm text-gray-600">
<CheckCircle className="w-4 h-4 text-green-500 mt-0.5 flex-shrink-0" />
<span>{requirement}</span>
</li>
))}
{(language === 'en' ? scholarship.eligibility : scholarship.eligibilityAr).length > 3 && (
<li className="text-sm text-gray-500 ml-6">
{language === 'en' ?
`+${(scholarship.eligibility.length - 3)} more requirements` :
`+${(scholarship.eligibilityAr.length - 3)} متطلبات أخرى`
}
</li>
)}
</ul>
</div>
<div className="bg-gray-50 rounded-lg p-4 mb-6">
<div className="flex items-center gap-2 mb-2">
<CalendarDays className="w-4 h-4 text-red-500" />
<span className="font-semibold text-gray-900">
{language === 'en' ? 'Application Deadline' : 'موعد التقديم النهائي'}
</span>
</div>
<div className="text-lg font-bold text-red-600">
{language === 'en' ? scholarship.deadline : scholarship.deadlineAr}
</div>
</div>
<div className="flex gap-3">
<button
className="flex-1 bg-blue-600 text-white py-3 px-4 rounded-lg font-semibold hover:bg-blue-700 transition-colors duration-200 flex items-center justify-center gap-2"
disabled={scholarship.status === 'closed'}
>
{scholarship.status === 'closed' ?
(language === 'en' ? 'Application Closed' : 'التقديم مغلق') :
(language === 'en' ? 'Apply Now' : 'قدم الآن')
}
{scholarship.status !== 'closed' && <ArrowRight size={16} />}
</button>
<button className="px-4 py-3 border border-gray-300 text-gray-700 rounded-lg font-semibold hover:bg-gray-50 transition-colors duration-200 flex items-center gap-2">
<ExternalLink size={16} />
{language === 'en' ? 'Details' : 'التفاصيل'}
</button>
</div>
</div>
</div>
);
return (
<div className={`min-h-screen bg-gray-50 ${dir === 'rtl' ? 'font-arabic' : ''}`} dir={dir}>
{/* Hero Section */}
<div className="bg-gradient-to-r from-blue-600 to-purple-600 text-white py-16">
<div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">
{t('scholarships')} & {language === 'en' ? 'Financial Support' : 'الدعم المالي'}
</h1>
<p className="text-xl opacity-90 mb-8">
{language === 'en'
? 'Invest in your future with UTAS scholarships. Up to $15,000 per year available for eligible students.'
: 'استثمر في مستقبلك مع منح UTAS الدراسية. حتى 15,000 دولار سنوياً متاح للطلاب المؤهلين.'
}
</p>
<div className="flex justify-center space-x-8 text-center">
<div>
<div className="text-3xl font-bold">$15,000</div>
<div className="opacity-80">{language === 'en' ? 'Max Annual Value' : 'أقصى قيمة سنوية'}</div>
</div>
<div>
<div className="text-3xl font-bold">150+</div>
<div className="opacity-80">{language === 'en' ? 'Available Scholarships' : 'منحة متاحة'}</div>
</div>
<div>
<div className="text-3xl font-bold">85%</div>
<div className="opacity-80">{language === 'en' ? 'Students Receive Support' : 'الطلاب يتلقون الدعم'}</div>
</div>
</div>
</div>
</div>
</div>
<div className="container mx-auto px-4 py-8">
{/* Search and Filters */}
<div className="bg-white rounded-xl shadow-lg p-6 mb-8">
{/* Search Bar */}
<div className="relative mb-6">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400" size={20} />
<input
type="text"
placeholder={language === 'en' ? 'Search scholarships by name, value, or category...' : 'البحث عن المنح بالاسم أو القيمة أو الفئة...'}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full pl-12 pr-4 py-4 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-lg"
/>
</div>
{/* Filter Toggle */}
<button
onClick={() => setShowFilters(!showFilters)}
className="flex items-center gap-2 mb-4 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
<Filter size={16} />
{t('filter')}
</button>
{/* Filters */}
{showFilters && (
<div className="grid md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
{language === 'en' ? 'Category' : 'الفئة'}
</label>
<select
value={selectedCategory}
onChange={(e) => setSelectedCategory(e.target.value)}
className="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
>
<option value="">{language === 'en' ? 'All Categories' : 'جميع الفئات'}</option>
<option value="merit">{language === 'en' ? 'Merit-based' : 'على أساس الجدارة'}</option>
<option value="need">{language === 'en' ? 'Need-based' : 'على أساس الحاجة'}</option>
<option value="research">{language === 'en' ? 'Research' : 'بحثي'}</option>
<option value="international">{language === 'en' ? 'International' : 'دولي'}</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
{language === 'en' ? 'Status' : 'الحالة'}
</label>
<select
value={selectedStatus}
onChange={(e) => setSelectedStatus(e.target.value)}
className="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
>
<option value="">{language === 'en' ? 'All Status' : 'جميع الحالات'}</option>
<option value="open">{language === 'en' ? 'Open for Applications' : 'مفتوح للتقديم'}</option>
<option value="closing">{language === 'en' ? 'Closing Soon' : 'يغلق قريباً'}</option>
</select>
</div>
</div>
)}
</div>
{/* Results Header */}
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold text-gray-900">
{language === 'en' ? `${filteredScholarships.length} Scholarships Available` : `${filteredScholarships.length} منحة متاحة`}
</h2>
<div className="flex items-center gap-2 text-sm text-gray-600">
<GraduationCap size={16} />
{language === 'en' ? 'Sorted by deadline' : 'مرتب حسب الموعد النهائي'}
</div>
</div>
{/* Scholarships Grid */}
{filteredScholarships.length > 0 ? (
<div className="grid lg:grid-cols-2 gap-8">
{filteredScholarships.map(scholarship => (
<ScholarshipCard key={scholarship.id} scholarship={scholarship} />
))}
</div>
) : (
<div className="text-center py-12">
<Award size={64} className="mx-auto text-gray-300 mb-4" />
<h3 className="text-xl font-semibold text-gray-600 mb-2">{t('no_results')}</h3>
<p className="text-gray-500">
{language === 'en'
? 'Try adjusting your search or filters to find more scholarships.'
: 'حاول تعديل البحث أو المرشحات للعثور على المزيد من المنح.'
}
</p>
</div>
)}
{/* Application Tips */}
<div className="mt-16 bg-gradient-to-r from-purple-600 to-blue-600 rounded-xl p-8 text-white">
<h2 className="text-3xl font-bold mb-6 text-center">
{language === 'en' ? 'Scholarship Application Tips' : 'نصائح تقديم المنح الدراسية'}
</h2>
<div className="grid md:grid-cols-3 gap-6">
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<CheckCircle size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Apply Early' : 'قدم مبكراً'}
</h3>
<p className="opacity-90">
{language === 'en'
? 'Submit your application as early as possible to avoid deadline rush.'
: 'قدم طلبك في أقرب وقت ممكن لتجنب زحمة الموعد النهائي.'
}
</p>
</div>
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<Users size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Meet Requirements' : 'استوف المتطلبات'}
</h3>
<p className="opacity-90">
{language === 'en'
? 'Carefully review and ensure you meet all eligibility criteria.'
: 'راجع بعناية وتأكد من استيفائك لجميع معايير الأهلية.'
}
</p>
</div>
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<ExternalLink size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Prepare Documents' : 'حضر الوثائق'}
</h3>
<p className="opacity-90">
{language === 'en'
? 'Gather all required documents including transcripts and references.'
: 'اجمع جميع الوثائق المطلوبة بما في ذلك النصوص والمراجع.'
}
</p>
</div>
</div>
</div>
</div>
</div>
);
}
+754
View File
@@ -0,0 +1,754 @@
'use client';
import React, { useState, useMemo } from 'react';
import { useLanguage } from '@/components/providers/LanguageProvider';
import { Award, DollarSign, Users, Globe, CheckCircle, Clock, Search, Filter, ExternalLink, ArrowRight, CalendarDays, GraduationCap } from 'lucide-react';
import { mockScholarships, getOpenScholarships, getScholarshipsByCategory, Scholarship } from '@/lib/mockData';
export default function ScholarshipsPage() {
const { language, t, dir } = useLanguage();
const [searchQuery, setSearchQuery] = useState('');
const [selectedCategory, setSelectedCategory] = useState('');
const [selectedStatus, setSelectedStatus] = useState('');
const [showFilters, setShowFilters] = useState(false);
// Filter scholarships based on search and filters
const filteredScholarships = useMemo(() => {
let results = mockScholarships;
// Text search
if (searchQuery) {
const query = searchQuery.toLowerCase();
results = results.filter(scholarship =>
(language === 'en' ? scholarship.title : scholarship.titleAr).toLowerCase().includes(query) ||
(language === 'en' ? scholarship.description : scholarship.descriptionAr).toLowerCase().includes(query) ||
(language === 'en' ? scholarship.value : scholarship.valueAr).toLowerCase().includes(query)
);
}
// Category filter
if (selectedCategory) {
results = results.filter(scholarship => scholarship.category === selectedCategory);
}
// Status filter
if (selectedStatus) {
results = results.filter(scholarship => scholarship.status === selectedStatus);
}
return results;
}, [searchQuery, selectedCategory, selectedStatus, language]);
const ScholarshipCard = ({ scholarship }: { scholarship: Scholarship }) => (
<div className="group bg-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden border border-gray-100">
<div className="p-6">
<div className="flex items-start justify-between mb-4">
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<div className={`p-2 rounded-lg ${
scholarship.category === 'merit' ? 'bg-blue-100 text-blue-600' :
scholarship.category === 'need' ? 'bg-green-100 text-green-600' :
scholarship.category === 'research' ? 'bg-purple-100 text-purple-600' :
'bg-orange-100 text-orange-600'
}`}>
<Award size={20} />
</div>
<div className="flex-1">
<h3 className="text-xl font-bold text-gray-900">
{language === 'en' ? scholarship.title : scholarship.titleAr}
</h3>
<div className="flex items-center gap-2 mt-1">
<span className={`px-3 py-1 rounded-full text-xs font-semibold ${
scholarship.status === 'open' ? 'bg-green-500 text-white' :
scholarship.status === 'closing' ? 'bg-yellow-500 text-white' :
'bg-red-500 text-white'
}`}>
{scholarship.status === 'open' ? (language === 'en' ? 'Open' : 'مفتوح') :
scholarship.status === 'closing' ? (language === 'en' ? 'Closing Soon' : 'يغلق قريباً') :
(language === 'en' ? 'Closed' : 'مغلق')}
</span>
<span className="text-sm text-gray-500 capitalize">
{scholarship.category === 'merit' ? (language === 'en' ? 'Merit-based' : 'على أساس الجدارة') :
scholarship.category === 'need' ? (language === 'en' ? 'Need-based' : 'على أساس الحاجة') :
scholarship.category === 'research' ? (language === 'en' ? 'Research' : 'بحثي') :
(language === 'en' ? 'International' : 'دولي')}
</span>
</div>
</div>
</div>
</div>
</div>
<p className="text-gray-600 mb-4 leading-relaxed">
{language === 'en' ? scholarship.description : scholarship.descriptionAr}
</p>
<div className="grid grid-cols-2 gap-4 mb-6">
<div className="flex items-center gap-2">
<DollarSign className="w-4 h-4 text-green-500" />
<div>
<div className="text-sm text-gray-500">{language === 'en' ? 'Value' : 'القيمة'}</div>
<div className="font-semibold text-gray-900">
{language === 'en' ? scholarship.value : scholarship.valueAr}
</div>
</div>
</div>
<div className="flex items-center gap-2">
<Clock className="w-4 h-4 text-blue-500" />
<div>
<div className="text-sm text-gray-500">{language === 'en' ? 'Duration' : 'المدة'}</div>
<div className="font-semibold text-gray-900">
{language === 'en' ? scholarship.duration : scholarship.durationAr}
</div>
</div>
</div>
</div>
<div className="mb-6">
<h4 className="font-semibold text-gray-900 mb-3 flex items-center gap-2">
<Users className="w-4 h-4" />
{language === 'en' ? 'Eligibility Requirements' : 'متطلبات الأهلية'}
</h4>
<ul className="space-y-2">
{(language === 'en' ? scholarship.eligibility : scholarship.eligibilityAr).slice(0, 3).map((requirement, index) => (
<li key={index} className="flex items-start gap-2 text-sm text-gray-600">
<CheckCircle className="w-4 h-4 text-green-500 mt-0.5 flex-shrink-0" />
<span>{requirement}</span>
</li>
))}
{(language === 'en' ? scholarship.eligibility : scholarship.eligibilityAr).length > 3 && (
<li className="text-sm text-gray-500 ml-6">
{language === 'en' ?
`+${(scholarship.eligibility.length - 3)} more requirements` :
`+${(scholarship.eligibilityAr.length - 3)} متطلبات أخرى`
}
</li>
)}
</ul>
</div>
<div className="bg-gray-50 rounded-lg p-4 mb-6">
<div className="flex items-center gap-2 mb-2">
<CalendarDays className="w-4 h-4 text-red-500" />
<span className="font-semibold text-gray-900">
{language === 'en' ? 'Application Deadline' : 'موعد التقديم النهائي'}
</span>
</div>
<div className="text-lg font-bold text-red-600">
{language === 'en' ? scholarship.deadline : scholarship.deadlineAr}
</div>
</div>
<div className="flex gap-3">
<button
className="flex-1 bg-blue-600 text-white py-3 px-4 rounded-lg font-semibold hover:bg-blue-700 transition-colors duration-200 flex items-center justify-center gap-2"
disabled={scholarship.status === 'closed'}
>
{scholarship.status === 'closed' ?
(language === 'en' ? 'Application Closed' : 'التقديم مغلق') :
(language === 'en' ? 'Apply Now' : 'قدم الآن')
}
{scholarship.status !== 'closed' && <ArrowRight size={16} />}
</button>
<button className="px-4 py-3 border border-gray-300 text-gray-700 rounded-lg font-semibold hover:bg-gray-50 transition-colors duration-200 flex items-center gap-2">
<ExternalLink size={16} />
{language === 'en' ? 'Details' : 'التفاصيل'}
</button>
</div>
</div>
</div>
);
return (
<div className={`min-h-screen bg-gray-50 ${dir === 'rtl' ? 'font-arabic' : ''}`} dir={dir}>
{/* Hero Section */}
<div className="bg-gradient-to-r from-blue-600 to-purple-600 text-white py-16">
<div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">
{t('scholarships')} & {language === 'en' ? 'Financial Support' : 'الدعم المالي'}
</h1>
<p className="text-xl opacity-90 mb-8">
{language === 'en'
? 'Invest in your future with UTAS scholarships. Up to $15,000 per year available for eligible students.'
: 'استثمر في مستقبلك مع منح UTAS الدراسية. حتى 15,000 دولار سنوياً متاح للطلاب المؤهلين.'
}
</p>
<div className="flex justify-center space-x-8 text-center">
<div>
<div className="text-3xl font-bold">$15,000</div>
<div className="opacity-80">{language === 'en' ? 'Max Annual Value' : 'أقصى قيمة سنوية'}</div>
</div>
<div>
<div className="text-3xl font-bold">150+</div>
<div className="opacity-80">{language === 'en' ? 'Available Scholarships' : 'منحة متاحة'}</div>
</div>
<div>
<div className="text-3xl font-bold">85%</div>
<div className="opacity-80">{language === 'en' ? 'Students Receive Support' : 'الطلاب يتلقون الدعم'}</div>
</div>
</div>
</div>
</div>
</div>
<div className="container mx-auto px-4 py-8">
{/* Search and Filters */}
<div className="bg-white rounded-xl shadow-lg p-6 mb-8">
{/* Search Bar */}
<div className="relative mb-6">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400" size={20} />
<input
type="text"
placeholder={language === 'en' ? 'Search scholarships by name, value, or category...' : 'البحث عن المنح بالاسم أو القيمة أو الفئة...'}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full pl-12 pr-4 py-4 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-lg"
/>
</div>
{/* Filter Toggle */}
<button
onClick={() => setShowFilters(!showFilters)}
className="flex items-center gap-2 mb-4 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
<Filter size={16} />
{t('filter')}
</button>
{/* Filters */}
{showFilters && (
<div className="grid md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
{language === 'en' ? 'Category' : 'الفئة'}
</label>
<select
value={selectedCategory}
onChange={(e) => setSelectedCategory(e.target.value)}
className="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
>
<option value="">{language === 'en' ? 'All Categories' : 'جميع الفئات'}</option>
<option value="merit">{language === 'en' ? 'Merit-based' : 'على أساس الجدارة'}</option>
<option value="need">{language === 'en' ? 'Need-based' : 'على أساس الحاجة'}</option>
<option value="research">{language === 'en' ? 'Research' : 'بحثي'}</option>
<option value="international">{language === 'en' ? 'International' : 'دولي'}</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
{language === 'en' ? 'Status' : 'الحالة'}
</label>
<select
value={selectedStatus}
onChange={(e) => setSelectedStatus(e.target.value)}
className="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
>
<option value="">{language === 'en' ? 'All Status' : 'جميع الحالات'}</option>
<option value="open">{language === 'en' ? 'Open for Applications' : 'مفتوح للتقديم'}</option>
<option value="closing">{language === 'en' ? 'Closing Soon' : 'يغلق قريباً'}</option>
</select>
</div>
</div>
)}
</div>
{/* Results Header */}
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold text-gray-900">
{language === 'en' ? `${filteredScholarships.length} Scholarships Available` : `${filteredScholarships.length} منحة متاحة`}
</h2>
<div className="flex items-center gap-2 text-sm text-gray-600">
<GraduationCap size={16} />
{language === 'en' ? 'Sorted by deadline' : 'مرتب حسب الموعد النهائي'}
</div>
</div>
{/* Scholarships Grid */}
{filteredScholarships.length > 0 ? (
<div className="grid lg:grid-cols-2 gap-8">
{filteredScholarships.map(scholarship => (
<ScholarshipCard key={scholarship.id} scholarship={scholarship} />
))}
</div>
) : (
<div className="text-center py-12">
<Award size={64} className="mx-auto text-gray-300 mb-4" />
<h3 className="text-xl font-semibold text-gray-600 mb-2">{t('no_results')}</h3>
<p className="text-gray-500">
{language === 'en'
? 'Try adjusting your search or filters to find more scholarships.'
: 'حاول تعديل البحث أو المرشحات للعثور على المزيد من المنح.'
}
</p>
</div>
)}
{/* Application Tips */}
<div className="mt-16 bg-gradient-to-r from-purple-600 to-blue-600 rounded-xl p-8 text-white">
<h2 className="text-3xl font-bold mb-6 text-center">
{language === 'en' ? 'Scholarship Application Tips' : 'نصائح تقديم المنح الدراسية'}
</h2>
<div className="grid md:grid-cols-3 gap-6">
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<CheckCircle size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Apply Early' : 'قدم مبكراً'}
</h3>
<p className="opacity-90">
{language === 'en'
? 'Submit your application as early as possible to avoid deadline rush.'
: 'قدم طلبك في أقرب وقت ممكن لتجنب زحمة الموعد النهائي.'
}
</p>
</div>
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<Users size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Meet Requirements' : 'استوف المتطلبات'}
</h3>
<p className="opacity-90">
{language === 'en'
? 'Carefully review and ensure you meet all eligibility criteria.'
: 'راجع بعناية وتأكد من استيفائك لجميع معايير الأهلية.'
}
</p>
</div>
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<ExternalLink size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Prepare Documents' : 'حضر الوثائق'}
</h3>
<p className="opacity-90">
{language === 'en'
? 'Gather all required documents including transcripts and references.'
: 'اجمع جميع الوثائق المطلوبة بما في ذلك النصوص والمراجع.'
}
</p>
</div>
</div>
</div>
</div>
</div>
);
}
],
description: 'Recognizes academic achievement and helps cover study costs for high-achieving students.',
type: 'merit',
deadline: 'January 15, 2025',
applicationUrl: '/apply/scholarship/merit'
},
{
id: 'equity-scholarship',
title: 'UTAS Equity Scholarship',
amount: '$5,000 per year',
duration: 'Duration of degree',
eligibility: [
'Financial disadvantage',
'First in family to attend university',
'Remote or regional background',
'Care leavers or refugee background'
],
description: 'Supporting students from disadvantaged backgrounds to access higher education.',
type: 'equity',
deadline: 'December 31, 2024',
applicationUrl: '/apply/scholarship/equity'
},
{
id: 'international-scholarship',
title: 'International Excellence Scholarship',
amount: '25% tuition reduction',
duration: 'Duration of degree',
eligibility: [
'International students',
'Academic excellence in previous studies',
'Commencing undergraduate or postgraduate',
'Full fee-paying students'
],
description: 'Attracts high-achieving international students to study at UTAS with significant tuition reduction.',
type: 'international',
deadline: 'Rolling applications',
applicationUrl: '/apply/scholarship/international'
},
{
id: 'research-scholarship',
title: 'Research Training Program (RTP)',
amount: '$28,994 per year (2024 rate)',
duration: '3-4 years',
eligibility: [
'PhD or Research Masters students',
'Strong academic background',
'Research proposal approved',
'Full-time enrollment'
],
description: 'Australian Government funded scholarship for research degree students, covering living costs.',
type: 'research',
deadline: 'Ongoing throughout year',
applicationUrl: '/apply/scholarship/rtp'
},
{
id: 'indigenous-scholarship',
title: 'Indigenous Student Success Scholarship',
amount: '$5,000 per year + support',
duration: 'Duration of degree',
eligibility: [
'Aboriginal or Torres Strait Islander students',
'Australian citizens',
'Enrolled in eligible programs',
'Maintaining satisfactory progress'
],
description: 'Comprehensive support including financial assistance, mentoring, and cultural programs.',
type: 'indigenous',
deadline: 'December 31, 2024',
applicationUrl: '/apply/scholarship/indigenous'
}
];
const scholarshipTypes = [
{ value: 'merit', label: 'Merit Based', icon: <Award className="w-4 h-4" /> },
{ value: 'equity', label: 'Equity & Access', icon: <Users className="w-4 h-4" /> },
{ value: 'international', label: 'International', icon: <Globe className="w-4 h-4" /> },
{ value: 'research', label: 'Research', icon: <CheckCircle className="w-4 h-4" /> },
{ value: 'indigenous', label: 'Indigenous', icon: <Users className="w-4 h-4" /> }
];
const filteredScholarships = scholarships.filter(scholarship => {
if (searchQuery && !scholarship.title.toLowerCase().includes(searchQuery.toLowerCase()) &&
!scholarship.description.toLowerCase().includes(searchQuery.toLowerCase())) {
return false;
}
if (selectedType && scholarship.type !== selectedType) return false;
return true;
});
const clearFilters = () => {
setSearchQuery('');
setSelectedType('');
};
return (
<div className="min-h-screen bg-gray-50">
{/* Hero Section */}
<div className="bg-gradient-to-r from-emerald-600 to-teal-600 text-white">
<div className="container mx-auto px-4 py-20">
<div className="max-w-4xl mx-auto text-center">
<Award className="w-16 h-16 mx-auto mb-6 text-emerald-200" />
<h1 className="text-4xl md:text-5xl font-bold mb-6">
UTAS Scholarships
</h1>
<p className="text-xl opacity-90 mb-8">
Invest in your future with scholarships worth over $20 million annually. From merit-based awards to equity support, we help make education accessible.
</p>
<div className="grid md:grid-cols-3 gap-6 mb-8">
<div className="bg-white/10 backdrop-blur-sm rounded-xl p-6">
<div className="text-3xl font-bold mb-2">$15,000</div>
<div className="text-emerald-200">Maximum annual award</div>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-xl p-6">
<div className="text-3xl font-bold mb-2">70%</div>
<div className="text-emerald-200">Students receive support</div>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-xl p-6">
<div className="text-3xl font-bold mb-2">$20M+</div>
<div className="text-emerald-200">Total scholarships annually</div>
</div>
</div>
<Link
href="/apply/scholarships"
className="bg-white text-emerald-600 px-8 py-4 rounded-xl font-semibold hover:bg-gray-100 transition-all duration-200 inline-flex items-center"
>
Apply for Scholarships
<ArrowRight className="ml-2" size={20} />
</Link>
</div>
</div>
</div>
{/* Search and Filters */}
<div className="bg-white shadow-sm border-b border-gray-200">
<div className="container mx-auto px-4 py-6">
<div className="max-w-4xl mx-auto">
<div className="flex flex-col md:flex-row gap-4 items-center">
<div className="relative flex-grow">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400" size={20} />
<input
type="text"
placeholder="Search scholarships by name or description..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full pl-12 pr-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-emerald-500"
/>
</div>
<button
onClick={() => setShowFilters(!showFilters)}
className="flex items-center space-x-2 px-4 py-3 bg-gray-100 text-gray-700 rounded-xl hover:bg-gray-200 transition-colors"
>
<Filter size={20} />
<span>Filters</span>
</button>
</div>
{showFilters && (
<div className="mt-4 p-4 bg-gray-50 rounded-xl">
<div className="flex flex-wrap gap-3 items-center">
<span className="text-sm font-medium text-gray-700">Filter by type:</span>
{scholarshipTypes.map(type => (
<button
key={type.value}
onClick={() => setSelectedType(selectedType === type.value ? '' : type.value)}
className={`flex items-center space-x-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
selectedType === type.value
? 'bg-emerald-600 text-white'
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
}`}
>
{type.icon}
<span>{type.label}</span>
</button>
))}
{(searchQuery || selectedType) && (
<button
onClick={clearFilters}
className="ml-4 text-sm text-gray-600 hover:text-gray-800 underline"
>
Clear filters
</button>
)}
</div>
</div>
)}
</div>
</div>
</div>
{/* Scholarships Grid */}
<div className="container mx-auto px-4 py-12">
<div className="max-w-6xl mx-auto">
<div className="flex justify-between items-center mb-8">
<h2 className="text-2xl font-bold text-gray-900">
{filteredScholarships.length} Scholarships Available
</h2>
</div>
{filteredScholarships.length === 0 ? (
<div className="text-center py-12">
<Award size={64} className="mx-auto text-gray-400 mb-4" />
<h3 className="text-xl font-semibold text-gray-600 mb-2">No scholarships found</h3>
<p className="text-gray-500 mb-4">Try adjusting your search criteria</p>
<button
onClick={clearFilters}
className="bg-emerald-600 text-white px-6 py-2 rounded-lg hover:bg-emerald-700 transition-colors"
>
Clear Filters
</button>
</div>
) : (
<div className="grid gap-8">
{filteredScholarships.map((scholarship) => (
<div key={scholarship.id} className="bg-white rounded-xl shadow-sm border border-gray-200 hover:shadow-md transition-shadow">
<div className="p-8">
<div className="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
<div className="flex-grow">
<div className="flex items-start justify-between mb-4">
<div>
<div className="flex items-center space-x-3 mb-2">
<span className={`inline-flex items-center px-3 py-1 rounded-full text-xs font-medium ${
scholarship.type === 'merit' ? 'bg-blue-100 text-blue-800' :
scholarship.type === 'equity' ? 'bg-purple-100 text-purple-800' :
scholarship.type === 'international' ? 'bg-green-100 text-green-800' :
scholarship.type === 'research' ? 'bg-orange-100 text-orange-800' :
'bg-pink-100 text-pink-800'
}`}>
{scholarshipTypes.find(t => t.value === scholarship.type)?.label}
</span>
<div className="flex items-center text-gray-500 text-sm">
<Clock size={16} className="mr-1" />
Deadline: {scholarship.deadline}
</div>
</div>
<h3 className="text-2xl font-bold text-gray-900 mb-3">
{scholarship.title}
</h3>
<p className="text-gray-600 mb-4 leading-relaxed">
{scholarship.description}
</p>
</div>
</div>
<div className="grid md:grid-cols-2 gap-6 mb-6">
<div>
<h4 className="font-semibold text-gray-900 mb-2 flex items-center">
<DollarSign size={18} className="mr-2 text-green-600" />
Financial Details
</h4>
<ul className="text-gray-600 space-y-1">
<li><strong>Amount:</strong> {scholarship.amount}</li>
<li><strong>Duration:</strong> {scholarship.duration}</li>
</ul>
</div>
<div>
<h4 className="font-semibold text-gray-900 mb-2 flex items-center">
<CheckCircle size={18} className="mr-2 text-emerald-600" />
Eligibility Requirements
</h4>
<ul className="text-gray-600 space-y-1">
{scholarship.eligibility.slice(0, 2).map((req, index) => (
<li key={index}> {req}</li>
))}
{scholarship.eligibility.length > 2 && (
<li className="text-gray-500">+ {scholarship.eligibility.length - 2} more requirements</li>
)}
</ul>
</div>
</div>
</div>
<div className="flex-shrink-0 lg:w-64">
<div className="bg-gray-50 rounded-xl p-6 text-center">
<div className="text-3xl font-bold text-emerald-600 mb-2">
{scholarship.amount.split(' ')[0]}
</div>
<div className="text-gray-600 text-sm mb-4">
{scholarship.amount.includes('per year') ? 'per year' : 'total value'}
</div>
<Link
href={scholarship.applicationUrl}
className="w-full bg-emerald-600 text-white px-6 py-3 rounded-xl font-semibold hover:bg-emerald-700 transition-colors inline-flex items-center justify-center"
>
Apply Now
<ExternalLink className="ml-2" size={16} />
</Link>
<Link
href={`/scholarships/${scholarship.id}`}
className="w-full mt-3 border border-gray-300 text-gray-700 px-6 py-3 rounded-xl font-medium hover:bg-gray-50 transition-colors inline-block"
>
View Details
</Link>
</div>
</div>
</div>
</div>
</div>
))}
</div>
)}
</div>
</div>
{/* Application Tips */}
<div className="bg-white">
<div className="container mx-auto px-4 py-16">
<div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center text-gray-900 mb-12">
Scholarship Application Tips
</h2>
<div className="grid md:grid-cols-2 gap-8">
<div className="space-y-6">
<div className="flex items-start space-x-4">
<div className="flex-shrink-0 w-8 h-8 bg-emerald-100 rounded-full flex items-center justify-center">
<span className="text-emerald-600 font-bold text-sm">1</span>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-2">Apply Early</h3>
<p className="text-gray-600">Many scholarships have limited places. Submit your application as early as possible to maximize your chances.</p>
</div>
</div>
<div className="flex items-start space-x-4">
<div className="flex-shrink-0 w-8 h-8 bg-emerald-100 rounded-full flex items-center justify-center">
<span className="text-emerald-600 font-bold text-sm">2</span>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-2">Read Requirements Carefully</h3>
<p className="text-gray-600">Ensure you meet all eligibility criteria before applying. Some scholarships are automatically considered upon course application.</p>
</div>
</div>
<div className="flex items-start space-x-4">
<div className="flex-shrink-0 w-8 h-8 bg-emerald-100 rounded-full flex items-center justify-center">
<span className="text-emerald-600 font-bold text-sm">3</span>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-2">Prepare Strong Supporting Documents</h3>
<p className="text-gray-600">Personal statements, academic transcripts, and references should clearly demonstrate your eligibility and motivation.</p>
</div>
</div>
</div>
<div className="space-y-6">
<div className="flex items-start space-x-4">
<div className="flex-shrink-0 w-8 h-8 bg-emerald-100 rounded-full flex items-center justify-center">
<span className="text-emerald-600 font-bold text-sm">4</span>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-2">Apply for Multiple Scholarships</h3>
<p className="text-gray-600">You can often apply for multiple scholarships. Don&apos;t limit yourself to just one opportunity.</p>
</div>
</div>
<div className="flex items-start space-x-4">
<div className="flex-shrink-0 w-8 h-8 bg-emerald-100 rounded-full flex items-center justify-center">
<span className="text-emerald-600 font-bold text-sm">5</span>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-2">Maintain Academic Standards</h3>
<p className="text-gray-600">Most scholarships require you to maintain satisfactory academic progress to continue receiving funding.</p>
</div>
</div>
<div className="flex items-start space-x-4">
<div className="flex-shrink-0 w-8 h-8 bg-emerald-100 rounded-full flex items-center justify-center">
<span className="text-emerald-600 font-bold text-sm">6</span>
</div>
<div>
<h3 className="font-semibold text-gray-900 mb-2">Get Help if Needed</h3>
<p className="text-gray-600">Contact our Student Central team for guidance on scholarship applications and eligibility questions.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Call to Action */}
<div className="bg-gradient-to-r from-teal-600 to-emerald-600 text-white">
<div className="container mx-auto px-4 py-16">
<div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-4">Don&apos;t Miss Out on Funding Opportunities</h2>
<p className="text-xl opacity-90 mb-8">
Start your scholarship applications today and invest in your future success
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link
href="/apply/scholarships"
className="bg-white text-emerald-600 px-8 py-4 rounded-xl font-semibold hover:bg-gray-100 transition-all duration-200"
>
Apply for Scholarships
</Link>
<Link
href="/contact/scholarships"
className="border-2 border-white text-white px-8 py-4 rounded-xl font-semibold hover:bg-white hover:text-emerald-600 transition-all duration-200"
>
Get Scholarship Advice
</Link>
</div>
</div>
</div>
</div>
</div>
);
}
+341
View File
@@ -0,0 +1,341 @@
'use client';
import React, { useState, useMemo } from 'react';
import { useLanguage } from '@/components/providers/LanguageProvider';
import { Award, DollarSign, Users, CheckCircle, Clock, Search, Filter, ExternalLink, ArrowRight, CalendarDays, GraduationCap } from 'lucide-react';
import { mockScholarships, Scholarship } from '@/lib/mockData';
export default function ScholarshipsPage() {
const { language, t, dir } = useLanguage();
const [searchQuery, setSearchQuery] = useState('');
const [selectedCategory, setSelectedCategory] = useState('');
const [selectedStatus, setSelectedStatus] = useState('');
const [showFilters, setShowFilters] = useState(false);
// Filter scholarships based on search and filters
const filteredScholarships = useMemo(() => {
let results = mockScholarships;
// Text search
if (searchQuery) {
const query = searchQuery.toLowerCase();
results = results.filter(scholarship =>
(language === 'en' ? scholarship.title : scholarship.titleAr).toLowerCase().includes(query) ||
(language === 'en' ? scholarship.description : scholarship.descriptionAr).toLowerCase().includes(query) ||
(language === 'en' ? scholarship.value : scholarship.valueAr).toLowerCase().includes(query)
);
}
// Category filter
if (selectedCategory) {
results = results.filter(scholarship => scholarship.category === selectedCategory);
}
// Status filter
if (selectedStatus) {
results = results.filter(scholarship => scholarship.status === selectedStatus);
}
return results;
}, [searchQuery, selectedCategory, selectedStatus, language]);
const ScholarshipCard = ({ scholarship }: { scholarship: Scholarship }) => (
<div className="group bg-white rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden border border-gray-100">
<div className="p-6">
<div className="flex items-start justify-between mb-4">
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<div className={`p-2 rounded-lg ${
scholarship.category === 'merit' ? 'bg-blue-100 text-blue-600' :
scholarship.category === 'need' ? 'bg-green-100 text-green-600' :
scholarship.category === 'research' ? 'bg-purple-100 text-purple-600' :
'bg-orange-100 text-orange-600'
}`}>
<Award size={20} />
</div>
<div className="flex-1">
<h3 className="text-xl font-bold text-gray-900">
{language === 'en' ? scholarship.title : scholarship.titleAr}
</h3>
<div className="flex items-center gap-2 mt-1">
<span className={`px-3 py-1 rounded-full text-xs font-semibold ${
scholarship.status === 'open' ? 'bg-green-500 text-white' :
scholarship.status === 'closing' ? 'bg-yellow-500 text-white' :
'bg-red-500 text-white'
}`}>
{scholarship.status === 'open' ? (language === 'en' ? 'Open' : 'مفتوح') :
scholarship.status === 'closing' ? (language === 'en' ? 'Closing Soon' : 'يغلق قريباً') :
(language === 'en' ? 'Closed' : 'مغلق')}
</span>
<span className="text-sm text-gray-500 capitalize">
{scholarship.category === 'merit' ? (language === 'en' ? 'Merit-based' : 'على أساس الجدارة') :
scholarship.category === 'need' ? (language === 'en' ? 'Need-based' : 'على أساس الحاجة') :
scholarship.category === 'research' ? (language === 'en' ? 'Research' : 'بحثي') :
(language === 'en' ? 'International' : 'دولي')}
</span>
</div>
</div>
</div>
</div>
</div>
<p className="text-gray-600 mb-4 leading-relaxed">
{language === 'en' ? scholarship.description : scholarship.descriptionAr}
</p>
<div className="grid grid-cols-2 gap-4 mb-6">
<div className="flex items-center gap-2">
<DollarSign className="w-4 h-4 text-green-500" />
<div>
<div className="text-sm text-gray-500">{language === 'en' ? 'Value' : 'القيمة'}</div>
<div className="font-semibold text-gray-900">
{language === 'en' ? scholarship.value : scholarship.valueAr}
</div>
</div>
</div>
<div className="flex items-center gap-2">
<Clock className="w-4 h-4 text-blue-500" />
<div>
<div className="text-sm text-gray-500">{language === 'en' ? 'Duration' : 'المدة'}</div>
<div className="font-semibold text-gray-900">
{language === 'en' ? scholarship.duration : scholarship.durationAr}
</div>
</div>
</div>
</div>
<div className="mb-6">
<h4 className="font-semibold text-gray-900 mb-3 flex items-center gap-2">
<Users className="w-4 h-4" />
{language === 'en' ? 'Eligibility Requirements' : 'متطلبات الأهلية'}
</h4>
<ul className="space-y-2">
{(language === 'en' ? scholarship.eligibility : scholarship.eligibilityAr).slice(0, 3).map((requirement, index) => (
<li key={index} className="flex items-start gap-2 text-sm text-gray-600">
<CheckCircle className="w-4 h-4 text-green-500 mt-0.5 flex-shrink-0" />
<span>{requirement}</span>
</li>
))}
{(language === 'en' ? scholarship.eligibility : scholarship.eligibilityAr).length > 3 && (
<li className="text-sm text-gray-500 ml-6">
{language === 'en' ?
`+${(scholarship.eligibility.length - 3)} more requirements` :
`+${(scholarship.eligibilityAr.length - 3)} متطلبات أخرى`
}
</li>
)}
</ul>
</div>
<div className="bg-gray-50 rounded-lg p-4 mb-6">
<div className="flex items-center gap-2 mb-2">
<CalendarDays className="w-4 h-4 text-red-500" />
<span className="font-semibold text-gray-900">
{language === 'en' ? 'Application Deadline' : 'موعد التقديم النهائي'}
</span>
</div>
<div className="text-lg font-bold text-red-600">
{language === 'en' ? scholarship.deadline : scholarship.deadlineAr}
</div>
</div>
<div className="flex gap-3">
<button
className="flex-1 bg-blue-600 text-white py-3 px-4 rounded-lg font-semibold hover:bg-blue-700 transition-colors duration-200 flex items-center justify-center gap-2"
disabled={scholarship.status === 'closed'}
>
{scholarship.status === 'closed' ?
(language === 'en' ? 'Application Closed' : 'التقديم مغلق') :
(language === 'en' ? 'Apply Now' : 'قدم الآن')
}
{scholarship.status !== 'closed' && <ArrowRight size={16} />}
</button>
<button className="px-4 py-3 border border-gray-300 text-gray-700 rounded-lg font-semibold hover:bg-gray-50 transition-colors duration-200 flex items-center gap-2">
<ExternalLink size={16} />
{language === 'en' ? 'Details' : 'التفاصيل'}
</button>
</div>
</div>
</div>
);
return (
<div className={`min-h-screen bg-gray-50 ${dir === 'rtl' ? 'font-arabic' : ''}`} dir={dir}>
{/* Hero Section */}
<div className="bg-gradient-to-r from-blue-600 to-purple-600 text-white py-16">
<div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold mb-6">
{t('scholarships')} & {language === 'en' ? 'Financial Support' : 'الدعم المالي'}
</h1>
<p className="text-xl opacity-90 mb-8">
{language === 'en'
? 'Invest in your future with UTAS scholarships. Up to $15,000 per year available for eligible students.'
: 'استثمر في مستقبلك مع منح UTAS الدراسية. حتى 15,000 دولار سنوياً متاح للطلاب المؤهلين.'
}
</p>
<div className="flex justify-center space-x-8 text-center">
<div>
<div className="text-3xl font-bold">$15,000</div>
<div className="opacity-80">{language === 'en' ? 'Max Annual Value' : 'أقصى قيمة سنوية'}</div>
</div>
<div>
<div className="text-3xl font-bold">150+</div>
<div className="opacity-80">{language === 'en' ? 'Available Scholarships' : 'منحة متاحة'}</div>
</div>
<div>
<div className="text-3xl font-bold">85%</div>
<div className="opacity-80">{language === 'en' ? 'Students Receive Support' : 'الطلاب يتلقون الدعم'}</div>
</div>
</div>
</div>
</div>
</div>
<div className="container mx-auto px-4 py-8">
{/* Search and Filters */}
<div className="bg-white rounded-xl shadow-lg p-6 mb-8">
{/* Search Bar */}
<div className="relative mb-6">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400" size={20} />
<input
type="text"
placeholder={language === 'en' ? 'Search scholarships by name, value, or category...' : 'البحث عن المنح بالاسم أو القيمة أو الفئة...'}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full pl-12 pr-4 py-4 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-lg"
/>
</div>
{/* Filter Toggle */}
<button
onClick={() => setShowFilters(!showFilters)}
className="flex items-center gap-2 mb-4 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
<Filter size={16} />
{t('filter')}
</button>
{/* Filters */}
{showFilters && (
<div className="grid md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
{language === 'en' ? 'Category' : 'الفئة'}
</label>
<select
value={selectedCategory}
onChange={(e) => setSelectedCategory(e.target.value)}
className="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
>
<option value="">{language === 'en' ? 'All Categories' : 'جميع الفئات'}</option>
<option value="merit">{language === 'en' ? 'Merit-based' : 'على أساس الجدارة'}</option>
<option value="need">{language === 'en' ? 'Need-based' : 'على أساس الحاجة'}</option>
<option value="research">{language === 'en' ? 'Research' : 'بحثي'}</option>
<option value="international">{language === 'en' ? 'International' : 'دولي'}</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
{language === 'en' ? 'Status' : 'الحالة'}
</label>
<select
value={selectedStatus}
onChange={(e) => setSelectedStatus(e.target.value)}
className="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
>
<option value="">{language === 'en' ? 'All Status' : 'جميع الحالات'}</option>
<option value="open">{language === 'en' ? 'Open for Applications' : 'مفتوح للتقديم'}</option>
<option value="closing">{language === 'en' ? 'Closing Soon' : 'يغلق قريباً'}</option>
</select>
</div>
</div>
)}
</div>
{/* Results Header */}
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold text-gray-900">
{language === 'en' ? `${filteredScholarships.length} Scholarships Available` : `${filteredScholarships.length} منحة متاحة`}
</h2>
<div className="flex items-center gap-2 text-sm text-gray-600">
<GraduationCap size={16} />
{language === 'en' ? 'Sorted by deadline' : 'مرتب حسب الموعد النهائي'}
</div>
</div>
{/* Scholarships Grid */}
{filteredScholarships.length > 0 ? (
<div className="grid lg:grid-cols-2 gap-8">
{filteredScholarships.map(scholarship => (
<ScholarshipCard key={scholarship.id} scholarship={scholarship} />
))}
</div>
) : (
<div className="text-center py-12">
<Award size={64} className="mx-auto text-gray-300 mb-4" />
<h3 className="text-xl font-semibold text-gray-600 mb-2">{t('no_results')}</h3>
<p className="text-gray-500">
{language === 'en'
? 'Try adjusting your search or filters to find more scholarships.'
: 'حاول تعديل البحث أو المرشحات للعثور على المزيد من المنح.'
}
</p>
</div>
)}
{/* Application Tips */}
<div className="mt-16 bg-gradient-to-r from-purple-600 to-blue-600 rounded-xl p-8 text-white">
<h2 className="text-3xl font-bold mb-6 text-center">
{language === 'en' ? 'Scholarship Application Tips' : 'نصائح تقديم المنح الدراسية'}
</h2>
<div className="grid md:grid-cols-3 gap-6">
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<CheckCircle size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Apply Early' : 'قدم مبكراً'}
</h3>
<p className="opacity-90">
{language === 'en'
? 'Submit your application as early as possible to avoid deadline rush.'
: 'قدم طلبك في أقرب وقت ممكن لتجنب زحمة الموعد النهائي.'
}
</p>
</div>
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<Users size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Meet Requirements' : 'استوف المتطلبات'}
</h3>
<p className="opacity-90">
{language === 'en'
? 'Carefully review and ensure you meet all eligibility criteria.'
: 'راجع بعناية وتأكد من استيفائك لجميع معايير الأهلية.'
}
</p>
</div>
<div className="text-center">
<div className="bg-white bg-opacity-20 rounded-full p-4 w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<ExternalLink size={32} />
</div>
<h3 className="font-semibold mb-2">
{language === 'en' ? 'Prepare Documents' : 'حضر الوثائق'}
</h3>
<p className="opacity-90">
{language === 'en'
? 'Gather all required documents including transcripts and references.'
: 'اجمع جميع الوثائق المطلوبة بما في ذلك النصوص والمراجع.'
}
</p>
</div>
</div>
</div>
</div>
</div>
);
}
+435
View File
@@ -0,0 +1,435 @@
'use client';
import React, { useState, useEffect } from 'react'
import { useAuth } from '@/components/providers/MockAuthProvider'
import { useLanguage } from '@/components/providers/LanguageProvider'
import { useRouter } from 'next/navigation'
import {
Heart,
MessageCircle,
Phone,
Calendar,
LogOut,
Languages,
ArrowLeft,
AlertTriangle,
CheckCircle,
Clock,
Users
} from 'lucide-react'
import Link from 'next/link'
export default function WellbeingPage() {
const { user, userProfile, logout } = useAuth()
const { t, language, setLanguage } = useLanguage()
const router = useRouter()
const [messages, setMessages] = useState<Array<{id: string; text: string; sender: 'user' | 'bot'; timestamp: Date}>>([])
const [inputText, setInputText] = useState('')
const [isTyping, setIsTyping] = useState(false)
const [showEmergencyModal, setShowEmergencyModal] = useState(false)
useEffect(() => {
if (!user) {
router.push('/')
}
}, [user, router])
useEffect(() => {
// Start with a welcome message
setMessages([
{
id: '1',
text: 'Hello! I\'m here to support your mental health and wellbeing. How are you feeling today?',
sender: 'bot',
timestamp: new Date()
}
])
}, [])
const handleSendMessage = async () => {
if (!inputText.trim()) return
const userMessage = inputText.trim()
setInputText('')
const newMessage = {
id: Date.now().toString(),
text: userMessage,
sender: 'user' as const,
timestamp: new Date()
}
setMessages(prev => [...prev, newMessage])
setIsTyping(true)
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: userMessage,
mode: 'mental_health',
history: messages,
}),
})
const data = await response.json()
setIsTyping(false)
const botMessage = {
id: (Date.now() + 1).toString(),
text: data.response,
sender: 'bot' as const,
timestamp: new Date()
}
setMessages(prev => [...prev, botMessage])
// Check for escalation
if (data.shouldEscalate) {
setShowEmergencyModal(true)
}
} catch (error) {
setIsTyping(false)
console.error('Chat error:', error)
}
}
const handleLogout = async () => {
await logout()
}
const toggleLanguage = () => {
setLanguage(language === 'en' ? 'ar' : 'en')
}
if (!user || !userProfile) {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-pink-600 mx-auto mb-4"></div>
<p className="text-gray-600">Loading wellbeing support...</p>
</div>
</div>
)
}
return (
<div className="min-h-screen bg-gradient-to-br from-pink-50 to-purple-50">
{/* Header */}
<header className="bg-white shadow-sm border-b">
<div className="container mx-auto px-4 py-4">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
<Link href="/dashboard" className="flex items-center space-x-2 text-pink-600 hover:text-pink-800">
<ArrowLeft size={20} />
<span>Back to Dashboard</span>
</Link>
<div className="text-gray-300">|</div>
<div className="flex items-center space-x-2">
<Heart className="text-pink-600" size={24} />
<h1 className="text-xl font-bold text-gray-900">
{t('wellbeing')} Support
</h1>
</div>
</div>
<div className="flex items-center space-x-4">
<button
onClick={toggleLanguage}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors"
>
<Languages size={16} />
<span className="text-sm font-medium">{language.toUpperCase()}</span>
</button>
<div className="flex items-center space-x-3">
<div className="w-8 h-8 bg-pink-600 rounded-full flex items-center justify-center">
<span className="text-white text-sm font-medium">
{userProfile.name.charAt(0)}
</span>
</div>
<div className="hidden md:block">
<p className="text-sm font-medium text-gray-900">{userProfile.name}</p>
<p className="text-xs text-gray-500">{userProfile.role}</p>
</div>
</div>
<button
onClick={handleLogout}
className="flex items-center space-x-2 px-3 py-2 rounded-lg bg-red-100 hover:bg-red-200 transition-colors text-red-700"
>
<LogOut size={16} />
<span className="text-sm font-medium">{t('logout')}</span>
</button>
</div>
</div>
</div>
</header>
{/* Main Content */}
<main className="container mx-auto px-4 py-8">
<div className="max-w-4xl mx-auto">
{/* Welcome Section */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-8">
<h2 className="text-2xl font-bold text-gray-900 mb-4">
Welcome to Mental Health Support
</h2>
<p className="text-gray-600 mb-6">
Your wellbeing is important to us. This is a safe space where you can talk about how you&apos;re feeling.
Our AI assistant is trained to provide empathetic support and can connect you with professional help when needed.
</p>
{/* Emergency Resources */}
<div className="bg-red-50 border border-red-200 rounded-lg p-4 mb-6">
<div className="flex items-start space-x-3">
<AlertTriangle className="text-red-600 mt-0.5" size={20} />
<div>
<h3 className="font-medium text-red-900 mb-2">
Emergency Resources
</h3>
<p className="text-sm text-red-800 mb-3">
If you&apos;re experiencing a mental health emergency, please contact:
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<div className="flex items-center space-x-2">
<Phone className="text-red-600" size={16} />
<span className="text-sm text-red-800">Crisis Line: 988</span>
</div>
<div className="flex items-center space-x-2">
<Phone className="text-red-600" size={16} />
<span className="text-sm text-red-800">Campus Security: (555) 123-4567</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Chat Interface */}
<div className="lg:col-span-2">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 h-[600px] flex flex-col">
<div className="p-4 border-b bg-pink-50">
<h3 className="font-semibold text-gray-900 flex items-center space-x-2">
<MessageCircle className="text-pink-600" size={20} />
<span>Wellbeing Chat</span>
</h3>
</div>
{/* Messages */}
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.map((message) => (
<div
key={message.id}
className={`flex ${message.sender === 'user' ? 'justify-end' : 'justify-start'}`}
>
<div
className={`max-w-xs px-4 py-2 rounded-lg ${
message.sender === 'user'
? 'bg-pink-600 text-white'
: 'bg-pink-100 text-pink-900'
}`}
>
<p className="text-sm">{message.text}</p>
<p className="text-xs opacity-75 mt-1">
{message.timestamp.toLocaleTimeString()}
</p>
</div>
</div>
))}
{isTyping && (
<div className="flex justify-start">
<div className="bg-pink-100 px-4 py-2 rounded-lg text-pink-900">
<div className="flex items-center space-x-2">
<div className="flex space-x-1">
<div className="w-2 h-2 bg-pink-600 rounded-full animate-bounce"></div>
<div className="w-2 h-2 bg-pink-600 rounded-full animate-bounce" style={{ animationDelay: '0.1s' }}></div>
<div className="w-2 h-2 bg-pink-600 rounded-full animate-bounce" style={{ animationDelay: '0.2s' }}></div>
</div>
<span className="text-xs">Typing...</span>
</div>
</div>
</div>
)}
</div>
{/* Input */}
<div className="p-4 border-t">
<div className="flex space-x-2">
<input
type="text"
value={inputText}
onChange={(e) => setInputText(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
placeholder={t('type_message')}
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-pink-500"
/>
<button
onClick={handleSendMessage}
disabled={!inputText.trim()}
className="bg-pink-600 text-white px-4 py-2 rounded-lg hover:bg-pink-700 disabled:opacity-50 disabled:cursor-not-allowed"
>
{t('send')}
</button>
</div>
</div>
</div>
</div>
{/* Sidebar */}
<div className="space-y-6">
{/* Quick Actions */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="font-semibold text-gray-900 mb-4">Quick Actions</h3>
<div className="space-y-3">
<button
onClick={() => setShowEmergencyModal(true)}
className="w-full flex items-center space-x-3 p-3 bg-red-50 border border-red-200 rounded-lg hover:bg-red-100 transition-colors"
>
<Phone className="text-red-600" size={20} />
<span className="text-red-900 font-medium">Emergency Help</span>
</button>
<a
href="https://calendly.com/university-counseling"
target="_blank"
rel="noopener noreferrer"
className="w-full flex items-center space-x-3 p-3 bg-blue-50 border border-blue-200 rounded-lg hover:bg-blue-100 transition-colors"
>
<Calendar className="text-blue-600" size={20} />
<span className="text-blue-900 font-medium">{t('book_counselor')}</span>
</a>
<Link
href="/wellbeing/resources"
className="w-full flex items-center space-x-3 p-3 bg-green-50 border border-green-200 rounded-lg hover:bg-green-100 transition-colors"
>
<Heart className="text-green-600" size={20} />
<span className="text-green-900 font-medium">Self-Care Resources</span>
</Link>
</div>
</div>
{/* Counseling Services */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="font-semibold text-gray-900 mb-4">Counseling Services</h3>
<div className="space-y-4">
<div className="flex items-center space-x-3">
<CheckCircle className="text-green-600" size={16} />
<span className="text-sm text-gray-700">Individual counseling</span>
</div>
<div className="flex items-center space-x-3">
<CheckCircle className="text-green-600" size={16} />
<span className="text-sm text-gray-700">Group therapy sessions</span>
</div>
<div className="flex items-center space-x-3">
<CheckCircle className="text-green-600" size={16} />
<span className="text-sm text-gray-700">Crisis intervention</span>
</div>
<div className="flex items-center space-x-3">
<CheckCircle className="text-green-600" size={16} />
<span className="text-sm text-gray-700">Stress management workshops</span>
</div>
</div>
</div>
{/* Office Hours */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="font-semibold text-gray-900 mb-4">Office Hours</h3>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm text-gray-700">Monday - Friday</span>
<span className="text-sm font-medium text-gray-900">8:00 AM - 6:00 PM</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-700">Saturday</span>
<span className="text-sm font-medium text-gray-900">10:00 AM - 4:00 PM</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-700">Sunday</span>
<span className="text-sm font-medium text-gray-900">Closed</span>
</div>
<div className="border-t pt-3">
<div className="flex items-center space-x-2">
<Clock className="text-blue-600" size={16} />
<span className="text-sm text-blue-900">24/7 Crisis Line Available</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
{/* Emergency Modal */}
{showEmergencyModal && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg p-8 w-full max-w-md">
<div className="flex items-center space-x-3 mb-6">
<AlertTriangle className="text-red-600" size={24} />
<h3 className="text-xl font-bold text-gray-900">Emergency Support</h3>
</div>
<p className="text-gray-600 mb-6">
If you&apos;re experiencing a mental health emergency, please contact one of these resources immediately:
</p>
<div className="space-y-4 mb-6">
<div className="flex items-center space-x-3 p-3 bg-red-50 border border-red-200 rounded-lg">
<Phone className="text-red-600" size={20} />
<div>
<p className="font-medium text-red-900">Crisis Lifeline</p>
<p className="text-sm text-red-800">988</p>
</div>
</div>
<div className="flex items-center space-x-3 p-3 bg-blue-50 border border-blue-200 rounded-lg">
<Users className="text-blue-600" size={20} />
<div>
<p className="font-medium text-blue-900">Campus Counseling</p>
<p className="text-sm text-blue-800">(555) 123-4567</p>
</div>
</div>
<div className="flex items-center space-x-3 p-3 bg-green-50 border border-green-200 rounded-lg">
<Calendar className="text-green-600" size={20} />
<div>
<p className="font-medium text-green-900">Schedule Appointment</p>
<a
href="https://calendly.com/university-counseling"
target="_blank"
rel="noopener noreferrer"
className="text-sm text-green-800 hover:underline"
>
Book with Counselor
</a>
</div>
</div>
</div>
<div className="flex space-x-4">
<button
onClick={() => setShowEmergencyModal(false)}
className="flex-1 bg-gray-300 text-gray-700 py-2 rounded-lg hover:bg-gray-400 transition-colors"
>
Close
</button>
<a
href="tel:988"
className="flex-1 bg-red-600 text-white py-2 rounded-lg hover:bg-red-700 transition-colors text-center"
>
Call 988
</a>
</div>
</div>
</div>
)}
</div>
)
}