farwew commited on
Commit
625a0da
·
verified ·
1 Parent(s): f1dc12f

Upload 9 files

Browse files
Files changed (3) hide show
  1. app.py +10 -6
  2. database.py +3 -1
  3. templates/index.html +467 -467
app.py CHANGED
@@ -58,13 +58,17 @@ def cetak_pdf():
58
  pdf.cell(80, 6, row['nama_lengkap'], 1, 0)
59
  pdf.cell(40, 6, str(row['no_hp']), 1, 0, 'C')
60
 
61
- # Format date for display - handle both datetime object and string
62
  tanggal = row['tanggal_lahir']
63
- if isinstance(tanggal, datetime):
64
- formatted_date = tanggal.strftime('%d-%m-%Y')
65
- else:
66
- # If it's already a string, use it directly
67
- formatted_date = tanggal
 
 
 
 
68
 
69
  pdf.cell(40, 6, formatted_date, 1, 1, 'C')
70
 
 
58
  pdf.cell(80, 6, row['nama_lengkap'], 1, 0)
59
  pdf.cell(40, 6, str(row['no_hp']), 1, 0, 'C')
60
 
61
+ # Improved date handling in the PDF generation
62
  tanggal = row['tanggal_lahir']
63
+ try:
64
+ if isinstance(tanggal, datetime):
65
+ formatted_date = tanggal.strftime('%d-%m-%Y')
66
+ else:
67
+ # Try to convert if it's a string in YYYY-MM-DD format
68
+ formatted_date = datetime.strptime(tanggal, '%Y-%m-%d').strftime('%d-%m-%Y')
69
+ except Exception:
70
+ # Fallback if parsing fails
71
+ formatted_date = str(tanggal)
72
 
73
  pdf.cell(40, 6, formatted_date, 1, 1, 'C')
74
 
database.py CHANGED
@@ -12,7 +12,9 @@ DB_NAME = os.environ.get('MONGO_DB_NAME', 'student_reports')
12
 
13
  def get_db_connection():
14
  try:
15
- client = MongoClient(MONGO_URI)
 
 
16
  db = client[DB_NAME]
17
  return db
18
  except Exception as e:
 
12
 
13
  def get_db_connection():
14
  try:
15
+ client = MongoClient(MONGO_URI, serverSelectionTimeoutMS=5000)
16
+ # Test the connection
17
+ client.server_info()
18
  db = client[DB_NAME]
19
  return db
20
  except Exception as e:
