source: src/app/semesters/page.tsx@ 636f86c

Last change on this file since 636f86c was 636f86c, checked in by stefansaveski <stefansaveski19@…>, 12 months ago

Add initial data files for applications, documents, semesters, student profiles, and subjects

  • Created applications.json with exam sessions and application details for 2024 and 2025.
  • Added documents.json containing various document types and their associated fees.
  • Introduced semesters.json with details of semesters, including status and financial information.
  • Established student-profile.json with personal and educational information for a sample student.
  • Implemented subjects.json detailing subjects offered per semester along with their respective professors and statuses.
  • Property mode set to 100644
File size: 12.7 KB
Line 
1"use client"
2
3import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4import {
5 faCalendarAlt,
6 faCheck,
7 faTimes,
8 faFileAlt,
9 faMoneyBillWave,
10 faSignature,
11 faCheckCircle,
12 faTimesCircle,
13 faExclamationTriangle
14} from '@fortawesome/free-solid-svg-icons';
15import semestersData from '@/data/semesters.json';
16
17interface TableCellProps {
18 children: React.ReactNode;
19 className?: string;
20}
21
22const TableCell = ({ children, className = "" }: TableCellProps) => (
23 <td className={`px-4 py-3 text-sm border-b border-gray-100 ${className}`}>
24 {children}
25 </td>
26);
27
28const StatusBadge = ({ status }: { status: string }) => {
29 const baseClasses = "px-2 py-1 rounded-full text-xs font-medium";
30
31 if (status === "валиден") {
32 return (
33 <span className={`${baseClasses} bg-green-100 text-green-800 flex items-center gap-1`}>
34 <FontAwesomeIcon icon={faCheckCircle} className="w-3 h-3" />
35 {status}
36 </span>
37 );
38 }
39
40 return (
41 <span className={`${baseClasses} bg-gray-100 text-gray-800`}>
42 {status}
43 </span>
44 );
45};
46
47const YesNoBadge = ({ value }: { value: string }) => {
48 if (value === "Да") {
49 return (
50 <span className="inline-flex items-center justify-center w-6 h-6 bg-green-100 text-green-600 rounded-full">
51 <FontAwesomeIcon icon={faCheck} className="w-3 h-3" />
52 </span>
53 );
54 } else if (value === "Не") {
55 return (
56 <span className="inline-flex items-center justify-center w-6 h-6 bg-red-100 text-red-600 rounded-full">
57 <FontAwesomeIcon icon={faTimes} className="w-3 h-3" />
58 </span>
59 );
60 }
61 return <span className="text-gray-400">—</span>;
62};
63
64const SignatureBadge = ({ signatures }: { signatures: string }) => {
65 const [completed, total] = signatures.split('/').map(Number);
66 const percentage = total > 0 ? (completed / total) * 100 : 0;
67
68 let colorClass = "text-red-600 bg-red-100";
69 if (percentage === 100) {
70 colorClass = "text-green-600 bg-green-100";
71 } else if (percentage >= 50) {
72 colorClass = "text-yellow-600 bg-yellow-100";
73 }
74
75 return (
76 <span className={`px-2 py-1 rounded-full text-xs font-medium flex items-center gap-1 ${colorClass}`}>
77 <FontAwesomeIcon icon={faSignature} className="w-3 h-3" />
78 {signatures}
79 </span>
80 );
81};
82
83export default function SemestersPage() {
84 const { semesters } = semestersData;
85
86 return (
87 <div className="min-h-screen pb-8">
88 {/* Header */}
89 <div className="bg-primary text-white rounded-xl p-8 mb-8">
90 <div className="flex items-center gap-4">
91 <div className="bg-white bg-opacity-20 rounded-full p-4">
92 <FontAwesomeIcon icon={faCalendarAlt} className="text-3xl text-primary" />
93 </div>
94 <div>
95 <h1 className="text-3xl font-bold mb-2">Семестри</h1>
96 <p className="text-lg opacity-90">
97 Преглед на сите запишани семестри и нивниот статус
98 </p>
99 </div>
100 </div>
101 </div>
102
103 {/* Table Container */}
104 <div className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
105 <div className="bg-primary text-white px-6 py-4">
106 <h2 className="text-xl font-bold">Листа на семестри</h2>
107 </div>
108
109 <div className="overflow-x-auto">
110 <table className="w-full">
111 <thead className="bg-gray-50">
112 <tr>
113 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">#</th>
114 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Семестар</th>
115 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Насока</th>
116 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Квота</th>
117 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Забелешка</th>
118 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Студ.Ком.</th>
119 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Сума</th>
120 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Платено</th>
121 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">УКИМ</th>
122 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Креирано на</th>
123 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Датум промена</th>
124 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Ц.Кр</th>
125 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Тип</th>
126 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Док.</th>
127 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Док1.</th>
128 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Вериф.</th>
129 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Таксени</th>
130 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Потписи</th>
131 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Статус</th>
132 <th className="px-4 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Зав.</th>
133 </tr>
134 </thead>
135 <tbody className="divide-y divide-gray-100">
136 {semesters.map((semester, index) => (
137 <tr key={semester.id} className="hover:bg-gray-50 transition-colors">
138 <TableCell className="font-medium text-gray-900">{semester.id}</TableCell>
139 <TableCell className="font-medium text-primary">{semester.semester}</TableCell>
140 <TableCell>{semester.direction}</TableCell>
141 <TableCell className="max-w-xs">
142 <div className="truncate" title={semester.quota}>
143 {semester.quota}
144 </div>
145 </TableCell>
146 <TableCell>
147 {semester.note ? (
148 <span className="text-yellow-600 font-medium" title={semester.note}>
149 {semester.note.length > 10 ? `${semester.note.substring(0, 10)}...` : semester.note}
150 </span>
151 ) : (
152 <span className="text-gray-400">—</span>
153 )}
154 </TableCell>
155 <TableCell>
156 {semester.studentCom ? (
157 <span className="text-blue-600 font-medium" title={semester.studentCom}>
158 {semester.studentCom.length > 10 ? `${semester.studentCom.substring(0, 10)}...` : semester.studentCom}
159 </span>
160 ) : (
161 <span className="text-gray-400">—</span>
162 )}
163 </TableCell>
164 <TableCell className="font-medium">
165 {semester.sum ? (
166 <span className="text-green-600 flex items-center gap-1">
167 <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
168 {semester.sum}
169 </span>
170 ) : (
171 <span className="text-gray-400">—</span>
172 )}
173 </TableCell>
174 <TableCell className="font-medium">
175 {semester.paid ? (
176 <span className="text-green-600 flex items-center gap-1">
177 <FontAwesomeIcon icon={faMoneyBillWave} className="w-3 h-3" />
178 {semester.paid}
179 </span>
180 ) : (
181 <span className="text-gray-400">—</span>
182 )}
183 </TableCell>
184 <TableCell className="font-medium">
185 {semester.ukim ? (
186 <span className="text-blue-600">{semester.ukim}</span>
187 ) : (
188 <span className="text-gray-400">—</span>
189 )}
190 </TableCell>
191 <TableCell className="text-gray-600">{semester.createdOn}</TableCell>
192 <TableCell className="text-gray-600">{semester.dateChanged}</TableCell>
193 <TableCell className="font-medium text-primary">{semester.credits}</TableCell>
194 <TableCell>
195 <span className="px-2 py-1 bg-blue-100 text-blue-800 rounded-full text-xs font-medium">
196 {semester.type}
197 </span>
198 </TableCell>
199 <TableCell className="text-center">
200 <YesNoBadge value={semester.doc} />
201 </TableCell>
202 <TableCell className="text-center">
203 <YesNoBadge value={semester.doc1} />
204 </TableCell>
205 <TableCell className="text-center">
206 <YesNoBadge value={semester.verified} />
207 </TableCell>
208 <TableCell className="font-medium text-green-600">{semester.taxes}</TableCell>
209 <TableCell>
210 <SignatureBadge signatures={semester.signatures} />
211 </TableCell>
212 <TableCell>
213 <StatusBadge status={semester.status} />
214 </TableCell>
215 <TableCell>
216 {semester.completed !== "Не" ? (
217 <span className="text-green-600 font-medium flex items-center gap-1">
218 <FontAwesomeIcon icon={faCheckCircle} className="w-3 h-3" />
219 {semester.completed}
220 </span>
221 ) : (
222 <span className="text-red-600 font-medium flex items-center gap-1">
223 <FontAwesomeIcon icon={faTimesCircle} className="w-3 h-3" />
224 {semester.completed}
225 </span>
226 )}
227 </TableCell>
228 </tr>
229 ))}
230 </tbody>
231 </table>
232 </div>
233 </div>
234
235 {/* Summary Cards */}
236 <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
237 <div className="bg-white rounded-xl p-6 shadow-sm border border-gray-100">
238 <div className="flex items-center gap-4">
239 <div className="bg-green-100 text-green-600 rounded-full p-3">
240 <FontAwesomeIcon icon={faCheckCircle} className="text-xl" />
241 </div>
242 <div>
243 <h3 className="text-lg font-bold text-gray-900">Завршени семестри</h3>
244 <p className="text-2xl font-bold text-green-600">
245 {semesters.filter(s => s.completed !== "Не").length}
246 </p>
247 </div>
248 </div>
249 </div>
250
251 <div className="bg-white rounded-xl p-6 shadow-sm border border-gray-100">
252 <div className="flex items-center gap-4">
253 <div className="bg-blue-100 text-blue-600 rounded-full p-3">
254 <FontAwesomeIcon icon={faFileAlt} className="text-xl" />
255 </div>
256 <div>
257 <h3 className="text-lg font-bold text-gray-900">Верифицирани</h3>
258 <p className="text-2xl font-bold text-blue-600">
259 {semesters.filter(s => s.verified === "Да").length}
260 </p>
261 </div>
262 </div>
263 </div>
264
265 <div className="bg-white rounded-xl p-6 shadow-sm border border-gray-100">
266 <div className="flex items-center gap-4">
267 <div className="bg-primary text-white rounded-full p-3">
268 <FontAwesomeIcon icon={faCalendarAlt} className="text-xl" />
269 </div>
270 <div>
271 <h3 className="text-lg font-bold text-gray-900">Вкупно семестри</h3>
272 <p className="text-2xl font-bold text-primary">
273 {semesters.length}
274 </p>
275 </div>
276 </div>
277 </div>
278 </div>
279 </div>
280 );
281}
Note: See TracBrowser for help on using the repository browser.