husseinelsaadi commited on
Commit
a4c7637
·
1 Parent(s): 4991915
backend/templates/base.html CHANGED
@@ -14,7 +14,6 @@
14
  --success: #2ecc71;
15
  --warning: #f39c12;
16
  --danger: #e74c3c;
17
- --info: #3498db;
18
  }
19
 
20
  * {
@@ -30,12 +29,8 @@
30
  line-height: 1.6;
31
  perspective: 1000px;
32
  overflow-x: hidden;
33
- min-height: 100vh;
34
- display: flex;
35
- flex-direction: column;
36
  }
37
 
38
- /* Header Styles */
39
  header {
40
  background: linear-gradient(135deg, var(--primary), var(--secondary));
41
  color: white;
@@ -57,11 +52,8 @@
57
  display: flex;
58
  justify-content: space-between;
59
  align-items: center;
60
- flex-wrap: wrap;
61
- gap: 1rem;
62
  }
63
 
64
- /* Logo Styles */
65
  .logo {
66
  display: flex;
67
  align-items: center;
@@ -100,37 +92,23 @@
100
  color: var(--accent);
101
  }
102
 
103
- /* Navigation Buttons */
104
  .login-buttons {
105
  display: flex;
106
  align-items: center;
107
- gap: 0.75rem;
108
- flex-wrap: wrap;
109
- }
110
-
111
- /* Mobile Menu Toggle */
112
- .mobile-menu-toggle {
113
- display: none;
114
- background: transparent;
115
- border: 2px solid var(--accent);
116
- color: var(--accent);
117
- padding: 0.5rem;
118
- border-radius: 5px;
119
- cursor: pointer;
120
- font-size: 1.5rem;
121
  }
122
 
123
- /* Welcome Message */
124
  .welcome-message {
125
  color: white;
126
  font-weight: 500;
 
127
  display: flex;
128
  align-items: center;
129
  background-color: rgba(255, 255, 255, 0.1);
130
  padding: 0.5rem 1rem;
131
  border-radius: 5px;
132
  transition: all 0.3s ease;
133
- white-space: nowrap;
134
  }
135
 
136
  .welcome-message:before {
@@ -138,7 +116,24 @@
138
  margin-right: 0.5rem;
139
  }
140
 
141
- /* Button Styles */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  .btn {
143
  padding: 0.5rem 1.5rem;
144
  border-radius: 5px;
@@ -150,8 +145,6 @@
150
  position: relative;
151
  overflow: hidden;
152
  z-index: 1;
153
- display: inline-block;
154
- white-space: nowrap;
155
  }
156
 
157
  .btn::before {
@@ -182,99 +175,11 @@
182
  color: white;
183
  }
184
 
185
- .btn-logout {
186
- background-color: transparent;
187
- border: 2px solid var(--accent);
188
- color: var(--accent);
189
- font-weight: 600;
190
- }
191
-
192
- .btn-logout:hover {
193
- background-color: var(--accent);
194
- color: var(--dark);
195
- transform: translateY(-2px);
196
- box-shadow: 0 5px 15px rgba(76, 201, 240, 0.3);
197
- }
198
-
199
  .btn:hover {
200
  transform: translateY(-2px);
201
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
202
  }
203
 
204
- /* Flash Messages */
205
- .flash-messages {
206
- margin: 1rem 0;
207
- }
208
-
209
- .alert {
210
- padding: 1rem 1.5rem;
211
- border-radius: 8px;
212
- margin-bottom: 1rem;
213
- font-weight: 500;
214
- position: relative;
215
- animation: slideIn 0.3s ease-out;
216
- display: flex;
217
- align-items: center;
218
- gap: 0.75rem;
219
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
220
- }
221
-
222
- @keyframes slideIn {
223
- from {
224
- transform: translateY(-20px);
225
- opacity: 0;
226
- }
227
- to {
228
- transform: translateY(0);
229
- opacity: 1;
230
- }
231
- }
232
-
233
- .alert::before {
234
- font-size: 1.2rem;
235
- }
236
-
237
- .alert-success {
238
- background-color: #d4edda;
239
- color: #155724;
240
- border: 1px solid #c3e6cb;
241
- }
242
-
243
- .alert-success::before {
244
- content: '✓';
245
- }
246
-
247
- .alert-danger, .alert-error {
248
- background-color: #f8d7da;
249
- color: #721c24;
250
- border: 1px solid #f5c6cb;
251
- }
252
-
253
- .alert-danger::before, .alert-error::before {
254
- content: '⚠';
255
- }
256
-
257
- .alert-warning {
258
- background-color: #fff3cd;
259
- color: #856404;
260
- border: 1px solid #ffeaa7;
261
- }
262
-
263
- .alert-warning::before {
264
- content: '!';
265
- }
266
-
267
- .alert-info {
268
- background-color: #d1ecf1;
269
- color: #0c5460;
270
- border: 1px solid #bee5eb;
271
- }
272
-
273
- .alert-info::before {
274
- content: 'ℹ';
275
- }
276
-
277
- /* Hero Section */
278
  .hero {
279
  background: linear-gradient(rgba(67, 97, 238, 0.8), rgba(58, 12, 163, 0.9)), url("/api/placeholder/1200/600") no-repeat center center/cover;
280
  color: white;
@@ -343,117 +248,249 @@
343
  animation: fadeIn 1s ease-out 0.3s both;
344
  }
345
 
346
- /* Main Content */
347
- main {
348
- flex: 1;
349
- padding: 2rem 0;
 
 
350
  }
351
 
352
- /* Breadcrumbs */
353
- .breadcrumbs {
354
- list-style: none;
 
 
 
 
 
 
 
 
355
  display: flex;
 
356
  align-items: center;
357
- gap: 0.5rem;
358
- margin-bottom: 2rem;
359
- padding: 0.75rem 1rem;
360
- background-color: white;
361
- border-radius: 8px;
362
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
363
- flex-wrap: wrap;
364
  }
365
 
366
- .breadcrumbs li {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  display: flex;
368
- align-items: center;
 
 
 
 
 
 
 
 
 
 
 
369
  }
370
 
371
- .breadcrumbs li:not(:last-child)::after {
372
- content: '›';
373
- margin-left: 0.5rem;
374
- color: #999;
 
375
  }
376
 
377
- .breadcrumbs a {
 
378
  color: var(--primary);
379
- text-decoration: none;
380
- transition: color 0.3s ease;
 
381
  }
382
 
383
- .breadcrumbs a:hover {
384
- color: var(--secondary);
 
 
 
 
 
 
 
385
  }
386
 
387
- /* Content Section */
388
- .content-section {
389
- padding: 3rem 1rem;
390
- background-color: white;
391
- min-height: 50vh;
392
  }
393
 
394
- /* Cards */
395
- .card {
 
 
 
 
 
396
  background-color: white;
397
  border-radius: 10px;
398
  overflow: hidden;
399
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
400
  transition: all 0.5s ease;
401
- margin-bottom: 2rem;
 
 
 
 
402
  }
403
 
404
- .card:hover {
405
- transform: translateY(-5px);
406
  box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
407
  }
408
 
409
- .card-header {
410
- background: linear-gradient(135deg, var(--primary), var(--secondary));
411
- color: white;
412
- padding: 1.5rem;
 
 
 
 
 
413
  }
414
 
415
- .card-body {
 
 
 
 
 
416
  padding: 1.5rem;
 
 
 
417
  }
418
 
419
- /* Form Styles */
420
- .form-group {
421
- margin-bottom: 1.5rem;
422
  }
423
 
424
- .form-group label {
425
- font-weight: 600;
426
- color: var(--primary);
427
- margin-bottom: 0.5rem;
428
- display: block;
 
 
 
 
 
 
 
 
 
 
 
 
429
  }
430
 
431
- .form-control {
432
  width: 100%;
433
- padding: 0.75rem;
434
- font-size: 1rem;
435
- border-radius: 6px;
436
- border: 1px solid #ddd;
437
- transition: all 0.3s ease;
438
  }
439
 
440
- .form-control:focus {
441
- outline: none;
442
- border-color: var(--primary);
443
- box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
  }
445
 
446
- /* Footer */
447
  footer {
448
  background-color: var(--dark);
449
  color: white;
450
  padding: 3rem 1rem;
451
- margin-top: auto;
452
  }
453
 
454
  .footer-grid {
455
  display: grid;
456
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
457
  gap: 2rem;
458
  }
459
 
@@ -507,236 +544,63 @@
507
  color: #aaa;
508
  }
509
 
510
- /* Chatbot Styles */
511
- #chatbot-toggle {
512
- position: fixed;
513
- bottom: 2rem;
514
- right: 2rem;
515
- width: 3.5rem;
516
- height: 3.5rem;
517
- background: linear-gradient(135deg, var(--primary), var(--secondary));
518
- color: white;
519
- border-radius: 50%;
520
- cursor: pointer;
521
- z-index: 1000;
522
- display: flex;
523
- align-items: center;
524
- justify-content: center;
525
- font-size: 1.5rem;
526
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
527
- transition: all 0.3s ease;
528
- }
529
-
530
- #chatbot-toggle:hover {
531
- transform: scale(1.1);
532
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
533
- }
534
-
535
- .chat-nav-icon {
536
- display: none;
537
- font-size: 1.5rem;
538
- color: var(--accent);
539
- cursor: pointer;
540
- }
541
-
542
- #chatbot-box {
543
- position: fixed;
544
- bottom: 6rem;
545
- right: 2rem;
546
- width: 350px;
547
- height: 500px;
548
- background: white;
549
- border-radius: 15px;
550
- display: none;
551
- flex-direction: column;
552
- z-index: 1000;
553
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
554
  overflow: hidden;
 
 
 
555
  }
556
 
557
- #chat-header {
558
- background: linear-gradient(135deg, var(--primary), var(--secondary));
559
- color: white;
560
- padding: 1rem;
561
- text-align: center;
562
- font-weight: bold;
563
- font-size: 1.2rem;
564
- }
565
-
566
- #chat-messages {
567
- flex: 1;
568
- padding: 1rem;
569
- overflow-y: auto;
570
- background-color: #f9f9f9;
571
- }
572
-
573
- #chat-messages .user-message {
574
- display: flex;
575
- justify-content: flex-end;
576
- margin-bottom: 1rem;
577
- }
578
-
579
- #chat-messages .bot-message {
580
- display: flex;
581
- justify-content: flex-start;
582
- margin-bottom: 1rem;
583
  }
584
 
585
- #chat-messages .user-bubble {
586
  background: linear-gradient(135deg, var(--primary), var(--secondary));
587
  color: white;
588
- padding: 0.75rem 1rem;
589
- border-radius: 18px 18px 4px 18px;
590
- max-width: 80%;
591
- word-wrap: break-word;
592
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
593
  }
594
 
595
- #chat-messages .bot-bubble {
596
- background-color: white;
597
- color: var(--dark);
598
- padding: 0.75rem 1rem;
599
- border-radius: 18px 18px 18px 4px;
600
- max-width: 80%;
601
- word-wrap: break-word;
602
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
603
- border: 1px solid #eee;
604
  }
605
 
606
- #chat-input {
607
- border: none;
608
- border-top: 1px solid #eee;
609
- padding: 1rem;
610
- width: 100%;
611
- box-sizing: border-box;
612
- font-size: 1rem;
613
- transition: all 0.3s ease;
614
  }
615
 
616
- #chat-input:focus {
617
- outline: none;
618
- background-color: #f9f9f9;
 
 
 
 
 
 
619
  }
620
 
621
- /* Responsive Styles */
622
- @media (max-width: 768px) {
623
- .nav-container {
624
- padding: 0.5rem 0;
625
- }
626
-
627
- .logo {
628
- font-size: 1.5rem;
629
- }
630
-
631
- .mobile-menu-toggle {
632
- display: block;
633
- }
634
-
635
- .login-buttons {
636
- width: 100%;
637
- order: 3;
638
- justify-content: center;
639
- padding: 1rem 0;
640
- background-color: rgba(0, 0, 0, 0.1);
641
- margin: 0 -1rem;
642
- border-radius: 8px;
643
- display: none;
644
- }
645
-
646
- .login-buttons.show {
647
- display: flex;
648
- }
649
-
650
- .welcome-message {
651
- font-size: 0.9rem;
652
- padding: 0.4rem 0.8rem;
653
- }
654
-
655
- .btn {
656
- padding: 0.4rem 1rem;
657
- font-size: 0.9rem;
658
- }
659
-
660
- .hero h1 {
661
- font-size: 2rem;
662
- }
663
-
664
- .hero p {
665
- font-size: 1rem;
666
- }
667
-
668
- #chatbot-toggle {
669
- display: none !important;
670
- }
671
-
672
- .chat-nav-icon {
673
- display: block;
674
- }
675
-
676
- #chatbot-box {
677
- width: 90vw;
678
- height: 70vh;
679
- bottom: 1rem;
680
- right: 5vw;
681
- max-width: 400px;
682
- }
683
-
684
- .card {
685
- margin-bottom: 1rem;
686
- }
687
-
688
- .content-section {
689
- padding: 2rem 1rem;
690
- }
691
-
692
- .footer-grid {
693
- grid-template-columns: 1fr;
694
- text-align: center;
695
- }
696
-
697
- .social-links {
698
- justify-content: center;
699
- }
700
  }
701
 
702
- @media (max-width: 480px) {
703
- .hero h1 {
704
- font-size: 1.75rem;
705
- }
706
-
707
- .btn {
708
- width: 100%;
709
- margin-bottom: 0.5rem;
710
- }
711
-
712
- .login-buttons {
713
- flex-direction: column;
714
- gap: 0.5rem;
715
- }
716
-
717
- .breadcrumbs {
718
- font-size: 0.9rem;
719
- }
720
  }
721
 
722
- /* Utility Classes */
723
- .text-center {
724
- text-align: center;
725
  }
726
 
727
- .mt-1 { margin-top: 0.5rem; }
728
- .mt-2 { margin-top: 1rem; }
729
- .mt-3 { margin-top: 1.5rem; }
730
- .mt-4 { margin-top: 2rem; }
731
-
732
- .mb-1 { margin-bottom: 0.5rem; }
733
- .mb-2 { margin-bottom: 1rem; }
734
- .mb-3 { margin-bottom: 1.5rem; }
735
- .mb-4 { margin-bottom: 2rem; }
736
-
737
- .gap-1 { gap: 0.5rem; }
738
- .gap-2 { gap: 1rem; }
739
- .gap-3 { gap: 1.5rem; }
740
  </style>
741
  </head>
742
  <body>
@@ -745,11 +609,13 @@
745
  <a href="{{ url_for('index') }}" class="logo">
746
  <span class="logo-part1">Cod</span><span class="logo-part2">in</span><span class="logo-part3">go</span>
747
  </a>