templates/index.html CHANGED
@@ -1,467 +1,467 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Sistem Laporan Siswa</title>
7
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
8
- <style>
9
- :root {
10
- --primary-color: #6d28d9; /* Ungu - matching with tambah_siswa.html */
11
- --secondary-color: #7c3aed;
12
- --success-color: #10b981; /* Green */
13
- --background-color: #f3f4f6;
14
- --card-color: #ffffff;
15
- --text-color: #374151;
16
- --border-color: #e5e7eb;
17
- --shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05);
18
- }
19
-
20
- * {
21
- margin: 0;
22
- padding: 0;
23
- box-sizing: border-box;
24
- }
25
-
26
- body {
27
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
28
- margin: 0;
29
- padding: 20px;
30
- background-color: var(--background-color);
31
- line-height: 1.6;
32
- color: var(--text-color);
33
- }
34
-
35
- .container {
36
- max-width: 1100px;
37
- margin: 0 auto;
38
- background-color: var(--card-color);
39
- padding: 30px;
40
- border-radius: 1rem;
41
- box-shadow: var(--shadow);
42
- animation: fadeIn 0.5s ease;
43
- }
44
-
45
- @keyframes fadeIn {
46
- from { opacity: 0; transform: translateY(20px); }
47
- to { opacity: 1; transform: translateY(0); }
48
- }
49
-
50
- .header {
51
- text-align: center;
52
- margin-bottom: 30px;
53
- padding-bottom: 20px;
54
- border-bottom: 2px solid var(--border-color);
55
- position: relative;
56
- }
57
-
58
- .header::after {
59
- content: '';
60
- position: absolute;
61
- bottom: -2px;
62
- left: 50%;
63
- transform: translateX(-50%);
64
- width: 100px;
65
- height: 4px;
66
- background-color: var(--primary-color);
67
- border-radius: 2px;
68
- }
69
-
70
- h1 {
71
- color: var(--primary-color);
72
- margin: 0;
73
- font-size: 28px;
74
- font-weight: 700;
75
- letter-spacing: -0.5px;
76
- }
77
-
78
- h2 {
79
- color: #555;
80
- font-size: 22px;
81
- margin: 15px 0;
82
- font-weight: 600;
83
- }
84
-
85
- h3 {
86
- color: var(--text-color);
87
- margin: 25px 0 15px 0;
88
- font-size: 18px;
89
- font-weight: 600;
90
- position: relative;
91
- padding-left: 15px;
92
- }
93
-
94
- h3::before {
95
- content: '';
96
- position: absolute;
97
- left: 0;
98
- top: 50%;
99
- transform: translateY(-50%);
100
- width: 5px;
101
- height: 20px;
102
- background-color: var(--primary-color);
103
- border-radius: 3px;
104
- }
105
-
106
- .action-buttons {
107
- display: flex;
108
- justify-content: center;
109
- gap: 20px;
110
- margin: 25px 0;
111
- }
112
-
113
- .action-btn {
114
- padding: 12px 25px;
115
- border-radius: 8px;
116
- color: white;
117
- text-decoration: none;
118
- font-weight: 600;
119
- display: flex;
120
- align-items: center;
121
- justify-content: center;
122
- transition: all 0.3s ease;
123
- }
124
-
125
- .action-btn i {
126
- margin-right: 8px;
127
- font-size: 16px;
128
- }
129
-
130
- .action-btn:hover {
131
- transform: translateY(-3px);
132
- box-shadow: 0 5px 15px rgba(0,0,0,0.1);
133
- }
134
-
135
- .btn-print {
136
- background-color: var(--success-color);
137
- }
138
-
139
- .btn-print:hover {
140
- background-color: #0da76f;
141
- }
142
-
143
- .btn-add {
144
- background-color: var(--primary-color);
145
- }
146
-
147
- .btn-add:hover {
148
- background-color: var(--secondary-color);
149
- }
150
-
151
- .table-container {
152
- overflow-x: auto;
153
- border-radius: 8px;
154
- box-shadow: var(--shadow);
155
- }
156
-
157
- table {
158
- width: 100%;
159
- border-collapse: collapse;
160
- border-radius: 8px;
161
- overflow: hidden;
162
- }
163
-
164
- th, td {
165
- padding: 15px 20px;
166
- text-align: left;
167
- }
168
-
169
- th {
170
- background-color: var(--primary-color);
171
- color: white;
172
- font-weight: 600;
173
- text-transform: uppercase;
174
- font-size: 14px;
175
- letter-spacing: 0.5px;
176
- }
177
-
178
- tr:nth-child(even) {
179
- background-color: #f9fafb;
180
- }
181
-
182
- tr:not(thead tr) {
183
- border-bottom: 1px solid var(--border-color);
184
- }
185
-
186
- tr:last-child {
187
- border-bottom: none;
188
- }
189
-
190
- tr:hover:not(thead tr) {
191
- background-color: #f3f4f6;
192
- }
193
-
194
- td {
195
- transition: all 0.2s ease;
196
- }
197
-
198
- .alert {
199
- padding: 15px 20px;
200
- background-color: #ecfdf5;
201
- border-left: 4px solid var(--success-color);
202
- color: #065f46;
203
- border-radius: 8px;
204
- margin-bottom: 20px;
205
- display: flex;
206
- align-items: center;
207
- opacity: 1;
208
- transition: opacity 0.5s ease, transform 0.5s ease;
209
- transform: translateY(0);
210
- box-shadow: 0 2px 5px rgba(0,0,0,0.05);
211
- {% if status != 'success' %}display: none;{% endif %}
212
- }
213
-
214
- .alert i {
215
- margin-right: 10px;
216
- font-size: 20px;
217
- color: var(--success-color);
218
- }
219
-
220
- .alert.fade-out {
221
- opacity: 0;
222
- transform: translateY(-20px);
223
- }
224
-
225
- .empty-state {
226
- text-align: center;
227
- padding: 40px 20px;
228
- color: #6b7280;
229
- }
230
-
231
- .empty-state i {
232
- font-size: 48px;
233
- color: #d1d5db;
234
- margin-bottom: 15px;
235
- }
236
-
237
- .empty-state p {
238
- font-size: 16px;
239
- margin-bottom: 20px;
240
- }
241
-
242
- /* Action icons styling */
243
- .actions {
244
- width: 100px;
245
- text-align: center;
246
- }
247
-
248
- .action-icon {
249
- display: inline-flex;
250
- align-items: center;
251
- justify-content: center;
252
- width: 36px;
253
- height: 36px;
254
- border-radius: 50%;
255
- color: white;
256
- margin: 0 3px;
257
- transition: all 0.2s ease;
258
- }
259
-
260
- .edit-icon {
261
- background-color: #3b82f6;
262
- }
263
-
264
- .edit-icon:hover {
265
- background-color: #2563eb;
266
- transform: translateY(-2px);
267
- }
268
-
269
- .delete-icon {
270
- background-color: #ef4444;
271
- }
272
-
273
- .delete-icon:hover {
274
- background-color: #dc2626;
275
- transform: translateY(-2px);
276
- }
277
-
278
- /* Modal styles */
279
- .modal {
280
- display: none;
281
- position: fixed;
282
- top: 0;
283
- left: 0;
284
- width: 100%;
285
- height: 100%;
286
- background-color: rgba(0, 0, 0, 0.5);
287
- z-index: 1000;
288
- align-items: center;
289
- justify-content: center;
290
- }
291
-
292
- .modal-content {
293
- background-color: white;
294
- padding: 2rem;
295
- border-radius: 1rem;
296
- width: 90%;
297
- max-width: 500px;
298
- box-shadow: var(--shadow);
299
- text-align: center;
300
- animation: modalFadeIn 0.3s ease;
301
- }
302
-
303
- @keyframes modalFadeIn {
304
- from { opacity: 0; transform: translateY(-50px); }
305
- to { opacity: 1; transform: translateY(0); }
306
- }
307
-
308
- .modal h3 {
309
- color: #dc2626;
310
- margin-bottom: 1rem;
311
- padding: 0;
312
- }
313
-
314
- .modal h3::before {
315
- display: none;
316
- }
317
-
318
- .modal p {
319
- margin-bottom: 1.5rem;
320
- }
321
-
322
- .modal-buttons {
323
- display: flex;
324
- justify-content: center;
325
- gap: 1rem;
326
- }
327
-
328
- .modal-btn {
329
- padding: 0.75rem 1.5rem;
330
- border-radius: 0.5rem;
331
- font-weight: 600;
332
- cursor: pointer;
333
- }
334
-
335
- .btn-confirm {
336
- background-color: #ef4444;
337
- color: white;
338
- }
339
-
340
- .btn-cancel {
341
- background-color: #e5e7eb;
342
- color: #4b5563;
343
- }
344
-
345
- /* Responsive Design */
346
- @media (max-width: 768px) {
347
- .action-buttons {
348
- flex-direction: column;
349
- gap: 10px;
350
- }
351
-
352
- .action-btn {
353
- width: 100%;
354
- }
355
-
356
- th, td {
357
- padding: 12px 15px;
358
- }
359
-
360
- h1 {
361
- font-size: 24px;
362
- }
363
-
364
- h2 {
365
- font-size: 18px;
366
- }
367
- }
368
- </style>
369
- </head>
370
- <body>
371
- <div class="container">
372
- <div class="header">
373
- <h1>SEKOLAH MENENGAH KEJURUAN NEGERI 5 CILEGON</h1>
374
- <h2>Sistem Laporan Siswa</h2>
375
- </div>
376
-
377
- <div class="alert">
378
- <i class="fas fa-check-circle"></i>
379
- <span>Data berhasil disimpan!</span>
380
- </div>
381
-
382
- <div class="action-buttons">
383
- <a href="{{ url_for('cetak_pdf') }}" class="action-btn btn-print" target="_blank">
384
- <i class="fas fa-file-pdf"></i> Cetak Laporan PDF
385
- </a>
386
- <a href="{{ url_for('tambah_siswa') }}" class="action-btn btn-add">
387
- <i class="fas fa-user-plus"></i> Tambah Data Siswa
388
- </a>
389
- </div>
390
-
391
- <h3>Daftar Siswa Kelas IX Jurusan Rekayasa Kecerdasan Artifisial</h3>
392
-
393
- <div class="table-container">
394
- {% if mahasiswa and mahasiswa|length > 0 %}
395
- <table>
396
- <thead>
397
- <tr>
398
- <th>NRP/NIM</th>
399
- <th>Nama Lengkap</th>
400
- <th>No HP</th>
401
- <th>Tanggal Lahir</th>
402
- <th>Aksi</th>
403
- </tr>
404
- </thead>
405
- <tbody>
406
- {% for student in mahasiswa %}
407
- <tr>
408
- <td>{{ student.NRP if student.NRP is defined else student.nim }}</td>
409
- <td>{{ student.nama_lengkap }}</td>
410
- <td>{{ student.no_hp }}</td>
411
- <td>{{ student.tanggal_lahir.strftime('%d-%m-%Y') if student.tanggal_lahir is not string else student.tanggal_lahir }}</td>
412
- <td class="actions">
413
- <a href="{{ url_for('edit_siswa', id=student.NRP if student.NRP is defined else student.nim) }}" class="action-icon edit-icon" title="Edit">
414
- <i class="fas fa-edit"></i>
415
- </a>
416
- <a href="#" onclick="confirmDelete('{{ student.NRP if student.NRP is defined else student.nim }}')" class="action-icon delete-icon" title="Hapus">
417
- <i class="fas fa-trash-alt"></i>
418
- </a>
419
- </td>
420
- </tr>
421
- {% endfor %}
422
- </tbody>
423
- </table>
424
- {% else %}
425
- <div class="empty-state">
426
- <i class="fas fa-user-graduate"></i>></i>
427
- <p>Tidak ada data siswa ditemukan.</p>ak ada data siswa ditemukan.</p>
428
- </div>
429
- {% endif %} endif %}
430
- </div>div>
431
- </div> </div>
432
-
433
- <!-- Modal for delete confirmation -->
434
- <div id="deleteModal" class="modal">
435
- <div class="modal-content">
436
- <h3><i class="fas fa-exclamation-triangle"></i> Konfirmasi Hapus</h3>
437
- <p>Apakah Anda yakin ingin menghapus data siswa ini?</p>
438
- <form id="deleteForm" action="{{ url_for('hapus_siswa') }}" method="POST">
439
- <input type="hidden" id="deleteId" name="id">
440
- <div class="modal-buttons">
441
- <button type="button" class="modal-btn btn-cancel" onclick="closeModal()">Batal</button>
442
- <button type="submit" class="modal-btn btn-confirm">Hapus</button>
443
- </div>
444
- </form>
445
- </div>
446
- </div>
447
-
448
- <script>
449
- function confirmDelete(id) {
450
- document.getElementById('deleteId').value = id;
451
- document.getElementById('deleteModal').style.display = 'flex';
452
- }
453
-
454
- function closeModal() {
455
- document.getElementById('deleteModal').style.display = 'none';
456
- }
457
-
458
- // Close modal when clicking outside of it
459
- window.onclick = function(event) {
460
- const modal = document.getElementById('deleteModal');
461
- if (event.target == modal) {
462
- closeModal();
463
- }
464
- }
465
- </script>
466
- </body>
467
- </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Sistem Laporan Siswa</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
8
+ <style>
9
+ :root {
10
+ --primary-color: #6d28d9; /* Ungu - matching with tambah_siswa.html */
11
+ --secondary-color: #7c3aed;
12
+ --success-color: #10b981; /* Green */
13
+ --background-color: #f3f4f6;
14
+ --card-color: #ffffff;
15
+ --text-color: #374151;
16
+ --border-color: #e5e7eb;
17
+ --shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05);
18
+ }
19
+
20
+ * {
21
+ margin: 0;
22
+ padding: 0;
23
+ box-sizing: border-box;
24
+ }
25
+
26
+ body {
27
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
28
+ margin: 0;
29
+ padding: 20px;
30
+ background-color: var(--background-color);
31
+ line-height: 1.6;
32
+ color: var(--text-color);
33
+ }
34
+
35
+ .container {
36
+ max-width: 1100px;
37
+ margin: 0 auto;
38
+ background-color: var(--card-color);
39
+ padding: 30px;
40
+ border-radius: 1rem;
41
+ box-shadow: var(--shadow);
42
+ animation: fadeIn 0.5s ease;
43
+ }
44
+
45
+ @keyframes fadeIn {
46
+ from { opacity: 0; transform: translateY(20px); }
47
+ to { opacity: 1; transform: translateY(0); }
48
+ }
49
+
50
+ .header {
51
+ text-align: center;
52
+ margin-bottom: 30px;
53
+ padding-bottom: 20px;
54
+ border-bottom: 2px solid var(--border-color);
55
+ position: relative;
56
+ }
57
+
58
+ .header::after {
59
+ content: '';
60
+ position: absolute;
61
+ bottom: -2px;
62
+ left: 50%;
63
+ transform: translateX(-50%);
64
+ width: 100px;
65
+ height: 4px;
66
+ background-color: var(--primary-color);
67
+ border-radius: 2px;
68
+ }
69
+
70
+ h1 {
71
+ color: var(--primary-color);
72
+ margin: 0;
73
+ font-size: 28px;
74
+ font-weight: 700;
75
+ letter-spacing: -0.5px;
76
+ }
77
+
78
+ h2 {
79
+ color: #555;
80
+ font-size: 22px;
81
+ margin: 15px 0;
82
+ font-weight: 600;
83
+ }
84
+
85
+ h3 {
86
+ color: var(--text-color);
87
+ margin: 25px 0 15px 0;
88
+ font-size: 18px;
89
+ font-weight: 600;
90
+ position: relative;
91
+ padding-left: 15px;
92
+ }
93
+
94
+ h3::before {
95
+ content: '';
96
+ position: absolute;
97
+ left: 0;
98
+ top: 50%;
99
+ transform: translateY(-50%);
100
+ width: 5px;
101
+ height: 20px;
102
+ background-color: var(--primary-color);
103
+ border-radius: 3px;
104
+ }
105
+
106
+ .action-buttons {
107
+ display: flex;
108
+ justify-content: center;
109
+ gap: 20px;
110
+ margin: 25px 0;
111
+ }
112
+
113
+ .action-btn {
114
+ padding: 12px 25px;
115
+ border-radius: 8px;
116
+ color: white;
117
+ text-decoration: none;
118
+ font-weight: 600;
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ transition: all 0.3s ease;
123
+ }
124
+
125
+ .action-btn i {
126
+ margin-right: 8px;
127
+ font-size: 16px;
128
+ }
129
+
130
+ .action-btn:hover {
131
+ transform: translateY(-3px);
132
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
133
+ }
134
+
135
+ .btn-print {
136
+ background-color: var(--success-color);
137
+ }
138
+
139
+ .btn-print:hover {
140
+ background-color: #0da76f;
141
+ }
142
+
143
+ .btn-add {
144
+ background-color: var(--primary-color);
145
+ }
146
+
147
+ .btn-add:hover {
148
+ background-color: var(--secondary-color);
149
+ }
150
+
151
+ .table-container {
152
+ overflow-x: auto;
153
+ border-radius: 8px;
154
+ box-shadow: var(--shadow);
155
+ }
156
+
157
+ table {
158
+ width: 100%;
159
+ border-collapse: collapse;
160
+ border-radius: 8px;
161
+ overflow: hidden;
162
+ }
163
+
164
+ th, td {
165
+ padding: 15px 20px;
166
+ text-align: left;
167
+ }
168
+
169
+ th {
170
+ background-color: var(--primary-color);
171
+ color: white;
172
+ font-weight: 600;
173
+ text-transform: uppercase;
174
+ font-size: 14px;
175
+ letter-spacing: 0.5px;
176
+ }
177
+
178
+ tr:nth-child(even) {
179
+ background-color: #f9fafb;
180
+ }
181
+
182
+ tr:not(thead tr) {
183
+ border-bottom: 1px solid var(--border-color);
184
+ }
185
+
186
+ tr:last-child {
187
+ border-bottom: none;
188
+ }
189
+
190
+ tr:hover:not(thead tr) {
191
+ background-color: #f3f4f6;
192
+ }
193
+
194
+ td {
195
+ transition: all 0.2s ease;
196
+ }
197
+
198
+ .alert {
199
+ padding: 15px 20px;
200
+ background-color: #ecfdf5;
201
+ border-left: 4px solid var(--success-color);
202
+ color: #065f46;
203
+ border-radius: 8px;
204
+ margin-bottom: 20px;
205
+ display: flex;
206
+ align-items: center;
207
+ opacity: 1;
208
+ transition: opacity 0.5s ease, transform 0.5s ease;
209
+ transform: translateY(0);
210
+ box-shadow: 0 2px 5px rgba(0,0,0,0.05);
211
+ {% if status != 'success' %}display: none;{% endif %}
212
+ }
213
+
214
+ .alert i {
215
+ margin-right: 10px;
216
+ font-size: 20px;
217
+ color: var(--success-color);
218
+ }
219
+
220
+ .alert.fade-out {
221
+ opacity: 0;
222
+ transform: translateY(-20px);
223
+ }
224
+
225
+ .empty-state {
226
+ text-align: center;
227
+ padding: 40px 20px;
228
+ color: #6b7280;
229
+ }
230
+
231
+ .empty-state i {
232
+ font-size: 48px;
233
+ color: #d1d5db;
234
+ margin-bottom: 15px;
235
+ }
236
+
237
+ .empty-state p {
238
+ font-size: 16px;
239
+ margin-bottom: 20px;
240
+ }
241
+
242
+ /* Action icons styling */
243
+ .actions {
244
+ width: 100px;
245
+ text-align: center;
246
+ }
247
+
248
+ .action-icon {
249
+ display: inline-flex;
250
+ align-items: center;
251
+ justify-content: center;
252
+ width: 36px;
253
+ height: 36px;
254
+ border-radius: 50%;
255
+ color: white;
256
+ margin: 0 3px;
257
+ transition: all 0.2s ease;
258
+ }
259
+
260
+ .edit-icon {
261
+ background-color: #3b82f6;
262
+ }
263
+
264
+ .edit-icon:hover {
265
+ background-color: #2563eb;
266
+ transform: translateY(-2px);
267
+ }
268
+
269
+ .delete-icon {
270
+ background-color: #ef4444;
271
+ }
272
+
273
+ .delete-icon:hover {
274
+ background-color: #dc2626;
275
+ transform: translateY(-2px);
276
+ }
277
+
278
+ /* Modal styles */
279
+ .modal {
280
+ display: none;
281
+ position: fixed;
282
+ top: 0;
283
+ left: 0;
284
+ width: 100%;
285
+ height: 100%;
286
+ background-color: rgba(0, 0, 0, 0.5);
287
+ z-index: 1000;
288
+ align-items: center;
289
+ justify-content: center;
290
+ }
291
+
292
+ .modal-content {
293
+ background-color: white;
294
+ padding: 2rem;
295
+ border-radius: 1rem;
296
+ width: 90%;
297
+ max-width: 500px;
298
+ box-shadow: var(--shadow);
299
+ text-align: center;
300
+ animation: modalFadeIn 0.3s ease;
301
+ }
302
+
303
+ @keyframes modalFadeIn {
304
+ from { opacity: 0; transform: translateY(-50px); }
305
+ to { opacity: 1; transform: translateY(0); }
306
+ }
307
+
308
+ .modal h3 {
309
+ color: #dc2626;
310
+ margin-bottom: 1rem;
311
+ padding: 0;
312
+ }
313
+
314
+ .modal h3::before {
315
+ display: none;
316
+ }
317
+
318
+ .modal p {
319
+ margin-bottom: 1.5rem;
320
+ }
321
+
322
+ .modal-buttons {
323
+ display: flex;
324
+ justify-content: center;
325
+ gap: 1rem;
326
+ }
327
+
328
+ .modal-btn {
329
+ padding: 0.75rem 1.5rem;
330
+ border-radius: 0.5rem;
331
+ font-weight: 600;
332
+ cursor: pointer;
333
+ }
334
+
335
+ .btn-confirm {
336
+ background-color: #ef4444;
337
+ color: white;
338
+ }
339
+
340
+ .btn-cancel {
341
+ background-color: #e5e7eb;
342
+ color: #4b5563;
343
+ }
344
+
345
+ /* Responsive Design */
346
+ @media (max-width: 768px) {
347
+ .action-buttons {
348
+ flex-direction: column;
349
+ gap: 10px;
350
+ }
351
+
352
+ .action-btn {
353
+ width: 100%;
354
+ }
355
+
356
+ th, td {
357
+ padding: 12px 15px;
358
+ }
359
+
360
+ h1 {
361
+ font-size: 24px;
362
+ }
363
+
364
+ h2 {
365
+ font-size: 18px;
366
+ }
367
+ }
368
+ </style>
369
+ </head>
370
+ <body>
371
+ <div class="container">
372
+ <div class="header">
373
+ <h1>SEKOLAH MENENGAH KEJURUAN NEGERI 5 CILEGON</h1>
374
+ <h2>Sistem Laporan Siswa</h2>
375
+ </div>
376
+
377
+ <div class="alert">
378
+ <i class="fas fa-check-circle"></i>
379
+ <span>Data berhasil disimpan!</span>
380
+ </div>
381
+
382
+ <div class="action-buttons">
383
+ <a href="{{ url_for('cetak_pdf') }}" class="action-btn btn-print" target="_blank">
384
+ <i class="fas fa-file-pdf"></i> Cetak Laporan PDF
385
+ </a>
386
+ <a href="{{ url_for('tambah_siswa') }}" class="action-btn btn-add">
387
+ <i class="fas fa-user-plus"></i> Tambah Data Siswa
388
+ </a>
389
+ </div>
390
+
391
+ <h3>Daftar Siswa Kelas IX Jurusan Rekayasa Kecerdasan Artifisial</h3>
392
+
393
+ <div class="table-container">
394
+ {% if mahasiswa and mahasiswa|length > 0 %}
395
+ <table>
396
+ <thead>
397
+ <tr>
398
+ <th>NRP/NIM</th>
399
+ <th>Nama Lengkap</th>
400
+ <th>No HP</th>
401
+ <th>Tanggal Lahir</th>
402
+ <th>Aksi</th>
403
+ </tr>
404
+ </thead>
405
+ <tbody>
406
+ {% for student in mahasiswa %}
407
+ <tr>
408
+ <td>{{ student.NRP if student.NRP is defined else student.nim }}</td>
409
+ <td>{{ student.nama_lengkap }}</td>
410
+ <td>{{ student.no_hp }}</td>
411
+ <td>{{ student.tanggal_lahir.strftime('%d-%m-%Y') if student.tanggal_lahir is not string else student.tanggal_lahir }}</td>
412
+ <td class="actions">
413
+ <a href="{{ url_for('edit_siswa', id=student.NRP if student.NRP is defined else student.nim) }}" class="action-icon edit-icon" title="Edit">
414
+ <i class="fas fa-edit"></i>
415
+ </a>
416
+ <a href="#" onclick="confirmDelete('{{ student.NRP if student.NRP is defined else student.nim }}')" class="action-icon delete-icon" title="Hapus">
417
+ <i class="fas fa-trash-alt"></i>
418
+ </a>
419
+ </td>
420
+ </tr>
421
+ {% endfor %}
422
+ </tbody>
423
+ </table>
424
+ {% else %}
425
+ <div class="empty-state">
426
+ <i class="fas fa-user-graduate"></i>
427
+ <p>Tidak ada data siswa ditemukan.</p>
428
+ </div>
429
+ {% endif %}
430
+ </div>
431
+ </div>
432
+
433
+ <!-- Modal for delete confirmation -->
434
+ <div id="deleteModal" class="modal">
435
+ <div class="modal-content">
436
+ <h3><i class="fas fa-exclamation-triangle"></i> Konfirmasi Hapus</h3>
437
+ <p>Apakah Anda yakin ingin menghapus data siswa ini?</p>
438
+ <form id="deleteForm" action="{{ url_for('hapus_siswa') }}" method="POST">
439
+ <input type="hidden" id="deleteId" name="id">
440
+ <div class="modal-buttons">
441
+ <button type="button" class="modal-btn btn-cancel" onclick="closeModal()">Batal</button>
442
+ <button type="submit" class="modal-btn btn-confirm">Hapus</button>
443
+ </div>
444
+ </form>
445
+ </div>
446
+ </div>
447
+
448
+ <script>
449
+ function confirmDelete(id) {
450
+ document.getElementById('deleteId').value = id;
451
+ document.getElementById('deleteModal').style.display = 'flex';
452
+ }
453
+
454
+ function closeModal() {
455
+ document.getElementById('deleteModal').style.display = 'none';
456
+ }
457
+
458
+ // Close modal when clicking outside of it
459
+ window.onclick = function(event) {
460
+ const modal = document.getElementById('deleteModal');
461
+ if (event.target == modal) {
462
+ closeModal();
463
+ }
464
+ }
465
+ </script>
466
+ </body>
467
+ </html>