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
- device_info (0.0.1):
- 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):
- Flutter
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
- fluttertoast (0.0.2):
- Flutter
@ -36,6 +70,9 @@ PODS:
- Flutter
- rive_common (0.0.1):
- Flutter
- SDWebImage (5.17.0):
- SDWebImage/Core (= 5.17.0)
- SDWebImage/Core (5.17.0)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
@ -43,6 +80,7 @@ PODS:
- Flutter
- FMDB (>= 2.7.5)
- SwiftProtobuf (1.20.3)
- SwiftyGif (5.4.4)
- Toast (4.0.0)
DEPENDENCIES:
@ -52,6 +90,7 @@ DEPENDENCIES:
- barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`)
- device_info (from `.symlinks/plugins/device_info/ios`)
- easy_app_installer (from `.symlinks/plugins/easy_app_installer/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- location (from `.symlinks/plugins/location/ios`)
@ -66,9 +105,13 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- FMDB
- MTBBarcodeScanner
- SDWebImage
- SwiftProtobuf
- SwiftyGif
- Toast
EXTERNAL SOURCES:
@ -84,6 +127,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/device_info/ios"
easy_app_installer:
:path: ".symlinks/plugins/easy_app_installer/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
fluttertoast:
@ -113,7 +158,10 @@ SPEC CHECKSUMS:
audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40
barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
easy_app_installer: 29abe397da7d86721fee853281202f414373f45c
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
@ -125,9 +173,11 @@ SPEC CHECKSUMS:
permission_handler_apple: 8f116445eff3c0e7c65ad60f5fef5490aa94b4e4
platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5
rive_common: 60ae7896ab40f9513974f36f015de33f70d2c5c5
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
SwiftProtobuf: b02b5075dcf60c9f5f403000b3b0c202a11b6ae1
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
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/sevices/profile/education_services.dart';
import '../../../model/profile/attachment.dart';
import '../../../utils/attachment_services.dart';
part 'education_event.dart';
part 'education_state.dart';
@ -11,20 +14,27 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
List<School> schools = [];
List<Course> programs = [];
List<Honor> honors = [];
List<AttachmentCategory> attachmentCategories = [];
EducationBloc() : super(EducationInitial()) {
on<GetEducationalBackground>((event, emit) async {
emit(EducationalBackgroundLoadingState());
try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
if (educationalBackgrounds.isEmpty) {
List<EducationalBackground> educations = await EducationService
.instace
.getEducationalBackground(event.profileId, event.token);
educationalBackgrounds = educations;
emit(EducationalBackgroundLoadedState(
educationalBackground: educationalBackgrounds));
emit(EducationalBackgroundLoadedState(
educationalBackground: educationalBackgrounds,
attachmentCategory: attachmentCategories));
} else {
emit(EducationalBackgroundLoadedState(
educationalBackground: educationalBackgrounds));
educationalBackground: educationalBackgrounds,
attachmentCategory: attachmentCategories));
}
} catch (e) {
emit(EducationalBackgroundErrorState(message: e.toString()));
@ -77,7 +87,8 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
token: event.token,
profileId: event.profileId);
if (status['success']) {
educationalBackgrounds.removeWhere((element) => event.educationalBackground.id == element.id);
educationalBackgrounds.removeWhere(
(element) => event.educationalBackground.id == element.id);
EducationalBackground educationalBackground =
EducationalBackground.fromJson(status['data']);
educationalBackgrounds.add(educationalBackground);
@ -89,7 +100,8 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
////LOAD
on<LoadEducations>((event, emit) {
emit(EducationalBackgroundLoadedState(
educationalBackground: educationalBackgrounds));
educationalBackground: educationalBackgrounds,
attachmentCategory: attachmentCategories));
});
//// SHOW EDIT FORM
on<ShowEditEducationForm>((event, emit) async {
@ -134,5 +146,65 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
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
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 EducationalBackgroundLoadedState extends EducationState {
final List<AttachmentCategory> attachmentCategory;
final List<EducationalBackground> educationalBackground;
const EducationalBackgroundLoadedState({required this.educationalBackground});
const EducationalBackgroundLoadedState(
{required this.educationalBackground, required this.attachmentCategory});
@override
List<Object> get props => [educationalBackground];
}
@ -57,6 +59,8 @@ class EducationAddedState extends EducationState {
@override
List<Object> get props => [response];
}
//// Edited State
class EditedEducationState extends EducationState {
final Map<dynamic, dynamic> response;
@ -72,3 +76,17 @@ class EducationDeletedState extends EducationState {
@override
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:equatable/equatable.dart';
import 'package:unit2/utils/attachment_services.dart';
import '../../../model/location/city.dart';
import '../../../model/location/country.dart';
import '../../../model/location/provinces.dart';
import '../../../model/location/region.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/profile/eligibility.dart';
import '../../../model/utils/eligibility.dart';
import '../../../sevices/profile/eligibility_services.dart';
@ -18,10 +20,13 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
List<Region> globalRegions = [];
List<Eligibility> globalEligibilities = [];
List<EligibityCert> eligibilities = [];
List<AttachmentCategory> attachmentCategories = [];
//// LOAD ELIGIBILTY
on<LoadEligibility>((event, emit) {
emit(EligibilityLoadingState());
emit(EligibilityLoaded(eligibilities: eligibilities));
emit(EligibilityLoaded(
eligibilities: eligibilities,
attachmentCategory: attachmentCategories));
});
//// DELETE
@ -34,11 +39,11 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
if (success) {
eligibilities.removeWhere(
((EligibityCert element) => element.id == event.eligibilityId));
emit(DeletedState(
emit(EligibilityDeletedState(
success: success,
));
} else {
emit(DeletedState(success: success));
emit(EligibilityDeletedState(success: success));
}
} catch (e) {
emit(EligibilityErrorState(message: e.toString()));
@ -48,13 +53,21 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
//// GET ELIGIBILITY
on<GetEligibilities>((event, emit) async {
try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
if (eligibilities.isNotEmpty) {
emit(EligibilityLoaded(eligibilities: eligibilities));
emit(EligibilityLoaded(
eligibilities: eligibilities,
attachmentCategory: attachmentCategories));
} else {
emit(EligibilityLoadingState());
eligibilities = await EligibilityService.instance
.getEligibilities(event.profileId, event.token);
emit(EligibilityLoaded(eligibilities: eligibilities));
emit(EligibilityLoaded(
eligibilities: eligibilities,
attachmentCategory: attachmentCategories));
}
} catch (e) {
emit(EligibilityErrorState(message: e.toString()));
@ -208,5 +221,63 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
emit(const EligibilityErrorState(
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 int eligibilityId;
final String token;
const DeleteEligibility(
{
required this.eligibilityId,
@ -67,5 +68,32 @@ class DeleteEligibility 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

@ -2,14 +2,13 @@ part of 'eligibility_bloc.dart';
abstract class EligibilityState extends Equatable {
const EligibilityState();
@override
List<Object> get props => [];
}
class EligibilityInitial extends EligibilityState {}
class EditEligibilityState extends EligibilityState {
final EligibityCert eligibityCert;
final List<Eligibility> eligibilities;
@ -23,13 +22,14 @@ class EditEligibilityState extends EligibilityState {
final Province? currentProvince;
final CityMunicipality? currentCity;
final Country selectedCountry;
const EditEligibilityState({
required this.provinces,
required this.cities,
required this.currentProvince,
required this.currentCity,
required this.currentRegion,
required this.currentEligibility,
const EditEligibilityState({
required this.provinces,
required this.cities,
required this.currentProvince,
required this.currentCity,
required this.currentRegion,
required this.currentEligibility,
required this.isOverseas,
required this.eligibityCert,
required this.eligibilities,
@ -42,9 +42,9 @@ class EditEligibilityState extends EligibilityState {
[isOverseas, eligibityCert, eligibilities, regions, countries];
}
class DeletedState extends EligibilityState {
class EligibilityDeletedState extends EligibilityState {
final bool success;
const DeletedState({required this.success});
const EligibilityDeletedState({required this.success});
@override
List<Object> get props => [success];
}
@ -53,41 +53,57 @@ class AddEligibilityState extends EligibilityState {
final List<Eligibility> eligibilities;
final List<Country> countries;
final List<Region> regions;
const AddEligibilityState({
const AddEligibilityState({
required this.eligibilities,
required this.countries,
required this.regions,
});
@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});
@override
List<Object> get props =>[ response];
List<Object> get props => [response];
}
class EligibilityAddedState extends EligibilityState{
final Map<dynamic,dynamic> response;
class EligibilityAddedState extends EligibilityState {
final Map<dynamic, dynamic> response;
const EligibilityAddedState({ required this.response});
const EligibilityAddedState({required this.response});
@override
List<Object> get props =>[response];
List<Object> get props => [response];
}
class EligibilityLoadingState extends EligibilityState{
}
class EligibilityErrorState extends EligibilityState{
class EligibilityLoadingState extends EligibilityState {}
class EligibilityErrorState extends EligibilityState {
final String message;
const EligibilityErrorState({required this.message});
@override
List<Object> get props =>[message];
@override
List<Object> get props => [message];
}
class EligibilityLoaded extends EligibilityState {
final List< AttachmentCategory> attachmentCategory;
final List<EligibityCert> eligibilities;
const EligibilityLoaded({required this.eligibilities});
const EligibilityLoaded({required this.eligibilities, required this.attachmentCategory});
@override
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/city.dart';
import '../../../model/location/provinces.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/profile/learning_development.dart';
import '../../../model/utils/agency.dart';
import '../../../model/utils/category.dart';
import '../../../utils/attachment_services.dart';
import '../../../utils/location_utilities.dart';
import '../../../utils/profile_utilities.dart';
part 'learning_development_event.dart';
@ -27,7 +29,7 @@ class LearningDevelopmentBloc
List<Barangay> globalBarangay = [];
List<Agency> agencies = [];
List<Category> agencyCategory = [];
List<AttachmentCategory> attachmentCategories = [];
Region? currentRegion;
Country? currentCountry;
Province? currentProvince;
@ -37,12 +39,16 @@ class LearningDevelopmentBloc
on<GetLearningDevelopments>((event, emit) async {
emit(LearningDevelopmentLoadingState());
try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
List<LearningDevelopement> learnings = await LearningDevelopmentServices
.instance
.getLearningDevelopments(event.profileId, event.token);
learningsAndDevelopments = learnings;
emit(LearningDevelopmentLoadedState(
learningsAndDevelopment: learningsAndDevelopments));
learningsAndDevelopment: learningsAndDevelopments,attachmentCategory: attachmentCategories));
} catch (e) {
emit(LearningDevelopmentErrorState(message: e.toString()));
}
@ -50,7 +56,7 @@ class LearningDevelopmentBloc
////load
on<LoadLearniningDevelopment>((event, emit) {
emit(LearningDevelopmentLoadedState(
learningsAndDevelopment: learningsAndDevelopments));
learningsAndDevelopment: learningsAndDevelopments,attachmentCategory: attachmentCategories));
});
//// show add form
on<ShowAddLearningDevelopmentForm>((event, emit) async {
@ -266,5 +272,58 @@ class LearningDevelopmentBloc
on<CallErrorState>((event, emit) {
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;
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 LearningDevelopmentLoadedState extends LearningDevelopmentState {
final List<AttachmentCategory> attachmentCategory;
final List<LearningDevelopement> learningsAndDevelopment;
const LearningDevelopmentLoadedState({required this.learningsAndDevelopment});
const LearningDevelopmentLoadedState(
{required this.learningsAndDevelopment,
required this.attachmentCategory});
@override
List<Object> get props => [learningsAndDevelopment];
}
@ -112,3 +115,21 @@ class LearningDevelopmentErrorState extends LearningDevelopmentState {
final String 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
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
class AddVoluntaryWorkState extends VoluntaryWorkState{
final List<Position> positions;
@ -71,6 +72,11 @@ class AddVoluntaryWorkState extends VoluntaryWorkState{
@override
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
class VoluntaryWorkDeletedState extends VoluntaryWorkState{
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/utils/profile_utilities.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/utils/category.dart';
import '../../../utils/attachment_services.dart';
part 'workHistory_event.dart';
part 'workHistory_state.dart';
@ -19,17 +21,24 @@ class WorkHistoryBloc extends Bloc<WorkHistorytEvent, WorkHistoryState> {
List<Agency> agencies = [];
List<AppoinemtStatus> appointmentStatus = [];
List<Category> agencyCategory = [];
List<AttachmentCategory> attachmentCategories = [];
WorkHistoryBloc() : super(EducationInitial()) {
////GET WORK HISTORIES
on<GetWorkHistories>((event, emit) async {
emit(WorkHistoryLoadingState());
try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
if (workExperiences.isEmpty) {
List<WorkHistory> works = await WorkHistoryService.instance
.getWorkExperiences(event.profileId, event.token);
workExperiences = works;
}
emit(WorkHistoryLoaded(workExperiences: workExperiences));
emit(WorkHistoryLoaded(
workExperiences: workExperiences,
attachmentCategory: attachmentCategories));
} catch (e) {
emit(WorkHistoryErrorState(message: e.toString()));
}
@ -37,7 +46,9 @@ class WorkHistoryBloc extends Bloc<WorkHistorytEvent, WorkHistoryState> {
///// LOAD WORK HISTORIES
on<LoadWorkHistories>((event, emit) {
emit(WorkHistoryLoadingState());
emit(WorkHistoryLoaded(workExperiences: workExperiences));
emit(WorkHistoryLoaded(
workExperiences: workExperiences,
attachmentCategory: attachmentCategories));
});
////DELETE
on<DeleteWorkHistory>((event, emit) async {
@ -182,5 +193,64 @@ class WorkHistoryBloc extends Bloc<WorkHistorytEvent, WorkHistoryState> {
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];
}
////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{
final List<WorkHistory> workExperiences;
const WorkHistoryLoaded({required this.workExperiences});
final List< AttachmentCategory> attachmentCategory;
const WorkHistoryLoaded({required this.workExperiences,required this.attachmentCategory});
@override
List<Object> get props => [workExperiences];
}
@ -72,3 +73,22 @@ class WorkHistoryAddedState extends WorkHistoryState{
@override
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:device_preview/device_preview.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:unit2/bloc/profile/profile_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/global_context.dart';
import 'package:unit2/utils/global_context.dart';
import 'package:path_provider/path_provider.dart' as path_provider;
import './utils/router.dart';
import './utils/global.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
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 'package:unit2/model/profile/attachment.dart';
EducationalBackground educationalBackgroundFromJson(String str) => EducationalBackground.fromJson(json.decode(str));
String educationalBackgroundToJson(EducationalBackground data) => json.encode(data.toJson());
@ -24,7 +26,7 @@ class EducationalBackground {
final List<Honor>? honors;
final Education? education;
final String? periodTo;
final dynamic attachments;
List<Attachment>? attachments;
final String? periodFrom;
final int? unitsEarned;
final String? yearGraduated;
@ -34,7 +36,7 @@ class EducationalBackground {
honors: json["honors"] == null ? [] : List<Honor>.from(json["honors"]!.map((x) => Honor.fromJson(x))),
education: json["education"] == null ? null : Education.fromJson(json["education"]),
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"],
unitsEarned: json["units_earned"],
yearGraduated: json["year_graduated"],

View File

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

View File

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

View File

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

View File

@ -1,9 +1,16 @@
import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.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_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/workHistory/workHistory_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/model/profile/educational_background.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/error_state.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/global.dart';
import '../../../widgets/Leadings/close_leading.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
import 'education/edit_modal.dart';
class EducationScreen extends StatelessWidget {
const EducationScreen({super.key});
@override
Widget build(BuildContext context) {
final parent = context;
List<PlatformFile>? results = [];
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
int profileId;
String? token;
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
if (state is EditedEducationState) {
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) {
if (state is EducationalBackgroundLoadedState) {
for (var cat in state.attachmentCategory) {
if (cat.subclass!.id == 1) {
attachmentCategories.add(cat);
}
}
if (state.educationalBackground.isNotEmpty) {
return ListView.builder(
padding: const EdgeInsets.symmetric(
@ -182,54 +249,91 @@ class EducationScreen extends StatelessWidget {
decoration: box1(),
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8),
child: Row(
child: Column(
children: [
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Row(
Row(
children: [
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Expanded(
child: Text(level,
style: Theme.of(
context)
.textTheme
.titleSmall!)),
Row(
children: [
Expanded(
child: Text(
level,
style: Theme.of(
context)
.textTheme
.titleSmall!)),
Text(
"$periodFrom - $periodTo",
style: Theme.of(
context)
.textTheme
.bodyMedium,
),
],
),
const SizedBox(
height: 5,
),
Text(
"$periodFrom - $periodTo",
school,
style: Theme.of(
context)
.textTheme
.bodyMedium,
.titleMedium!
.copyWith(
color:
primary,
fontWeight:
FontWeight
.w500),
),
],
),
const SizedBox(
height: 5,
),
Text(
school,
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(
color: primary,
fontWeight:
FontWeight
.w500),
),
Container(
padding:
const EdgeInsets
.only(top: 8),
child: honors
.isNotEmpty
? Column(
Container(
padding:
const EdgeInsets
.only(
top: 8),
child: honors
.isNotEmpty
? Column(
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
const SizedBox(
height:
8,
),
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(),
),
],
)
: const SizedBox()),
program == null
? const SizedBox()
: Column(
mainAxisAlignment:
MainAxisAlignment
.start,
@ -238,104 +342,420 @@ class EducationScreen extends StatelessWidget {
.start,
children: [
const SizedBox(
height: 8,
),
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(),
height: 5,
),
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),
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],
////Show Attachments
SizedBox(
child: state
.educationalBackground[
index]
.attachments ==
null ||
state
.educationalBackground[
index]
.attachments!
.isEmpty
? const SizedBox()
: state
.educationalBackground[
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,
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]));
}
},
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",
)
token: token!,
eligibilityName: state
.educationalBackground[
index]
.education!
.school!
.name!,
attachments: state
.educationalBackground[
index]
.attachments!,
educationBloc:
BlocProvider.of<
EducationBloc>(
parent),
eligibilityBloc:
null,
workHistoryBloc:
null,
learningDevelopmentBloc:
null,
blocId: 1,
moduleId: state
.educationalBackground[
index]
.id!,
))
],
),
),

View File

@ -1,16 +1,26 @@
import 'dart:io';
import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.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_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/workHistory/workHistory_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/screens/profile/components/eligibility/add_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/btn-style.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/text_container.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 '../../../bloc/profile/eligibility/eligibility_bloc.dart';
import '../../../utils/alerts.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
class EligibiltyScreen extends StatelessWidget {
const EligibiltyScreen({super.key});
@override
Widget build(BuildContext context) {
BuildContext parent = context;
String? token;
int? profileId;
List<PlatformFile>? results = [];
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
return WillPopScope(
onWillPop: () async {
return true;
},
child: Scaffold(
resizeToAvoidBottomInset: true,
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: context.watch<EligibilityBloc>().state is AddEligibilityState
? const Text("Add Eligiblity")
@ -42,31 +58,37 @@ class EligibiltyScreen extends StatelessWidget {
: const Text(elibilityScreenTitle),
centerTitle: true,
backgroundColor: primary,
actions: (context.watch<EligibilityBloc>().state is EligibilityLoaded)
? [
AddLeading(onPressed: () {
context
.read<EligibilityBloc>()
.add(ShowAddEligibilityForm());
})
]
:(context.watch<EligibilityBloc>().state is AddEligibilityState || context.watch<EligibilityBloc>().state is EditEligibilityState)? [
CloseLeading(onPressed: () {
context.read<EligibilityBloc>().add(const LoadEligibility());
})
]:[],
actions:
(context.watch<EligibilityBloc>().state is EligibilityLoaded)
? [
AddLeading(onPressed: () {
context
.read<EligibilityBloc>()
.add(ShowAddEligibilityForm());
})
]
: (context.watch<EligibilityBloc>().state
is AddEligibilityState ||
context.watch<EligibilityBloc>().state
is EditEligibilityState)
? [
CloseLeading(onPressed: () {
context
.read<EligibilityBloc>()
.add(const LoadEligibility());
})
]
: [],
),
body: BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if (state is UserLoggedIn) {
token = state.userData!.user!.login!.token;
profileId =
state.userData!.user!.login!.user!.profileId;
profileId = state.userData!.user!.login!.user!.profileId;
return BlocBuilder<ProfileBloc, ProfileState>(
builder: (context, state) {
if(state is ProfileLoaded){
return ProgressHUD(
builder: (context, state) {
if (state is ProfileLoaded) {
return ProgressHUD(
padding: const EdgeInsets.all(24),
indicatorWidget: const SpinKitFadingCircle(
color: Colors.white,
@ -81,30 +103,53 @@ class EligibiltyScreen extends StatelessWidget {
if (state is EligibilityLoaded ||
state is AddEligibilityState ||
state is EditEligibilityState ||
state is DeletedState ||
state is EligibilityDeletedState ||
state is EligibilityAddedState ||
state is EligibilityEditedState ||
state is EligibilityErrorState
) {
state is EligibilityErrorState) {
final progress = ProgressHUD.of(context);
progress!.dismiss();
}
////DELETED STATE
if (state is DeletedState) {
if (state is EligibilityDeletedState) {
if (state.success) {
successAlert(context, "Deletion Successfull",
"Eligibility has been deleted successfully",
() {
Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility(
));
context
.read<EligibilityBloc>()
.add(const LoadEligibility());
});
} else {
errorAlert(context, "Deletion Failed",
"Error deleting eligibility", () {
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!",
state.response['message'], () {
Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility(
));
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(
));
context
.read<EligibilityBloc>()
.add(const LoadEligibility());
});
}
}
@ -133,16 +180,39 @@ class EligibiltyScreen extends StatelessWidget {
successAlert(context, "Update Successfull!",
state.response['message'], () {
Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility(
));
context
.read<EligibilityBloc>()
.add(const LoadEligibility());
});
} else {
errorAlert(context, "Update Failed",
"Something went wrong. Please try again.",
() {
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>(
builder: (context, state) {
if (state is EligibilityLoaded) {
for (var cat in state.attachmentCategory) {
if (cat.subclass!.id == 3) {
attachmentCategories.add(cat);
}
}
if (state.eligibilities.isNotEmpty) {
return ListView.builder(
padding: const EdgeInsets.symmetric(
@ -164,153 +238,466 @@ class EligibiltyScreen extends StatelessWidget {
.eligibility!
.title;
return Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
width: screenWidth,
padding:
const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8),
decoration: box1(),
child: Row(
child: Column(
children: [
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
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)
]),
Row(
children: [
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
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),
]),
),
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;
eligibityCert
.overseas =
overseas;
context
.read<
EligibilityBloc>()
.add(ShowEditEligibilityForm(
eligibityCert:
eligibityCert));
}
////Attachment
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(
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>(
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
const Divider(),
////Show Attachments
SizedBox(
width: screenWidth,
child: state
.eligibilities[
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.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;
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",
)
profileId!,
token: token!,
moduleId: state
.eligibilities[
index]
.eligibility!
.id,
educationBloc:
null,
learningDevelopmentBloc:
null,
workHistoryBloc:
null,
eligibilityBloc:
BlocProvider.of<
EligibilityBloc>(
context),
blocId: 2,
eligibilityName: state
.eligibilities[
index]
.eligibility!
.title,
attachments: state
.eligibilities[
index]
.attachments!,
))
],
),
),
const SizedBox(
height: 5,
)
),
],
);
});
@ -322,17 +709,25 @@ class EligibiltyScreen extends StatelessWidget {
}
if (state is EditEligibilityState) {
return EditEligibilityScreen(
profileId: profileId!,
token: token!,
profileId: profileId!,
token: token!,
eligibityCert: state.eligibityCert);
}
if (state is AddEligibilityState) {
return AddEligibilityScreen(token: token!,profileId: profileId!,);
return AddEligibilityScreen(
token: token!,
profileId: profileId!,
);
}
if (state is EligibilityErrorState) {
return SomethingWentWrong(message: state.message, onpressed: (){
context.read<EligibilityBloc>().add(GetEligibilities(token: token!,profileId: profileId!));
});
return SomethingWentWrong(
message: state.message,
onpressed: () {
context.read<EligibilityBloc>().add(
GetEligibilities(
token: token!,
profileId: profileId!));
});
}
return Container(
color: Colors.grey.shade200,
@ -342,11 +737,9 @@ class EligibiltyScreen extends StatelessWidget {
},
),
);
}
return Container();
}
);
return Container();
});
}
return Container();
},

View File

@ -1,15 +1,18 @@
import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.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_form_builder/flutter_form_builder.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.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: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/workHistory/workHistory_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/theme-data.dart/box_shadow.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/error_state.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 '../../../widgets/Leadings/close_leading.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
import 'learning_development/add_modal.dart';
class LearningAndDevelopmentScreen extends StatelessWidget {
@ -32,7 +40,11 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
Widget build(BuildContext context) {
String token;
int profileId;
BuildContext parent = context;
DateFormat dteFormat2 = DateFormat.yMMMMd('en_US');
List<PlatformFile>? results = [];
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
return Scaffold(
appBar: AppBar(
title: context.watch<LearningDevelopmentBloc>().state
@ -76,13 +88,11 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
backgroundColor: Colors.black87,
child: BlocBuilder<UserBloc, UserState>(
builder: (context, state) {
if (state is UserLoggedIn) {
token = state.userData!.user!.login!.token!;
profileId = state.userData!.user!.login!.user!.profileId!;
return BlocBuilder<ProfileBloc, ProfileState>(
builder: (context, state) {
if (state is ProfileLoaded) {
return BlocConsumer<LearningDevelopmentBloc,
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
if (state is LearningDevelopmentUpdatedState) {
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
},
builder: (context, state) {
print(state);
if (state is LearningDevelopmentLoadedState) {
for (var cat in state.attachmentCategory) {
if (cat.subclass!.id == 2) {
attachmentCategories.add(cat);
}
}
if (state.learningsAndDevelopment.isNotEmpty) {
return ListView.builder(
padding: const EdgeInsets.symmetric(
@ -208,66 +263,73 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8),
width: screenWidth,
child: Row(
child: Column(
children: [
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
training,
style: Theme.of(context)
.textTheme
.titleMedium!
.copyWith(
fontWeight:
FontWeight
.w600,
color: primary),
),
const SizedBox(
height: 8,
),
Text(
provider,
style: Theme.of(context)
.textTheme
.titleSmall,
),
const SizedBox(
height: 5,
),
Text(
"$duration: $start to $end",
style: Theme.of(context)
.textTheme
.labelMedium,
),
const SizedBox(
height: 5,
),
]),
),
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...");
BlocProvider.of<
LearningDevelopmentBloc>(
context)
.add(DeleteLearningDevelopment(
Row(
children: [
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
training,
style: Theme.of(
context)
.textTheme
.titleMedium!
.copyWith(
fontWeight:
FontWeight
.w600,
color:
primary),
),
const SizedBox(
height: 8,
),
Text(
provider,
style: Theme.of(
context)
.textTheme
.titleSmall,
),
const SizedBox(
height: 5,
),
Text(
"$duration: $start to $end",
style: Theme.of(
context)
.textTheme
.labelMedium,
),
const SizedBox(
height: 5,
),
]),
),
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...");
BlocProvider.of<LearningDevelopmentBloc>(context).add(DeleteLearningDevelopment(
trainingId: state
.learningsAndDevelopment[
index]
@ -286,62 +348,394 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
profileId:
profileId,
token: token));
}, "Delete?",
"Confirm Delete?");
}
if (value == 1) {
bool isOverseas;
////edit = = = = = = = =>>
final progress =
ProgressHUD.of(context);
progress!.showWithText(
"Loading...");
}, "Delete?",
"Confirm Delete?");
}
if (value == 1) {
bool isOverseas;
////edit = = = = = = = =>>
final progress =
ProgressHUD.of(
context);
progress!.showWithText(
"Loading...");
if (state
.learningsAndDevelopment[
index]
.conductedTraining
?.venue
?.cityMunicipality ==
null) {
isOverseas = true;
} else {
isOverseas = false;
}
context
.read<
LearningDevelopmentBloc>()
.add(ShowEditLearningDevelopmentForm(
profileId:
profileId,
token: token,
learningDevelopment:
state.learningsAndDevelopment[
index],
isOverseas:
isOverseas));
}
},
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),
if (state
.learningsAndDevelopment[
index]
.conductedTraining
?.venue
?.cityMunicipality ==
null) {
isOverseas = true;
} else {
isOverseas = false;
}
context
.read<
LearningDevelopmentBloc>()
.add(ShowEditLearningDevelopmentForm(
profileId:
profileId,
token: token,
learningDevelopment:
state.learningsAndDevelopment[
index],
isOverseas:
isOverseas));
}
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(
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,
color: Colors.grey,
),
tooltip: "Options",
)
),
SizedBox(
child: state
.learningsAndDevelopment[
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 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.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_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: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/user/user_bloc.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/empty_data.dart';
import 'package:unit2/widgets/error_state.dart';
import '../../../bloc/profile/workHistory/workHistory_bloc.dart';
import '../../../model/profile/attachment.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/global.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
class WorkHistoryScreen extends StatelessWidget {
const WorkHistoryScreen({super.key});
@ -29,8 +39,13 @@ class WorkHistoryScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
DateFormat dteFormat2 = DateFormat.yMMMMd('en_US');
BuildContext parent = context;
String? token;
int profileId;
int? profileId;
List<PlatformFile>? results = [];
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
return Scaffold(
appBar: AppBar(
title: context.watch<WorkHistoryBloc>().state is AddWorkHistoryState
@ -95,7 +110,7 @@ class WorkHistoryScreen extends StatelessWidget {
final progress = ProgressHUD.of(context);
progress!.dismiss();
}
//DELETED STATE
////DELETED STATE
if (state is DeletedState) {
if (state.success) {
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
if (state is WorkHistoryEditedState) {
if (state.response['success']) {
@ -160,6 +217,11 @@ class WorkHistoryScreen extends StatelessWidget {
},
builder: (context, state) {
if (state is WorkHistoryLoaded) {
for (var cat in state.attachmentCategory) {
if (cat.subclass!.id == 4) {
attachmentCategories.add(cat);
}
}
if (state.workExperiences.isNotEmpty) {
return ListView.builder(
padding: const EdgeInsets.symmetric(
@ -185,114 +247,467 @@ class WorkHistoryScreen extends StatelessWidget {
return Column(
children: [
Container(
width: screenWidth,
decoration: box1(),
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8),
child: Row(children: [
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
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,
),
],
)),
AppPopupMenu<int>(
offset: const Offset(-10, -10),
elevation: 3,
onSelected: (value) {
////delete workhistory-= = = = = = = = =>>
if (value == 2) {
confirmAlert(context, () {
final progress =
ProgressHUD.of(context);
progress!.showWithText(
"Loading...");
BlocProvider.of<
WorkHistoryBloc>(
context)
.add(DeleteWorkHistory(
profileId: profileId,
token: token!,
workHistory:
state.workExperiences[
child: Column(
children: [
Row(children: [
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
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,
),
],
)),
AppPopupMenu<int>(
offset:
const Offset(-10, -10),
elevation: 3,
onSelected: (value) {
////delete workhistory-= = = = = = = = =>>
if (value == 2) {
confirmAlert(context, () {
final progress =
ProgressHUD.of(
context);
progress!.showWithText(
"Loading...");
BlocProvider.of<
WorkHistoryBloc>(
context)
.add(
DeleteWorkHistory(
profileId: profileId!,
token: token!,
workHistory: state
.workExperiences[
index],
));
}, "Delete?",
"Confirm Delete?");
}
if (value == 1) {
////edit eligibilty-= = = = = = = = =>>
final progress =
ProgressHUD.of(context);
progress!.showWithText(
"Loading...");
WorkHistory workHistory =
state.workExperiences[
index];
context
.read<WorkHistoryBloc>()
.add(
ShowEditWorkHistoryForm(
));
}, "Delete?",
"Confirm Delete?");
}
if (value == 1) {
////edit eligibilty-= = = = = = = = =>>
final progress =
ProgressHUD.of(
context);
progress!.showWithText(
"Loading...");
WorkHistory workHistory =
state.workExperiences[
index];
context
.read<
WorkHistoryBloc>()
.add(ShowEditWorkHistoryForm(
workHistory:
workHistory));
}
},
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",
)
]),
}
////Attachment
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(
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) {
for (var res in results) {
paths.add(res.path!);
}
setState(() {
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(
height: 5,
@ -308,13 +723,13 @@ class WorkHistoryScreen extends StatelessWidget {
}
if (state is AddWorkHistoryState) {
return AddWorkHistoryScreen(
profileId: profileId,
profileId: profileId!,
token: token!,
);
}
if (state is EditWorkHistoryState) {
return EditWorkHistoryScreen(
profileId: profileId,
profileId: profileId!,
token: token!,
);
}
@ -324,7 +739,8 @@ class WorkHistoryScreen extends StatelessWidget {
onpressed: () {
context.read<WorkHistoryBloc>().add(
GetWorkHistories(
profileId: profileId, token: token!));
profileId: profileId!,
token: token!));
});
}
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 'package:unit2/model/profile/attachment.dart';
import 'package:unit2/model/profile/eligibility.dart';
import 'package:unit2/utils/request.dart';
import 'package:unit2/utils/urls.dart';
@ -8,33 +9,33 @@ import 'package:http/http.dart' as http;
class EligibilityService {
static final EligibilityService _instance = EligibilityService();
static EligibilityService get instance => _instance;
Future<List<EligibityCert>> getEligibilities(int profileId, String token)async{
List<EligibityCert> eligibilities = [];
Future<List<EligibityCert>> getEligibilities(
int profileId, String token) async {
List<EligibityCert> eligibilities = [];
String authToken = "Token $token";
String path = "${Url.instance.getEligibilities()}$profileId/";
Map<String, String> headers = {
String path = "${Url.instance.getEligibilities()}$profileId/";
Map<String, String> headers = {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': authToken
};
try{
http.Response response = await Request.instance.getRequest(path: path,headers: headers,param: {});
if(response.statusCode == 200){
Map data = jsonDecode(response.body);
if (data['data']!= null) {
data['data'].forEach((var cert) {
EligibityCert eligibility = EligibityCert.fromJson(cert);
eligibilities.add(eligibility);
});
}
try {
http.Response response = await Request.instance
.getRequest(path: path, headers: headers, param: {});
if (response.statusCode == 200) {
Map data = jsonDecode(response.body);
if (data['data'] != null) {
data['data'].forEach((var cert) {
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(
@ -50,18 +51,17 @@ class EligibilityService {
'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());
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!;
}
@ -70,7 +70,7 @@ class EligibilityService {
{required EligibityCert eligibityCert,
required String token,
required int profileId}) async {
Map<dynamic, dynamic>? _response={};
Map<dynamic, dynamic>? _response = {};
String authtoken = "Token $token";
String path = '${Url.instance.addEligibility()}$profileId/';
Map<String, String> headers = {
@ -94,7 +94,7 @@ class EligibilityService {
Map data = jsonDecode(response.body);
_response = data;
} else {
_response.addAll({'success':false});
_response.addAll({'success': false});
}
return _response;
@ -103,11 +103,12 @@ class EligibilityService {
}
}
Future<Map<dynamic, dynamic>> update(
Future<Map<dynamic, dynamic>> update(
{required EligibityCert eligibityCert,
required String token,
required int profileId, required int oldEligibility}) async {
Map<dynamic, dynamic>? response={};
required int profileId,
required int oldEligibility}) async {
Map<dynamic, dynamic>? response = {};
String authtoken = "Token $token";
String path = '${Url.instance.addEligibility()}$profileId/';
Map<String, String> headers = {
@ -132,7 +133,7 @@ class EligibilityService {
Map data = jsonDecode(res.body);
response = data;
} else {
response.addAll({'success':false});
response.addAll({'success': false});
}
return response;
@ -140,4 +141,63 @@ class EligibilityService {
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() {
// return '192.168.10.183:3000';
// return 'agusandelnorte.gov.ph';
// return "192.168.10.219:3000";
// return "192.168.10.241";
return "192.168.10.221:3004";
return "192.168.10.219:3000";
// // return "192.168.10.241";
// return "192.168.10.221:3004";
// return "playweb.agusandelnorte.gov.ph";
// return 'devapi.agusandelnorte.gov.ph:3004';
}
@ -167,6 +167,9 @@ class Url {
String getServiceTypes() {
return "/api/jobnet_app/comm_service_type/";
}
String attachments(){
return "/api/jobnet_app/profile/attachment/";
}
//// address path
String addressPath() {
@ -319,4 +322,7 @@ class Url {
String getAddressCategory() {
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"
source: hosted
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:
dependency: transitive
description:

View File

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