748
-
749
- <button class="mobile-menu-toggle" onclick="toggleMobileMenu()">☰</button>
750
-
751
- <div class="login-buttons" id="nav-menu">
752
  {% if current_user.is_authenticated %}
 
 
 
 
 
753
  {% if current_user.role == 'unemployed' %}
754
  <a href="{{ url_for('jobs') }}" class="btn btn-outline">Jobs</a>
755
  <a href="{{ url_for('my_applications') }}" class="btn btn-outline">My Applications</a>
@@ -765,8 +631,9 @@
765
  <a href="{{ url_for('auth.signup') }}" class="btn btn-primary">Sign Up</a>
766
  {% endif %}
767
  </div>
768
-
769
- <div class="chat-nav-icon" onclick="toggleChatbot()">💬</div>
 
770
  </div>
771
  </header>
772
 
@@ -787,15 +654,123 @@
787
  {% block content %}{% endblock %}
788
  </div>
789
 
790
- <!-- Chatbot Toggle Button -->
 
 
 
 
 
 
 
791
  <div id="chatbot-toggle" onclick="toggleChatbot()">💬</div>
792
 
793
- <!-- Chatbox Popup -->
794
- <div id="chatbot-box">
795
- <div id="chat-header">LUNA AI Assistant</div>
796
- <div id="chat-messages"></div>
797
- <input id="chat-input" type="text" placeholder="Ask me anything..." onkeydown="sendChat(event)">
798
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
799
  </main>
800
 
801
  <footer>
@@ -805,9 +780,9 @@
805
  <h3>Codingo</h3>
806
  <p>AI-powered recruitment platform that revolutionizes how companies hire technical talent.</p>
807
  <div class="social-links">
808
- <a href="#" aria-label="Facebook"><span>f</span></a>
809
- <a href="#" aria-label="Twitter"><span>t</span></a>
810
- <a href="#" aria-label="LinkedIn"><span>in</span></a>
811
  </div>
812
  </div>
813
  </div>
@@ -817,83 +792,91 @@
817
  </div>
818
  </footer>
819
 
820
- <script type="text/javascript">
821
- // Mobile menu toggle
822
- function toggleMobileMenu() {
823
- const menu = document.getElementById('nav-menu');
824
- menu.classList.toggle('show');
825
- }
826
-
827
- // Chatbot functionality
828
- function toggleChatbot() {
 
 
 
 
829
  const box = document.getElementById('chatbot-box');
830
  if (!box) return;
 
831
  box.style.display = (box.style.display === 'flex') ? 'none' : 'flex';
832
- }
833
 
834
- function sendChat(event) {
835
  if (event.key === 'Enter') {
836
- event.preventDefault();
837
- const input = document.getElementById('chat-input');
838
- const message = input.value.trim();
839
- if (!message) return;
840
-
841
- appendChatMessage(message, 'user');
842
- input.value = '';
843
-
844
- // Show typing indicator
845
- const typingIndicator = appendChatMessage('...', 'bot');
846
-
847
- fetch("{{ url_for('chatbot_endpoint') }}", {
848
- method: 'POST',
849
- headers: { 'Content-Type': 'application/json' },
850
- body: JSON.stringify({ message: message })
851
- })
852
- .then(response => response.json())
853
  .then(data => {
854
- // Remove typing indicator
855
- typingIndicator.remove();
856
-
857
- if (data.response) {
858
- appendChatMessage(data.response, 'bot');
859
- } else {
860
- appendChatMessage(data.error || 'Error occurred.', 'bot');
861
- }
862
- })
863
- .catch(() => {
864
- typingIndicator.remove();
865
- appendChatMessage('Network error. Please try again.', 'bot');
866
  });
867
  }
868
- }
869
 
870
- function appendChatMessage(text, sender) {
871
  const container = document.getElementById('chat-messages');
872
  if (!container) return;
873
-
874
  const wrapper = document.createElement('div');
875
  wrapper.className = sender === 'user' ? 'user-message' : 'bot-message';
876
-
877
  const bubble = document.createElement('div');
878
  bubble.className = sender === 'user' ? 'user-bubble' : 'bot-bubble';
879
  bubble.textContent = text;
880
-
881
  wrapper.appendChild(bubble);
882
  container.appendChild(wrapper);
883
  container.scrollTop = container.scrollHeight;
884
-
885
- return wrapper;
886
- }
887
-
888
- // Close mobile menu when clicking outside
889
- document.addEventListener('click', function(event) {
890
- const menu = document.getElementById('nav-menu');
891
- const toggle = document.querySelector('.mobile-menu-toggle');
892
-
893
- if (!menu.contains(event.target) && !toggle.contains(event.target)) {
894
- menu.classList.remove('show');
895
- }
896
- });
897
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
898
  </body>
899
- </html>
 
14
  --success: #2ecc71;
15
  --warning: #f39c12;
16
  --danger: #e74c3c;
 
17
  }
18
 
19
  * {
 
29
  line-height: 1.6;
30
  perspective: 1000px;
31
  overflow-x: hidden;
 
 
 
32
  }
33
 
 
34
  header {
35
  background: linear-gradient(135deg, var(--primary), var(--secondary));
36
  color: white;
 
52
  display: flex;
53
  justify-content: space-between;
54
  align-items: center;
 
 
55
  }
56
 
 
57
  .logo {
58
  display: flex;
59
  align-items: center;
 
92
  color: var(--accent);
93
  }
94
 
 
95
  .login-buttons {
96
  display: flex;
97
  align-items: center;
98
+ gap: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  }
100
 
101
+ /* Style for the welcome message */
102
  .welcome-message {
103
  color: white;
104
  font-weight: 500;
105
+ margin-right: 0.5rem;
106
  display: flex;
107
  align-items: center;
108
  background-color: rgba(255, 255, 255, 0.1);
109
  padding: 0.5rem 1rem;
110
  border-radius: 5px;
111
  transition: all 0.3s ease;
 
112
  }
113
 
114
  .welcome-message:before {
 
116
  margin-right: 0.5rem;
117
  }
118
 
119
+ /* Enhanced logout button */
120
+ .btn-logout {
121
+ background-color: transparent;
122
+ border: 2px solid var(--accent);
123
+ color: var(--accent);
124
+ font-weight: 600;
125
+ padding: 0.5rem 1.5rem;
126
+ border-radius: 5px;
127
+ transition: all 0.3s ease;
128
+ }
129
+
130
+ .btn-logout:hover {
131
+ background-color: var(--accent);
132
+ color: var(--dark);
133
+ transform: translateY(-2px);
134
+ box-shadow: 0 5px 15px rgba(76, 201, 240, 0.3);
135
+ }
136
+
137
  .btn {
138
  padding: 0.5rem 1.5rem;
139
  border-radius: 5px;
 
145
  position: relative;
146
  overflow: hidden;
147
  z-index: 1;
 
 
148
  }
149
 
150
  .btn::before {
 
175
  color: white;
176
  }
177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  .btn:hover {
179
  transform: translateY(-2px);
180
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
181
  }
182
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  .hero {
184
  background: linear-gradient(rgba(67, 97, 238, 0.8), rgba(58, 12, 163, 0.9)), url("/api/placeholder/1200/600") no-repeat center center/cover;
185
  color: white;
 
248
  animation: fadeIn 1s ease-out 0.3s both;
249
  }
250
 
251
+ .luna-avatar-container {
252
+ position: relative;
253
+ width: 250px;
254
+ height: 250px;
255
+ margin-bottom: 2rem;
256
+ perspective: 1000px;
257
  }
258
 
259
+ .luna-avatar {
260
+ width: 100%;
261
+ height: 100%;
262
+ border-radius: 50%;
263
+ border: 4px solid var(--accent);
264
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3), 0 0 20px rgba(76, 201, 240, 0.5);
265
+ overflow: hidden;
266
+ animation: float 4s ease-in-out infinite;
267
+ position: relative;
268
+ z-index: 2;
269
+ background: linear-gradient(135deg, rgba(76, 201, 240, 0.2), rgba(58, 12, 163, 0.2));
270
  display: flex;
271
+ justify-content: center;
272
  align-items: center;
 
 
 
 
 
 
 
273
  }
274
 
275
+ .luna-glow {
276
+ position: absolute;
277
+ width: 100%;
278
+ height: 100%;
279
+ border-radius: 50%;
280
+ background: radial-gradient(circle, rgba(76, 201, 240, 0.8) 0%, rgba(76, 201, 240, 0) 70%);
281
+ filter: blur(15px);
282
+ opacity: 0.7;
283
+ z-index: 1;
284
+ animation: pulse 4s ease-in-out infinite alternate;
285
+ }
286
+
287
+ @keyframes pulse {
288
+ 0% {
289
+ transform: scale(0.9);
290
+ opacity: 0.5;
291
+ }
292
+ 100% {
293
+ transform: scale(1.1);
294
+ opacity: 0.7;
295
+ }
296
+ }
297
+
298
+ @keyframes float {
299
+ 0% {
300
+ transform: translateY(0px) rotateY(0deg);
301
+ }
302
+ 50% {
303
+ transform: translateY(-15px) rotateY(5deg);
304
+ }
305
+ 100% {
306
+ transform: translateY(0px) rotateY(0deg);
307
+ }
308
+ }
309
+
310
+ .luna-avatar img {
311
+ width: 100%;
312
+ height: 100%;
313
+ object-fit: cover;
314
+ object-position: center -10px;
315
+ top: 0;
316
+ left: 0;
317
+ }
318
+
319
+ .hero-buttons {
320
  display: flex;
321
+ justify-content: center;
322
+ gap: 1.5rem;
323
+ flex-wrap: wrap;
324
+ transform: translateZ(15px);
325
+ animation: fadeIn 1s ease-out 0.6s both;
326
+ }
327
+
328
+ .features {
329
+ padding: 5rem 1rem;
330
+ background-color: white;
331
+ position: relative;
332
+ z-index: 1;
333
  }
334
 
335
+ .section-title {
336
+ text-align: center;
337
+ margin-bottom: 3rem;
338
+ transform-style: preserve-3d;
339
+ transition: transform 0.3s ease;
340
  }
341
 
342
+ .section-title h2 {
343
+ font-size: 2.5rem;
344
  color: var(--primary);
345
+ margin-bottom: 1rem;
346
+ position: relative;
347
+ display: inline-block;
348
  }
349
 
350
+ .section-title h2::after {
351
+ content: '';
352
+ position: absolute;
353
+ bottom: -10px;
354
+ left: 50%;
355
+ transform: translateX(-50%);
356
+ width: 80px;
357
+ height: 3px;
358
+ background: linear-gradient(to right, var(--primary), var(--accent));
359
  }
360
 
361
+ .section-title p {
362
+ max-width: 600px;
363
+ margin: 0 auto;
364
+ color: #666;
 
365
  }
366
 
367
+ .features-grid {
368
+ display: grid;
369
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
370
+ gap: 2rem;
371
+ }
372
+
373
+ .feature-card {
374
  background-color: white;
375
  border-radius: 10px;
376
  overflow: hidden;
377
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
378
  transition: all 0.5s ease;
379
+ display: flex;
380
+ flex-direction: column;
381
+ height: 100%;
382
+ transform-style: preserve-3d;
383
+ perspective: 1000px;
384
  }
385
 
386
+ .feature-card:hover {
387
+ transform: translateY(-10px) rotateX(5deg);
388
  box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
389
  }
390
 
391
+ .feature-icon {
392
+ background: linear-gradient(135deg, rgba(67, 97, 238, 0.1), rgba(76, 201, 240, 0.1));
393
+ padding: 2rem;
394
+ display: flex;
395
+ justify-content: center;
396
+ align-items: center;
397
+ font-size: 2.5rem;
398
+ color: var(--primary);
399
+ transition: all 0.3s ease;
400
  }
401
 
402
+ .feature-card:hover .feature-icon {
403
+ transform: translateZ(20px);
404
+ color: var(--accent);
405
+ }
406
+
407
+ .feature-content {
408
  padding: 1.5rem;
409
+ flex-grow: 1;
410
+ transform: translateZ(0);
411
+ transition: transform 0.3s ease;
412
  }
413
 
414
+ .feature-card:hover .feature-content {
415
+ transform: translateZ(10px);
 
416
  }
417
 
418
+ .feature-content h3 {
419
+ font-size : 1.5rem;
420
+ margin-bottom: 1rem;
421
+ color: var(--dark);
422
+ position: relative;
423
+ display: inline-block;
424
+ }
425
+
426
+ .feature-content h3::after {
427
+ content: '';
428
+ position: absolute;
429
+ bottom: -5px;
430
+ left: 0;
431
+ width: 40px;
432
+ height: 2px;
433
+ background: var(--primary);
434
+ transition: width 0.3s ease;
435
  }
436
 
437
+ .feature-card:hover .feature-content h3::after {
438
  width: 100%;
 
 
 
 
 
439
  }
440
 
441
+ .content-section {
442
+ padding: 5rem 1rem;
443
+ background-color: white;
444
+ min-height: 50vh;
445
+ }
446
+
447
+ .cta {
448
+ background: linear-gradient(135deg, var(--secondary), var(--primary));
449
+ color: white;
450
+ padding: 5rem 1rem;
451
+ text-align: center;
452
+ position: relative;
453
+ overflow: hidden;
454
+ }
455
+
456
+ .cta::before {
457
+ content: '';
458
+ position: absolute;
459
+ top: -50%;
460
+ left: -50%;
461
+ width: 200%;
462
+ height: 200%;
463
+ background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 60%);
464
+ animation: rotate 20s linear infinite;
465
+ z-index: 1;
466
+ }
467
+
468
+ .cta .container {
469
+ position: relative;
470
+ z-index: 2;
471
+ }
472
+
473
+ .cta h2 {
474
+ font-size: 2.5rem;
475
+ margin-bottom: 1.5rem;
476
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
477
+ }
478
+
479
+ .cta p {
480
+ max-width: 600px;
481
+ margin: 0 auto 2rem;
482
+ font-size: 1.2rem;
483
  }
484
 
 
485
  footer {
486
  background-color: var(--dark);
487
  color: white;
488
  padding: 3rem 1rem;
 
489
  }
490
 
491
  .footer-grid {
492
  display: grid;
493
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
494
  gap: 2rem;
495
  }
496
 
 
544
  color: #aaa;
545
  }
546
 
547
+ .card {
548
+ background-color: white;
549
+ border-radius: 10px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
550
  overflow: hidden;
551
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
552
+ transition: all 0.5s ease;
553
+ margin-bottom: 2rem;
554
  }
555
 
556
+ .card:hover {
557
+ transform: translateY(-5px);
558
+ box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
559
  }
560
 
561
+ .card-header {
562
  background: linear-gradient(135deg, var(--primary), var(--secondary));
563
  color: white;
564
+ padding: 1.5rem;
 
 
 
 
565
  }
566
 
567
+ .card-body {
568
+ padding: 1.5rem;
 
 
 
 
 
 
 
569
  }
570
 
571
+ .job-grid {
572
+ display: grid;
573
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
574
+ gap: 2rem;
 
 
 
 
575
  }
576
 
577
+ .job-card {
578
+ background-color: white;
579
+ border-radius: 10px;
580
+ overflow: hidden;
581
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
582
+ transition: all 0.5s ease;
583
+ height: 100%;
584
+ display: flex;
585
+ flex-direction: column;
586
  }
587
 
588
+ .job-card:hover {
589
+ transform: translateY(-10px);
590
+ box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591
  }
592
 
593
+ .job-header {
594
+ background: linear-gradient(135deg, rgba(67, 97, 238, 0.9), rgba(58, 12, 163, 0.9));
595
+ color: white;
596
+ padding: 1.5rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
597
  }
598
 
599
+ .job-header h3 {
600
+ font-size: 1.5rem;
 
601
  }
602
 
603
+ /* Additional content styling omitted for brevity */
 
 
 
 
 
 
 
 
 
 
 
 
604
  </style>
605
  </head>
606
  <body>
 
609
  <a href="{{ url_for('index') }}" class="logo">
610
  <span class="logo-part1">Cod</span><span class="logo-part2">in</span><span class="logo-part3">go</span>
611
  </a>
612
+ <div class="login-buttons">
 
 
 
613
  {% if current_user.is_authenticated %}
614
+ {#
615
+ Display navigation options based on the authenticated user's role.
616
+ Job seekers (role: "unemployed") can view available jobs and their own applications.
617
+ Recruiters and admins can post new jobs, view the jobs list and access the recruiter dashboard.
618
+ #}
619
  {% if current_user.role == 'unemployed' %}
620
  <a href="{{ url_for('jobs') }}" class="btn btn-outline">Jobs</a>
621
  <a href="{{ url_for('my_applications') }}" class="btn btn-outline">My Applications</a>
 
631
  <a href="{{ url_for('auth.signup') }}" class="btn btn-primary">Sign Up</a>
632
  {% endif %}
633
  </div>
634
+ <!-- Mobile chat icon visible only on small screens -->
635
+ <div id="chatbot-nav" class="chat-nav-icon" onclick="toggleChatbot()">💬</div>
636
+
637
  </div>
638
  </header>
639
 
 
654
  {% block content %}{% endblock %}
655
  </div>
656
 
657
+ #CHATBOT START
658
+ <!-- Chatbot Toggle Button -->
659
+ <!--
660
+ The floating chat button toggles the visibility of the chat window.
661
+ We use a flex container here to ensure the emoji and text remain
662
+ centred on all screen sizes. Additional media queries adjust the
663
+ button's position and padding for very small viewports.
664
+ -->
665
  <div id="chatbot-toggle" onclick="toggleChatbot()">💬</div>
666
 
667
+ <!-- Chatbox Popup -->
668
+ <div id="chatbot-box">
669
+ <div id="chat-header">LUNA AI</div>
670
+ <div id="chat-messages"></div>
671
+ <input id="chat-input" type="text" placeholder="Ask me anything..." onkeydown="sendChat(event)">
672
+ </div>
673
+
674
+ <style>
675
+ #chatbot-toggle {
676
+ /* Floating circular button on desktop. It is vertically centred along the right edge */
677
+ position: fixed;
678
+ top: 50%;
679
+ right: 1rem;
680
+ transform: translateY(-50%);
681
+ width: 3rem;
682
+ height: 3rem;
683
+ background-color: #4caf50;
684
+ color: #ffffff;
685
+ border-radius: 50%;
686
+ cursor: pointer;
687
+ z-index: 1000;
688
+ display: flex;
689
+ align-items: center;
690
+ justify-content: center;
691
+ font-size: 1.5rem;
692
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
693
+ transition: background-color 0.2s ease;
694
+ }
695
+
696
+ #chatbot-toggle:hover {
697
+ background-color: #43a047;
698
+ }
699
+
700
+ /* Chat icon inside the navbar (hidden by default and shown on small screens via media query) */
701
+ #chatbot-nav {
702
+ display: none;
703
+ }
704
+
705
+ #chatbot-box {
706
+ position: fixed;
707
+ /* Align the chat window vertically with the toggle on desktop */
708
+ top: 50%;
709
+ right: calc(1rem + 3rem + 1rem);
710
+ transform: translateY(-50%);
711
+ /* Default dimensions for larger screens */
712
+ width: 20rem;
713
+ height: 25rem;
714
+ background: white;
715
+ border: 2px solid #ccc;
716
+ border-radius: 10px;
717
+ display: none;
718
+ flex-direction: column;
719
+ z-index: 1000;
720
+ box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
721
+ }
722
+
723
+ #chat-header {
724
+ background-color: #4caf50;
725
+ color: white;
726
+ padding: 10px;
727
+ text-align: center;
728
+ font-weight: bold;
729
+ }
730
+
731
+ #chat-messages {
732
+ flex: 1;
733
+ padding: 10px;
734
+ overflow-y: auto;
735
+ max-height: 300px;
736
+ }
737
+
738
+ /* Responsive adjustments for small screens */
739
+ @media (max-width: 768px) {
740
+ /* Hide the floating button and reveal the navbar icon on mobile */
741
+ #chatbot-toggle {
742
+ display: none !important;
743
+ }
744
+ #chatbot-nav {
745
+ display: block;
746
+ font-size: 1.5rem;
747
+ color: var(--accent);
748
+ margin-left: 1rem;
749
+ cursor: pointer;
750
+ }
751
+ #chatbot-box {
752
+ width: 90vw;
753
+ height: 60vh;
754
+ bottom: 1rem;
755
+ right: 5vw;
756
+ top: auto;
757
+ transform: none;
758
+ }
759
+ #chat-messages {
760
+ max-height: calc(60vh - 5.5rem);
761
+ }
762
+ }
763
+
764
+ #chat-input {
765
+ border: none;
766
+ border-top: 1px solid #ccc;
767
+ padding: 10px;
768
+ width: 100%;
769
+ box-sizing: border-box;
770
+ }
771
+ </style>
772
+
773
+ #CHATBOT END
774
  </main>
775
 
776
  <footer>
 
780
  <h3>Codingo</h3>
781
  <p>AI-powered recruitment platform that revolutionizes how companies hire technical talent.</p>
782
  <div class="social-links">
783
+ <a href="#"><span>f</span></a>
784
+ <a href="#"><span>t</span></a>
785
+ <a href="#"><span>in</span></a>
786
  </div>
787
  </div>
788
  </div>
 
792
  </div>
793
  </footer>
794
 
