Merge pull request 'feature/unit2/UNIT2-#20Implement-attachment-feature' (#28) from feature/unit2/UNIT2-#20Implement-attachment-feature into develop

Reviewed-on: http://git.agusandelnorte.gov.ph:3000/SoftwareDevelopmentSection/unit2-null-safety-repository/pulls/28
feature/passo/PASSO-#1-Sync-data-from-device-to-postgre-and-vice-versa
rodolfobacuinjr 2023-08-08 13:41:18 +08:00
commit 58c8435f9e
35 changed files with 3470 additions and 646 deletions

View File

@ -0,0 +1,33 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="461.000000pt" height="547.000000pt" viewBox="0 0 461.000000 547.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,547.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M291 5399 c-105 -20 -175 -79 -208 -174 -17 -47 -18 -189 -18 -2515
0 -2388 1 -2467 19 -2519 25 -71 86 -132 157 -157 52 -18 121 -19 2069 -19
1948 0 2017 1 2069 19 68 23 131 85 157 152 18 47 19 105 22 1769 2 1189 -1
1740 -8 1785 -6 36 -25 94 -42 130 -28 60 -89 124 -727 761 -523 522 -709 702
-747 722 -112 59 -64 57 -1439 56 -693 -1 -1280 -5 -1304 -10z m2599 -309 c13
-8 16 -85 20 -562 5 -551 5 -553 28 -603 41 -89 97 -132 200 -154 35 -7 225
-11 565 -11 305 0 518 -4 527 -10 13 -8 15 -52 18 -275 l3 -265 -1941 0 -1940
0 2 919 c3 879 4 920 22 939 10 12 28 23 40 25 46 9 2441 6 2456 -3z m-611
-2175 c170 -41 263 -149 264 -308 1 -225 -152 -356 -418 -361 l-95 -1 -2 -185
-3 -185 -117 -3 -118 -3 0 520 0 520 33 5 c66 11 96 13 242 14 103 1 170 -3
214 -13z m1176 -5 c43 -11 80 -22 82 -24 6 -5 -37 -169 -47 -179 -4 -5 -34 0
-66 9 -41 13 -93 18 -169 18 -100 0 -116 -2 -173 -28 -115 -53 -172 -143 -180
-283 -9 -164 53 -281 180 -338 53 -24 77 -29 148 -29 125 -1 120 -6 120 124
l0 110 -85 0 -85 0 0 90 0 90 200 0 200 0 0 -274 0 -275 -52 -14 c-163 -47
-385 -56 -508 -23 -234 64 -370 247 -370 501 0 263 151 459 402 525 104 27
297 27 403 0z m-1867 -392 c-3 -391 -4 -405 -26 -459 -30 -76 -81 -132 -150
-166 -50 -24 -70 -28 -167 -31 -60 -2 -128 1 -150 5 l-40 9 1 50 c0 27 4 70 8
97 l7 47 42 -7 c66 -12 145 -7 173 12 14 9 34 35 45 58 17 39 19 71 19 415 l0
372 121 0 120 0 -3 -402z m2660 -1543 l-3 -604 -23 -23 -23 -23 -1889 0 -1889
0 -23 23 -23 23 -3 604 -3 605 1941 0 1941 0 -3 -605z"/>
<path d="M2030 2590 l0 -160 73 0 c128 1 197 52 204 154 8 109 -60 166 -199
166 l-78 0 0 -160z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,32 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="454.000000pt" height="545.000000pt" viewBox="0 0 454.000000 545.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,545.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M251 5399 c-105 -20 -175 -79 -208 -174 -17 -47 -18 -189 -18 -2515
0 -2388 1 -2467 19 -2519 25 -71 86 -132 157 -157 52 -18 121 -19 2069 -19
1948 0 2017 1 2069 19 68 23 131 85 157 152 18 47 19 105 22 1769 2 1189 -1
1740 -8 1785 -6 36 -25 94 -42 130 -28 60 -89 124 -727 761 -523 522 -709 702
-747 722 -112 59 -64 57 -1439 56 -693 -1 -1280 -5 -1304 -10z m2599 -309 c13
-8 16 -85 20 -562 5 -551 5 -553 28 -603 41 -89 97 -132 200 -154 35 -7 225
-11 565 -11 305 0 518 -4 527 -10 13 -8 15 -52 18 -275 l3 -265 -1941 0 -1940
0 2 919 c3 879 4 920 22 939 10 12 28 23 40 25 46 9 2441 6 2456 -3z m-520
-2165 c77 -8 195 -45 251 -81 139 -88 209 -229 209 -424 0 -175 -55 -317 -158
-411 -117 -107 -225 -140 -480 -146 -100 -3 -207 -2 -237 2 l-55 6 0 520 c0
448 2 520 15 525 21 9 271 22 335 18 30 -2 84 -6 120 -9z m-898 -6 c180 -38
278 -166 265 -349 -14 -211 -175 -330 -449 -330 l-68 0 0 -185 0 -185 -120 0
-120 0 2 523 3 522 45 6 c81 11 388 9 442 -2z m2168 -89 l0 -100 -205 0 -205
0 0 -120 0 -120 190 0 190 0 0 -100 0 -100 -190 0 -190 0 0 -210 0 -210 -120
0 -120 0 0 530 0 530 325 0 325 0 0 -100z m608 -1855 l-3 -604 -23 -23 -23
-23 -1889 0 -1889 0 -23 23 -23 23 -3 604 -3 605 1941 0 1941 0 -3 -605z"/>
<path d="M2105 2739 c-3 -8 -4 -167 -3 -354 l3 -340 86 1 c115 1 179 24 245
89 72 70 97 138 98 270 2 163 -46 255 -160 311 -47 23 -73 28 -160 32 -82 4
-105 2 -109 -9z"/>
<path d="M1180 2590 l0 -160 75 0 c87 0 128 14 170 59 25 27 30 41 33 99 4 63
2 71 -24 101 -39 47 -80 61 -174 61 l-80 0 0 -160z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,28 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="228.000000pt" height="317.000000pt" viewBox="0 0 228.000000 317.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,317.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M95 3120 c-11 -4 -31 -20 -45 -35 l-25 -27 -3 -1465 c-2 -1456 -2
-1466 18 -1498 43 -69 -23 -66 1109 -63 l1021 3 37 38 38 37 3 1003 c1 551 0
1013 -3 1027 -7 28 -923 952 -967 976 -23 12 -121 14 -595 13 -312 0 -577 -4
-588 -9z m1085 -585 l5 -470 473 -3 472 -2 -2 -298 -3 -297 -992 -3 -993 -2 0
768 c0 423 3 772 7 775 3 4 236 6 517 5 l511 -3 5 -470z m-465 -1301 c54 -27
77 -63 83 -128 9 -109 -73 -186 -197 -186 l-61 0 0 -90 0 -90 -60 0 -60 0 0
253 c0 140 3 257 8 261 4 5 61 6 128 4 92 -4 130 -9 159 -24z m378 -146 l112
-171 5 169 5 169 53 3 52 3 0 -260 0 -261 -58 0 -59 0 -116 178 -116 177 -1
-177 0 -178 -55 0 -55 0 0 260 0 260 61 0 60 0 112 -172z m697 163 c22 -6 25
-13 28 -60 3 -48 1 -53 -15 -46 -50 19 -129 27 -170 16 -107 -29 -154 -168
-93 -269 27 -44 70 -64 133 -60 l52 3 3 53 3 52 -50 0 -51 0 0 45 0 45 110 0
110 0 0 -109 c0 -60 -4 -121 -9 -134 -14 -36 -70 -52 -181 -52 -86 0 -100 3
-147 29 -88 49 -129 131 -121 245 8 107 63 187 158 230 35 16 65 20 130 20 47
-1 96 -4 110 -8z m340 -906 l0 -185 -995 0 -995 0 0 185 0 185 995 0 995 0 0
-185z"/>
<path d="M540 1089 l0 -80 51 3 c67 4 95 36 85 93 -6 29 -14 39 -41 51 -19 8
-48 14 -65 14 l-30 0 0 -81z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -11,8 +11,42 @@ PODS:
- SwiftProtobuf - SwiftProtobuf
- device_info (0.0.1): - device_info (0.0.1):
- Flutter - Flutter
- DKImagePickerController/Core (4.3.4):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.4)
- DKImagePickerController/PhotoGallery (4.3.4):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.4)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- easy_app_installer (0.0.1): - easy_app_installer (0.0.1):
- Flutter - Flutter
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0) - Flutter (1.0.0)
- fluttertoast (0.0.2): - fluttertoast (0.0.2):
- Flutter - Flutter
@ -36,6 +70,9 @@ PODS:
- Flutter - Flutter
- rive_common (0.0.1): - rive_common (0.0.1):
- Flutter - Flutter
- SDWebImage (5.17.0):
- SDWebImage/Core (= 5.17.0)
- SDWebImage/Core (5.17.0)
- shared_preferences_foundation (0.0.1): - shared_preferences_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@ -43,6 +80,7 @@ PODS:
- Flutter - Flutter
- FMDB (>= 2.7.5) - FMDB (>= 2.7.5)
- SwiftProtobuf (1.20.3) - SwiftProtobuf (1.20.3)
- SwiftyGif (5.4.4)
- Toast (4.0.0) - Toast (4.0.0)
DEPENDENCIES: DEPENDENCIES:
@ -52,6 +90,7 @@ DEPENDENCIES:
- barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`) - barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`)
- device_info (from `.symlinks/plugins/device_info/ios`) - device_info (from `.symlinks/plugins/device_info/ios`)
- easy_app_installer (from `.symlinks/plugins/easy_app_installer/ios`) - easy_app_installer (from `.symlinks/plugins/easy_app_installer/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- location (from `.symlinks/plugins/location/ios`) - location (from `.symlinks/plugins/location/ios`)
@ -66,9 +105,13 @@ DEPENDENCIES:
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- DKImagePickerController
- DKPhotoGallery
- FMDB - FMDB
- MTBBarcodeScanner - MTBBarcodeScanner
- SDWebImage
- SwiftProtobuf - SwiftProtobuf
- SwiftyGif
- Toast - Toast
EXTERNAL SOURCES: EXTERNAL SOURCES:
@ -84,6 +127,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/device_info/ios" :path: ".symlinks/plugins/device_info/ios"
easy_app_installer: easy_app_installer:
:path: ".symlinks/plugins/easy_app_installer/ios" :path: ".symlinks/plugins/easy_app_installer/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter: Flutter:
:path: Flutter :path: Flutter
fluttertoast: fluttertoast:
@ -113,7 +158,10 @@ SPEC CHECKSUMS:
audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40 audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40
barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0 barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
easy_app_installer: 29abe397da7d86721fee853281202f414373f45c easy_app_installer: 29abe397da7d86721fee853281202f414373f45c
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
@ -125,9 +173,11 @@ SPEC CHECKSUMS:
permission_handler_apple: 8f116445eff3c0e7c65ad60f5fef5490aa94b4e4 permission_handler_apple: 8f116445eff3c0e7c65ad60f5fef5490aa94b4e4
platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5 platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5
rive_common: 60ae7896ab40f9513974f36f015de33f70d2c5c5 rive_common: 60ae7896ab40f9513974f36f015de33f70d2c5c5
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
SwiftProtobuf: b02b5075dcf60c9f5f403000b3b0c202a11b6ae1 SwiftProtobuf: b02b5075dcf60c9f5f403000b3b0c202a11b6ae1
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3

View File

@ -3,6 +3,9 @@ import 'package:equatable/equatable.dart';
import 'package:unit2/model/profile/educational_background.dart'; import 'package:unit2/model/profile/educational_background.dart';
import 'package:unit2/sevices/profile/education_services.dart'; import 'package:unit2/sevices/profile/education_services.dart';
import '../../../model/profile/attachment.dart';
import '../../../utils/attachment_services.dart';
part 'education_event.dart'; part 'education_event.dart';
part 'education_state.dart'; part 'education_state.dart';
@ -11,20 +14,27 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
List<School> schools = []; List<School> schools = [];
List<Course> programs = []; List<Course> programs = [];
List<Honor> honors = []; List<Honor> honors = [];
List<AttachmentCategory> attachmentCategories = [];
EducationBloc() : super(EducationInitial()) { EducationBloc() : super(EducationInitial()) {
on<GetEducationalBackground>((event, emit) async { on<GetEducationalBackground>((event, emit) async {
emit(EducationalBackgroundLoadingState()); emit(EducationalBackgroundLoadingState());
try { try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
if (educationalBackgrounds.isEmpty) { if (educationalBackgrounds.isEmpty) {
List<EducationalBackground> educations = await EducationService List<EducationalBackground> educations = await EducationService
.instace .instace
.getEducationalBackground(event.profileId, event.token); .getEducationalBackground(event.profileId, event.token);
educationalBackgrounds = educations; educationalBackgrounds = educations;
emit(EducationalBackgroundLoadedState( emit(EducationalBackgroundLoadedState(
educationalBackground: educationalBackgrounds)); educationalBackground: educationalBackgrounds,
attachmentCategory: attachmentCategories));
} else { } else {
emit(EducationalBackgroundLoadedState( emit(EducationalBackgroundLoadedState(
educationalBackground: educationalBackgrounds)); educationalBackground: educationalBackgrounds,
attachmentCategory: attachmentCategories));
} }
} catch (e) { } catch (e) {
emit(EducationalBackgroundErrorState(message: e.toString())); emit(EducationalBackgroundErrorState(message: e.toString()));
@ -77,7 +87,8 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
token: event.token, token: event.token,
profileId: event.profileId); profileId: event.profileId);
if (status['success']) { if (status['success']) {
educationalBackgrounds.removeWhere((element) => event.educationalBackground.id == element.id); educationalBackgrounds.removeWhere(
(element) => event.educationalBackground.id == element.id);
EducationalBackground educationalBackground = EducationalBackground educationalBackground =
EducationalBackground.fromJson(status['data']); EducationalBackground.fromJson(status['data']);
educationalBackgrounds.add(educationalBackground); educationalBackgrounds.add(educationalBackground);
@ -89,7 +100,8 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
////LOAD ////LOAD
on<LoadEducations>((event, emit) { on<LoadEducations>((event, emit) {
emit(EducationalBackgroundLoadedState( emit(EducationalBackgroundLoadedState(
educationalBackground: educationalBackgrounds)); educationalBackground: educationalBackgrounds,
attachmentCategory: attachmentCategories));
}); });
//// SHOW EDIT FORM //// SHOW EDIT FORM
on<ShowEditEducationForm>((event, emit) async { on<ShowEditEducationForm>((event, emit) async {
@ -134,5 +146,65 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
emit(EducationalBackgroundErrorState(message: e.toString())); emit(EducationalBackgroundErrorState(message: e.toString()));
} }
}); });
////Add attachment
on<AddEducationAttachment>((event, emit) async {
emit(EducationalBackgroundLoadingState());
EducationalBackground educationalBackground =
educationalBackgrounds.firstWhere(
(element) => element.id.toString() == event.attachmentModule);
List<Attachment> attachments = [];
try {
Map<dynamic, dynamic> status = await AttachmentServices.instance
.attachment(
categoryId: event.categoryId,
module: event.attachmentModule,
paths: event.filePaths,
token: event.token,
profileId: event.profileId);
if (status['success']) {
status['data'].forEach((element) {
Attachment newAttachment = Attachment.fromJson(element);
attachments.add(newAttachment);
});
educationalBackground.attachments == null
? educationalBackground.attachments = attachments
: educationalBackground.attachments = [
...educationalBackground.attachments!,
...attachments
];
emit(EducationAddedState(response: status));
} else {
emit(EducationAddedState(response: status));
}
} catch (e) {
emit(EducationalBackgroundErrorState(message: e.toString()));
}
});
on<DeleteEducationAttachment>((event, emit) async {
emit(EducationalBackgroundLoadingState());
try {
final bool success = await AttachmentServices.instance.deleteAttachment(
attachment: event.attachment,
moduleId: event.moduleId,
profileId: event.profileId.toString(),
token: event.token);
if (success) {
final EducationalBackground educationalBackground =
educationalBackgrounds
.firstWhere((element) => element.id == event.moduleId);
educationalBackground.attachments
?.removeWhere((element) => element.id == event.attachment.id);
educationalBackgrounds
.removeWhere((element) => element.id == event.moduleId);
educationalBackgrounds.add(educationalBackground);
emit(EducationAttachmentDeletedState(success: success));
} else {
emit(EducationAttachmentDeletedState(success: success));
}
} catch (e) {
emit(EducationalBackgroundErrorState(message: e.toString()));
}
});
} }
} }

View File

@ -63,3 +63,23 @@ class DeleteEducation extends EducationEvent{
@override @override
List<Object> get props => [educationalBackground, profileId, token]; List<Object> get props => [educationalBackground, profileId, token];
} }
////Add attachment
class AddEducationAttachment extends EducationEvent{
final String categoryId;
final String attachmentModule;
final List<String> filePaths;
final String token;
final String profileId;
const AddEducationAttachment({required this.attachmentModule, required this.filePaths, required this.categoryId, required this.profileId, required this.token});
@override
List<Object> get props => [categoryId,attachmentModule,filePaths, token,profileId];
}
////Delete Attachment
class DeleteEducationAttachment extends EducationEvent{
final int moduleId;
final Attachment attachment;
final String token;
final int profileId;
const DeleteEducationAttachment({required this.attachment, required this.moduleId, required this.profileId, required this.token});
}

View File

@ -10,8 +10,10 @@ abstract class EducationState extends Equatable {
class EducationInitial extends EducationState {} class EducationInitial extends EducationState {}
class EducationalBackgroundLoadedState extends EducationState { class EducationalBackgroundLoadedState extends EducationState {
final List<AttachmentCategory> attachmentCategory;
final List<EducationalBackground> educationalBackground; final List<EducationalBackground> educationalBackground;
const EducationalBackgroundLoadedState({required this.educationalBackground}); const EducationalBackgroundLoadedState(
{required this.educationalBackground, required this.attachmentCategory});
@override @override
List<Object> get props => [educationalBackground]; List<Object> get props => [educationalBackground];
} }
@ -57,6 +59,8 @@ class EducationAddedState extends EducationState {
@override @override
List<Object> get props => [response]; List<Object> get props => [response];
} }
//// Edited State //// Edited State
class EditedEducationState extends EducationState { class EditedEducationState extends EducationState {
final Map<dynamic, dynamic> response; final Map<dynamic, dynamic> response;
@ -72,3 +76,17 @@ class EducationDeletedState extends EducationState {
@override @override
List<Object> get props => [success]; List<Object> get props => [success];
} }
////Attachment AddedState
class EducationAttachmentAddedState extends EducationState {
final Map<dynamic, dynamic> response;
const EducationAttachmentAddedState({required this.response});
}
////Attachment Deleted State State
class EducationAttachmentDeletedState extends EducationState {
final bool success;
const EducationAttachmentDeletedState({required this.success});
@override
List<Object> get props => [success];
}

View File

@ -1,9 +1,11 @@
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:unit2/utils/attachment_services.dart';
import '../../../model/location/city.dart'; import '../../../model/location/city.dart';
import '../../../model/location/country.dart'; import '../../../model/location/country.dart';
import '../../../model/location/provinces.dart'; import '../../../model/location/provinces.dart';
import '../../../model/location/region.dart'; import '../../../model/location/region.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/profile/eligibility.dart'; import '../../../model/profile/eligibility.dart';
import '../../../model/utils/eligibility.dart'; import '../../../model/utils/eligibility.dart';
import '../../../sevices/profile/eligibility_services.dart'; import '../../../sevices/profile/eligibility_services.dart';
@ -18,10 +20,13 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
List<Region> globalRegions = []; List<Region> globalRegions = [];
List<Eligibility> globalEligibilities = []; List<Eligibility> globalEligibilities = [];
List<EligibityCert> eligibilities = []; List<EligibityCert> eligibilities = [];
List<AttachmentCategory> attachmentCategories = [];
//// LOAD ELIGIBILTY //// LOAD ELIGIBILTY
on<LoadEligibility>((event, emit) { on<LoadEligibility>((event, emit) {
emit(EligibilityLoadingState()); emit(EligibilityLoadingState());
emit(EligibilityLoaded(eligibilities: eligibilities)); emit(EligibilityLoaded(
eligibilities: eligibilities,
attachmentCategory: attachmentCategories));
}); });
//// DELETE //// DELETE
@ -34,11 +39,11 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
if (success) { if (success) {
eligibilities.removeWhere( eligibilities.removeWhere(
((EligibityCert element) => element.id == event.eligibilityId)); ((EligibityCert element) => element.id == event.eligibilityId));
emit(DeletedState( emit(EligibilityDeletedState(
success: success, success: success,
)); ));
} else { } else {
emit(DeletedState(success: success)); emit(EligibilityDeletedState(success: success));
} }
} catch (e) { } catch (e) {
emit(EligibilityErrorState(message: e.toString())); emit(EligibilityErrorState(message: e.toString()));
@ -48,13 +53,21 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
//// GET ELIGIBILITY //// GET ELIGIBILITY
on<GetEligibilities>((event, emit) async { on<GetEligibilities>((event, emit) async {
try { try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
if (eligibilities.isNotEmpty) { if (eligibilities.isNotEmpty) {
emit(EligibilityLoaded(eligibilities: eligibilities)); emit(EligibilityLoaded(
eligibilities: eligibilities,
attachmentCategory: attachmentCategories));
} else { } else {
emit(EligibilityLoadingState()); emit(EligibilityLoadingState());
eligibilities = await EligibilityService.instance eligibilities = await EligibilityService.instance
.getEligibilities(event.profileId, event.token); .getEligibilities(event.profileId, event.token);
emit(EligibilityLoaded(eligibilities: eligibilities)); emit(EligibilityLoaded(
eligibilities: eligibilities,
attachmentCategory: attachmentCategories));
} }
} catch (e) { } catch (e) {
emit(EligibilityErrorState(message: e.toString())); emit(EligibilityErrorState(message: e.toString()));
@ -208,5 +221,63 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
emit(const EligibilityErrorState( emit(const EligibilityErrorState(
message: "Something went wrong. Please try again")); message: "Something went wrong. Please try again"));
}); });
////Add attachment
on<AddEligibiltyAttachment>((event, emit) async {
emit(EligibilityLoadingState());
List<Attachment> attachments = [];
EligibityCert eligibityCert = eligibilities.firstWhere(
(element) => element.id.toString() == event.attachmentModule);
try {
Map<dynamic, dynamic> status = await AttachmentServices.instance
.attachment(
categoryId: event.categoryId,
module: event.attachmentModule,
paths: event.filePaths,
token: event.token,
profileId: event.profileId);
if (status['success']) {
status['data'].forEach((element) {
Attachment newAttachment = Attachment.fromJson(element);
attachments.add(newAttachment);
});
eligibityCert.attachments == null
? eligibityCert.attachments = attachments
: eligibityCert.attachments = [
...eligibityCert.attachments!,
...attachments
];
emit(EligibilityAttachmentAddedState(response: status));
} else {
emit(EligibilityAttachmentAddedState(response: status));
}
} catch (e) {
emit(EligibilityErrorState(message: e.toString()));
}
});
on<DeleteEligibyAttachment>((event, emit) async {
emit(EligibilityLoadingState());
// try {
final bool success = await AttachmentServices.instance.deleteAttachment(
attachment: event.attachment,
moduleId: int.parse(event.moduleId),
profileId: event.profileId.toString(),
token: event.token);
if (success) {
final EligibityCert eligibityCert = eligibilities
.firstWhere((element) => element.id.toString() == event.moduleId);
eligibityCert.attachments
?.removeWhere((element) => element.id == event.attachment.id);
eligibilities.removeWhere(
(element) => element.id.toString() == event.moduleId);
eligibilities.add(eligibityCert);
emit(EligibilitytAttachmentDeletedState(success: success));
} else {
emit(EligibilitytAttachmentDeletedState(success: success));
}
// } catch (e) {
// emit(EligibilityErrorState(message: e.toString()));
// }
});
} }
} }

View File

@ -55,6 +55,7 @@ class DeleteEligibility extends EligibilityEvent {
final String profileId; final String profileId;
final int eligibilityId; final int eligibilityId;
final String token; final String token;
const DeleteEligibility( const DeleteEligibility(
{ {
required this.eligibilityId, required this.eligibilityId,
@ -67,5 +68,32 @@ class DeleteEligibility extends EligibilityEvent {
class CallErrorState extends EligibilityEvent{ class CallErrorState extends EligibilityEvent{
} }
////Add Attachment
class AddEligibiltyAttachment extends EligibilityEvent{
final String categoryId;
final String attachmentModule;
final List<String> filePaths;
final String token;
final String profileId;
const AddEligibiltyAttachment({required this.attachmentModule, required this.filePaths, required this.categoryId, required this.profileId, required this.token});
@override
List<Object> get props => [categoryId,attachmentModule,filePaths, token,profileId];
}
////Delete Attachment
class DeleteEligibyAttachment extends EligibilityEvent{
final String profileId;
final String token;
final Attachment attachment;
final String moduleId;
const DeleteEligibyAttachment({required this.attachment,required this.moduleId, required this.profileId, required this.token});
}

View File

@ -9,7 +9,6 @@ abstract class EligibilityState extends Equatable {
class EligibilityInitial extends EligibilityState {} class EligibilityInitial extends EligibilityState {}
class EditEligibilityState extends EligibilityState { class EditEligibilityState extends EligibilityState {
final EligibityCert eligibityCert; final EligibityCert eligibityCert;
final List<Eligibility> eligibilities; final List<Eligibility> eligibilities;
@ -23,13 +22,14 @@ class EditEligibilityState extends EligibilityState {
final Province? currentProvince; final Province? currentProvince;
final CityMunicipality? currentCity; final CityMunicipality? currentCity;
final Country selectedCountry; final Country selectedCountry;
const EditEligibilityState({
required this.provinces, const EditEligibilityState({
required this.cities, required this.provinces,
required this.currentProvince, required this.cities,
required this.currentCity, required this.currentProvince,
required this.currentRegion, required this.currentCity,
required this.currentEligibility, required this.currentRegion,
required this.currentEligibility,
required this.isOverseas, required this.isOverseas,
required this.eligibityCert, required this.eligibityCert,
required this.eligibilities, required this.eligibilities,
@ -42,9 +42,9 @@ class EditEligibilityState extends EligibilityState {
[isOverseas, eligibityCert, eligibilities, regions, countries]; [isOverseas, eligibityCert, eligibilities, regions, countries];
} }
class DeletedState extends EligibilityState { class EligibilityDeletedState extends EligibilityState {
final bool success; final bool success;
const DeletedState({required this.success}); const EligibilityDeletedState({required this.success});
@override @override
List<Object> get props => [success]; List<Object> get props => [success];
} }
@ -53,41 +53,57 @@ class AddEligibilityState extends EligibilityState {
final List<Eligibility> eligibilities; final List<Eligibility> eligibilities;
final List<Country> countries; final List<Country> countries;
final List<Region> regions; final List<Region> regions;
const AddEligibilityState({ const AddEligibilityState({
required this.eligibilities, required this.eligibilities,
required this.countries, required this.countries,
required this.regions, required this.regions,
}); });
@override @override
List<Object> get props => [eligibilities,countries,regions]; List<Object> get props => [eligibilities, countries, regions];
} }
class EligibilityEditedState extends EligibilityState{
final Map<dynamic,dynamic> response; class EligibilityEditedState extends EligibilityState {
final Map<dynamic, dynamic> response;
const EligibilityEditedState({required this.response}); const EligibilityEditedState({required this.response});
@override @override
List<Object> get props =>[ response]; List<Object> get props => [response];
} }
class EligibilityAddedState extends EligibilityState{ class EligibilityAddedState extends EligibilityState {
final Map<dynamic,dynamic> response; final Map<dynamic, dynamic> response;
const EligibilityAddedState({ required this.response}); const EligibilityAddedState({required this.response});
@override @override
List<Object> get props =>[response]; List<Object> get props => [response];
} }
class EligibilityLoadingState extends EligibilityState{
} class EligibilityLoadingState extends EligibilityState {}
class EligibilityErrorState extends EligibilityState{
class EligibilityErrorState extends EligibilityState {
final String message; final String message;
const EligibilityErrorState({required this.message}); const EligibilityErrorState({required this.message});
@override @override
List<Object> get props =>[message]; List<Object> get props => [message];
} }
class EligibilityLoaded extends EligibilityState { class EligibilityLoaded extends EligibilityState {
final List< AttachmentCategory> attachmentCategory;
final List<EligibityCert> eligibilities; final List<EligibityCert> eligibilities;
const EligibilityLoaded({required this.eligibilities}); const EligibilityLoaded({required this.eligibilities, required this.attachmentCategory});
@override @override
List<Object> get props => [eligibilities]; List<Object> get props => [eligibilities];
} }
////Attachment AddedState
class EligibilityAttachmentAddedState extends EligibilityState {
final Map<dynamic, dynamic> response;
const EligibilityAttachmentAddedState({required this.response});
}
////Attachment Deleted State State
class EligibilitytAttachmentDeletedState extends EligibilityState {
final bool success;
const EligibilitytAttachmentDeletedState({required this.success});
@override
List<Object> get props => [success];
}

View File

@ -6,9 +6,11 @@ import 'package:unit2/sevices/profile/learningDevelopment_service.dart';
import '../../../model/location/barangay.dart'; import '../../../model/location/barangay.dart';
import '../../../model/location/city.dart'; import '../../../model/location/city.dart';
import '../../../model/location/provinces.dart'; import '../../../model/location/provinces.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/profile/learning_development.dart'; import '../../../model/profile/learning_development.dart';
import '../../../model/utils/agency.dart'; import '../../../model/utils/agency.dart';
import '../../../model/utils/category.dart'; import '../../../model/utils/category.dart';
import '../../../utils/attachment_services.dart';
import '../../../utils/location_utilities.dart'; import '../../../utils/location_utilities.dart';
import '../../../utils/profile_utilities.dart'; import '../../../utils/profile_utilities.dart';
part 'learning_development_event.dart'; part 'learning_development_event.dart';
@ -27,7 +29,7 @@ class LearningDevelopmentBloc
List<Barangay> globalBarangay = []; List<Barangay> globalBarangay = [];
List<Agency> agencies = []; List<Agency> agencies = [];
List<Category> agencyCategory = []; List<Category> agencyCategory = [];
List<AttachmentCategory> attachmentCategories = [];
Region? currentRegion; Region? currentRegion;
Country? currentCountry; Country? currentCountry;
Province? currentProvince; Province? currentProvince;
@ -37,12 +39,16 @@ class LearningDevelopmentBloc
on<GetLearningDevelopments>((event, emit) async { on<GetLearningDevelopments>((event, emit) async {
emit(LearningDevelopmentLoadingState()); emit(LearningDevelopmentLoadingState());
try { try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
List<LearningDevelopement> learnings = await LearningDevelopmentServices List<LearningDevelopement> learnings = await LearningDevelopmentServices
.instance .instance
.getLearningDevelopments(event.profileId, event.token); .getLearningDevelopments(event.profileId, event.token);
learningsAndDevelopments = learnings; learningsAndDevelopments = learnings;
emit(LearningDevelopmentLoadedState( emit(LearningDevelopmentLoadedState(
learningsAndDevelopment: learningsAndDevelopments)); learningsAndDevelopment: learningsAndDevelopments,attachmentCategory: attachmentCategories));
} catch (e) { } catch (e) {
emit(LearningDevelopmentErrorState(message: e.toString())); emit(LearningDevelopmentErrorState(message: e.toString()));
} }
@ -50,7 +56,7 @@ class LearningDevelopmentBloc
////load ////load
on<LoadLearniningDevelopment>((event, emit) { on<LoadLearniningDevelopment>((event, emit) {
emit(LearningDevelopmentLoadedState( emit(LearningDevelopmentLoadedState(
learningsAndDevelopment: learningsAndDevelopments)); learningsAndDevelopment: learningsAndDevelopments,attachmentCategory: attachmentCategories));
}); });
//// show add form //// show add form
on<ShowAddLearningDevelopmentForm>((event, emit) async { on<ShowAddLearningDevelopmentForm>((event, emit) async {
@ -266,5 +272,58 @@ class LearningDevelopmentBloc
on<CallErrorState>((event, emit) { on<CallErrorState>((event, emit) {
emit(LearningDevelopmentErrorState(message: event.message)); emit(LearningDevelopmentErrorState(message: event.message));
}); });
////Add attachment
on<AddALearningDevttachment>((event, emit) async {
emit(LearningDevelopmentLoadingState());
List<Attachment> attachments = [];
LearningDevelopement learningDevelopement = learningsAndDevelopments.firstWhere((element) => element.conductedTraining!.id.toString () == event.attachmentModule);
try {
Map<dynamic, dynamic> status = await AttachmentServices.instance
.attachment(
categoryId: event.categoryId,
module: event.attachmentModule,
paths: event.filePaths,
token: event.token,
profileId: event.profileId);
if (status['success']) {
status['data'].forEach((element){
Attachment newAttachment = Attachment.fromJson(element);
attachments.add(newAttachment);
});
learningDevelopement.attachments == null? learningDevelopement.attachments = attachments:learningDevelopement.attachments = [...learningDevelopement.attachments!,...attachments];
emit(LearningDevelopmentAddedState(response: status));
} else {
emit(LearningDevelopmentAddedState(response: status));
}
} catch (e) {
emit(LearningDevelopmentErrorState(message: e.toString()));
}
});
////Delete Attachment
on<DeleteLearningDevAttachment>((event, emit) async {
emit(LearningDevelopmentLoadingState());
try {
final bool success = await AttachmentServices.instance.deleteAttachment(
attachment: event.attachment,
moduleId: event.moduleId,
profileId: event.profileId.toString(),
token: event.token);
if (success) {
final LearningDevelopement learningDevelopement =
learningsAndDevelopments
.firstWhere((element) => element.conductedTraining!.id == event.moduleId);
learningDevelopement.attachments
?.removeWhere((element) => element.id == event.attachment.id);
learningsAndDevelopments
.removeWhere((element) => element.conductedTraining!.id == event.moduleId);
learningsAndDevelopments.add(learningDevelopement);
emit(LearningDevAttachmentDeletedState(success: success));
} else {
emit(LearningDevAttachmentDeletedState(success: success));
}
} catch (e) {
emit(LearningDevelopmentErrorState(message: e.toString()));
}
});
} }
} }

View File

@ -66,3 +66,25 @@ class CallErrorState extends LearningDevelopmentEvent{
final String message; final String message;
const CallErrorState({required this.message}); const CallErrorState({required this.message});
} }
////Add Attachment
class AddALearningDevttachment extends LearningDevelopmentEvent{
final String categoryId;
final String attachmentModule;
final List<String> filePaths;
final String token;
final String profileId;
const AddALearningDevttachment({required this.attachmentModule, required this.filePaths, required this.categoryId, required this.profileId, required this.token});
@override
List<Object> get props => [categoryId,attachmentModule,filePaths, token,profileId];
}
//// Delete Attachment
class DeleteLearningDevAttachment extends LearningDevelopmentEvent{
final int moduleId;
final Attachment attachment;
final String token;
final int profileId;
const DeleteLearningDevAttachment({required this.attachment, required this.moduleId, required this.profileId, required this.token});
}

View File

@ -10,8 +10,11 @@ abstract class LearningDevelopmentState extends Equatable {
class LearningDevelopmentInitial extends LearningDevelopmentState {} class LearningDevelopmentInitial extends LearningDevelopmentState {}
class LearningDevelopmentLoadedState extends LearningDevelopmentState { class LearningDevelopmentLoadedState extends LearningDevelopmentState {
final List<AttachmentCategory> attachmentCategory;
final List<LearningDevelopement> learningsAndDevelopment; final List<LearningDevelopement> learningsAndDevelopment;
const LearningDevelopmentLoadedState({required this.learningsAndDevelopment}); const LearningDevelopmentLoadedState(
{required this.learningsAndDevelopment,
required this.attachmentCategory});
@override @override
List<Object> get props => [learningsAndDevelopment]; List<Object> get props => [learningsAndDevelopment];
} }
@ -112,3 +115,21 @@ class LearningDevelopmentErrorState extends LearningDevelopmentState {
final String message; final String message;
const LearningDevelopmentErrorState({required this.message}); const LearningDevelopmentErrorState({required this.message});
} }
////Attachment AddedState
class LearningDevAttachmentAddedState extends LearningDevelopmentState {
final Map<dynamic, dynamic> response;
const LearningDevAttachmentAddedState({required this.response});
@override
List<Object> get props => [response];
}
////Attachment Deleted State State
class LearningDevAttachmentDeletedState extends LearningDevelopmentState {
final bool success;
const LearningDevAttachmentDeletedState({required this.success});
@override
List<Object> get props => [success];
}

View File

@ -72,3 +72,13 @@ class DeleteVoluntaryWork extends VoluntaryWorkEvent {
@override @override
List<Object> get props => [profileId, token, work]; List<Object> get props => [profileId, token, work];
} }
class AddAttachment extends VoluntaryWorkEvent{
final String categoryId;
final String attachmentModule;
final List<String> filePaths;
final String token;
final String profileId;
const AddAttachment({required this.attachmentModule, required this.filePaths, required this.categoryId, required this.profileId, required this.token});
@override
List<Object> get props => [categoryId,attachmentModule,filePaths, token,profileId];
}

View File

@ -60,6 +60,7 @@ class EditVoluntaryWorks extends VoluntaryWorkState{
} }
////Adding State ////Adding State
class AddVoluntaryWorkState extends VoluntaryWorkState{ class AddVoluntaryWorkState extends VoluntaryWorkState{
final List<Position> positions; final List<Position> positions;
@ -71,6 +72,11 @@ class AddVoluntaryWorkState extends VoluntaryWorkState{
@override @override
List<Object> get props => [positions,agencies,countries,regions]; List<Object> get props => [positions,agencies,countries,regions];
} }
////Add Attachment
class AttachmentAddedState extends VoluntaryWorkState {
final Map<dynamic, dynamic> response;
const AttachmentAddedState({required this.response});
}
//// Deleted State //// Deleted State
class VoluntaryWorkDeletedState extends VoluntaryWorkState{ class VoluntaryWorkDeletedState extends VoluntaryWorkState{
final bool success; final bool success;

View File

@ -8,7 +8,9 @@ import 'package:unit2/model/utils/position.dart';
import 'package:unit2/sevices/profile/work_history_services.dart'; import 'package:unit2/sevices/profile/work_history_services.dart';
import 'package:unit2/utils/profile_utilities.dart'; import 'package:unit2/utils/profile_utilities.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/utils/category.dart'; import '../../../model/utils/category.dart';
import '../../../utils/attachment_services.dart';
part 'workHistory_event.dart'; part 'workHistory_event.dart';
part 'workHistory_state.dart'; part 'workHistory_state.dart';
@ -19,17 +21,24 @@ class WorkHistoryBloc extends Bloc<WorkHistorytEvent, WorkHistoryState> {
List<Agency> agencies = []; List<Agency> agencies = [];
List<AppoinemtStatus> appointmentStatus = []; List<AppoinemtStatus> appointmentStatus = [];
List<Category> agencyCategory = []; List<Category> agencyCategory = [];
List<AttachmentCategory> attachmentCategories = [];
WorkHistoryBloc() : super(EducationInitial()) { WorkHistoryBloc() : super(EducationInitial()) {
////GET WORK HISTORIES ////GET WORK HISTORIES
on<GetWorkHistories>((event, emit) async { on<GetWorkHistories>((event, emit) async {
emit(WorkHistoryLoadingState()); emit(WorkHistoryLoadingState());
try { try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
if (workExperiences.isEmpty) { if (workExperiences.isEmpty) {
List<WorkHistory> works = await WorkHistoryService.instance List<WorkHistory> works = await WorkHistoryService.instance
.getWorkExperiences(event.profileId, event.token); .getWorkExperiences(event.profileId, event.token);
workExperiences = works; workExperiences = works;
} }
emit(WorkHistoryLoaded(workExperiences: workExperiences)); emit(WorkHistoryLoaded(
workExperiences: workExperiences,
attachmentCategory: attachmentCategories));
} catch (e) { } catch (e) {
emit(WorkHistoryErrorState(message: e.toString())); emit(WorkHistoryErrorState(message: e.toString()));
} }
@ -37,7 +46,9 @@ class WorkHistoryBloc extends Bloc<WorkHistorytEvent, WorkHistoryState> {
///// LOAD WORK HISTORIES ///// LOAD WORK HISTORIES
on<LoadWorkHistories>((event, emit) { on<LoadWorkHistories>((event, emit) {
emit(WorkHistoryLoadingState()); emit(WorkHistoryLoadingState());
emit(WorkHistoryLoaded(workExperiences: workExperiences)); emit(WorkHistoryLoaded(
workExperiences: workExperiences,
attachmentCategory: attachmentCategories));
}); });
////DELETE ////DELETE
on<DeleteWorkHistory>((event, emit) async { on<DeleteWorkHistory>((event, emit) async {
@ -182,5 +193,64 @@ class WorkHistoryBloc extends Bloc<WorkHistorytEvent, WorkHistoryState> {
emit(WorkHistoryErrorState(message: e.toString())); emit(WorkHistoryErrorState(message: e.toString()));
} }
}); });
////Add Attachment
on<AddWorkHistoryAttachment>((event, emit) async {
emit(WorkHistoryLoadingState());
List<Attachment> attachments = [];
WorkHistory workHistory = workExperiences.firstWhere(
(element) => element.id.toString() == event.attachmentModule);
try {
Map<dynamic, dynamic> status = await AttachmentServices.instance
.attachment(
categoryId: event.categoryId,
module: event.attachmentModule,
paths: event.filePaths,
token: event.token,
profileId: event.profileId);
if (status['success']) {
status['data'].forEach((element) {
Attachment newAttachment = Attachment.fromJson(element);
attachments.add(newAttachment);
});
workHistory.attachments == null
? workHistory.attachments = attachments
: workHistory.attachments = [
...workHistory.attachments!,
...attachments
];
emit(WorkHistoryDevAttachmentAddedState(response: status));
} else {
emit(WorkHistoryDevAttachmentAddedState(response: status));
}
} catch (e) {
emit(WorkHistoryErrorState(message: e.toString()));
}
});
////Delete Attachment
on<DeleteWorkHistoryAttachment>((event, emit) async {
emit(WorkHistoryLoadingState());
try {
final bool success = await AttachmentServices.instance.deleteAttachment(
attachment: event.attachment,
moduleId: event.moduleId,
profileId: event.profileId.toString(),
token: event.token);
if (success) {
final WorkHistory workHistory =
workExperiences
.firstWhere((element) => element.id == event.moduleId);
workHistory.attachments
?.removeWhere((element) => element.id == event.attachment.id);
workExperiences
.removeWhere((element) => element.id == event.moduleId);
workExperiences.add(workHistory);
emit(WorkHistoryDevAttachmentDeletedState(success: success));
} else {
emit(WorkHistoryDevAttachmentDeletedState(success: success));
}
} catch (e) {
emit(WorkHistoryErrorState(message: e.toString()));
}
});
} }
} }

View File

@ -61,4 +61,26 @@ class AddWorkHostory extends WorkHistorytEvent{
List<Object> get props => [workHistory,profileId,token,isPrivate]; List<Object> get props => [workHistory,profileId,token,isPrivate];
} }
////Add Attachment
class AddWorkHistoryAttachment extends WorkHistorytEvent{
final String categoryId;
final String attachmentModule;
final List<String> filePaths;
final String token;
final String profileId;
const AddWorkHistoryAttachment({required this.attachmentModule, required this.filePaths, required this.categoryId, required this.profileId, required this.token});
@override
List<Object> get props => [categoryId,attachmentModule,filePaths, token,profileId];
}
////Delete Attachment
class DeleteWorkHistoryAttachment extends WorkHistorytEvent{
final int moduleId;
final Attachment attachment;
final String token;
final int profileId;
const DeleteWorkHistoryAttachment({required this.attachment, required this.moduleId, required this.profileId, required this.token});
}

View File

@ -11,7 +11,8 @@ class EducationInitial extends WorkHistoryState {}
class WorkHistoryLoaded extends WorkHistoryState{ class WorkHistoryLoaded extends WorkHistoryState{
final List<WorkHistory> workExperiences; final List<WorkHistory> workExperiences;
const WorkHistoryLoaded({required this.workExperiences}); final List< AttachmentCategory> attachmentCategory;
const WorkHistoryLoaded({required this.workExperiences,required this.attachmentCategory});
@override @override
List<Object> get props => [workExperiences]; List<Object> get props => [workExperiences];
} }
@ -72,3 +73,22 @@ class WorkHistoryAddedState extends WorkHistoryState{
@override @override
List<Object> get props => [response]; List<Object> get props => [response];
} }
////Attachment AddedState
class WorkHistoryDevAttachmentAddedState extends WorkHistoryState {
final Map<dynamic, dynamic> response;
const WorkHistoryDevAttachmentAddedState({required this.response});
@override
List<Object> get props => [response];
}
////Attachment Deleted State State
class WorkHistoryDevAttachmentDeletedState extends WorkHistoryState {
final bool success;
const WorkHistoryDevAttachmentDeletedState({required this.success});
@override
List<Object> get props => [success];
}

View File

@ -1,24 +1,14 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:device_preview/device_preview.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/theme-data.dart/colors.dart';
import 'package:unit2/utils/app_router.dart'; import 'package:unit2/utils/app_router.dart';
import 'package:unit2/utils/global_context.dart'; import 'package:unit2/utils/global_context.dart';
import 'package:unit2/utils/global_context.dart';
import 'package:path_provider/path_provider.dart' as path_provider; import 'package:path_provider/path_provider.dart' as path_provider;
import './utils/router.dart';
import './utils/global.dart'; import './utils/global.dart';
Future main() async { Future main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
var appDirectory = await path_provider.getApplicationDocumentsDirectory(); var appDirectory = await path_provider.getApplicationDocumentsDirectory();
@ -92,4 +82,3 @@ class MyApp extends StatelessWidget {
); );
} }
} }

View File

@ -0,0 +1,118 @@
import 'dart:convert';
Attachment attachmentFromJson(String str) =>
Attachment.fromJson(json.decode(str));
String attachmentToJson(Attachment data) => json.encode(data.toJson());
class Attachment {
final int? id;
final String? source;
final AttachmentCategory? category;
final String? filename;
final Subclass? subclass;
final DateTime? createdAt;
Attachment({
required this.id,
required this.source,
required this.category,
required this.filename,
required this.subclass,
required this.createdAt,
});
factory Attachment.fromJson(Map<String, dynamic> json) => Attachment(
id: json["id"],
source: json["source"],
category: json['category'] == null
? null
: AttachmentCategory.fromJson(json["category"]),
filename: json["filename"],
subclass: json['subclass'] == null
? null
: Subclass.fromJson(json["subclass"]),
createdAt: json['created_at'] == null
? null
: DateTime.parse(json["created_at"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"source": source,
"category": category?.toJson(),
"filename": filename,
"subclass": subclass?.toJson(),
"created_at": createdAt?.toIso8601String(),
};
}
class AttachmentCategory {
final int? id;
final Subclass? subclass;
final String? description;
AttachmentCategory({
required this.id,
required this.subclass,
required this.description,
});
factory AttachmentCategory.fromJson(Map<String, dynamic> json) => AttachmentCategory(
id: json["id"],
subclass:json['subclass'] == null? null: Subclass.fromJson(json["subclass"]),
description: json["description"],
);
Map<String, dynamic> toJson() => {
"id": id,
"subclass": subclass?.toJson(),
"description": description,
};
}
class Subclass {
final int? id;
final String? name;
final AttachmentClass? attachmentClass;
Subclass({
required this.id,
required this.name,
required this.attachmentClass,
});
factory Subclass.fromJson(Map<String, dynamic> json) => Subclass(
id: json["id"],
name: json["name"],
attachmentClass: json['attachment_class'] == null? null: AttachmentClass.fromJson(json["attachment_class"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"attachment_class": attachmentClass?.toJson(),
};
}
class AttachmentClass {
final int? id;
final String? name;
AttachmentClass({
required this.id,
required this.name,
});
factory AttachmentClass.fromJson(Map<String, dynamic> json) =>
AttachmentClass(
id: json["id"],
name: json["name"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
};
}

View File

@ -4,6 +4,8 @@
import 'dart:convert'; import 'dart:convert';
import 'package:unit2/model/profile/attachment.dart';
EducationalBackground educationalBackgroundFromJson(String str) => EducationalBackground.fromJson(json.decode(str)); EducationalBackground educationalBackgroundFromJson(String str) => EducationalBackground.fromJson(json.decode(str));
String educationalBackgroundToJson(EducationalBackground data) => json.encode(data.toJson()); String educationalBackgroundToJson(EducationalBackground data) => json.encode(data.toJson());
@ -24,7 +26,7 @@ class EducationalBackground {
final List<Honor>? honors; final List<Honor>? honors;
final Education? education; final Education? education;
final String? periodTo; final String? periodTo;
final dynamic attachments; List<Attachment>? attachments;
final String? periodFrom; final String? periodFrom;
final int? unitsEarned; final int? unitsEarned;
final String? yearGraduated; final String? yearGraduated;
@ -34,7 +36,7 @@ class EducationalBackground {
honors: json["honors"] == null ? [] : List<Honor>.from(json["honors"]!.map((x) => Honor.fromJson(x))), honors: json["honors"] == null ? [] : List<Honor>.from(json["honors"]!.map((x) => Honor.fromJson(x))),
education: json["education"] == null ? null : Education.fromJson(json["education"]), education: json["education"] == null ? null : Education.fromJson(json["education"]),
periodTo: json["period_to"], periodTo: json["period_to"],
attachments: json["attachments"], attachments: json['attachments'] ==null?null: List<Attachment>.from(json["attachments"].map((x) => Attachment.fromJson(x))),
periodFrom: json["period_from"], periodFrom: json["period_from"],
unitsEarned: json["units_earned"], unitsEarned: json["units_earned"],
yearGraduated: json["year_graduated"], yearGraduated: json["year_graduated"],

View File

@ -6,6 +6,7 @@ import 'package:meta/meta.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:unit2/model/location/region.dart'; import 'package:unit2/model/location/region.dart';
import 'package:unit2/model/profile/attachment.dart';
import '../location/address_category.dart'; import '../location/address_category.dart';
import '../location/city.dart'; import '../location/city.dart';
@ -33,7 +34,8 @@ class EligibityCert {
final int? id; final int? id;
final double? rating; final double? rating;
final DateTime? examDate; final DateTime? examDate;
final dynamic attachments; List<Attachment>? attachments;
final Eligibility? eligibility; final Eligibility? eligibility;
final ExamAddress? examAddress; final ExamAddress? examAddress;
final DateTime? validityDate; final DateTime? validityDate;
@ -45,7 +47,7 @@ class EligibityCert {
examDate: json['exam_date'] == null examDate: json['exam_date'] == null
? null ? null
: DateTime.parse(json["exam_date"]), : DateTime.parse(json["exam_date"]),
attachments: null, attachments: json['attachments'] ==null?null: List<Attachment>.from(json["attachments"].map((x) => Attachment.fromJson(x))),
eligibility: json['eligibility'] == null eligibility: json['eligibility'] == null
? null ? null
: Eligibility.fromJson(json["eligibility"]), : Eligibility.fromJson(json["eligibility"]),

View File

@ -10,6 +10,7 @@ import '../location/city.dart';
import '../location/country.dart'; import '../location/country.dart';
import '../utils/agency.dart'; import '../utils/agency.dart';
import '../utils/industry_class.dart'; import '../utils/industry_class.dart';
import 'attachment.dart';
LearningDevelopement learningDevelopementFromJson(String str) => LearningDevelopement.fromJson(json.decode(str)); LearningDevelopement learningDevelopementFromJson(String str) => LearningDevelopement.fromJson(json.decode(str));
@ -23,13 +24,13 @@ class LearningDevelopement {
this.totalHoursAttended, this.totalHoursAttended,
}); });
final dynamic attachments; List<Attachment>? attachments;
final Agency? sponsoredBy; final Agency? sponsoredBy;
final ConductedTraining? conductedTraining; final ConductedTraining? conductedTraining;
final double? totalHoursAttended; final double? totalHoursAttended;
factory LearningDevelopement.fromJson(Map<String, dynamic> json) => LearningDevelopement( factory LearningDevelopement.fromJson(Map<String, dynamic> json) => LearningDevelopement(
attachments: json["attachments"], attachments: json['attachments'] ==null?null: List<Attachment>.from(json["attachments"].map((x) => Attachment.fromJson(x))),
sponsoredBy: json["sponsored_by"] == null ? null : Agency.fromJson(json["sponsored_by"]), sponsoredBy: json["sponsored_by"] == null ? null : Agency.fromJson(json["sponsored_by"]),
conductedTraining: json["conducted_training"] == null ? null : ConductedTraining.fromJson(json["conducted_training"]), conductedTraining: json["conducted_training"] == null ? null : ConductedTraining.fromJson(json["conducted_training"]),
totalHoursAttended: json["total_hours_attended"], totalHoursAttended: json["total_hours_attended"],

View File

@ -8,6 +8,7 @@ import '../utils/agency.dart';
import '../utils/category.dart'; import '../utils/category.dart';
import '../utils/industry_class.dart'; import '../utils/industry_class.dart';
import '../utils/position.dart'; import '../utils/position.dart';
import 'attachment.dart';
WorkHistory workHistoryFromJson(String str) => WorkHistory.fromJson(json.decode(str)); WorkHistory workHistoryFromJson(String str) => WorkHistory.fromJson(json.decode(str));
@ -21,7 +22,7 @@ class WorkHistory {
this.toDate, this.toDate,
this.position, this.position,
this.fromDate, this.fromDate,
// this.attachments, this.attachments,
this.salaryGrade, this.salaryGrade,
this.monthlySalary, this.monthlySalary,
this.appointmentStatus, this.appointmentStatus,
@ -33,7 +34,7 @@ class WorkHistory {
final DateTime? toDate; final DateTime? toDate;
final Position? position; final Position? position;
final DateTime? fromDate; final DateTime? fromDate;
// final dynamic attachments; List<Attachment>? attachments;
final int? salaryGrade; final int? salaryGrade;
final double? monthlySalary; final double? monthlySalary;
final String? appointmentStatus; final String? appointmentStatus;
@ -45,7 +46,7 @@ class WorkHistory {
toDate: json["to_date"] == null ? null : DateTime.parse(json["to_date"]), toDate: json["to_date"] == null ? null : DateTime.parse(json["to_date"]),
position: json["position"] == null ? null : Position.fromJson(json["position"]), position: json["position"] == null ? null : Position.fromJson(json["position"]),
fromDate: json["from_date"] == null ? null : DateTime.parse(json["from_date"]), fromDate: json["from_date"] == null ? null : DateTime.parse(json["from_date"]),
// attachments: json["attachments"], attachments: json['attachments'] ==null?null: List<Attachment>.from(json["attachments"].map((x) => Attachment.fromJson(x))),
salaryGrade: json["salary_grade"], salaryGrade: json["salary_grade"],
monthlySalary: json["monthly_salary"], monthlySalary: json["monthly_salary"],
appointmentStatus: json["appointment_status"], appointmentStatus: json["appointment_status"],

View File

@ -1,9 +1,16 @@
import 'package:app_popup_menu/app_popup_menu.dart'; import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_svg/svg.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:unit2/bloc/profile/eligibility/eligibility_bloc.dart';
import 'package:unit2/bloc/profile/learningDevelopment/learning_development_bloc.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/profile/workHistory/workHistory_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/model/profile/educational_background.dart'; import 'package:unit2/model/profile/educational_background.dart';
import 'package:unit2/screens/profile/components/education/add_modal.dart'; import 'package:unit2/screens/profile/components/education/add_modal.dart';
@ -13,13 +20,25 @@ import 'package:unit2/widgets/Leadings/add_leading.dart';
import 'package:unit2/widgets/empty_data.dart'; import 'package:unit2/widgets/empty_data.dart';
import 'package:unit2/widgets/error_state.dart'; import 'package:unit2/widgets/error_state.dart';
import '../../../bloc/profile/education/education_bloc.dart'; import '../../../bloc/profile/education/education_bloc.dart';
import '../../../model/profile/attachment.dart';
import '../../../theme-data.dart/btn-style.dart';
import '../../../theme-data.dart/form-style.dart';
import '../../../utils/alerts.dart'; import '../../../utils/alerts.dart';
import '../../../utils/global.dart';
import '../../../widgets/Leadings/close_leading.dart'; import '../../../widgets/Leadings/close_leading.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
import 'education/edit_modal.dart'; import 'education/edit_modal.dart';
class EducationScreen extends StatelessWidget { class EducationScreen extends StatelessWidget {
const EducationScreen({super.key}); const EducationScreen({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final parent = context;
List<PlatformFile>? results = [];
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
int profileId; int profileId;
String? token; String? token;
return Scaffold( return Scaffold(
@ -99,6 +118,28 @@ class EducationScreen extends StatelessWidget {
}); });
} }
} }
////ATTACHMENT ADDED STATE
if (state is EducationAttachmentAddedState) {
if (state.response['success']) {
successAlert(context, "Adding Successfull!",
state.response['message'], () {
Navigator.of(context).pop();
context
.read<EducationBloc>()
.add(LoadEducations());
});
} else {
errorAlert(context, "Adding Failed",
"Something went wrong. Please try again.",
() {
Navigator.of(context).pop();
context
.read<EducationBloc>()
.add(LoadEducations());
});
}
}
////EDITED STATE ////EDITED STATE
if (state is EditedEducationState) { if (state is EditedEducationState) {
if (state.response['success']) { if (state.response['success']) {
@ -141,9 +182,35 @@ class EducationScreen extends StatelessWidget {
}); });
} }
} }
////ATTACHMENT DELETED STATE
if (state is EducationAttachmentDeletedState) {
if (state.success) {
successAlert(context, "Deletion Successfull",
"Attachment has been deleted successfully",
() {
Navigator.of(context).pop();
context
.read<EducationBloc>()
.add(LoadEducations());
});
} else {
errorAlert(context, "Deletion Failed",
"Error deleting Attachment", () {
Navigator.of(context).pop();
context
.read<EducationBloc>()
.add(LoadEducations());
});
}
}
}, },
builder: (context, state) { builder: (context, state) {
if (state is EducationalBackgroundLoadedState) { if (state is EducationalBackgroundLoadedState) {
for (var cat in state.attachmentCategory) {
if (cat.subclass!.id == 1) {
attachmentCategories.add(cat);
}
}
if (state.educationalBackground.isNotEmpty) { if (state.educationalBackground.isNotEmpty) {
return ListView.builder( return ListView.builder(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -182,54 +249,91 @@ class EducationScreen extends StatelessWidget {
decoration: box1(), decoration: box1(),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8), horizontal: 12, vertical: 8),
child: Row( child: Column(
children: [ children: [
Expanded( Row(
child: Column( children: [
mainAxisAlignment: Expanded(
MainAxisAlignment.start, child: Column(
crossAxisAlignment: mainAxisAlignment:
CrossAxisAlignment MainAxisAlignment
.start, .start,
children: [ crossAxisAlignment:
Row( CrossAxisAlignment
.start,
children: [ children: [
Expanded( Row(
child: Text(level, children: [
style: Theme.of( Expanded(
context) child: Text(
.textTheme level,
.titleSmall!)), style: Theme.of(
context)
.textTheme
.titleSmall!)),
Text(
"$periodFrom - $periodTo",
style: Theme.of(
context)
.textTheme
.bodyMedium,
),
],
),
const SizedBox(
height: 5,
),
Text( Text(
"$periodFrom - $periodTo", school,
style: Theme.of( style: Theme.of(
context) context)
.textTheme .textTheme
.bodyMedium, .titleMedium!
.copyWith(
color:
primary,
fontWeight:
FontWeight
.w500),
), ),
], Container(
), padding:
const SizedBox( const EdgeInsets
height: 5, .only(
), top: 8),
Text( child: honors
school, .isNotEmpty
style: Theme.of(context) ? Column(
.textTheme mainAxisAlignment:
.titleMedium! MainAxisAlignment
.copyWith( .start,
color: primary, crossAxisAlignment:
fontWeight: CrossAxisAlignment
FontWeight .start,
.w500), children: [
), const SizedBox(
Container( height:
padding: 8,
const EdgeInsets ),
.only(top: 8), const Text(
child: honors " honors: ",
.isNotEmpty style:
? Column( TextStyle(fontWeight: FontWeight.w600),
),
Column(
children: honors
.map((Honor honor) => Text(
"-${honor.name!.trim()}",
style: Theme.of(context).textTheme.labelMedium,
))
.toList(),
),
],
)
: const SizedBox()),
program == null
? const SizedBox()
: Column(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment MainAxisAlignment
.start, .start,
@ -238,104 +342,420 @@ class EducationScreen extends StatelessWidget {
.start, .start,
children: [ children: [
const SizedBox( const SizedBox(
height: 8, height: 5,
),
const Text(
" honors: ",
style: TextStyle(
fontWeight:
FontWeight.w600),
),
Column(
children: honors
.map((Honor honor) => Text(
"-${honor.name!.trim()}",
style: Theme.of(context).textTheme.labelMedium,
))
.toList(),
), ),
Text(
program),
], ],
)
: const SizedBox()),
program == null
? const SizedBox()
: Column(
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
const SizedBox(
height: 5,
), ),
Text(program), ]),
], ),
), AppPopupMenu<int>(
]), offset:
const Offset(-10, -10),
elevation: 3,
onSelected: (value) {
////delete -= = = = = = = = =>>
if (value == 2) {
confirmAlert(context,
() {
final progress =
ProgressHUD.of(
context);
progress!
.showWithText(
"Loading...");
context
.read<
EducationBloc>()
.add(DeleteEducation(
educationalBackground:
state.educationalBackground[
index],
profileId:
profileId,
token:
token!));
}, "Delete?",
"Confirm Delete?");
}
if (value == 1) {
////edit -= = = = = = = = =>>
final progress =
ProgressHUD.of(
context);
progress!.showWithText(
"Loading...");
context
.read<
EducationBloc>()
.add(ShowEditEducationForm(
profileId:
profileId,
token: token!,
educationalBackground:
state.educationalBackground[
index]));
}
if (value == 3) {
results.clear();
showDialog(
context: context,
builder:
(BuildContext
context) {
return AlertDialog(
contentPadding:
const EdgeInsets
.all(0),
backgroundColor:
Colors.grey
.shade100,
icon:
const Icon(
Icons
.file_copy,
size: 32,
color:
primary,
),
title: const Text(
"File Attachment:"),
content: StatefulBuilder(
builder:
(context,
setState) {
return Padding(
padding: const EdgeInsets
.all(
16.0),
child: Column(
mainAxisSize:
MainAxisSize
.min,
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const Divider(),
Text(
program ??
level,
style:
Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w500, color: primary),
),
const SizedBox(
height:
5,
),
Text(
school,
style: Theme.of(context).textTheme.titleSmall),
const SizedBox(
height:
3,
),
Text(
"$periodFrom - $periodTo",
style: Theme.of(context).textTheme.titleSmall),
const Divider(),
FormBuilderDropdown(
autovalidateMode: AutovalidateMode.always,
decoration: normalTextFieldStyle("attachment category", "attachment category"),
name: 'attachments_categorues',
validator: FormBuilderValidators.required(errorText: "This field is required"),
onChanged: (value) {
selectedAttachmentCategory = value;
},
items: attachmentCategories.map((e) {
return DropdownMenuItem(value: e, child: Text(e.description!));
}).toList()),
const SizedBox(
height:
8,
),
Text(
"You may attach necessary documents such as Transcript of Records (TOR), diploma, and the likes.",
style:
Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black),
),
const SizedBox(
height:
5,
),
Text(
"Acceptable Files: PDF, JPEG, PNG",
style:
Theme.of(context).textTheme.bodySmall,
),
Text(
"Max File Size (per attachment): 1MB",
style:
Theme.of(context).textTheme.bodySmall,
),
const Divider(),
ElevatedButton(
style: ButtonStyle(
elevation: MaterialStateProperty.all(0),
backgroundColor: MaterialStateProperty.all<Color>(Colors.white),
),
onPressed: () async {
FilePickerResult? newResult = await FilePicker.platform.pickFiles(allowMultiple: true, type: FileType.custom, allowedExtensions: [
'jpg',
'png',
'jpeg',
'pdf'
]);
setState(() {
if (newResult != null) {
newResult.files.forEach((element) {
results.add(element);
});
}
});
},
child: const Center(
child: Text(
"Select Files",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black),
))),
const Divider(),
SingleChildScrollView(
child:
SizedBox(
height: 100,
width: double.maxFinite,
child: results.isEmpty
? const SizedBox()
: Expanded(
child: ListView.builder(
itemCount: results.length,
itemBuilder: (BuildContext context, index) {
final kb = results[index].size / 1024;
final mb = kb / 1024;
final size = mb >= 1 ? '${mb.toStringAsFixed(2)}MB' : '${kb.toStringAsFixed(2)}KB';
return Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: double.infinity,
child: Row(
children: [
Flexible(
child: SizedBox(
child: results[index].extension!.toLowerCase() == 'pdf'
? SvgPicture.asset(
'assets/svgs/pdf.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: results[index].extension!.toLowerCase() == 'png'
? SvgPicture.asset(
'assets/svgs/png.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: results[index].extension!.toLowerCase() == 'jpg' || results[index].extension!.toLowerCase() == 'jpeg'
? SvgPicture.asset(
'assets/svgs/jpg.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: const SizedBox())),
const SizedBox(
width: 12,
),
Flexible(
flex: 6,
child: Text(
results[index].name,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.headlineLarge!.copyWith(fontSize: blockSizeVertical * 2),
),
),
const SizedBox(
width: 12,
),
Flexible(
flex: 2,
child: Text(
size,
style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.grey),
)),
Flexible(
flex: 1,
child: IconButton(
icon: const Icon(
Icons.close,
color: Colors.grey,
),
onPressed: () {
setState(() {
results.removeAt(index);
});
},
))
],
)),
const Divider()
],
);
}),
),
),
),
const SizedBox(
height:
12,
),
SizedBox(
width:
double.maxFinite,
height:
50,
child: ElevatedButton(
style: mainBtnStyle(primary, Colors.transparent, second),
onPressed: () {
List<String> paths = [];
if (selectedAttachmentCategory != null && results.isNotEmpty) {
for (var res in results) {
paths.add(res.path!);
}
setState(() {
results.clear();
});
Navigator.pop(context);
parent.read<EducationBloc>().add(AddEducationAttachment(attachmentModule: state.educationalBackground[index].id.toString(), filePaths: paths, categoryId: selectedAttachmentCategory!.id.toString(), token: token!, profileId: profileId.toString()));
}
},
child: const Text("Submit")),
)
]),
);
}),
);
});
}
},
menuItems: [
popMenuItem(
text: "Update",
value: 1,
icon: Icons.edit),
popMenuItem(
text: "Remove",
value: 2,
icon: Icons.delete),
popMenuItem(
text: "Attach",
value: 3,
icon: Icons
.attach_file),
],
icon: const Icon(
Icons.more_vert,
color: Colors.grey,
),
tooltip: "Options",
)
],
), ),
AppPopupMenu<int>(
offset: const Offset(-10, -10), ////Show Attachments
elevation: 3, SizedBox(
onSelected: (value) { child: state
////delete -= = = = = = = = =>> .educationalBackground[
if (value == 2) { index]
confirmAlert(context, () { .attachments ==
final progress = null ||
ProgressHUD.of( state
context); .educationalBackground[
progress!.showWithText( index]
"Loading..."); .attachments!
context .isEmpty
.read<EducationBloc>() ? const SizedBox()
.add(DeleteEducation( : state
educationalBackground: .educationalBackground[
state.educationalBackground[ index]
index], .attachments !=
null &&
state
.educationalBackground[
index]
.attachments!
.length ==
1
?
////Single Attachment view
Column(
children: [
const Divider(),
SingleAttachment(
onpressed:
() {
confirmAlert(
context,
() {
parent.read<EducationBloc>().add(DeleteEducationAttachment(
attachment: state
.educationalBackground[
index]
.attachments!
.first,
moduleId: state
.educationalBackground[
index]
.id!,
profileId:
profileId,
token:
token!));
}, "Delete?",
"Confirm Delete?");
},
attachment: state
.educationalBackground[
index]
.attachments!
.first,
),
],
)
////Multiple Attachments View
: MultipleAttachments(
profileId: profileId:
profileId, profileId,
token: token!)); token: token!,
}, "Delete?", eligibilityName: state
"Confirm Delete?"); .educationalBackground[
} index]
if (value == 1) { .education!
////edit -= = = = = = = = =>> .school!
final progress = .name!,
ProgressHUD.of(context); attachments: state
progress!.showWithText( .educationalBackground[
"Loading..."); index]
context .attachments!,
.read<EducationBloc>() educationBloc:
.add(ShowEditEducationForm( BlocProvider.of<
profileId: EducationBloc>(
profileId, parent),
token: token!, eligibilityBloc:
educationalBackground: null,
state.educationalBackground[ workHistoryBloc:
index])); null,
} learningDevelopmentBloc:
}, null,
menuItems: [ blocId: 1,
popMenuItem( moduleId: state
text: "Update", .educationalBackground[
value: 1, index]
icon: Icons.edit), .id!,
popMenuItem( ))
text: "Remove",
value: 2,
icon: Icons.delete),
popMenuItem(
text: "Attach",
value: 2,
icon: Icons.attach_file),
],
icon: const Icon(
Icons.more_vert,
color: Colors.grey,
),
tooltip: "Options",
)
], ],
), ),
), ),

View File

@ -1,16 +1,26 @@
import 'dart:io';
import 'package:app_popup_menu/app_popup_menu.dart'; import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:fluttericon/font_awesome_icons.dart'; import 'package:flutter_svg/svg.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:unit2/bloc/profile/education/education_bloc.dart';
import 'package:unit2/bloc/profile/learningDevelopment/learning_development_bloc.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/profile/workHistory/workHistory_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/model/profile/attachment.dart';
import 'package:unit2/model/profile/eligibility.dart'; import 'package:unit2/model/profile/eligibility.dart';
import 'package:unit2/screens/profile/components/eligibility/add_modal.dart'; import 'package:unit2/screens/profile/components/eligibility/add_modal.dart';
import 'package:unit2/screens/profile/components/eligibility/edit_modal.dart'; import 'package:unit2/screens/profile/components/eligibility/edit_modal.dart';
import 'package:unit2/theme-data.dart/box_shadow.dart'; import 'package:unit2/theme-data.dart/box_shadow.dart';
import 'package:unit2/theme-data.dart/btn-style.dart';
import 'package:unit2/theme-data.dart/colors.dart'; import 'package:unit2/theme-data.dart/colors.dart';
import 'package:unit2/theme-data.dart/form-style.dart';
import 'package:unit2/utils/global.dart'; import 'package:unit2/utils/global.dart';
import 'package:unit2/utils/text_container.dart'; import 'package:unit2/utils/text_container.dart';
import 'package:unit2/widgets/Leadings/add_leading.dart'; import 'package:unit2/widgets/Leadings/add_leading.dart';
@ -19,21 +29,27 @@ import 'package:unit2/widgets/empty_data.dart';
import 'package:unit2/widgets/error_state.dart'; import 'package:unit2/widgets/error_state.dart';
import '../../../bloc/profile/eligibility/eligibility_bloc.dart'; import '../../../bloc/profile/eligibility/eligibility_bloc.dart';
import '../../../utils/alerts.dart'; import '../../../utils/alerts.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
class EligibiltyScreen extends StatelessWidget { class EligibiltyScreen extends StatelessWidget {
const EligibiltyScreen({super.key}); const EligibiltyScreen({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
BuildContext parent = context;
String? token; String? token;
int? profileId; int? profileId;
List<PlatformFile>? results = [];
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
return true; return true;
}, },
child: Scaffold( child: Scaffold(
resizeToAvoidBottomInset: true, resizeToAvoidBottomInset: true,
appBar: AppBar( appBar: AppBar(
title: context.watch<EligibilityBloc>().state is AddEligibilityState title: context.watch<EligibilityBloc>().state is AddEligibilityState
? const Text("Add Eligiblity") ? const Text("Add Eligiblity")
@ -42,31 +58,37 @@ class EligibiltyScreen extends StatelessWidget {
: const Text(elibilityScreenTitle), : const Text(elibilityScreenTitle),
centerTitle: true, centerTitle: true,
backgroundColor: primary, backgroundColor: primary,
actions: (context.watch<EligibilityBloc>().state is EligibilityLoaded) actions:
(context.watch<EligibilityBloc>().state is EligibilityLoaded)
? [ ? [
AddLeading(onPressed: () { AddLeading(onPressed: () {
context context
.read<EligibilityBloc>() .read<EligibilityBloc>()
.add(ShowAddEligibilityForm()); .add(ShowAddEligibilityForm());
}) })
] ]
:(context.watch<EligibilityBloc>().state is AddEligibilityState || context.watch<EligibilityBloc>().state is EditEligibilityState)? [ : (context.watch<EligibilityBloc>().state
CloseLeading(onPressed: () { is AddEligibilityState ||
context.read<EligibilityBloc>().add(const LoadEligibility()); context.watch<EligibilityBloc>().state
}) is EditEligibilityState)
]:[], ? [
CloseLeading(onPressed: () {
context
.read<EligibilityBloc>()
.add(const LoadEligibility());
})
]
: [],
), ),
body: BlocBuilder<UserBloc, UserState>( body: BlocBuilder<UserBloc, UserState>(
builder: (context, state) { builder: (context, state) {
if (state is UserLoggedIn) { if (state is UserLoggedIn) {
token = state.userData!.user!.login!.token; token = state.userData!.user!.login!.token;
profileId = profileId = state.userData!.user!.login!.user!.profileId;
state.userData!.user!.login!.user!.profileId;
return BlocBuilder<ProfileBloc, ProfileState>( return BlocBuilder<ProfileBloc, ProfileState>(
builder: (context, state) { builder: (context, state) {
if(state is ProfileLoaded){ if (state is ProfileLoaded) {
return ProgressHUD( return ProgressHUD(
padding: const EdgeInsets.all(24), padding: const EdgeInsets.all(24),
indicatorWidget: const SpinKitFadingCircle( indicatorWidget: const SpinKitFadingCircle(
color: Colors.white, color: Colors.white,
@ -81,30 +103,53 @@ class EligibiltyScreen extends StatelessWidget {
if (state is EligibilityLoaded || if (state is EligibilityLoaded ||
state is AddEligibilityState || state is AddEligibilityState ||
state is EditEligibilityState || state is EditEligibilityState ||
state is DeletedState || state is EligibilityDeletedState ||
state is EligibilityAddedState || state is EligibilityAddedState ||
state is EligibilityEditedState || state is EligibilityEditedState ||
state is EligibilityErrorState state is EligibilityErrorState) {
) {
final progress = ProgressHUD.of(context); final progress = ProgressHUD.of(context);
progress!.dismiss(); progress!.dismiss();
} }
////DELETED STATE ////DELETED STATE
if (state is DeletedState) { if (state is EligibilityDeletedState) {
if (state.success) { if (state.success) {
successAlert(context, "Deletion Successfull", successAlert(context, "Deletion Successfull",
"Eligibility has been deleted successfully", "Eligibility has been deleted successfully",
() { () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} else { } else {
errorAlert(context, "Deletion Failed", errorAlert(context, "Deletion Failed",
"Error deleting eligibility", () { "Error deleting eligibility", () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
});
}
}
////ATTACHMENT ADDED STATE
if (state is EligibilityAttachmentAddedState) {
if (state.response['success']) {
successAlert(context, "Adding Successfull!",
state.response['message'], () {
Navigator.of(context).pop();
context
.read<EligibilityBloc>()
.add(const LoadEligibility());
});
} else {
errorAlert(context, "Adding Failed",
"Something went wrong. Please try again.",
() {
Navigator.of(context).pop();
context
.read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} }
} }
@ -114,16 +159,18 @@ class EligibiltyScreen extends StatelessWidget {
successAlert(context, "Adding Successfull!", successAlert(context, "Adding Successfull!",
state.response['message'], () { state.response['message'], () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} else { } else {
errorAlert(context, "Adding Failed", errorAlert(context, "Adding Failed",
"Something went wrong. Please try again.", "Something went wrong. Please try again.",
() { () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} }
} }
@ -133,16 +180,39 @@ class EligibiltyScreen extends StatelessWidget {
successAlert(context, "Update Successfull!", successAlert(context, "Update Successfull!",
state.response['message'], () { state.response['message'], () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} else { } else {
errorAlert(context, "Update Failed", errorAlert(context, "Update Failed",
"Something went wrong. Please try again.", "Something went wrong. Please try again.",
() { () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
});
}
}
////ATTACHMENT DELETED STATE
if (state is EligibilitytAttachmentDeletedState) {
if (state.success) {
successAlert(context, "Deletion Successfull",
"Attachment has been deleted successfully",
() {
Navigator.of(context).pop();
context
.read<EligibilityBloc>()
.add(const LoadEligibility());
});
} else {
errorAlert(context, "Deletion Failed",
"Error deleting Attachment", () {
Navigator.of(context).pop();
context
.read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} }
} }
@ -151,7 +221,11 @@ class EligibiltyScreen extends StatelessWidget {
return BlocBuilder<EligibilityBloc, EligibilityState>( return BlocBuilder<EligibilityBloc, EligibilityState>(
builder: (context, state) { builder: (context, state) {
if (state is EligibilityLoaded) { if (state is EligibilityLoaded) {
for (var cat in state.attachmentCategory) {
if (cat.subclass!.id == 3) {
attachmentCategories.add(cat);
}
}
if (state.eligibilities.isNotEmpty) { if (state.eligibilities.isNotEmpty) {
return ListView.builder( return ListView.builder(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -164,153 +238,466 @@ class EligibiltyScreen extends StatelessWidget {
.eligibility! .eligibility!
.title; .title;
return Column( return Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [ children: [
Container( Container(
width: screenWidth,
padding: padding:
const EdgeInsets.symmetric( const EdgeInsets.symmetric(
horizontal: 12, horizontal: 12,
vertical: 8), vertical: 8),
decoration: box1(), decoration: box1(),
child: Row( child: Column(
children: [ children: [
Expanded( Row(
child: Column( children: [
mainAxisAlignment: Expanded(
MainAxisAlignment child: Column(
.start, mainAxisAlignment:
crossAxisAlignment: MainAxisAlignment
CrossAxisAlignment .start,
.start, crossAxisAlignment:
children: [ CrossAxisAlignment
Text( .start,
title, children: [
style: Theme.of( Text(
context) title,
.textTheme style: Theme.of(
.titleMedium! context)
.copyWith( .textTheme
fontWeight: .titleMedium!
FontWeight .copyWith(
.w500,color: primary), fontWeight:
), FontWeight
.w500,
color:
primary),
),
const SizedBox(
height: 5,
),
Text(
"$licenseNumber: ${state.eligibilities[index].licenseNumber == null ? 'N/A' : state.eligibilities[index].licenseNumber.toString()}",
style: Theme.of(
context)
.textTheme
.titleSmall),
const SizedBox(
height: 3,
),
Text(
"Rating : ${state.eligibilities[index].rating ?? 'N/A'}",
style: Theme.of(
context)
.textTheme
.titleSmall),
]),
),
AppPopupMenu<int>(
offset: const Offset(
-10, -10),
elevation: 3,
onSelected: (value) {
////delete eligibilty-= = = = = = = = =>>
if (value == 2) {
confirmAlert(
context, () {
final progress =
ProgressHUD.of(
context);
progress!
.showWithText(
"Loading...");
BlocProvider
.of<EligibilityBloc>(
context)
.add(DeleteEligibility(
eligibilityId: state
.eligibilities[
index]
.id!,
profileId:
profileId
.toString(),
token:
token!));
}, "Delete?",
"Confirm Delete?");
}
if (value == 1) {
////edit eligibilty-= = = = = = = = =>>
final progress =
ProgressHUD.of(
context);
progress!
.showWithText(
"Loading...");
EligibityCert
eligibityCert =
state.eligibilities[
index];
bool overseas = eligibityCert
.examAddress!
.country!
.id
.toString() ==
'175'
? false
: true;
eligibityCert
.overseas =
overseas;
const SizedBox( eligibityCert
height: 5, .overseas =
), overseas;
Text(
"$licenseNumber: ${state.eligibilities[index].licenseNumber == null ? 'N/A' : state.eligibilities[index].licenseNumber.toString()}", context
style: Theme.of( .read<
context) EligibilityBloc>()
.textTheme .add(ShowEditEligibilityForm(
.titleSmall), eligibityCert:
const SizedBox( eligibityCert));
height: 3, }
), ////Attachment
Text( if (value == 3) {
"Rating : ${state.eligibilities[index].rating ?? 'N/A'}.", results.clear();
style: Theme.of( showDialog(
context) context:
.textTheme context,
.titleSmall) builder:
]), (BuildContext
context) {
return AlertDialog(
contentPadding:
const EdgeInsets
.all(0),
backgroundColor:
Colors
.grey
.shade100,
icon:
const Icon(
Icons
.file_copy,
size: 32,
color:
primary,
),
title: const Text(
"File Attachment:"),
content: StatefulBuilder(builder:
(context,
setState) {
return Padding(
padding:
const EdgeInsets.all(16.0),
child: Column(
mainAxisSize:
MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Divider(),
Text(
title,
style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w500, color: primary),
),
const SizedBox(
height: 5,
),
Text("$licenseNumber: ${state.eligibilities[index].licenseNumber == null ? 'N/A' : state.eligibilities[index].licenseNumber.toString()}", style: Theme.of(context).textTheme.titleSmall),
const SizedBox(
height: 3,
),
Text("Rating : ${state.eligibilities[index].rating ?? 'N/A'}", style: Theme.of(context).textTheme.titleSmall),
const Divider(),
FormBuilderDropdown(
autovalidateMode: AutovalidateMode.always,
decoration: normalTextFieldStyle("attachment category", "attachment category"),
name: 'attachments_categorues',
validator: FormBuilderValidators.required(errorText: "This field is required"),
onChanged: (value) {
selectedAttachmentCategory = value;
},
items: attachmentCategories.map((e) {
return DropdownMenuItem(value: e, child: Text(e.description!));
}).toList()),
const SizedBox(
height: 8,
),
Text(
"You may attach necessary documents such as Transcript of Records (TOR), diploma, and the likes.",
style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black),
),
const SizedBox(
height: 5,
),
Text(
"Acceptable Files: PDF, JPEG, PNG",
style: Theme.of(context).textTheme.bodySmall,
),
Text(
"Max File Size (per attachment): 1MB",
style: Theme.of(context).textTheme.bodySmall,
),
const Divider(),
ElevatedButton(
style: ButtonStyle(
elevation: MaterialStateProperty.all(0),
backgroundColor: MaterialStateProperty.all<Color>(Colors.white),
),
onPressed: () async {
FilePickerResult? newResult = await FilePicker.platform.pickFiles(allowMultiple: true, type: FileType.custom, allowedExtensions: [
'jpg',
'png',
'jpeg',
'pdf'
]);
setState(() {
FilePickerResult? x;
if (newResult != null) {
newResult.files.forEach((element) {
results.add(element);
});
}
});
},
child: const Center(
child: Text(
"Select Files",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black),
))),
const Divider(),
SingleChildScrollView(
child: SizedBox(
height: 100,
width: double.maxFinite,
child: results.isEmpty
? const SizedBox()
: Expanded(
child: ListView.builder(
itemCount: results.length,
itemBuilder: (BuildContext context, index) {
final kb = results[index].size / 1024;
final mb = kb / 1024;
final size = mb >= 1 ? '${mb.toStringAsFixed(2)}MB' : '${kb.toStringAsFixed(2)}KB';
return Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: double.infinity,
child: Row(
children: [
Flexible(
child: SizedBox(
child: results[index].extension!.toLowerCase() == 'pdf'
? SvgPicture.asset(
'assets/svgs/pdf.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: results[index].extension!.toLowerCase() == 'png'
? SvgPicture.asset(
'assets/svgs/png.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: results[index].extension!.toLowerCase() == 'jpg' || results[index].extension!.toLowerCase() == 'jpeg'
? SvgPicture.asset(
'assets/svgs/jpg.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: const SizedBox())),
const SizedBox(
width: 12,
),
Flexible(
flex: 6,
child: Text(
results[index].name,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.headlineLarge!.copyWith(fontSize: blockSizeVertical * 2),
),
),
const SizedBox(
width: 8,
),
Flexible(
flex: 2,
child: Text(
size,
style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.grey),
)),
Flexible(
flex: 1,
child: IconButton(
icon: const Icon(
Icons.close,
color: Colors.grey,
),
onPressed: () {
setState(() {
results.removeAt(index);
});
},
))
],
)),
const Divider()
],
);
}),
),
),
),
const SizedBox(
height: 12,
),
SizedBox(
width: double.maxFinite,
height: 50,
child: ElevatedButton(
style: mainBtnStyle(primary, Colors.transparent, second),
onPressed: () {
List<String> paths = [];
if (selectedAttachmentCategory != null && results.isNotEmpty) {
for (var res in results) {
paths.add(res.path!);
}
setState(() {
results.clear();
});
Navigator.pop(context);
parent.read<EligibilityBloc>().add(AddEligibiltyAttachment(attachmentModule: state.eligibilities[index].id.toString(), filePaths: paths, categoryId: selectedAttachmentCategory!.id.toString(), token: token!, profileId: profileId.toString()));
}
},
child: const Text("Submit")),
)
]),
);
}),
);
});
}
},
menuItems: [
popMenuItem(
text: "Update",
value: 1,
icon: Icons.edit),
popMenuItem(
text: "Remove",
value: 2,
icon:
Icons.delete),
popMenuItem(
text: "Attach",
value: 3,
icon: Icons
.attach_file),
],
icon: const Icon(
Icons.more_vert,
color: Colors.grey,
),
tooltip: "Options",
)
],
), ),
AppPopupMenu<int>( const Divider(),
offset: ////Show Attachments
const Offset(-10, -10), SizedBox(
elevation: 3, width: screenWidth,
onSelected: (value) { child: state
////delete eligibilty-= = = = = = = = =>>
if (value == 2) {
confirmAlert(context,
() {
final progress =
ProgressHUD.of(
context);
progress!.showWithText(
"Loading...");
BlocProvider.of<
EligibilityBloc>(
context)
.add(DeleteEligibility(
eligibilityId: state
.eligibilities[ .eligibilities[
index] index]
.id!, .attachments ==
null ||
state
.eligibilities[
index]
.attachments!
.isEmpty
? const SizedBox()
: state.eligibilities[index].attachments !=
null &&
state
.eligibilities[
index]
.attachments!
.length ==
1
?
////Single Attachment view
SingleAttachment(
onpressed:
() {
confirmAlert(
context,
() {
parent.read<EligibilityBloc>().add(DeleteEligibyAttachment(
attachment: state
.eligibilities[
index]
.attachments!
.first,
moduleId: state
.eligibilities[
index]
.id
.toString(),
profileId: profileId
.toString(),
token:
token!));
}, "Delete?",
"Confirm Delete?");
},
attachment: state
.eligibilities[
index]
.attachments!
.first,
)
////Multiple Attachments View
: MultipleAttachments(
profileId: profileId:
profileId.toString(), profileId!,
token: token: token!,
token!)); moduleId: state
}, "Delete?", .eligibilities[
"Confirm Delete?"); index]
} .eligibility!
if (value == 1) { .id,
////edit eligibilty-= = = = = = = = =>> educationBloc:
final progress = null,
ProgressHUD.of( learningDevelopmentBloc:
context); null,
progress!.showWithText( workHistoryBloc:
"Loading..."); null,
EligibityCert eligibilityBloc:
eligibityCert = BlocProvider.of<
state.eligibilities[ EligibilityBloc>(
index]; context),
bool overseas = eligibityCert blocId: 2,
.examAddress! eligibilityName: state
.country! .eligibilities[
.id index]
.toString() == .eligibility!
'175' .title,
? false attachments: state
: true; .eligibilities[
eligibityCert.overseas = index]
overseas; .attachments!,
))
eligibityCert.overseas =
overseas;
context
.read<EligibilityBloc>()
.add(ShowEditEligibilityForm(
eligibityCert:
eligibityCert));
}
},
menuItems: [
popMenuItem(
text: "Update",
value: 1,
icon: Icons.edit),
popMenuItem(
text: "Remove",
value: 2,
icon: Icons.delete),
popMenuItem(
text: "Attach",
value: 2,
icon: Icons.attach_file),
],
icon: const Icon(
Icons.more_vert,
color: Colors.grey,
),
tooltip: "Options",
)
], ],
), ),
), ),
const SizedBox( const SizedBox(
height: 5, height: 5,
) ),
], ],
); );
}); });
@ -322,17 +709,25 @@ class EligibiltyScreen extends StatelessWidget {
} }
if (state is EditEligibilityState) { if (state is EditEligibilityState) {
return EditEligibilityScreen( return EditEligibilityScreen(
profileId: profileId!, profileId: profileId!,
token: token!, token: token!,
eligibityCert: state.eligibityCert); eligibityCert: state.eligibityCert);
} }
if (state is AddEligibilityState) { if (state is AddEligibilityState) {
return AddEligibilityScreen(token: token!,profileId: profileId!,); return AddEligibilityScreen(
token: token!,
profileId: profileId!,
);
} }
if (state is EligibilityErrorState) { if (state is EligibilityErrorState) {
return SomethingWentWrong(message: state.message, onpressed: (){ return SomethingWentWrong(
context.read<EligibilityBloc>().add(GetEligibilities(token: token!,profileId: profileId!)); message: state.message,
}); onpressed: () {
context.read<EligibilityBloc>().add(
GetEligibilities(
token: token!,
profileId: profileId!));
});
} }
return Container( return Container(
color: Colors.grey.shade200, color: Colors.grey.shade200,
@ -342,11 +737,9 @@ class EligibiltyScreen extends StatelessWidget {
}, },
), ),
); );
}
return Container();
} }
); return Container();
});
} }
return Container(); return Container();
}, },

View File

@ -1,15 +1,18 @@
import 'package:app_popup_menu/app_popup_menu.dart'; import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/src/widgets/placeholder.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:fluttericon/font_awesome_icons.dart'; import 'package:flutter_svg/svg.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:unit2/bloc/profile/education/education_bloc.dart';
import 'package:unit2/bloc/profile/eligibility/eligibility_bloc.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/profile/workHistory/workHistory_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/model/profile/learning_development.dart';
import 'package:unit2/screens/profile/components/learning_development/edit_modal.dart'; import 'package:unit2/screens/profile/components/learning_development/edit_modal.dart';
import 'package:unit2/theme-data.dart/box_shadow.dart'; import 'package:unit2/theme-data.dart/box_shadow.dart';
import 'package:unit2/theme-data.dart/colors.dart'; import 'package:unit2/theme-data.dart/colors.dart';
@ -19,8 +22,13 @@ import 'package:unit2/widgets/Leadings/add_leading.dart';
import 'package:unit2/widgets/empty_data.dart'; import 'package:unit2/widgets/empty_data.dart';
import 'package:unit2/widgets/error_state.dart'; import 'package:unit2/widgets/error_state.dart';
import '../../../bloc/profile/learningDevelopment/learning_development_bloc.dart'; import '../../../bloc/profile/learningDevelopment/learning_development_bloc.dart';
import '../../../model/profile/attachment.dart';
import '../../../theme-data.dart/btn-style.dart';
import '../../../theme-data.dart/form-style.dart';
import '../../../utils/alerts.dart'; import '../../../utils/alerts.dart';
import '../../../widgets/Leadings/close_leading.dart'; import '../../../widgets/Leadings/close_leading.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
import 'learning_development/add_modal.dart'; import 'learning_development/add_modal.dart';
class LearningAndDevelopmentScreen extends StatelessWidget { class LearningAndDevelopmentScreen extends StatelessWidget {
@ -32,7 +40,11 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
String token; String token;
int profileId; int profileId;
BuildContext parent = context;
DateFormat dteFormat2 = DateFormat.yMMMMd('en_US'); DateFormat dteFormat2 = DateFormat.yMMMMd('en_US');
List<PlatformFile>? results = [];
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: context.watch<LearningDevelopmentBloc>().state title: context.watch<LearningDevelopmentBloc>().state
@ -76,13 +88,11 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
backgroundColor: Colors.black87, backgroundColor: Colors.black87,
child: BlocBuilder<UserBloc, UserState>( child: BlocBuilder<UserBloc, UserState>(
builder: (context, state) { builder: (context, state) {
if (state is UserLoggedIn) { if (state is UserLoggedIn) {
token = state.userData!.user!.login!.token!; token = state.userData!.user!.login!.token!;
profileId = state.userData!.user!.login!.user!.profileId!; profileId = state.userData!.user!.login!.user!.profileId!;
return BlocBuilder<ProfileBloc, ProfileState>( return BlocBuilder<ProfileBloc, ProfileState>(
builder: (context, state) { builder: (context, state) {
if (state is ProfileLoaded) { if (state is ProfileLoaded) {
return BlocConsumer<LearningDevelopmentBloc, return BlocConsumer<LearningDevelopmentBloc,
LearningDevelopmentState>( LearningDevelopmentState>(
@ -121,6 +131,27 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
}); });
} }
} }
////Attachment Added State
if (state is LearningDevAttachmentAddedState) {
if (state.response['success']) {
successAlert(context, "Adding Successfull!",
state.response['message'], () {
Navigator.of(context).pop();
context
.read<LearningDevelopmentBloc>()
.add(LoadLearniningDevelopment());
});
} else {
errorAlert(context, "Adding Failed",
"Something went wrong. Please try again.",
() {
Navigator.of(context).pop();
context
.read<LearningDevelopmentBloc>()
.add(LoadLearniningDevelopment());
});
}
}
////Updated State ////Updated State
if (state is LearningDevelopmentUpdatedState) { if (state is LearningDevelopmentUpdatedState) {
if (state.response['success']) { if (state.response['success']) {
@ -164,12 +195,36 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
}); });
} }
} }
////ATTACHMENT DELETED STATE
if (state is LearningDevAttachmentDeletedState) {
if (state.success) {
successAlert(context, "Deletion Successfull",
"Attachment has been deleted successfully",
() {
Navigator.of(context).pop();
context
.read<LearningDevelopmentBloc>()
.add(LoadLearniningDevelopment());
});
} else {
errorAlert(context, "Deletion Failed",
"Error deleting Attachment", () {
Navigator.of(context).pop();
context
.read<LearningDevelopmentBloc>()
.add(LoadLearniningDevelopment());
});
}
}
// TODO: implement listener // TODO: implement listener
}, },
builder: (context, state) { builder: (context, state) {
print(state);
if (state is LearningDevelopmentLoadedState) { if (state is LearningDevelopmentLoadedState) {
for (var cat in state.attachmentCategory) {
if (cat.subclass!.id == 2) {
attachmentCategories.add(cat);
}
}
if (state.learningsAndDevelopment.isNotEmpty) { if (state.learningsAndDevelopment.isNotEmpty) {
return ListView.builder( return ListView.builder(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -208,66 +263,73 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8), horizontal: 12, vertical: 8),
width: screenWidth, width: screenWidth,
child: Row( child: Column(
children: [ children: [
Expanded( Row(
child: Column( children: [
mainAxisAlignment: Expanded(
MainAxisAlignment.start, child: Column(
crossAxisAlignment: mainAxisAlignment:
CrossAxisAlignment MainAxisAlignment
.start, .start,
children: [ crossAxisAlignment:
Text( CrossAxisAlignment
training, .start,
style: Theme.of(context) children: [
.textTheme Text(
.titleMedium! training,
.copyWith( style: Theme.of(
fontWeight: context)
FontWeight .textTheme
.w600, .titleMedium!
color: primary), .copyWith(
), fontWeight:
const SizedBox( FontWeight
height: 8, .w600,
), color:
Text( primary),
provider, ),
style: Theme.of(context) const SizedBox(
.textTheme height: 8,
.titleSmall, ),
), Text(
const SizedBox( provider,
height: 5, style: Theme.of(
), context)
Text( .textTheme
"$duration: $start to $end", .titleSmall,
style: Theme.of(context) ),
.textTheme const SizedBox(
.labelMedium, height: 5,
), ),
const SizedBox( Text(
height: 5, "$duration: $start to $end",
), style: Theme.of(
]), context)
), .textTheme
AppPopupMenu<int>( .labelMedium,
offset: const Offset(-10, -10), ),
elevation: 3, const SizedBox(
onSelected: (value) { height: 5,
////delete -= = = = = = = = =>> ),
if (value == 2) { ]),
confirmAlert(context, () { ),
final progress = AppPopupMenu<int>(
ProgressHUD.of( offset:
context); const Offset(-10, -10),
progress!.showWithText( elevation: 3,
"Loading..."); onSelected: (value) {
BlocProvider.of< ////delete -= = = = = = = = =>>
LearningDevelopmentBloc>( if (value == 2) {
context) confirmAlert(context,
.add(DeleteLearningDevelopment( () {
final progress =
ProgressHUD.of(
context);
progress!
.showWithText(
"Loading...");
BlocProvider.of<LearningDevelopmentBloc>(context).add(DeleteLearningDevelopment(
trainingId: state trainingId: state
.learningsAndDevelopment[ .learningsAndDevelopment[
index] index]
@ -286,62 +348,394 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
profileId: profileId:
profileId, profileId,
token: token)); token: token));
}, "Delete?", }, "Delete?",
"Confirm Delete?"); "Confirm Delete?");
} }
if (value == 1) { if (value == 1) {
bool isOverseas; bool isOverseas;
////edit = = = = = = = =>> ////edit = = = = = = = =>>
final progress = final progress =
ProgressHUD.of(context); ProgressHUD.of(
progress!.showWithText( context);
"Loading..."); progress!.showWithText(
"Loading...");
if (state if (state
.learningsAndDevelopment[ .learningsAndDevelopment[
index] index]
.conductedTraining .conductedTraining
?.venue ?.venue
?.cityMunicipality == ?.cityMunicipality ==
null) { null) {
isOverseas = true; isOverseas = true;
} else { } else {
isOverseas = false; isOverseas = false;
} }
context context
.read< .read<
LearningDevelopmentBloc>() LearningDevelopmentBloc>()
.add(ShowEditLearningDevelopmentForm( .add(ShowEditLearningDevelopmentForm(
profileId: profileId:
profileId, profileId,
token: token, token: token,
learningDevelopment: learningDevelopment:
state.learningsAndDevelopment[ state.learningsAndDevelopment[
index], index],
isOverseas: isOverseas:
isOverseas)); isOverseas));
} }
}, if (value == 3) {
menuItems: [ results.clear();
popMenuItem( showDialog(
text: "Update", context: context,
value: 1, builder:
icon: Icons.edit), (BuildContext
popMenuItem( context) {
text: "Remove", return AlertDialog(
value: 2, contentPadding:
icon: Icons.delete), const EdgeInsets
popMenuItem( .all(0),
text: "Attach", backgroundColor:
value: 2, Colors.grey
icon: Icons.attach_file), .shade100,
icon:
const Icon(
Icons
.file_copy,
size: 32,
color:
primary,
),
title: const Text(
"File Attachment:"),
content: StatefulBuilder(
builder:
(context,
setState) {
return Padding(
padding: const EdgeInsets
.all(
16.0),
child: Column(
mainAxisSize:
MainAxisSize
.min,
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const Divider(),
Text(
training,
style:
Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w500, color: primary),
),
const SizedBox(
height:
5,
),
Text(
provider,
style: Theme.of(context).textTheme.titleSmall),
const SizedBox(
height:
3,
),
Text(
"$start TO $end",
style: Theme.of(context).textTheme.titleSmall),
const Divider(),
FormBuilderDropdown(
autovalidateMode: AutovalidateMode.always,
decoration: normalTextFieldStyle("attachment category", "attachment category"),
name: 'attachments_categorues',
validator: FormBuilderValidators.required(errorText: "This field is required"),
onChanged: (value) {
selectedAttachmentCategory = value;
},
items: attachmentCategories.map((e) {
return DropdownMenuItem(value: e, child: Text(e.description!));
}).toList()),
const SizedBox(
height:
8,
),
Text(
"You may attach necessary documents such as Transcript of Records (TOR), diploma, and the likes.",
style:
Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black),
),
const SizedBox(
height:
5,
),
Text(
"Acceptable Files: PDF, JPEG, PNG",
style:
Theme.of(context).textTheme.bodySmall,
),
Text(
"Max File Size (per attachment): 1MB",
style:
Theme.of(context).textTheme.bodySmall,
),
const Divider(),
ElevatedButton(
style: ButtonStyle(
elevation: MaterialStateProperty.all(0),
backgroundColor: MaterialStateProperty.all<Color>(Colors.white),
),
onPressed: () async {
FilePickerResult? newResult = await FilePicker.platform.pickFiles(allowMultiple: true, type: FileType.custom, allowedExtensions: [
'jpg',
'png',
'jpeg',
'pdf'
]);
setState(() {
if (newResult != null) {
newResult.files.forEach((element) {
results.add(element);
});
}
});
},
child: const Center(
child: Text(
"Select Files",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black),
))),
const Divider(),
SingleChildScrollView(
child:
SizedBox(
height: 100,
width: double.maxFinite,
child: results.isEmpty
? const SizedBox()
: Expanded(
child: ListView.builder(
itemCount: results.length,
itemBuilder: (BuildContext context, index) {
final kb = results[index].size / 1024;
final mb = kb / 1024;
final size = mb >= 1 ? '${mb.toStringAsFixed(2)}MB' : '${kb.toStringAsFixed(2)}KB';
return Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: double.infinity,
child: Row(
children: [
Flexible(
flex: 1,
child: SizedBox(
child: results[index].extension!.toLowerCase() == 'pdf'
? SvgPicture.asset(
'assets/svgs/pdf.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: results[index].extension!.toLowerCase() == 'png'
? SvgPicture.asset(
'assets/svgs/png.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: results[index].extension!.toLowerCase() == 'jpg' || results[index].extension!.toLowerCase() == 'jpeg'
? SvgPicture.asset(
'assets/svgs/jpg.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: const SizedBox())),
const SizedBox(
width: 12,
),
Flexible(
flex: 6,
child: Text(
results[index].name,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.headlineLarge!.copyWith(fontSize: blockSizeVertical * 2),
),
),
const SizedBox(
width: 8,
),
Flexible(
flex: 2,
child: Text(
size,
style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.grey),
)),
Flexible(
flex: 1,
child: IconButton(
icon: const Icon(
Icons.close,
color: Colors.grey,
),
onPressed: () {
setState(() {
results.removeAt(index);
});
},
))
],
)),
const Divider()
],
);
}),
),
),
),
const SizedBox(
height:
12,
),
SizedBox(
width:
double.maxFinite,
height:
50,
child: ElevatedButton(
style: mainBtnStyle(primary, Colors.transparent, second),
onPressed: () {
List<String> paths = [];
if (selectedAttachmentCategory != null && results.isNotEmpty) {
for (var res in results) {
paths.add(res.path!);
}
results.clear();
Navigator.pop(context);
parent.read<LearningDevelopmentBloc>().add(AddALearningDevttachment(attachmentModule: state.learningsAndDevelopment[index].conductedTraining!.id.toString(), filePaths: paths, categoryId: selectedAttachmentCategory!.id.toString(), token: token, profileId: profileId.toString()));
}
},
child: const Text("Submit")),
)
]),
);
}),
);
});
}
},
menuItems: [
popMenuItem(
text: "Update",
value: 1,
icon: Icons.edit),
popMenuItem(
text: "Remove",
value: 2,
icon: Icons.delete),
popMenuItem(
text: "Attach",
value: 3,
icon: Icons
.attach_file),
],
icon: const Icon(
Icons.more_vert,
color: Colors.grey,
),
tooltip: "Options",
)
], ],
icon: const Icon( ),
Icons.more_vert, SizedBox(
color: Colors.grey, child: state
), .learningsAndDevelopment[
tooltip: "Options", index]
) .attachments ==
null ||
state
.learningsAndDevelopment[
index]
.attachments!
.isEmpty
? const SizedBox()
: state
.learningsAndDevelopment[
index]
.attachments !=
null &&
state
.learningsAndDevelopment[
index]
.attachments!
.length ==
1
?
////Single Attachment view
SingleAttachment(
onpressed: () {
confirmAlert(
context,
() {
parent.read<LearningDevelopmentBloc>().add(DeleteLearningDevAttachment(
attachment: state
.learningsAndDevelopment[
index]
.attachments!
.first,
moduleId: state
.learningsAndDevelopment[
index]
.conductedTraining!
.id!,
profileId:
profileId,
token:
token));
}, "Delete?",
"Confirm Delete?");
},
attachment: state
.learningsAndDevelopment[
index]
.attachments!
.first,
)
////Multiple Attachments View
: MultipleAttachments(
profileId:
profileId,
token: token,
moduleId: state
.learningsAndDevelopment[
index]
.conductedTraining!
.title!
.id!,
educationBloc:
null,
eligibilityBloc:
null,
learningDevelopmentBloc:
BlocProvider.of<
LearningDevelopmentBloc>(
context),
workHistoryBloc:
null,
blocId: 4,
eligibilityName: state
.learningsAndDevelopment[
index]
.conductedTraining!
.title!
.title!,
attachments: state
.learningsAndDevelopment[
index]
.attachments!,
))
], ],
), ),
), ),

View File

@ -1,11 +1,17 @@
import 'dart:io'; import 'dart:io';
import 'package:app_popup_menu/app_popup_menu.dart'; import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:fluttericon/font_awesome_icons.dart'; import 'package:flutter_svg/svg.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:unit2/bloc/profile/education/education_bloc.dart';
import 'package:unit2/bloc/profile/eligibility/eligibility_bloc.dart';
import 'package:unit2/bloc/profile/learningDevelopment/learning_development_bloc.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/screens/profile/components/work_history/add_modal.dart'; import 'package:unit2/screens/profile/components/work_history/add_modal.dart';
@ -17,11 +23,15 @@ import 'package:unit2/widgets/Leadings/add_leading.dart';
import 'package:unit2/widgets/Leadings/close_leading.dart'; import 'package:unit2/widgets/Leadings/close_leading.dart';
import 'package:unit2/widgets/empty_data.dart'; import 'package:unit2/widgets/empty_data.dart';
import 'package:unit2/widgets/error_state.dart'; import 'package:unit2/widgets/error_state.dart';
import '../../../bloc/profile/workHistory/workHistory_bloc.dart'; import '../../../bloc/profile/workHistory/workHistory_bloc.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/profile/work_history.dart'; import '../../../model/profile/work_history.dart';
import '../../../theme-data.dart/btn-style.dart';
import '../../../theme-data.dart/form-style.dart';
import '../../../utils/alerts.dart'; import '../../../utils/alerts.dart';
import '../../../utils/global.dart'; import '../../../utils/global.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
class WorkHistoryScreen extends StatelessWidget { class WorkHistoryScreen extends StatelessWidget {
const WorkHistoryScreen({super.key}); const WorkHistoryScreen({super.key});
@ -29,8 +39,13 @@ class WorkHistoryScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
DateFormat dteFormat2 = DateFormat.yMMMMd('en_US'); DateFormat dteFormat2 = DateFormat.yMMMMd('en_US');
BuildContext parent = context;
String? token; String? token;
int profileId; int? profileId;
List<PlatformFile>? results = [];
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: context.watch<WorkHistoryBloc>().state is AddWorkHistoryState title: context.watch<WorkHistoryBloc>().state is AddWorkHistoryState
@ -95,7 +110,7 @@ class WorkHistoryScreen extends StatelessWidget {
final progress = ProgressHUD.of(context); final progress = ProgressHUD.of(context);
progress!.dismiss(); progress!.dismiss();
} }
//DELETED STATE ////DELETED STATE
if (state is DeletedState) { if (state is DeletedState) {
if (state.success) { if (state.success) {
successAlert(context, "Deletion Successfull", successAlert(context, "Deletion Successfull",
@ -136,6 +151,48 @@ class WorkHistoryScreen extends StatelessWidget {
}); });
} }
} }
if (state is WorkHistoryDevAttachmentAddedState) {
if (state.response['success']) {
successAlert(context, "Adding Successfull!",
state.response['message'], () {
Navigator.of(context).pop();
context
.read<WorkHistoryBloc>()
.add(LoadWorkHistories());
});
} else {
errorAlert(context, "Adding Failed",
"Something went wrong. Please try again.",
() {
Navigator.of(context).pop();
context
.read<WorkHistoryBloc>()
.add(LoadWorkHistories());
});
}
}
////ATTACHMENT DELETED STATE
if (state is WorkHistoryDevAttachmentDeletedState) {
if (state.success) {
successAlert(context, "Deletion Successfull",
"Attachment has been deleted successfully",
() {
Navigator.of(context).pop();
context
.read<WorkHistoryBloc>()
.add(LoadWorkHistories());
});
} else {
errorAlert(context, "Deletion Failed",
"Error deleting Attachment", () {
Navigator.of(context).pop();
context
.read<WorkHistoryBloc>()
.add(LoadWorkHistories());
});
}
}
//// EDITED STATE //// EDITED STATE
if (state is WorkHistoryEditedState) { if (state is WorkHistoryEditedState) {
if (state.response['success']) { if (state.response['success']) {
@ -160,6 +217,11 @@ class WorkHistoryScreen extends StatelessWidget {
}, },
builder: (context, state) { builder: (context, state) {
if (state is WorkHistoryLoaded) { if (state is WorkHistoryLoaded) {
for (var cat in state.attachmentCategory) {
if (cat.subclass!.id == 4) {
attachmentCategories.add(cat);
}
}
if (state.workExperiences.isNotEmpty) { if (state.workExperiences.isNotEmpty) {
return ListView.builder( return ListView.builder(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -185,114 +247,467 @@ class WorkHistoryScreen extends StatelessWidget {
return Column( return Column(
children: [ children: [
Container( Container(
width: screenWidth,
decoration: box1(), decoration: box1(),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8), horizontal: 12, vertical: 8),
child: Row(children: [ child: Column(
Expanded( children: [
child: Column( Row(children: [
mainAxisAlignment: Expanded(
MainAxisAlignment.start, child: Column(
crossAxisAlignment: mainAxisAlignment:
CrossAxisAlignment.start, MainAxisAlignment.start,
children: [ crossAxisAlignment:
Text( CrossAxisAlignment.start,
position, children: [
style: Theme.of(context) Text(
.textTheme position,
.titleMedium! style: Theme.of(context)
.copyWith( .textTheme
fontWeight: .titleMedium!
FontWeight.w600, .copyWith(
color: primary), fontWeight:
), FontWeight
const SizedBox( .w600,
height: 8, color: primary),
), ),
Text( const SizedBox(
agency, height: 8,
style: Theme.of(context) ),
.textTheme Text(
.titleSmall! agency,
.copyWith( style: Theme.of(context)
fontWeight: .textTheme
FontWeight.w500), .titleSmall!
), .copyWith(
const SizedBox( fontWeight:
height: 5, FontWeight
), .w500),
Text( ),
"$from - $to ", const SizedBox(
style: Theme.of(context) height: 5,
.textTheme ),
.labelMedium, Text(
), "$from - $to ",
], style: Theme.of(context)
)), .textTheme
AppPopupMenu<int>( .labelMedium,
offset: const Offset(-10, -10), ),
elevation: 3, ],
onSelected: (value) { )),
////delete workhistory-= = = = = = = = =>> AppPopupMenu<int>(
if (value == 2) { offset:
confirmAlert(context, () { const Offset(-10, -10),
final progress = elevation: 3,
ProgressHUD.of(context); onSelected: (value) {
progress!.showWithText( ////delete workhistory-= = = = = = = = =>>
"Loading..."); if (value == 2) {
BlocProvider.of< confirmAlert(context, () {
WorkHistoryBloc>( final progress =
context) ProgressHUD.of(
.add(DeleteWorkHistory( context);
profileId: profileId, progress!.showWithText(
token: token!, "Loading...");
workHistory: BlocProvider.of<
state.workExperiences[ WorkHistoryBloc>(
context)
.add(
DeleteWorkHistory(
profileId: profileId!,
token: token!,
workHistory: state
.workExperiences[
index], index],
)); ));
}, "Delete?", }, "Delete?",
"Confirm Delete?"); "Confirm Delete?");
} }
if (value == 1) { if (value == 1) {
////edit eligibilty-= = = = = = = = =>> ////edit eligibilty-= = = = = = = = =>>
final progress = final progress =
ProgressHUD.of(context); ProgressHUD.of(
progress!.showWithText( context);
"Loading..."); progress!.showWithText(
WorkHistory workHistory = "Loading...");
state.workExperiences[ WorkHistory workHistory =
index]; state.workExperiences[
context index];
.read<WorkHistoryBloc>() context
.add( .read<
ShowEditWorkHistoryForm( WorkHistoryBloc>()
.add(ShowEditWorkHistoryForm(
workHistory: workHistory:
workHistory)); workHistory));
} }
}, ////Attachment
menuItems: [ if (value == 3) {
popMenuItem( results.clear();
text: "Update", showDialog(
value: 1, context: context,
icon: Icons.edit), builder: (BuildContext
popMenuItem( context) {
text: "Remove", return AlertDialog(
value: 2, contentPadding:
icon: Icons.delete), const EdgeInsets
popMenuItem( .all(0),
text: "Attach", backgroundColor:
value: 2, Colors.grey
icon: Icons.attach_file), .shade100,
icon: const Icon(
Icons.file_copy,
size: 32,
color: primary,
),
title: const Text(
"File Attachment:"),
content: StatefulBuilder(
builder: (context,
setState) {
return Padding(
padding:
const EdgeInsets
.all(
16.0),
child: Column(
mainAxisSize:
MainAxisSize
.min,
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
const Divider(),
Text(
position,
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(fontWeight: FontWeight.w600, color: primary),
),
const SizedBox(
height:
8,
),
Text(
agency,
style: Theme.of(context)
.textTheme
.titleSmall!
.copyWith(fontWeight: FontWeight.w500),
),
const SizedBox(
height:
5,
),
Text(
"$from - $to ",
style: Theme.of(context)
.textTheme
.labelMedium,
),
const Divider(),
FormBuilderDropdown(
autovalidateMode: AutovalidateMode
.always,
decoration: normalTextFieldStyle(
"attachment category", "attachment category"),
name:
'attachments_categorues',
validator:
FormBuilderValidators.required(errorText: "This field is required"),
onChanged: (value) {
selectedAttachmentCategory = value;
},
items: attachmentCategories.map((e) {
return DropdownMenuItem(value: e, child: Text(e.description!));
}).toList()),
const SizedBox(
height:
8,
),
Text(
"You may attach necessary documents such as Transcript of Records (TOR), diploma, and the likes.",
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black),
),
const SizedBox(
height:
5,
),
Text(
"Acceptable Files: PDF, JPEG, PNG",
style: Theme.of(context)
.textTheme
.bodySmall,
),
Text(
"Max File Size (per attachment): 1MB",
style: Theme.of(context)
.textTheme
.bodySmall,
),
const Divider(),
ElevatedButton(
style:
ButtonStyle(
elevation: MaterialStateProperty.all(0),
backgroundColor: MaterialStateProperty.all<Color>(Colors.white),
),
onPressed:
() async {
FilePickerResult? newResult = await FilePicker.platform.pickFiles(allowMultiple: true, type: FileType.custom, allowedExtensions: [
'jpg',
'png',
'jpeg',
'pdf'
]);
setState(() {
if (newResult != null) {
newResult.files.forEach((element) {
results.add(element);
});
}
});
},
child: const Center(
child: Text(
"Select Files",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black),
))),
const Divider(),
SingleChildScrollView(
child:
SizedBox(
height:
100,
width:
double.maxFinite,
child: results.isEmpty
? const SizedBox()
: Expanded(
child: ListView.builder(
itemCount: results.length,
itemBuilder: (BuildContext context, index) {
final kb = results[index].size / 1024;
final mb = kb / 1024;
final size = mb >= 1 ? '${mb.toStringAsFixed(2)}MB' : '${kb.toStringAsFixed(2)}KB';
return Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: double.infinity,
child: Row(
children: [
Flexible(
child: SizedBox(
child: results[index].extension!.toLowerCase() == 'pdf'
? SvgPicture.asset(
'assets/svgs/pdf.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: results[index].extension!.toLowerCase() == 'png'
? SvgPicture.asset(
'assets/svgs/png.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: results[index].extension!.toLowerCase() == 'jpg' || results[index].extension!.toLowerCase() == 'jpeg'
? SvgPicture.asset(
'assets/svgs/jpg.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: const SizedBox())),
const SizedBox(
width: 12,
),
Flexible(
flex: 6,
child: Text(
results[index].name,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.headlineLarge!.copyWith(fontSize: blockSizeVertical * 2),
),
),
const SizedBox(
width: 6,
),
Flexible(
flex: 2,
child: Text(
size,
style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.grey),
)),
Flexible(
flex: 1,
child: IconButton(
icon: const Icon(
Icons.close,
color: Colors.grey,
),
onPressed: () {
setState(() {
results.removeAt(index);
});
},
))
],
)),
const Divider()
],
);
}),
),
),
),
const SizedBox(
height:
12,
),
SizedBox(
width:
double.maxFinite,
height:
50,
child: ElevatedButton(
style: mainBtnStyle(primary, Colors.transparent, second),
onPressed: () {
List<String> paths = [];
], if (selectedAttachmentCategory != null && results.isNotEmpty) {
icon: const Icon( for (var res in results) {
Icons.more_vert, paths.add(res.path!);
color: Colors.grey, }
), setState(() {
tooltip: "Options", results.clear();
) });
]), Navigator.pop(context);
parent.read<WorkHistoryBloc>().add(AddWorkHistoryAttachment(attachmentModule: state.workExperiences[index].id.toString(), filePaths: paths, categoryId: selectedAttachmentCategory!.id.toString(), token: token!, profileId: profileId.toString()));
}
},
child: const Text("Submit")),
)
]),
);
}),
);
});
}
},
menuItems: [
popMenuItem(
text: "Update",
value: 1,
icon: Icons.edit),
popMenuItem(
text: "Remove",
value: 2,
icon: Icons.delete),
popMenuItem(
text: "Attach",
value: 3,
icon:
Icons.attach_file),
],
icon: const Icon(
Icons.more_vert,
color: Colors.grey,
),
tooltip: "Options",
)
]),
const Divider(),
////Show Attachments
SizedBox(
child: state
.workExperiences[
index]
.attachments ==
null ||
state
.workExperiences[
index]
.attachments!
.isEmpty
? const SizedBox()
: state
.workExperiences[
index]
.attachments !=
null &&
state
.workExperiences[
index]
.attachments!
.length ==
1
?
////Single Attachment view
SingleAttachment(
onpressed: () {
confirmAlert(
context,
() {
parent.read<WorkHistoryBloc>().add(DeleteWorkHistoryAttachment(
attachment: state
.workExperiences[
index]
.attachments!
.first,
moduleId: state
.workExperiences[
index]
.id!,
profileId:
profileId!,
token:
token!));
}, "Delete?",
"Confirm Delete?");
},
attachment: state
.workExperiences[
index]
.attachments!
.first,
)
////Multiple Attachments View
: MultipleAttachments(
profileId:
profileId!,
token: token!,
moduleId: state
.workExperiences[
index]
.id!,
educationBloc:
null,
workHistoryBloc:
BlocProvider.of<WorkHistoryBloc>(context),
eligibilityBloc:
null,
learningDevelopmentBloc:
null,
blocId: 3,
eligibilityName: state
.workExperiences[
index]
.position!
.title!,
attachments: state
.workExperiences[
index]
.attachments!,
))
],
),
), ),
const SizedBox( const SizedBox(
height: 5, height: 5,
@ -308,13 +723,13 @@ class WorkHistoryScreen extends StatelessWidget {
} }
if (state is AddWorkHistoryState) { if (state is AddWorkHistoryState) {
return AddWorkHistoryScreen( return AddWorkHistoryScreen(
profileId: profileId, profileId: profileId!,
token: token!, token: token!,
); );
} }
if (state is EditWorkHistoryState) { if (state is EditWorkHistoryState) {
return EditWorkHistoryScreen( return EditWorkHistoryScreen(
profileId: profileId, profileId: profileId!,
token: token!, token: token!,
); );
} }
@ -324,7 +739,8 @@ class WorkHistoryScreen extends StatelessWidget {
onpressed: () { onpressed: () {
context.read<WorkHistoryBloc>().add( context.read<WorkHistoryBloc>().add(
GetWorkHistories( GetWorkHistories(
profileId: profileId, token: token!)); profileId: profileId!,
token: token!));
}); });
} }
return Container(); return Container();

View File

@ -0,0 +1,234 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:fluttericon/entypo_icons.dart';
import 'package:unit2/bloc/profile/education/education_bloc.dart';
import 'package:unit2/bloc/profile/eligibility/eligibility_bloc.dart';
import 'package:unit2/bloc/profile/learningDevelopment/learning_development_bloc.dart';
import 'package:unit2/bloc/profile/workHistory/workHistory_bloc.dart';
import 'package:unit2/utils/global_context.dart';
import '../../../model/profile/attachment.dart';
import '../../../theme-data.dart/box_shadow.dart';
import '../../../theme-data.dart/colors.dart';
import '../../../utils/alerts.dart';
import '../../../utils/global.dart';
class MultipleAttachments extends StatelessWidget {
final List<Attachment> attachments;
final String eligibilityName;
final EducationBloc? educationBloc;
final EligibilityBloc? eligibilityBloc;
final LearningDevelopmentBloc? learningDevelopmentBloc;
final WorkHistoryBloc? workHistoryBloc;
final int blocId;
final int moduleId;
final int profileId;
final String token;
const MultipleAttachments(
{super.key,
required this.blocId,
required this.educationBloc,
required this.eligibilityBloc,
required this.learningDevelopmentBloc,
required this.workHistoryBloc,
required this.attachments,
required this.eligibilityName,
required this.moduleId,
required this.profileId,
required this.token});
@override
Widget build(BuildContext context) {
return Row(
children: [
Flexible(
flex: 3,
child: Container(
padding: const EdgeInsets.all(5),
decoration:
box1().copyWith(color: Colors.grey.shade300, boxShadow: []),
child: AutoSizeText(
attachments.first.filename!,
wrapWords: false,
maxLines: 1,
))),
const SizedBox(
width: 8,
),
Flexible(
child: FittedBox(
child: Container(
padding: const EdgeInsets.all(3),
decoration:
box1().copyWith(color: Colors.grey.shade300, boxShadow: []),
child: InkWell(
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"$eligibilityName Attachments",
textAlign: TextAlign.center,
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: attachments.map((e) {
String ext = e.filename!
.substring(e.filename!.lastIndexOf("."));
return Column(
children: [
Row(
children: [
Flexible(
child: SizedBox(
child: ext == '.pdf'
? SvgPicture.asset(
'assets/svgs/pdf.svg',
height: blockSizeVertical * 5,
allowDrawingOutsideViewBox:
true,
)
: ext == '.png'
? SvgPicture.asset(
'assets/svgs/png.svg',
height:
blockSizeVertical *
5.5,
allowDrawingOutsideViewBox:
true,
)
: ext == '.jpg'
? SvgPicture.asset(
'assets/svgs/jpg.svg',
height:
blockSizeVertical *
5,
allowDrawingOutsideViewBox:
true,
)
: SvgPicture.asset(
'assets/svgs/jpg.svg',
height:
blockSizeVertical *
5,
allowDrawingOutsideViewBox:
true,
),
),
),
const SizedBox(
width: 8,
),
Flexible(
flex: 4,
child: Tooltip(
message: e.filename,
child: Text(
e.filename!,
overflow: TextOverflow.ellipsis,
)),
),
const SizedBox(
width: 8,
),
Flexible(
child: Row(
children: [
Flexible(
child: IconButton(
icon: const Icon(
Icons.delete,
color: primary,
),
onPressed: () {
confirmAlert(context, () {
if (blocId == 1) {
Navigator.pop(
NavigationService
.navigatorKey
.currentContext!);
educationBloc!.add(
DeleteEducationAttachment(
attachment: e,
moduleId:
moduleId,
profileId:
profileId,
token: token));
} else if (blocId == 2) {
Navigator.pop(
NavigationService
.navigatorKey
.currentContext!);
eligibilityBloc!.add(
DeleteEligibyAttachment(
attachment: e,
moduleId: moduleId
.toString(),
profileId: profileId
.toString(),
token: token));
} else if (blocId == 3) {
Navigator.pop(
NavigationService
.navigatorKey
.currentContext!);
workHistoryBloc!.add(
DeleteWorkHistoryAttachment(
attachment: e,
moduleId:
moduleId,
profileId:
profileId,
token: token));
} else {
Navigator.pop(
NavigationService
.navigatorKey
.currentContext!);
learningDevelopmentBloc!.add(
DeleteLearningDevAttachment(
attachment: e,
moduleId:
moduleId,
profileId:
profileId,
token: token));
}
}, "Delete?",
"Confirm Delete?");
}),
)
],
),
),
],
),
const Divider()
],
);
}).toList(),
));
});
},
child: Row(
children: const [
Text(" See more.."),
Icon(
Icons.keyboard_arrow_right,
color: Colors.black54,
),
],
),
),
),
)),
],
);
}
}

View File

@ -0,0 +1,51 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../../model/profile/attachment.dart';
import '../../../theme-data.dart/box_shadow.dart';
import '../../../theme-data.dart/colors.dart';
import '../../../utils/alerts.dart';
class SingleAttachment extends StatelessWidget {
final Function()? onpressed;
final Attachment attachment;
const SingleAttachment({
required this.attachment,
required this.onpressed,
super.key,
});
@override
Widget build(BuildContext context) {
return Container(
padding:
const EdgeInsets.all(
5),
decoration: box1().copyWith(
color: Colors
.grey
.shade300,
boxShadow: []),
child:
Row(
children: [
Expanded(
child:
AutoSizeText(
attachment.filename!,
wrapWords: false,
maxLines: 1,
),
),
const SizedBox(
width:
8,
),
GestureDetector(
onTap:onpressed,
child: const Icon(Icons.delete,color: primary,))
],
));
}
}

View File

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:unit2/model/profile/attachment.dart';
import 'package:unit2/model/profile/eligibility.dart'; import 'package:unit2/model/profile/eligibility.dart';
import 'package:unit2/utils/request.dart'; import 'package:unit2/utils/request.dart';
import 'package:unit2/utils/urls.dart'; import 'package:unit2/utils/urls.dart';
@ -9,32 +10,32 @@ class EligibilityService {
static final EligibilityService _instance = EligibilityService(); static final EligibilityService _instance = EligibilityService();
static EligibilityService get instance => _instance; static EligibilityService get instance => _instance;
Future<List<EligibityCert>> getEligibilities(
Future<List<EligibityCert>> getEligibilities(int profileId, String token)async{ int profileId, String token) async {
List<EligibityCert> eligibilities = []; List<EligibityCert> eligibilities = [];
String authToken = "Token $token"; String authToken = "Token $token";
String path = "${Url.instance.getEligibilities()}$profileId/"; String path = "${Url.instance.getEligibilities()}$profileId/";
Map<String, String> headers = { Map<String, String> headers = {
'Content-Type': 'application/json; charset=UTF-8', 'Content-Type': 'application/json; charset=UTF-8',
'Authorization': authToken 'Authorization': authToken
}; };
try{ try {
http.Response response = await Request.instance.getRequest(path: path,headers: headers,param: {}); http.Response response = await Request.instance
if(response.statusCode == 200){ .getRequest(path: path, headers: headers, param: {});
Map data = jsonDecode(response.body); if (response.statusCode == 200) {
if (data['data']!= null) { Map data = jsonDecode(response.body);
data['data'].forEach((var cert) { if (data['data'] != null) {
EligibityCert eligibility = EligibityCert.fromJson(cert); data['data'].forEach((var cert) {
eligibilities.add(eligibility); EligibityCert eligibility = EligibityCert.fromJson(cert);
}); eligibilities.add(eligibility);
} });
} }
}catch(e){
throw e.toString();
} }
return eligibilities; } catch (e) {
throw e.toString();
}
return eligibilities;
} }
Future<bool> delete( Future<bool> delete(
@ -50,18 +51,17 @@ class EligibilityService {
'Content-Type': 'application/json; charset=UTF-8', 'Content-Type': 'application/json; charset=UTF-8',
'Authorization': authtoken 'Authorization': authtoken
}; };
try{ try {
http.Response response = await Request.instance http.Response response = await Request.instance.deleteRequest(
.deleteRequest(path: path, headers: headers, body: body, param: params); path: path, headers: headers, body: body, param: params);
if (response.statusCode == 200) { if (response.statusCode == 200) {
Map data = jsonDecode(response.body); Map data = jsonDecode(response.body);
success = data['success']; success = data['success'];
} else { } else {
success = false; success = false;
} }
} catch (e) {
}catch(e){ throw (e.toString());
throw(e.toString());
} }
return success!; return success!;
} }
@ -70,7 +70,7 @@ class EligibilityService {
{required EligibityCert eligibityCert, {required EligibityCert eligibityCert,
required String token, required String token,
required int profileId}) async { required int profileId}) async {
Map<dynamic, dynamic>? _response={}; Map<dynamic, dynamic>? _response = {};
String authtoken = "Token $token"; String authtoken = "Token $token";
String path = '${Url.instance.addEligibility()}$profileId/'; String path = '${Url.instance.addEligibility()}$profileId/';
Map<String, String> headers = { Map<String, String> headers = {
@ -94,7 +94,7 @@ class EligibilityService {
Map data = jsonDecode(response.body); Map data = jsonDecode(response.body);
_response = data; _response = data;
} else { } else {
_response.addAll({'success':false}); _response.addAll({'success': false});
} }
return _response; return _response;
@ -103,11 +103,12 @@ class EligibilityService {
} }
} }
Future<Map<dynamic, dynamic>> update( Future<Map<dynamic, dynamic>> update(
{required EligibityCert eligibityCert, {required EligibityCert eligibityCert,
required String token, required String token,
required int profileId, required int oldEligibility}) async { required int profileId,
Map<dynamic, dynamic>? response={}; required int oldEligibility}) async {
Map<dynamic, dynamic>? response = {};
String authtoken = "Token $token"; String authtoken = "Token $token";
String path = '${Url.instance.addEligibility()}$profileId/'; String path = '${Url.instance.addEligibility()}$profileId/';
Map<String, String> headers = { Map<String, String> headers = {
@ -132,7 +133,7 @@ class EligibilityService {
Map data = jsonDecode(res.body); Map data = jsonDecode(res.body);
response = data; response = data;
} else { } else {
response.addAll({'success':false}); response.addAll({'success': false});
} }
return response; return response;
@ -140,4 +141,63 @@ class EligibilityService {
throw e.toString(); throw e.toString();
} }
} }
Future<bool> deleteAttachment(
{required Attachment attachment,
required int moduleId,
required String profileId,
required String token}) async {
bool? success;
String authtoken = "Token $token";
String path = "${Url.instance.attachments()}$profileId/";
Map? body;
try{
body = {
"attachment_module": moduleId,
attachment: [
{
"id": attachment.id,
"created_at": attachment.createdAt,
"source": attachment.source,
"filename": attachment.filename,
"category": {
"id": attachment.category?.id,
"subclass": {
"id": attachment.category?.subclass?.id,
"name": attachment.category?.subclass?.name,
"attachment_class": {
"id": attachment.category?.subclass?.attachmentClass?.id,
"name": attachment.category?.subclass?.attachmentClass?.name
}
},
"description": attachment.category?.description
}
}
]
};
}catch(e){
print("body error"+e.toString());
}
Map<String, dynamic> params = {"force_mode": "true"};
Map<String, String> headers = {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': authtoken
};
// try {
http.Response response = await Request.instance
.deleteRequest(path: path, headers: headers, body: body, param: params);
if (response.statusCode == 200) {
Map data = jsonDecode(response.body);
success = data['success'];
} else {
success = false;
}
// } catch (e) {
// throw (e.toString());
// }
return success!;
}
} }

View File

@ -0,0 +1,130 @@
import 'dart:convert';
import 'package:unit2/utils/request.dart';
import 'package:unit2/utils/urls.dart';
import '../model/profile/attachment.dart';
import 'package:http/http.dart' as http;
class AttachmentServices {
static final AttachmentServices _instance = AttachmentServices();
static AttachmentServices get instance => _instance;
Future<List<AttachmentCategory>> getCategories() async {
List<AttachmentCategory> attachmentCategories = [];
String path = Url.instance.attachmentCategories();
Map<String, String> headers = {
'Content-Type': 'application/json; charset=UTF-8',
};
try {
http.Response response = await Request.instance
.getRequest(param: {}, path: path, headers: headers);
if (response.statusCode == 200) {
Map data = jsonDecode(response.body);
for (var cat in data['data']) {
AttachmentCategory newCat = AttachmentCategory.fromJson(cat);
attachmentCategories.add(newCat);
}
}
} catch (e) {
throw e.toString();
}
return attachmentCategories;
}
Future<Map<dynamic, dynamic>> attachment(
{required String categoryId,
required String module,
required List<String> paths,
required String token,
required String profileId}) async {
String authtoken = "Token $token";
Map<String, String> headers = {'Authorization': authtoken};
String path = Url.instance.attachments();
Map<dynamic, dynamic>? response = {};
Map<String, String> body = {
"attachment_category_id": categoryId.toString(),
"attachment_module": module.toString()
};
try {
var request = http.MultipartRequest(
'POST', Uri.parse('https://${Url.instance.host()}$path$profileId/'));
request.fields.addAll(body);
request.headers.addAll(headers);
paths.forEach((element) async {
request.files
.add(await http.MultipartFile.fromPath('attachments', element));
});
http.StreamedResponse res = await request.send();
final steamResponse = await res.stream.bytesToString();
Map data = jsonDecode(steamResponse);
if (res.statusCode == 201) {
response = data;
} else {
String message = data['response']['details'];
response.addAll({'message': message});
response.addAll(
{'success': false},
);
}
} catch (e) {
throw e.toString();
}
return response;
}
Future<bool> deleteAttachment(
{required Attachment attachment,
required int moduleId,
required String profileId,
required String token}) async {
bool? success;
String authtoken = "Token $token";
String path = "${Url.instance.attachments()}$profileId/";
Map? body;
body = {
"attachment_module": moduleId,
"attachments": [
{
"id": attachment.id,
"created_at": attachment.createdAt?.toString(),
"source": attachment.source,
"filename": attachment.filename,
"category": {
"id": attachment.category?.id,
"subclass": {
"id": attachment.category?.subclass?.id,
"name": attachment.category?.subclass?.name,
"attachment_class": {
"id": attachment.category?.subclass?.attachmentClass?.id,
"name": attachment.category?.subclass?.attachmentClass?.name
}
},
"description": attachment.category?.description
}
}
]
};
Map<String, dynamic> params = {"force_mode": "true"};
Map<String, String> headers = {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': authtoken
};
// try {
http.Response response = await Request.instance.deleteRequest(
path: path, headers: headers, body: body, param: params);
if (response.statusCode == 200) {
Map data = jsonDecode(response.body);
success = data['success'];
} else {
success = false;
}
// } catch (e) {
// throw (e.toString());
// }
return success!;
}
}

View File

@ -6,9 +6,9 @@ class Url {
String host() { String host() {
// return '192.168.10.183:3000'; // return '192.168.10.183:3000';
// return 'agusandelnorte.gov.ph'; // return 'agusandelnorte.gov.ph';
// return "192.168.10.219:3000"; return "192.168.10.219:3000";
// return "192.168.10.241"; // // return "192.168.10.241";
return "192.168.10.221:3004"; // return "192.168.10.221:3004";
// return "playweb.agusandelnorte.gov.ph"; // return "playweb.agusandelnorte.gov.ph";
// return 'devapi.agusandelnorte.gov.ph:3004'; // return 'devapi.agusandelnorte.gov.ph:3004';
} }
@ -167,6 +167,9 @@ class Url {
String getServiceTypes() { String getServiceTypes() {
return "/api/jobnet_app/comm_service_type/"; return "/api/jobnet_app/comm_service_type/";
} }
String attachments(){
return "/api/jobnet_app/profile/attachment/";
}
//// address path //// address path
String addressPath() { String addressPath() {
@ -319,4 +322,7 @@ class Url {
String getAddressCategory() { String getAddressCategory() {
return "/api/jobnet_app/address_categories/"; return "/api/jobnet_app/address_categories/";
} }
String attachmentCategories(){
return "/api/jobnet_app/attachment_categories/";
}
} }

View File

@ -449,6 +449,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.4" version: "6.1.4"
file_picker:
dependency: "direct main"
description:
name: file_picker
sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf"
url: "https://pub.dev"
source: hosted
version: "5.3.1"
file_utils: file_utils:
dependency: transitive dependency: transitive
description: description:

View File

@ -86,6 +86,7 @@ dependencies:
flutter_staggered_animations: ^1.1.1 flutter_staggered_animations: ^1.1.1
group_list_view: ^1.1.1 group_list_view: ^1.1.1
search_page: ^2.3.0 search_page: ^2.3.0
file_picker: ^5.3.1
dev_dependencies: dev_dependencies: