source: frontend/src/app/students/applications/page.tsx

Last change on this file was b8093a0, checked in by imbrsk <boris696boris@…>, 3 days ago

Merge iknow-remaster into frontend/

Bring the Next.js frontend into this repository as a monorepo subdirectory,
preserving its full commit history via a subtree merge.

  • Property mode set to 100644
File size: 11.6 KB
RevLine 
[636f86c]1"use client"
2
3import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4import {
5 faPenToSquare,
6 faChevronDown,
7 faCalendarAlt,
8 faFileText,
9 faMoneyBillWave,
10 faUser,
11 faInfoCircle,
12 faCheckCircle,
13 faTimesCircle
14} from '@fortawesome/free-solid-svg-icons';
15import { useState } from 'react';
[50f2fb4]16import { useTranslation } from 'react-i18next';
[636f86c]17import applicationsData from '@/data/applications.json';
18
19interface TableCellProps {
20 children: React.ReactNode;
21 className?: string;
22}
23
24const TableCell = ({ children, className = "" }: TableCellProps) => (
[ba52069]25 <td className={`px-4 py-3 text-sm border-b border-border ${className}`}>
[636f86c]26 {children}
27 </td>
28);
29
30const CompletedBadge = ({ completed }: { completed: string }) => {
[50f2fb4]31 const { t } = useTranslation();
[4fe4582]32 if (completed === 'Да') {
[636f86c]33 return (
[50f2fb4]34 <span className="inline-flex items-center justify-center w-6 h-6 bg-green-100 text-green-600 rounded-full" title={t('completed')}>
[636f86c]35 <FontAwesomeIcon icon={faCheckCircle} className="w-4 h-4" />
36 </span>
37 );
38 } else {
39 return (
[50f2fb4]40 <span className="inline-flex items-center justify-center w-6 h-6 bg-red-100 text-red-600 rounded-full" title={t('not_completed')}>
[636f86c]41 <FontAwesomeIcon icon={faTimesCircle} className="w-4 h-4" />
42 </span>
43 );
44 }
45};
46
47const FeeBadge = ({ fee }: { fee: string }) => {
48 const feeValue = parseFloat(fee.replace(',', '.'));
49
50 if (feeValue === 0) {
51 return (
52 <span className="inline-flex items-center gap-1 px-2 py-1 bg-green-100 text-green-800 rounded-md text-xs font-medium">
53 <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
54 {fee}
55 </span>
56 );
57 } else {
58 return (
59 <span className="inline-flex items-center gap-1 px-2 py-1 bg-yellow-100 text-yellow-800 rounded-md text-xs font-medium">
60 <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
61 {fee}
62 </span>
63 );
64 }
65};
66
67export default function ApplicationsPage() {
[50f2fb4]68 const { t } = useTranslation();
[636f86c]69 const [selectedSession, setSelectedSession] = useState(applicationsData.currentSession.id);
70 const [isDropdownOpen, setIsDropdownOpen] = useState(false);
[50f2fb4]71
[636f86c]72 const currentSessionData = applicationsData.examSessions.find(s => s.id === selectedSession) || applicationsData.currentSession;
73 const { applications } = applicationsData;
74
75 return (
76 <div className="min-h-screen pb-8">
77 {/* Header */}
78 <div className="bg-primary text-white rounded-xl p-8 mb-8">
79 <div className="flex items-center gap-4">
[ba52069]80 <div className="bg-white rounded-full p-4">
81 <FontAwesomeIcon icon={faPenToSquare} className="text-3xl text-[#0272D1]" />
[636f86c]82 </div>
83 <div>
[50f2fb4]84 <h1 className="text-3xl font-bold mb-2">{t('applications_header', 'Пријави')}</h1>
[636f86c]85 <p className="text-lg opacity-90">
[50f2fb4]86 {t('applications_subheader', 'Електронски пријави за испити')}
[636f86c]87 </p>
88 </div>
89 </div>
90 </div>
91
92 {/* Session Selection */}
[ba52069]93 <div className="bg-card rounded-xl p-6 shadow-sm border border-border mb-8">
[636f86c]94 <div className="flex items-center justify-between">
[ba52069]95 <h2 className="text-lg font-semibold text-card-foreground flex items-center gap-2">
[636f86c]96 <FontAwesomeIcon icon={faCalendarAlt} className="text-primary" />
[50f2fb4]97 {t('select_exam_session', 'Избери испитна сесија:')}
[636f86c]98 </h2>
[50f2fb4]99
[636f86c]100 <div className="relative">
101 <button
102 onClick={() => setIsDropdownOpen(!isDropdownOpen)}
[ba52069]103 className="bg-card border border-border rounded-lg px-4 py-2 text-left focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary min-w-80"
[636f86c]104 >
105 <div className="flex items-center justify-between">
106 <span className="text-sm font-medium text-primary">
[50f2fb4]107 {t(currentSessionData.id, currentSessionData.name)}
[636f86c]108 </span>
[50f2fb4]109 <FontAwesomeIcon
110 icon={faChevronDown}
[ba52069]111 className={`w-4 h-4 text-muted-foreground transition-transform ml-4 ${isDropdownOpen ? 'rotate-180' : ''}`}
[636f86c]112 />
113 </div>
114 </button>
[50f2fb4]115
[636f86c]116 {isDropdownOpen && (
[ba52069]117 <div className="absolute z-10 right-0 mt-1 w-80 bg-card border border-border rounded-lg shadow-lg">
[636f86c]118 {applicationsData.examSessions.map((session) => (
119 <button
120 key={session.id}
121 onClick={() => {
122 setSelectedSession(session.id);
123 setIsDropdownOpen(false);
124 }}
[ba52069]125 className="w-full px-4 py-3 text-left text-sm hover:bg-accent focus:outline-none focus:bg-accent first:rounded-t-lg last:rounded-b-lg"
[636f86c]126 >
[ba52069]127 <div className="font-medium text-card-foreground">{t(session.id, session.name)}</div>
128 <div className="text-xs text-muted-foreground">{session.year} - {t(session.semester, session.semester)} - {t(session.session, session.session)}</div>
[636f86c]129 </button>
130 ))}
131 </div>
132 )}
133 </div>
134 </div>
135 </div>
136
137 {/* Applications Section */}
[ba52069]138 <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
[636f86c]139 <div className="bg-primary text-white px-6 py-4">
[50f2fb4]140 <h2 className="text-xl font-bold">{t('registered_exams', 'Пријавени испити')}</h2>
[636f86c]141 </div>
[50f2fb4]142
[636f86c]143 <div className="overflow-x-auto">
144 <table className="w-full">
[ba52069]145 <thead className="bg-accent">
[636f86c]146 <tr>
[ba52069]147 <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">#</th>
148 <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('serial_number', 'Сериски број')}</th>
149 <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('code', 'Код')}</th>
150 <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('subject', 'Предмет')}</th>
151 <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('completed', 'Завршена')}</th>
152 <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('fee', 'Таксени')}</th>
153 <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('date', 'Датум')}</th>
154 <th className="px-4 py-4 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('instructor', 'Наставник')}</th>
155 <th className="px-4 py-4 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider">{t('decade', 'Декада')}</th>
[636f86c]156 </tr>
157 </thead>
[ba52069]158 <tbody className="divide-y divide-border">
[636f86c]159 {applications.map((application) => (
[ba52069]160 <tr key={application.id} className="hover:bg-accent transition-colors">
161 <TableCell className="font-medium text-card-foreground">{application.id}</TableCell>
[636f86c]162 <TableCell>
163 <span className="font-mono text-sm text-primary font-medium hover:underline cursor-pointer">
164 {application.serviceNumber}
165 </span>
166 </TableCell>
167 <TableCell className="font-mono text-sm font-medium">{application.code}</TableCell>
[ba52069]168 <TableCell className="font-medium text-card-foreground max-w-xs">
[636f86c]169 <div className="flex items-center gap-2">
170 <FontAwesomeIcon icon={faFileText} className="w-4 h-4 text-primary" />
[50f2fb4]171 {t(application.subject, application.subject)}
[636f86c]172 </div>
173 </TableCell>
174 <TableCell className="text-center">
175 <CompletedBadge completed={application.completed} />
176 </TableCell>
177 <TableCell className="text-center">
178 <FeeBadge fee={application.fee} />
179 </TableCell>
[ba52069]180 <TableCell className="text-muted-foreground font-medium">{application.date}</TableCell>
[636f86c]181 <TableCell>
182 <div className="flex items-center gap-2">
[ba52069]183 <FontAwesomeIcon icon={faUser} className="w-4 h-4 text-muted-foreground" />
184 <span className="font-medium text-card-foreground">{t(application.instructor, application.instructor)}</span>
[636f86c]185 </div>
186 </TableCell>
187 <TableCell className="text-center font-medium text-primary">{application.decade}</TableCell>
188 </tr>
189 ))}
190 </tbody>
191 </table>
192 </div>
193
194 {/* Important Note */}
195 <div className="bg-blue-50 border-t border-blue-100 p-6">
196 <div className="flex items-start gap-3">
197 <FontAwesomeIcon icon={faInfoCircle} className="w-5 h-5 text-blue-600 mt-0.5 flex-shrink-0" />
198 <div>
[50f2fb4]199 <h3 className="font-medium text-blue-900 mb-1">{t('important_note', 'Важна забелешка')}</h3>
[636f86c]200 <p className="text-sm text-blue-800 leading-relaxed">
[50f2fb4]201 {t('applications_important_note_text')}
[636f86c]202 </p>
203 </div>
204 </div>
205 </div>
206 </div>
207
208 {/* Statistics Cards */}
209 <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
[ba52069]210 <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
[636f86c]211 <div className="flex items-center gap-4">
212 <div className="bg-blue-100 text-blue-600 rounded-full p-3">
213 <FontAwesomeIcon icon={faFileText} className="text-xl" />
214 </div>
215 <div>
[ba52069]216 <h3 className="text-lg font-bold text-card-foreground">{t('registered_exams', 'Пријавени испити')}</h3>
[636f86c]217 <p className="text-2xl font-bold text-blue-600">
218 {applications.length}
219 </p>
220 </div>
221 </div>
222 </div>
223
[ba52069]224 <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
[636f86c]225 <div className="flex items-center gap-4">
226 <div className="bg-green-100 text-green-600 rounded-full p-3">
227 <FontAwesomeIcon icon={faCheckCircle} className="text-xl" />
228 </div>
229 <div>
[ba52069]230 <h3 className="text-lg font-bold text-card-foreground">{t('completed', 'Завршени')}</h3>
[636f86c]231 <p className="text-2xl font-bold text-green-600">
[4fe4582]232 {applications.filter(app => app.completed === 'Да').length}
[636f86c]233 </p>
234 </div>
235 </div>
236 </div>
237
[ba52069]238 <div className="bg-card rounded-xl p-6 shadow-sm border border-border">
[636f86c]239 <div className="flex items-center gap-4">
240 <div className="bg-yellow-100 text-yellow-600 rounded-full p-3">
241 <FontAwesomeIcon icon={faMoneyBillWave} className="text-xl" />
242 </div>
243 <div>
[ba52069]244 <h3 className="text-lg font-bold text-card-foreground">{t('total_fee', 'Вкупна такса')}</h3>
[636f86c]245 <p className="text-2xl font-bold text-yellow-600">
246 {applications.reduce((sum, app) => sum + parseFloat(app.fee.replace(',', '.')), 0).toFixed(2)}
247 </p>
248 </div>
249 </div>
250 </div>
251 </div>
252 </div>
253 );
254}
Note: See TracBrowser for help on using the repository browser.