795
+ {# -------------------------------------------------------------------------
796
+ Chatbot UI scripts and styles
797
+
798
+ The following script powers the floating chatbot widget located at the
799
+ bottom right of every page. When the user clicks the 💬 button, the
800
+ widget toggles visibility. Pressing Enter in the input box sends the
801
+ message to the `/chatbot` endpoint defined in ``app.py``. Both user
802
+ and bot messages are appended to the conversation pane with simple
803
+ styling defined below. Jinja's ``url_for`` helper is used to
804
+ dynamically generate the correct path to the endpoint at render time.
805
+ #}
806
+ <script type="text/javascript">
807
+ function toggleChatbot() {
808
  const box = document.getElementById('chatbot-box');
809
  if (!box) return;
810
+ // Toggle between flex (visible) and none (hidden)
811
  box.style.display = (box.style.display === 'flex') ? 'none' : 'flex';
812
+ }
813
 
814
+ function sendChat(event) {
815
  if (event.key === 'Enter') {
816
+ event.preventDefault();
817
+ const input = document.getElementById('chat-input');
818
+ const message = input.value.trim();
819
+ if (!message) return;
820
+ appendChatMessage(message, 'user');
821
+ input.value = '';
822
+ fetch("{{ url_for('chatbot_endpoint') }}", {
823
+ method: 'POST',
824
+ headers: { 'Content-Type': 'application/json' },
825
+ body: JSON.stringify({ message: message })
826
+ }).then(response => response.json())
 
 
 
 
 
 
827
  .then(data => {
828
+ if (data.response) {
829
+ appendChatMessage(data.response, 'bot');
830
+ } else {
831
+ appendChatMessage(data.error || 'Error occurred.', 'bot');
832
+ }
833
+ }).catch(() => {
834
+ appendChatMessage('Network error.', 'bot');
 
 
 
 
 
835
  });
836
  }
837
+ }
838
 
839
+ function appendChatMessage(text, sender) {
840
  const container = document.getElementById('chat-messages');
841
  if (!container) return;
 
842
  const wrapper = document.createElement('div');
843
  wrapper.className = sender === 'user' ? 'user-message' : 'bot-message';
 
844
  const bubble = document.createElement('div');
845
  bubble.className = sender === 'user' ? 'user-bubble' : 'bot-bubble';
846
  bubble.textContent = text;
 
847
  wrapper.appendChild(bubble);
848
  container.appendChild(wrapper);
849
  container.scrollTop = container.scrollHeight;
850
+ }
851
+ </script>
852
+ <style>
853
+ /* Chat message styling for user and bot */
854
+ #chat-messages .user-message {
855
+ display: flex;
856
+ justify-content: flex-end;
857
+ margin-bottom: 8px;
858
+ }
859
+ #chat-messages .bot-message {
860
+ display: flex;
861
+ justify-content: flex-start;
862
+ margin-bottom: 8px;
863
+ }
864
+ #chat-messages .user-bubble {
865
+ background-color: #4caf50;
866
+ color: #ffffff;
867
+ padding: 8px 12px;
868
+ border-radius: 12px;
869
+ max-width: 80%;
870
+ word-wrap: break-word;
871
+ }
872
+ #chat-messages .bot-bubble {
873
+ background-color: #f1f0f0;
874
+ color: #000000;
875
+ padding: 8px 12px;
876
+ border-radius: 12px;
877
+ max-width: 80%;
878
+ word-wrap: break-word;
879
+ }
880
+ </style>
881
  </body>
882
+ </html>
backend/templates/my_applications.html CHANGED
@@ -4,9 +4,9 @@
4
 
5
  {% block content %}
6
  <section class="content-section">
7
- <div class="section-header">
8
  <h2>My Applications</h2>
9
- <p>Track and manage your job applications</p>
10
  </div>
11
 
12
  <ul class="breadcrumbs">
@@ -14,525 +14,120 @@
14
  <li>My Applications</li>
15
  </ul>
16
 
17
- <!-- Interview Guidelines Section -->
18
- <div class="interview-guidelines">
19
- <div class="guidelines-header">
20
- <h3><span class="icon">🎯</span> Important Interview Guidelines</h3>
21
- </div>
22
- <div class="guidelines-content">
23
- <div class="guideline-item">
24
- <span class="guideline-icon">⚡</span>
25
- <div class="guideline-text">
26
- <strong>One-time opportunity:</strong> The interview can be taken only once, so please be well-prepared.
27
- </div>
28
- </div>
29
- <div class="guideline-item">
30
- <span class="guideline-icon">🎧</span>
31
- <div class="guideline-text">
32
- <strong>Environment:</strong> Ensure you're in a quiet space with a stable internet connection.
33
- </div>
34
- </div>
35
- <div class="guideline-item">
36
- <span class="guideline-icon">📋</span>
37
- <div class="guideline-text">
38
- <strong>Purpose:</strong> This helps companies shortlist the most relevant candidates for the role.
39
- </div>
40
- </div>
41
- <div class="guideline-item">
42
- <span class="guideline-icon">🎯</span>
43
- <div class="guideline-text">
44
- <strong>Customization:</strong> Questions are tailored based on your CV and job requirements.
45
- </div>
46
- </div>
47
- <div class="guideline-item">
48
- <span class="guideline-icon">⏱️</span>
49
- <div class="guideline-text">
50
- <strong>Duration:</strong> 10-15 minutes including general and skill-based questions.
51
- </div>
52
- </div>
53
- </div>
54
  </div>
55
 
56
- <!-- Applications Grid -->
57
- <div class="applications-container">
58
  {% if applications %}
59
- <div class="applications-grid">
60
- {% for application in applications %}
61
- <div class="application-card" data-status="{{ application.status }}">
62
- <div class="card-status-badge status-{{ application.status.lower().replace(' ', '-') }}">
63
- {{ application.status }}
64
- </div>
65
-
66
- <div class="application-header">
67
- <h3>{{ application.job.role if application.job else 'Unknown Role' }}</h3>
68
- <div class="company-info">
69
- <span class="company-name">{{ application.job.company if application.job else '' }}</span>
70
- {% if application.job and application.job.location %}
71
- <span class="location">📍 {{ application.job.location }}</span>
72
- {% endif %}
73
- </div>
74
- </div>
75
-
76
- <div class="application-body">
77
- <div class="application-meta">
78
- <span class="meta-item">
79
- <i class="icon">📅</i>
80
- Applied {{ application.date_applied.strftime('%B %d, %Y') }}
81
- </span>
82
- {% if application.job and application.job.seniority %}
83
- <span class="meta-item">
84
- <i class="icon">💼</i>
85
- {{ application.job.seniority }}
86
- </span>
87
- {% endif %}
88
- </div>
89
-
90
- {% if application.job %}
91
- <p class="job-description">
92
- {{ application.job.description[:150] }}{% if application.job.description|length > 150 %}...{% endif %}
93
- </p>
94
- {% endif %}
95
- </div>
96
-
97
- <div class="application-footer">
98
- {% if application.job %}
99
- <a href="{{ url_for('job_detail', job_id=application.job.id) }}" class="btn btn-outline btn-sm">
100
- <span class="btn-icon">👁️</span> View Job
101
- </a>
102
- {% endif %}
103
-
104
- {% if application.extracted_features %}
105
- <a href="{{ url_for('interview_page', job_id=application.job.id) }}" class="btn btn-primary btn-sm">
106
- <span class="btn-icon">🎤</span> Take Interview
107
- </a>
108
- {% endif %}
109
  </div>
110
  </div>
111
- {% endfor %}
112
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  {% else %}
114
- <div class="empty-state">
115
- <div class="empty-state-icon">📋</div>
116
- <h3>No Applications Yet</h3>
117
- <p>You haven't applied to any jobs yet. Start exploring opportunities!</p>
118
- <a href="{{ url_for('jobs') }}" class="btn btn-primary">
119
- <span class="btn-icon">🔍</span> Browse Jobs
120
- </a>
121
  </div>
122
  {% endif %}
123
  </div>
