feat: update profile setup and bank account management; enhance API integration and data handling
This commit is contained in:
@@ -18,7 +18,8 @@ class EmergencyContactRepositoryImpl
|
||||
Future<List<EmergencyContact>> getContacts() async {
|
||||
final ApiResponse response =
|
||||
await _api.get(StaffEndpoints.emergencyContacts);
|
||||
final List<dynamic> items = response.data['contacts'] as List<dynamic>? ?? <dynamic>[];
|
||||
final List<dynamic> items =
|
||||
response.data['items'] as List<dynamic>? ?? <dynamic>[];
|
||||
return items
|
||||
.map((dynamic json) =>
|
||||
EmergencyContact.fromJson(json as Map<String, dynamic>))
|
||||
@@ -27,12 +28,27 @@ class EmergencyContactRepositoryImpl
|
||||
|
||||
@override
|
||||
Future<void> saveContacts(List<EmergencyContact> contacts) async {
|
||||
await _api.post(
|
||||
StaffEndpoints.emergencyContacts,
|
||||
data: <String, dynamic>{
|
||||
'contacts':
|
||||
contacts.map((EmergencyContact c) => c.toJson()).toList(),
|
||||
},
|
||||
);
|
||||
for (final EmergencyContact contact in contacts) {
|
||||
final Map<String, dynamic> body = <String, dynamic>{
|
||||
'fullName': contact.fullName,
|
||||
'phone': contact.phone,
|
||||
'relationshipType': contact.relationshipType,
|
||||
'isPrimary': contact.isPrimary,
|
||||
};
|
||||
|
||||
if (contact.contactId.isNotEmpty) {
|
||||
// Existing contact — update via PUT.
|
||||
await _api.put(
|
||||
StaffEndpoints.emergencyContactUpdate(contact.contactId),
|
||||
data: body,
|
||||
);
|
||||
} else {
|
||||
// New contact — create via POST.
|
||||
await _api.post(
|
||||
StaffEndpoints.emergencyContacts,
|
||||
data: body,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
@@ -10,20 +11,12 @@ import 'package:staff_profile_info/src/domain/repositories/personal_info_reposit
|
||||
class PersonalInfoRepositoryImpl implements PersonalInfoRepositoryInterface {
|
||||
/// Creates a [PersonalInfoRepositoryImpl].
|
||||
///
|
||||
/// Requires the V2 [BaseApiService] for HTTP communication,
|
||||
/// [FileUploadService] for uploading files to cloud storage, and
|
||||
/// [SignedUrlService] for generating signed download URLs.
|
||||
/// Requires the V2 [BaseApiService] for HTTP communication.
|
||||
PersonalInfoRepositoryImpl({
|
||||
required BaseApiService apiService,
|
||||
required FileUploadService uploadService,
|
||||
required SignedUrlService signedUrlService,
|
||||
}) : _api = apiService,
|
||||
_uploadService = uploadService,
|
||||
_signedUrlService = signedUrlService;
|
||||
}) : _api = apiService;
|
||||
|
||||
final BaseApiService _api;
|
||||
final FileUploadService _uploadService;
|
||||
final SignedUrlService _signedUrlService;
|
||||
|
||||
@override
|
||||
Future<StaffPersonalInfo> getStaffProfile() async {
|
||||
@@ -39,39 +32,34 @@ class PersonalInfoRepositoryImpl implements PersonalInfoRepositoryInterface {
|
||||
required String staffId,
|
||||
required Map<String, dynamic> data,
|
||||
}) async {
|
||||
final ApiResponse response = await _api.put(
|
||||
// The PUT response returns { staffId, fullName, email, phone, metadata }
|
||||
// which does not match the StaffPersonalInfo shape. Perform the update
|
||||
// and then re-fetch the full profile to return the correct entity.
|
||||
await _api.put(
|
||||
StaffEndpoints.personalInfo,
|
||||
data: data,
|
||||
);
|
||||
final Map<String, dynamic> json =
|
||||
response.data as Map<String, dynamic>;
|
||||
return StaffPersonalInfo.fromJson(json);
|
||||
return getStaffProfile();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> uploadProfilePhoto(String filePath) async {
|
||||
// 1. Upload the file to cloud storage.
|
||||
final FileUploadResponse uploadRes = await _uploadService.uploadFile(
|
||||
filePath: filePath,
|
||||
fileName:
|
||||
'staff_profile_photo_${DateTime.now().millisecondsSinceEpoch}.jpg',
|
||||
visibility: FileVisibility.public,
|
||||
);
|
||||
// The backend expects a multipart file upload at /staff/profile/photo.
|
||||
// It uploads to GCS, updates staff metadata, and returns a signed URL.
|
||||
final String fileName =
|
||||
'staff_profile_photo_${DateTime.now().millisecondsSinceEpoch}.jpg';
|
||||
final FormData formData = FormData.fromMap(<String, dynamic>{
|
||||
'file': await MultipartFile.fromFile(filePath, filename: fileName),
|
||||
});
|
||||
|
||||
// 2. Generate a signed URL for the uploaded file.
|
||||
final SignedUrlResponse signedUrlRes =
|
||||
await _signedUrlService.createSignedUrl(fileUri: uploadRes.fileUri);
|
||||
final String photoUrl = signedUrlRes.signedUrl;
|
||||
|
||||
// 3. Submit the photo URL to the V2 API.
|
||||
await _api.post(
|
||||
final ApiResponse response = await _api.post(
|
||||
StaffEndpoints.profilePhoto,
|
||||
data: <String, dynamic>{
|
||||
'fileUri': uploadRes.fileUri,
|
||||
'photoUrl': photoUrl,
|
||||
},
|
||||
data: formData,
|
||||
);
|
||||
final Map<String, dynamic> json =
|
||||
response.data as Map<String, dynamic>;
|
||||
|
||||
return photoUrl;
|
||||
// Backend returns { staffId, fileUri, signedUrl, expiresAt }.
|
||||
return json['signedUrl'] as String? ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ class StaffProfileInfoModule extends Module {
|
||||
i.addLazySingleton<PersonalInfoRepositoryInterface>(
|
||||
() => PersonalInfoRepositoryImpl(
|
||||
apiService: i.get<BaseApiService>(),
|
||||
uploadService: i.get<FileUploadService>(),
|
||||
signedUrlService: i.get<SignedUrlService>(),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ dependencies:
|
||||
flutter_bloc: ^8.1.0
|
||||
bloc: ^8.1.0
|
||||
flutter_modular: ^6.3.0
|
||||
dio: ^5.9.1
|
||||
equatable: ^2.0.5
|
||||
|
||||
# Architecture Packages
|
||||
|
||||
Reference in New Issue
Block a user