Skip to content

Commit 4b8fcf1

Browse files
committed
Fix screens
1 parent 3efa66b commit 4b8fcf1

36 files changed

Lines changed: 3637 additions & 2987 deletions

assets/screenshots/Modifier forme phone (1).jpeg renamed to assets/screenshots/.jpeg

File renamed without changes.

assets/screenshots/Dashboard.png

995 KB
Loading
-245 KB
Binary file not shown.
-272 KB
Binary file not shown.
-1.03 MB
Binary file not shown.
-1.67 MB
Binary file not shown.

lib/common/widgets/unified_form_field.dart

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,24 +49,35 @@ class _UnifiedFormFieldState extends State<UnifiedFormField>
4949
@override
5050
void initState() {
5151
super.initState();
52-
_animationController = AnimationController(
53-
duration: const Duration(milliseconds: 200),
54-
vsync: this,
55-
);
56-
_scaleAnimation = Tween<double>(
57-
begin: 1.0,
58-
end: 1.02,
59-
).animate(CurvedAnimation(
60-
parent: _animationController,
61-
curve: Curves.easeInOut,
62-
));
63-
_borderColorAnimation = ColorTween(
64-
begin: const Color(0xFF000647),
65-
end: const Color(0xFFFF8C00),
66-
).animate(CurvedAnimation(
67-
parent: _animationController,
68-
curve: Curves.easeInOut,
69-
));
52+
try {
53+
_animationController = AnimationController(
54+
duration: const Duration(milliseconds: 200),
55+
vsync: this,
56+
);
57+
_scaleAnimation = Tween<double>(
58+
begin: 1.0,
59+
end: 1.02,
60+
).animate(CurvedAnimation(
61+
parent: _animationController,
62+
curve: Curves.easeInOut,
63+
));
64+
_borderColorAnimation = ColorTween(
65+
begin: const Color(0xFF000647),
66+
end: const Color(0xFFFF8C00),
67+
).animate(CurvedAnimation(
68+
parent: _animationController,
69+
curve: Curves.easeInOut,
70+
));
71+
} catch (e) {
72+
print('Error initializing animations in UnifiedFormField: $e');
73+
// Fallback: create dummy animations
74+
_animationController = AnimationController(
75+
duration: const Duration(milliseconds: 200),
76+
vsync: this,
77+
);
78+
_scaleAnimation = AlwaysStoppedAnimation<double>(1.0);
79+
_borderColorAnimation = AlwaysStoppedAnimation<Color?>(const Color(0xFF000647));
80+
}
7081
}
7182

7283
@override
@@ -76,13 +87,20 @@ class _UnifiedFormFieldState extends State<UnifiedFormField>
7687
}
7788

7889
void _onFocusChange(bool focused) {
90+
if (!mounted) return;
91+
7992
setState(() {
8093
_isFocused = focused;
8194
});
82-
if (focused) {
83-
_animationController.forward();
84-
} else {
85-
_animationController.reverse();
95+
96+
try {
97+
if (focused) {
98+
_animationController.forward();
99+
} else {
100+
_animationController.reverse();
101+
}
102+
} catch (e) {
103+
print('Error in animation focus change: $e');
86104
}
87105
}
88106

lib/controllers/candidate_controller.dart

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import 'package:get/get.dart';
33
import 'package:flutter/foundation.dart';
44
import 'package:file_picker/file_picker.dart';
5+
import 'package:image_picker/image_picker.dart';
56
import 'dart:io';
67

78
import '../models/candidate_profile_model.dart';
@@ -75,6 +76,57 @@ class CandidateController extends GetxController {
7576

7677
// --- Profile ---
7778

79+
// Upload profile picture
80+
Future<bool> uploadProfilePicture() async {
81+
try {
82+
_isLoading.value = true;
83+
_errorMessage.value = '';
84+
85+
final ImagePicker picker = ImagePicker();
86+
final XFile? image = await picker.pickImage(
87+
source: ImageSource.gallery,
88+
maxWidth: 800,
89+
maxHeight: 800,
90+
imageQuality: 85,
91+
);
92+
93+
if (image == null) {
94+
_isLoading.value = false;
95+
return false;
96+
}
97+
98+
final file = File(image.path);
99+
100+
// Upload to Storage
101+
final photoUrl = await CandidateApiService.uploadProfilePhoto(file: file);
102+
103+
// Update Profile with new URL
104+
if (_candidateProfile.value != null) {
105+
final updatedProfile = _candidateProfile.value!.copyWith(photoURL: photoUrl);
106+
await updateProfile(updatedProfile);
107+
}
108+
109+
AppTheme.showStandardSnackBar(
110+
title: 'Success',
111+
message: 'Profile picture updated',
112+
isSuccess: true,
113+
);
114+
115+
return true;
116+
} catch (e) {
117+
_errorMessage.value = 'Photo upload failed: $e';
118+
AppTheme.showStandardSnackBar(
119+
title: 'Error',
120+
message: _errorMessage.value,
121+
isError: true,
122+
);
123+
if (kDebugMode) print('CandidateController uploadProfilePicture error: $e');
124+
return false;
125+
} finally {
126+
_isLoading.value = false;
127+
}
128+
}
129+
78130
// Load candidate profile
79131
Future<void> loadCandidateProfile() async {
80132
try {

lib/controllers/employer_applications_controller.dart

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:get/get.dart';
44
import 'package:timeless/models/application_model.dart';
55
import 'package:timeless/models/job_offer_model.dart';
66
import 'package:timeless/services/job_service.dart';
7+
import 'package:timeless/services/email_service.dart';
78
import 'package:timeless/services/preferences_service.dart';
89

910
// Employer applications controller
@@ -290,4 +291,53 @@ class EmployerApplicationsController extends GetxController {
290291
return Colors.green;
291292
}
292293
}
294+
295+
// Send interview invitation
296+
Future<void> sendInterviewInvitation({
297+
required ApplicationModel application,
298+
required DateTime interviewDate,
299+
required String location,
300+
String? additionalMessage,
301+
}) async {
302+
try {
303+
// Get job details for the invitation
304+
final job = getJobForApplication(application);
305+
if (job == null) {
306+
throw Exception('Job not found for this application');
307+
}
308+
309+
// Send the invitation email
310+
final emailSent = await EmailService.sendInterviewInvitation(
311+
candidateEmail: application.candidateEmail,
312+
candidateName: application.candidateName,
313+
companyName: job.companyName,
314+
jobTitle: job.title,
315+
interviewDate: interviewDate,
316+
location: location,
317+
additionalMessage: additionalMessage,
318+
);
319+
320+
if (emailSent) {
321+
// Update application status to interview
322+
await updateApplicationStatus(application.id, ApplicationStatus.interview);
323+
324+
Get.snackbar(
325+
'✅ Interview Invitation Sent!',
326+
'The candidate has been notified and the application status has been updated.',
327+
backgroundColor: Colors.green,
328+
colorText: Colors.white,
329+
duration: const Duration(seconds: 4),
330+
);
331+
} else {
332+
throw Exception('Failed to send email invitation');
333+
}
334+
} catch (e) {
335+
Get.snackbar(
336+
'❌ Error',
337+
'Failed to send interview invitation: $e',
338+
backgroundColor: Colors.red,
339+
colorText: Colors.white,
340+
);
341+
}
342+
}
293343
}

0 commit comments

Comments
 (0)