124
-
125
- <!-- Stats Section -->
126
- {% if applications %}
127
- <div class="applications-stats">
128
- <div class="stat-card">
129
- <div class="stat-number">{{ applications|length }}</div>
130
- <div class="stat-label">Total Applications</div>
131
- </div>
132
- <div class="stat-card">
133
- <div class="stat-number">{{ applications|selectattr('status', 'equalto', 'pending')|list|length }}</div>
134
- <div class="stat-label">Pending Review</div>
135
- </div>
136
- <div class="stat-card">
137
- <div class="stat-number">{{ applications|selectattr('extracted_features')|list|length }}</div>
138
- <div class="stat-label">Ready for Interview</div>
139
- </div>
140
- </div>
141
- {% endif %}
142
  </section>
143
 
144
  <style>
145
- /* Section Header */
146
- .section-header {
147
- text-align: center;
148
- margin-bottom: 3rem;
149
- }
150
-
151
- .section-header h2 {
152
- font-size: 2.5rem;
153
- color: var(--primary);
154
- margin-bottom: 0.5rem;
155
- position: relative;
156
- display: inline-block;
157
- }
158
-
159
- .section-header h2::after {
160
- content: '';
161
- position: absolute;
162
- bottom: -10px;
163
- left: 50%;
164
- transform: translateX(-50%);
165
- width: 80px;
166
- height: 3px;
167
- background: linear-gradient(to right, var(--primary), var(--accent));
168
- }
169
-
170
- .section-header p {
171
- color: #666;
172
- font-size: 1.1rem;
173
- }
174
-
175
- /* Interview Guidelines */
176
- .interview-guidelines {
177
- background: linear-gradient(135deg, #f5f7ff 0%, #e8ecff 100%);
178
- border-radius: 12px;
179
- padding: 2rem;
180
- margin: 2rem 0;
181
- box-shadow: 0 5px 15px rgba(67, 97, 238, 0.1);
182
- border: 1px solid rgba(67, 97, 238, 0.1);
183
- }
184
-
185
- .guidelines-header {
186
- margin-bottom: 1.5rem;
187
- }
188
-
189
- .guidelines-header h3 {
190
- color: var(--primary);
191
- font-size: 1.5rem;
192
- margin: 0;
193
- display: flex;
194
- align-items: center;
195
- gap: 0.5rem;
196
- }
197
-
198
- .guidelines-header .icon {
199
- font-size: 1.75rem;
200
- }
201
-
202
- .guidelines-content {
203
- display: grid;
204
- gap: 1rem;
205
- }
206
-
207
- .guideline-item {
208
- display: flex;
209
- align-items: flex-start;
210
- gap: 1rem;
211
- padding: 0.75rem;
212
- background: white;
213
- border-radius: 8px;
214
- transition: all 0.3s ease;
215
- }
216
-
217
- .guideline-item:hover {
218
- transform: translateX(5px);
219
- box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
220
- }
221
-
222
- .guideline-icon {
223
- font-size: 1.5rem;
224
- min-width: 2rem;
225
- display: flex;
226
- align-items: center;
227
- justify-content: center;
228
- }
229
-
230
- .guideline-text {
231
- flex: 1;
232
- line-height: 1.6;
233
- }
234
-
235
- .guideline-text strong {
236
- color: var(--primary);
237
- }
238
-
239
- /* Applications Container */
240
- .applications-container {
241
- margin: 3rem 0;
242
- }
243
-
244
- /* Applications Grid */
245
- .applications-grid {
246
  display: grid;
247
- grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
248
  gap: 1.5rem;
249
  }
250
 
251
- /* Application Card */
252
  .application-card {
253
- background: white;
254
- border-radius: 12px;
255
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
256
- position: relative;
257
- transition: all 0.3s ease;
258
- overflow: hidden;
259
  display: flex;
260
  flex-direction: column;
261
- }
262
-
263
- .application-card:hover {
264
- transform: translateY(-5px);
265
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
266
- }
267
-
268
- /* Status Badge */
269
- .card-status-badge {
270
- position: absolute;
271
- top: 1rem;
272
- right: 1rem;
273
- padding: 0.25rem 0.75rem;
274
- border-radius: 20px;
275
- font-size: 0.875rem;
276
- font-weight: 600;
277
- text-transform: uppercase;
278
- }
279
-
280
- .status-pending {
281
- background-color: #fff3cd;
282
- color: #856404;
283
- }
284
-
285
- .status-approved {
286
- background-color: #d4edda;
287
- color: #155724;
288
- }
289
-
290
- .status-rejected {
291
- background-color: #f8d7da;
292
- color: #721c24;
293
- }
294
-
295
- .status-interview-scheduled {
296
- background-color: #d1ecf1;
297
- color: #0c5460;
298
- }
299
-
300
- /* Application Header */
301
- .application-header {
302
- padding: 1.5rem 1.5rem 0;
303
  }
304
 
305
  .application-header h3 {
 
306
  color: var(--primary);
307
- margin: 0 0 0.5rem 0;
308
- font-size: 1.5rem;
309
  }
310
 
311
- .company-info {
312
- display: flex;
313
- flex-wrap: wrap;
314
- gap: 1rem;
315
- color: #666;
316
- font-size: 0.95rem;
317
- }
318
-
319
- .company-name {
320
- font-weight: 600;
321
  color: var(--dark);
 
322
  }
323
 
324
- /* Application Body */
325
- .application-body {
326
- padding: 1rem 1.5rem;
327
- flex: 1;
328
- }
329
-
330
- .application-meta {
331
- display: flex;
332
- flex-wrap: wrap;
333
- gap: 1rem;
334
- margin-bottom: 1rem;
335
- font-size: 0.9rem;
336
- color: #666;
337
- }
338
-
339
- .meta-item {
340
- display: flex;
341
- align-items: center;
342
- gap: 0.25rem;
343
- }
344
-
345
- .meta-item .icon {
346
- font-size: 1rem;
347
- }
348
-
349
- .job-description {
350
- color: #495057;
351
- line-height: 1.6;
352
- margin: 0;
353
- }
354
-
355
- /* Application Footer */
356
  .application-footer {
357
- padding: 0 1.5rem 1.5rem;
358
  display: flex;
359
- gap: 0.75rem;
360
- flex-wrap: wrap;
361
- }
362
-
363
- .btn-sm {
364
- padding: 0.5rem 1rem;
365
- font-size: 0.9rem;
366
- }
367
-
368
- /* Empty State */
369
- .empty-state {
370
- text-align: center;
371
- padding: 4rem 2rem;
372
- background: #f8f9fa;
373
- border-radius: 12px;
374
- border: 2px dashed #dee2e6;
375
- }
376
-
377
- .empty-state-icon {
378
- font-size: 4rem;
379
- margin-bottom: 1rem;
380
- opacity: 0.5;
381
- }
382
-
383
- .empty-state h3 {
384
- color: var(--primary);
385
- margin-bottom: 0.5rem;
386
- }
387
-
388
- .empty-state p {
389
- color: #666;
390
- margin-bottom: 2rem;
391
- }
392
-
393
- /* Stats Section */
394
- .applications-stats {
395
- display: grid;
396
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
397
- gap: 1.5rem;
398
- margin-top: 3rem;
399
  }
400
 
401
- .stat-card {
402
- background: white;
 
 
 
403
  padding: 2rem;
404
- border-radius: 12px;
405
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
406
- text-align: center;
407
- transition: all 0.3s ease;
408
- }
409
-
410
- .stat-card:hover {
411
- transform: translateY(-3px);
412
- box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
413
  }
414
-
415
- .stat-number {
416
- font-size: 2.5rem;
417
- font-weight: 700;
418
  color: var(--primary);
419
- margin-bottom: 0.5rem;
420
- }
421
-
422
- .stat-label {
423
- color: #666;
424
- font-size: 1rem;
425
- }
426
-
427
- /* Responsive Design */
428
- @media (max-width: 768px) {
429
- .section-header h2 {
430
- font-size: 2rem;
431
- }
432
-
433
- .interview-guidelines {
434
- padding: 1.5rem;
435
- }
436
-
437
- .guidelines-header h3 {
438
- font-size: 1.25rem;
439
- }
440
-
441
- .guideline-item {
442
- padding: 0.5rem;
443
- }
444
-
445
- .guideline-icon {
446
- font-size: 1.25rem;
447
- }
448
-
449
- .applications-grid {
450
- grid-template-columns: 1fr;
451
- }
452
-
453
- .application-card {
454
- margin-bottom: 1rem;
455
- }
456
-
457
- .applications-stats {
458
- grid-template-columns: 1fr;
459
- }
460
-
461
- .stat-card {
462
- padding: 1.5rem;
463
- }
464
  }
465
-
466
- @media (max-width: 480px) {
467
- .company-info {
468
- flex-direction: column;
469
- gap: 0.5rem;
470
- }
471
-
472
- .application-meta {
473
- flex-direction: column;
474
- gap: 0.5rem;
475
- }
476
-
477
- .application-footer {
478
- flex-direction: column;
479
- }
480
-
481
- .application-footer .btn {
482
- width: 100%;
483
- justify-content: center;
484
- }
485
  }
486
-
487
- /* Loading Animation */
488
- @keyframes shimmer {
489
- 0% {
490
- background-position: -1000px 0;
491
- }
492
- 100% {
493
- background-position: 1000px 0;
494
  }
495
  }
496
-
497
- .loading {
498
- background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
499
- background-size: 1000px 100%;
500
- animation: shimmer 2s infinite;
501
- }
502
  </style>
503
-
504
- <script>
505
- document.addEventListener('DOMContentLoaded', function() {
506
- // Add animation to cards on page load
507
- const cards = document.querySelectorAll('.application-card');
508
- cards.forEach((card, index) => {
509
- setTimeout(() => {
510
- card.style.opacity = '0';
511
- card.style.transform = 'translateY(20px)';
512
- card.style.animation = 'fadeInUp 0.5s ease forwards';
513
- }, index * 100);
514
- });
515
-
516
- // Filter functionality (if needed in future)
517
- const statusBadges = document.querySelectorAll('.card-status-badge');
518
- statusBadges.forEach(badge => {
519
- badge.addEventListener('click', function() {
520
- const status = this.textContent.trim();
521
- // Add filter logic here if needed
522
- });
523
- });
524
- });
525
-
526
- // Animation keyframes
527
- const style = document.createElement('style');
528
- style.textContent = `
529
- @keyframes fadeInUp {
530
- to {
531
- opacity: 1;
532
- transform: translateY(0);
533
- }
534
- }
535
- `;
536
- document.head.appendChild(style);
537
- </script>
538
- {% endblock %}
 
4
 
5
  {% block content %}
6
  <section class="content-section">
7
+ <div class="section-title">
8
  <h2>My Applications</h2>
9
+ <p>Your submitted job applications are listed below.</p>
10
  </div>
11
 
12
  <ul class="breadcrumbs">
 
14
  <li>My Applications</li>
15
  </ul>
16
 
17
+ <!-- Prominent interview tips moved from the apply page. This section is placed
18
+ near the top of the My Applications page so candidates see the
19
+ guidelines before initiating their AI interview. It is responsive
20
+ and uses colours consistent with the overall theme. -->
21
+ <div class="tips-section">
22
+ <h3>Important Interview Guidelines</h3>
23
+ <ul>
24
+ <li>The interview can be taken only once, so please be prepared.</li>
25
+ <li>Make sure you are in a quiet environment with a stable internet connection.</li>
26
+ <li>This is not a final job interview, but it helps the company shortlist the most relevant candidates.</li>
27
+ <li>The interview is customized based on your CV and the job requirements.</li>
28
+ <li>It takes 10 to 15 minutes and includes both general and skill‑based questions.</li>
29
+ </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  </div>
31
 
32
+ <div class="application-list">
 
33
  {% if applications %}
34
+ {% for application in applications %}
35
+ <div class="application-card">
36
+ <div class="application-header">
37
+ <h3>{{ application.job.role if application.job else 'Unknown Role' }}</h3>
38
+ <div class="application-info">
39
+ <span>{{ application.job.company if application.job else '' }}</span>
40
+ <span>Status: {{ application.status }}</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  </div>
42
  </div>
43
+ <div class="application-body">
44
+ <p>Applied on {{ application.date_applied.strftime('%B %d, %Y') }}</p>
45
+ {% if application.job %}
46
+ <p>{{ application.job.description[:150] }}{% if application.job.description|length > 150 %}...{% endif %}</p>
47
+ {% endif %}
48
+ </div>
49
+ <div class="application-footer">
50
+ {% if application.job %}
51
+ <a href="{{ url_for('job_detail', job_id=application.job.id) }}" class="btn btn-outline">View Job</a>
52
+ {% endif %}
53
+ {% if application.extracted_features %}
54
+ <!-- Offer to take the interview if CV data exists -->
55
+ <a href="{{ url_for('interview_page', job_id=application.job.id) }}" class="btn btn-primary">Take Interview</a>
56
+ {% endif %}
57
+ </div>
58
+ </div>
59
+ {% endfor %}
60
  {% else %}
61
+ <div class="card">
62
+ <div class="card-body">
63
+ <p>You haven't applied to any jobs yet. Browse available positions on the <a href="{{ url_for('jobs') }}">jobs page</a>.</p>
64
+ </div>
 
 
 
65
  </div>
66
  {% endif %}
67
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  </section>
69
 
70
  <style>
71
+ .application-list {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  display: grid;
73
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
74
  gap: 1.5rem;
75
  }
76
 
 
77
  .application-card {
78
+ background-color: var(--light);
79
+ border: 1px solid #eee;
80
+ border-radius: 8px;
81
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
 
 
82
  display: flex;
83
  flex-direction: column;
84
+ justify-content: space-between;
85
+ padding: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  }
87
 
88
  .application-header h3 {
89
+ margin-bottom: 0.5rem;
90
  color: var(--primary);
 
 
91
  }
92
 
93
+ .application-info span {
94
+ margin-right: 1rem;
 
 
 
 
 
 
 
 
95
  color: var(--dark);
96
+ font-weight: 500;
97
  }
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  .application-footer {
100
+ margin-top: 1rem;
101
  display: flex;
102
+ justify-content: flex-end;
103
+ gap: 0.5rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  }
105
 
106
+ /* Interview tips styling. Creates a highlighted panel with a coloured
107
+ border and responsive padding. */
108
+ .tips-section {
109
+ background-color: #f8f9fa;
110
+ border-left: 5px solid var(--primary);
111
  padding: 2rem;
112
+ margin: 2rem 0;
113
+ border-radius: 8px;
 
 
 
 
 
 
 
114
  }
115
+ .tips-section h3 {
116
+ margin-top: 0;
 
 
117
  color: var(--primary);
118
+ margin-bottom: 1rem;
119
+ font-size: 1.5rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  }
121
+ .tips-section ul {
122
+ margin-left: 1rem;
123
+ padding-left: 1rem;
124
+ list-style-type: disc;
125
+ line-height: 1.6;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
127
+ @media (max-width: 600px) {
128
+ .tips-section {
129
+ padding: 1rem;
 
 
 
 
 
130
  }
131
  }
 
 
 
 
 
 
132
  </style>
133
+ {% endblock %}