Implemented attachment features to profile screens

feature/passo/PASSO-#1-Sync-data-from-device-to-postgre-and-vice-versa
PGAN-MIS 2023-08-01 16:20:38 +08:00
parent 603275ec6d
commit c32ed51198
33 changed files with 2586 additions and 540 deletions

View File

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

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

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

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

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

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

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

View File

@ -3,6 +3,9 @@ import 'package:equatable/equatable.dart';
import 'package:unit2/model/profile/educational_background.dart'; import 'package:unit2/model/profile/educational_background.dart';
import 'package:unit2/sevices/profile/education_services.dart'; import 'package:unit2/sevices/profile/education_services.dart';
import '../../../model/profile/attachment.dart';
import '../../../utils/attachment_categories.dart';
part 'education_event.dart'; part 'education_event.dart';
part 'education_state.dart'; part 'education_state.dart';
@ -11,20 +14,25 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
List<School> schools = []; List<School> schools = [];
List<Course> programs = []; List<Course> programs = [];
List<Honor> honors = []; List<Honor> honors = [];
List<AttachmentCategory> attachmentCategories = [];
EducationBloc() : super(EducationInitial()) { EducationBloc() : super(EducationInitial()) {
on<GetEducationalBackground>((event, emit) async { on<GetEducationalBackground>((event, emit) async {
emit(EducationalBackgroundLoadingState()); emit(EducationalBackgroundLoadingState());
try { try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
if (educationalBackgrounds.isEmpty) { if (educationalBackgrounds.isEmpty) {
List<EducationalBackground> educations = await EducationService List<EducationalBackground> educations = await EducationService
.instace .instace
.getEducationalBackground(event.profileId, event.token); .getEducationalBackground(event.profileId, event.token);
educationalBackgrounds = educations; educationalBackgrounds = educations;
emit(EducationalBackgroundLoadedState( emit(EducationalBackgroundLoadedState(
educationalBackground: educationalBackgrounds)); educationalBackground: educationalBackgrounds, attachmentCategory: attachmentCategories));
} else { } else {
emit(EducationalBackgroundLoadedState( emit(EducationalBackgroundLoadedState(
educationalBackground: educationalBackgrounds)); educationalBackground: educationalBackgrounds,attachmentCategory: attachmentCategories));
} }
} catch (e) { } catch (e) {
emit(EducationalBackgroundErrorState(message: e.toString())); emit(EducationalBackgroundErrorState(message: e.toString()));
@ -89,7 +97,7 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
////LOAD ////LOAD
on<LoadEducations>((event, emit) { on<LoadEducations>((event, emit) {
emit(EducationalBackgroundLoadedState( emit(EducationalBackgroundLoadedState(
educationalBackground: educationalBackgrounds)); educationalBackground: educationalBackgrounds,attachmentCategory: attachmentCategories));
}); });
//// SHOW EDIT FORM //// SHOW EDIT FORM
on<ShowEditEducationForm>((event, emit) async { on<ShowEditEducationForm>((event, emit) async {
@ -134,5 +142,25 @@ class EducationBloc extends Bloc<EducationEvent, EducationState> {
emit(EducationalBackgroundErrorState(message: e.toString())); emit(EducationalBackgroundErrorState(message: e.toString()));
} }
}); });
////Add attachment
on<AddAttachment>((event, emit) async {
emit(EducationalBackgroundLoadingState());
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']) {
emit(EducationAddedState(response: status));
} else {
emit(EducationAddedState(response: status));
}
} catch (e) {
emit(EducationalBackgroundErrorState(message: e.toString()));
}
});
} }
} }

View File

@ -63,3 +63,14 @@ class DeleteEducation extends EducationEvent{
@override @override
List<Object> get props => [educationalBackground, profileId, token]; List<Object> get props => [educationalBackground, profileId, token];
} }
////Add attachment
class AddAttachment extends EducationEvent{
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

@ -10,8 +10,9 @@ abstract class EducationState extends Equatable {
class EducationInitial extends EducationState {} class EducationInitial extends EducationState {}
class EducationalBackgroundLoadedState extends EducationState { class EducationalBackgroundLoadedState extends EducationState {
final List< AttachmentCategory> attachmentCategory;
final List<EducationalBackground> educationalBackground; final List<EducationalBackground> educationalBackground;
const EducationalBackgroundLoadedState({required this.educationalBackground}); const EducationalBackgroundLoadedState({required this.educationalBackground, required this.attachmentCategory});
@override @override
List<Object> get props => [educationalBackground]; List<Object> get props => [educationalBackground];
} }

View File

@ -1,9 +1,11 @@
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:unit2/utils/attachment_categories.dart';
import '../../../model/location/city.dart'; import '../../../model/location/city.dart';
import '../../../model/location/country.dart'; import '../../../model/location/country.dart';
import '../../../model/location/provinces.dart'; import '../../../model/location/provinces.dart';
import '../../../model/location/region.dart'; import '../../../model/location/region.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/profile/eligibility.dart'; import '../../../model/profile/eligibility.dart';
import '../../../model/utils/eligibility.dart'; import '../../../model/utils/eligibility.dart';
import '../../../sevices/profile/eligibility_services.dart'; import '../../../sevices/profile/eligibility_services.dart';
@ -18,10 +20,13 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
List<Region> globalRegions = []; List<Region> globalRegions = [];
List<Eligibility> globalEligibilities = []; List<Eligibility> globalEligibilities = [];
List<EligibityCert> eligibilities = []; List<EligibityCert> eligibilities = [];
List<AttachmentCategory> attachmentCategories = [];
//// LOAD ELIGIBILTY //// LOAD ELIGIBILTY
on<LoadEligibility>((event, emit) { on<LoadEligibility>((event, emit) {
emit(EligibilityLoadingState()); emit(EligibilityLoadingState());
emit(EligibilityLoaded(eligibilities: eligibilities)); emit(EligibilityLoaded(
eligibilities: eligibilities,
attachmentCategory: attachmentCategories));
}); });
//// DELETE //// DELETE
@ -48,13 +53,21 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
//// GET ELIGIBILITY //// GET ELIGIBILITY
on<GetEligibilities>((event, emit) async { on<GetEligibilities>((event, emit) async {
try { try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
if (eligibilities.isNotEmpty) { if (eligibilities.isNotEmpty) {
emit(EligibilityLoaded(eligibilities: eligibilities)); emit(EligibilityLoaded(
eligibilities: eligibilities,
attachmentCategory: attachmentCategories));
} else { } else {
emit(EligibilityLoadingState()); emit(EligibilityLoadingState());
eligibilities = await EligibilityService.instance eligibilities = await EligibilityService.instance
.getEligibilities(event.profileId, event.token); .getEligibilities(event.profileId, event.token);
emit(EligibilityLoaded(eligibilities: eligibilities)); emit(EligibilityLoaded(
eligibilities: eligibilities,
attachmentCategory: attachmentCategories));
} }
} catch (e) { } catch (e) {
emit(EligibilityErrorState(message: e.toString())); emit(EligibilityErrorState(message: e.toString()));
@ -208,5 +221,48 @@ class EligibilityBloc extends Bloc<EligibilityEvent, EligibilityState> {
emit(const EligibilityErrorState( emit(const EligibilityErrorState(
message: "Something went wrong. Please try again")); message: "Something went wrong. Please try again"));
}); });
////Add attachment
on<AddAttachment>((event, emit) async {
emit(EligibilityLoadingState());
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']) {
emit(EligibilityAddedState(response: status));
} else {
emit(EligibilityAddedState(response: status));
}
} catch (e) {
emit(EligibilityErrorState(message: e.toString()));
}
});
on<DeleteAttachment>((event, emit) async {
// try {
final bool success = await EligibilityService.instance.deleteAttachment(
moduleId: int.parse(event.moduleId),
attachment: event.attachment,
profileId: event.profileId,
token: event.token);
if (success) {
EligibityCert eligibityCert = eligibilities.firstWhere((element) =>element.id.toString() == event.moduleId);
eligibityCert.attachments!.removeWhere((element){
return event.attachment.id == element.id;
});
emit(DeletedState(
success: success,
));
} else {
emit(DeletedState(success: success));
}
// } catch (e) {
// emit(EligibilityErrorState(message: e.toString()));
// }
});
} }
} }

View File

@ -55,6 +55,7 @@ class DeleteEligibility extends EligibilityEvent {
final String profileId; final String profileId;
final int eligibilityId; final int eligibilityId;
final String token; final String token;
const DeleteEligibility( const DeleteEligibility(
{ {
required this.eligibilityId, required this.eligibilityId,
@ -68,4 +69,30 @@ class CallErrorState extends EligibilityEvent{
} }
class AddAttachment extends EligibilityEvent{
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];
}
class DeleteAttachment extends EligibilityEvent{
final String profileId;
final String token;
final Attachment attachment;
final String moduleId;
const DeleteAttachment({required this.attachment,required this.moduleId, required this.profileId, required this.token});
}

View File

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

View File

@ -6,9 +6,11 @@ import 'package:unit2/sevices/profile/learningDevelopment_service.dart';
import '../../../model/location/barangay.dart'; import '../../../model/location/barangay.dart';
import '../../../model/location/city.dart'; import '../../../model/location/city.dart';
import '../../../model/location/provinces.dart'; import '../../../model/location/provinces.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/profile/learning_development.dart'; import '../../../model/profile/learning_development.dart';
import '../../../model/utils/agency.dart'; import '../../../model/utils/agency.dart';
import '../../../model/utils/category.dart'; import '../../../model/utils/category.dart';
import '../../../utils/attachment_categories.dart';
import '../../../utils/location_utilities.dart'; import '../../../utils/location_utilities.dart';
import '../../../utils/profile_utilities.dart'; import '../../../utils/profile_utilities.dart';
part 'learning_development_event.dart'; part 'learning_development_event.dart';
@ -27,7 +29,7 @@ class LearningDevelopmentBloc
List<Barangay> globalBarangay = []; List<Barangay> globalBarangay = [];
List<Agency> agencies = []; List<Agency> agencies = [];
List<Category> agencyCategory = []; List<Category> agencyCategory = [];
List<AttachmentCategory> attachmentCategories = [];
Region? currentRegion; Region? currentRegion;
Country? currentCountry; Country? currentCountry;
Province? currentProvince; Province? currentProvince;
@ -37,12 +39,16 @@ class LearningDevelopmentBloc
on<GetLearningDevelopments>((event, emit) async { on<GetLearningDevelopments>((event, emit) async {
emit(LearningDevelopmentLoadingState()); emit(LearningDevelopmentLoadingState());
try { try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
List<LearningDevelopement> learnings = await LearningDevelopmentServices List<LearningDevelopement> learnings = await LearningDevelopmentServices
.instance .instance
.getLearningDevelopments(event.profileId, event.token); .getLearningDevelopments(event.profileId, event.token);
learningsAndDevelopments = learnings; learningsAndDevelopments = learnings;
emit(LearningDevelopmentLoadedState( emit(LearningDevelopmentLoadedState(
learningsAndDevelopment: learningsAndDevelopments)); learningsAndDevelopment: learningsAndDevelopments,attachmentCategory: attachmentCategories));
} catch (e) { } catch (e) {
emit(LearningDevelopmentErrorState(message: e.toString())); emit(LearningDevelopmentErrorState(message: e.toString()));
} }
@ -50,7 +56,7 @@ class LearningDevelopmentBloc
////load ////load
on<LoadLearniningDevelopment>((event, emit) { on<LoadLearniningDevelopment>((event, emit) {
emit(LearningDevelopmentLoadedState( emit(LearningDevelopmentLoadedState(
learningsAndDevelopment: learningsAndDevelopments)); learningsAndDevelopment: learningsAndDevelopments,attachmentCategory: attachmentCategories));
}); });
//// show add form //// show add form
on<ShowAddLearningDevelopmentForm>((event, emit) async { on<ShowAddLearningDevelopmentForm>((event, emit) async {
@ -266,5 +272,25 @@ class LearningDevelopmentBloc
on<CallErrorState>((event, emit) { on<CallErrorState>((event, emit) {
emit(LearningDevelopmentErrorState(message: event.message)); emit(LearningDevelopmentErrorState(message: event.message));
}); });
////Add attachment
on<AddAttachment>((event, emit) async {
emit(LearningDevelopmentLoadingState());
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']) {
emit(LearningDevelopmentAddedState(response: status));
} else {
emit(LearningDevelopmentAddedState(response: status));
}
} catch (e) {
emit(LearningDevelopmentErrorState(message: e.toString()));
}
});
} }
} }

View File

@ -66,3 +66,14 @@ class CallErrorState extends LearningDevelopmentEvent{
final String message; final String message;
const CallErrorState({required this.message}); const CallErrorState({required this.message});
} }
class AddAttachment extends LearningDevelopmentEvent{
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

@ -10,8 +10,9 @@ abstract class LearningDevelopmentState extends Equatable {
class LearningDevelopmentInitial extends LearningDevelopmentState {} class LearningDevelopmentInitial extends LearningDevelopmentState {}
class LearningDevelopmentLoadedState extends LearningDevelopmentState { class LearningDevelopmentLoadedState extends LearningDevelopmentState {
final List< AttachmentCategory> attachmentCategory;
final List<LearningDevelopement> learningsAndDevelopment; final List<LearningDevelopement> learningsAndDevelopment;
const LearningDevelopmentLoadedState({required this.learningsAndDevelopment}); const LearningDevelopmentLoadedState({required this.learningsAndDevelopment, required this.attachmentCategory});
@override @override
List<Object> get props => [learningsAndDevelopment]; List<Object> get props => [learningsAndDevelopment];
} }

View File

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

View File

@ -8,7 +8,9 @@ import 'package:unit2/model/utils/position.dart';
import 'package:unit2/sevices/profile/work_history_services.dart'; import 'package:unit2/sevices/profile/work_history_services.dart';
import 'package:unit2/utils/profile_utilities.dart'; import 'package:unit2/utils/profile_utilities.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/utils/category.dart'; import '../../../model/utils/category.dart';
import '../../../utils/attachment_categories.dart';
part 'workHistory_event.dart'; part 'workHistory_event.dart';
part 'workHistory_state.dart'; part 'workHistory_state.dart';
@ -19,17 +21,22 @@ class WorkHistoryBloc extends Bloc<WorkHistorytEvent, WorkHistoryState> {
List<Agency> agencies = []; List<Agency> agencies = [];
List<AppoinemtStatus> appointmentStatus = []; List<AppoinemtStatus> appointmentStatus = [];
List<Category> agencyCategory = []; List<Category> agencyCategory = [];
List<AttachmentCategory> attachmentCategories = [];
WorkHistoryBloc() : super(EducationInitial()) { WorkHistoryBloc() : super(EducationInitial()) {
////GET WORK HISTORIES ////GET WORK HISTORIES
on<GetWorkHistories>((event, emit) async { on<GetWorkHistories>((event, emit) async {
emit(WorkHistoryLoadingState()); emit(WorkHistoryLoadingState());
try { try {
if (attachmentCategories.isEmpty) {
attachmentCategories =
await AttachmentServices.instance.getCategories();
}
if (workExperiences.isEmpty) { if (workExperiences.isEmpty) {
List<WorkHistory> works = await WorkHistoryService.instance List<WorkHistory> works = await WorkHistoryService.instance
.getWorkExperiences(event.profileId, event.token); .getWorkExperiences(event.profileId, event.token);
workExperiences = works; workExperiences = works;
} }
emit(WorkHistoryLoaded(workExperiences: workExperiences)); emit(WorkHistoryLoaded(workExperiences: workExperiences, attachmentCategory: attachmentCategories));
} catch (e) { } catch (e) {
emit(WorkHistoryErrorState(message: e.toString())); emit(WorkHistoryErrorState(message: e.toString()));
} }
@ -37,7 +44,7 @@ class WorkHistoryBloc extends Bloc<WorkHistorytEvent, WorkHistoryState> {
///// LOAD WORK HISTORIES ///// LOAD WORK HISTORIES
on<LoadWorkHistories>((event, emit) { on<LoadWorkHistories>((event, emit) {
emit(WorkHistoryLoadingState()); emit(WorkHistoryLoadingState());
emit(WorkHistoryLoaded(workExperiences: workExperiences)); emit(WorkHistoryLoaded(workExperiences: workExperiences,attachmentCategory: attachmentCategories));
}); });
////DELETE ////DELETE
on<DeleteWorkHistory>((event, emit) async { on<DeleteWorkHistory>((event, emit) async {
@ -182,5 +189,25 @@ class WorkHistoryBloc extends Bloc<WorkHistorytEvent, WorkHistoryState> {
emit(WorkHistoryErrorState(message: e.toString())); emit(WorkHistoryErrorState(message: e.toString()));
} }
}); });
////Add Attachment
on<AddAttachment>((event, emit) async {
emit(WorkHistoryLoadingState());
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']) {
emit(WorkHistoryAddedState(response: status));
} else {
emit(WorkHistoryAddedState(response: status));
}
} catch (e) {
emit(WorkHistoryErrorState(message: e.toString()));
}
});
} }
} }

View File

@ -60,5 +60,15 @@ class AddWorkHostory extends WorkHistorytEvent{
@override @override
List<Object> get props => [workHistory,profileId,token,isPrivate]; List<Object> get props => [workHistory,profileId,token,isPrivate];
} }
class AddAttachment extends WorkHistorytEvent{
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

@ -11,7 +11,8 @@ class EducationInitial extends WorkHistoryState {}
class WorkHistoryLoaded extends WorkHistoryState{ class WorkHistoryLoaded extends WorkHistoryState{
final List<WorkHistory> workExperiences; final List<WorkHistory> workExperiences;
const WorkHistoryLoaded({required this.workExperiences}); final List< AttachmentCategory> attachmentCategory;
const WorkHistoryLoaded({required this.workExperiences,required this.attachmentCategory});
@override @override
List<Object> get props => [workExperiences]; List<Object> get props => [workExperiences];
} }

View File

@ -0,0 +1,122 @@
// To parse this JSON data, do
//
// final attachment = attachmentFromJson(jsonString);
import 'package:meta/meta.dart';
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: 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: AttachmentClass.fromJson(json["attachment_class"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"attachment_class": attachmentClass.toJson(),
};
}
class AttachmentClass {
final int id;
final String name;
AttachmentClass({
required this.id,
required this.name,
});
factory AttachmentClass.fromJson(Map<String, dynamic> json) =>
AttachmentClass(
id: json["id"],
name: json["name"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
};
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,12 @@
import 'package:app_popup_menu/app_popup_menu.dart'; import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_svg/svg.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/model/profile/educational_background.dart'; import 'package:unit2/model/profile/educational_background.dart';
@ -12,14 +16,26 @@ import 'package:unit2/theme-data.dart/colors.dart';
import 'package:unit2/widgets/Leadings/add_leading.dart'; import 'package:unit2/widgets/Leadings/add_leading.dart';
import 'package:unit2/widgets/empty_data.dart'; import 'package:unit2/widgets/empty_data.dart';
import 'package:unit2/widgets/error_state.dart'; import 'package:unit2/widgets/error_state.dart';
import '../../../bloc/profile/education/education_bloc.dart'; import '../../../bloc/profile/education/education_bloc.dart';
import '../../../model/profile/attachment.dart';
import '../../../theme-data.dart/btn-style.dart';
import '../../../theme-data.dart/form-style.dart';
import '../../../utils/alerts.dart'; import '../../../utils/alerts.dart';
import '../../../utils/global.dart';
import '../../../widgets/Leadings/close_leading.dart'; import '../../../widgets/Leadings/close_leading.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
import 'education/edit_modal.dart'; import 'education/edit_modal.dart';
class EducationScreen extends StatelessWidget { class EducationScreen extends StatelessWidget {
const EducationScreen({super.key}); const EducationScreen({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final parent = context;
FilePickerResult? result;
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
int profileId; int profileId;
String? token; String? token;
return Scaffold( return Scaffold(
@ -144,6 +160,11 @@ class EducationScreen extends StatelessWidget {
}, },
builder: (context, state) { builder: (context, state) {
if (state is EducationalBackgroundLoadedState) { if (state is EducationalBackgroundLoadedState) {
for (var cat in state.attachmentCategory) {
if (cat.subclass.id == 1) {
attachmentCategories.add(cat);
}
}
if (state.educationalBackground.isNotEmpty) { if (state.educationalBackground.isNotEmpty) {
return ListView.builder( return ListView.builder(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -182,54 +203,91 @@ class EducationScreen extends StatelessWidget {
decoration: box1(), decoration: box1(),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8), horizontal: 12, vertical: 8),
child: Row( child: Column(
children: [ children: [
Expanded( Row(
child: Column( children: [
mainAxisAlignment: Expanded(
MainAxisAlignment.start, child: Column(
crossAxisAlignment: mainAxisAlignment:
CrossAxisAlignment MainAxisAlignment
.start, .start,
children: [ crossAxisAlignment:
Row( CrossAxisAlignment
.start,
children: [ children: [
Expanded( Row(
child: Text(level, children: [
style: Theme.of( Expanded(
context) child: Text(
.textTheme level,
.titleSmall!)), style: Theme.of(
context)
.textTheme
.titleSmall!)),
Text(
"$periodFrom - $periodTo",
style: Theme.of(
context)
.textTheme
.bodyMedium,
),
],
),
const SizedBox(
height: 5,
),
Text( Text(
"$periodFrom - $periodTo", school,
style: Theme.of( style: Theme.of(
context) context)
.textTheme .textTheme
.bodyMedium, .titleMedium!
.copyWith(
color:
primary,
fontWeight:
FontWeight
.w500),
), ),
], Container(
), padding:
const SizedBox( const EdgeInsets
height: 5, .only(
), top: 8),
Text( child: honors
school, .isNotEmpty
style: Theme.of(context) ? Column(
.textTheme mainAxisAlignment:
.titleMedium! MainAxisAlignment
.copyWith( .start,
color: primary, crossAxisAlignment:
fontWeight: CrossAxisAlignment
FontWeight .start,
.w500), children: [
), const SizedBox(
Container( height:
padding: 8,
const EdgeInsets ),
.only(top: 8), const Text(
child: honors " honors: ",
.isNotEmpty style:
? Column( TextStyle(fontWeight: FontWeight.w600),
),
Column(
children: honors
.map((Honor honor) => Text(
"-${honor.name!.trim()}",
style: Theme.of(context).textTheme.labelMedium,
))
.toList(),
),
],
)
: const SizedBox()),
program == null
? const SizedBox()
: Column(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment MainAxisAlignment
.start, .start,
@ -238,104 +296,357 @@ class EducationScreen extends StatelessWidget {
.start, .start,
children: [ children: [
const SizedBox( const SizedBox(
height: 8, height: 5,
),
const Text(
" honors: ",
style: TextStyle(
fontWeight:
FontWeight.w600),
),
Column(
children: honors
.map((Honor honor) => Text(
"-${honor.name!.trim()}",
style: Theme.of(context).textTheme.labelMedium,
))
.toList(),
), ),
Text(
program),
], ],
)
: const SizedBox()),
program == null
? const SizedBox()
: Column(
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
const SizedBox(
height: 5,
), ),
Text(program), ]),
], ),
), AppPopupMenu<int>(
]), offset:
), const Offset(-10, -10),
AppPopupMenu<int>( elevation: 3,
offset: const Offset(-10, -10), onSelected: (value) {
elevation: 3, ////delete -= = = = = = = = =>>
onSelected: (value) { if (value == 2) {
////delete -= = = = = = = = =>> confirmAlert(context,
if (value == 2) { () {
confirmAlert(context, () { final progress =
final progress = ProgressHUD.of(
ProgressHUD.of( context);
context); progress!
progress!.showWithText( .showWithText(
"Loading..."); "Loading...");
context context
.read<EducationBloc>() .read<
.add(DeleteEducation( EducationBloc>()
educationalBackground: .add(DeleteEducation(
state.educationalBackground[ educationalBackground:
index], state.educationalBackground[
profileId: index],
profileId, profileId:
token: token!)); profileId,
}, "Delete?", token:
"Confirm Delete?"); token!));
} }, "Delete?",
if (value == 1) { "Confirm Delete?");
////edit -= = = = = = = = =>> }
final progress = if (value == 1) {
ProgressHUD.of(context); ////edit -= = = = = = = = =>>
progress!.showWithText( final progress =
"Loading..."); ProgressHUD.of(
context context);
.read<EducationBloc>() progress!.showWithText(
.add(ShowEditEducationForm( "Loading...");
profileId: context
profileId, .read<
token: token!, EducationBloc>()
educationalBackground: .add(ShowEditEducationForm(
state.educationalBackground[ profileId:
index])); profileId,
} token: token!,
}, educationalBackground:
menuItems: [ state.educationalBackground[
popMenuItem( index]));
text: "Update", }
value: 1, if (value == 3) {
icon: Icons.edit), showDialog(
popMenuItem( context: context,
text: "Remove", builder:
value: 2, (BuildContext
icon: Icons.delete), context) {
popMenuItem( return AlertDialog(
text: "Attach", contentPadding:
value: 2, const EdgeInsets
icon: Icons.attach_file), .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) {
result = newResult;
}
});
},
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: result == null
? const SizedBox()
: Expanded(
child: ListView.builder(
itemCount: result!.files.length,
itemBuilder: (BuildContext context, index) {
final kb = result!.files[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: result!.files[index].extension!.toLowerCase() == 'pdf'
? SvgPicture.asset(
'assets/svgs/pdf.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: result!.files[index].extension!.toLowerCase() == 'png'
? SvgPicture.asset(
'assets/svgs/png.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: result!.files[index].extension!.toLowerCase() == 'jpg' || result!.files[index].extension!.toLowerCase() == 'jpeg'
? SvgPicture.asset(
'assets/svgs/jpg.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: const SizedBox())),
const SizedBox(
width: 12,
),
Flexible(
flex: 4,
child: Text(
result!.files[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))
],
)),
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) {
for (var res in result!.files) {
paths.add(res.path!);
}
Navigator.pop(context);
parent.read<EducationBloc>().add(AddAttachment(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",
)
], ],
icon: const Icon( ),
Icons.more_vert, ////Show Attachments
color: Colors.grey, SizedBox(
), child: state
tooltip: "Options", .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
SingleAttachment(
onpressed: () {
confirmAlert(
context,
() {},
"Delete?",
"Confirm Delete?");
},
attachment: state
.educationalBackground[
index]
.attachments!
.first,
)
////Multiple Attachments View
: MultipleAttachments(
eligibilityName: state
.educationalBackground[
index]
.education!
.school!
.name!,
attachments: state
.educationalBackground[
index]
.attachments!,
))
], ],
), ),
), ),

View File

@ -1,16 +1,24 @@
import 'dart:io';
import 'package:app_popup_menu/app_popup_menu.dart'; import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:fluttericon/font_awesome_icons.dart'; import 'package:flutter_svg/svg.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart';
import 'package:unit2/model/profile/attachment.dart';
import 'package:unit2/model/profile/eligibility.dart'; import 'package:unit2/model/profile/eligibility.dart';
import 'package:unit2/screens/profile/components/eligibility/add_modal.dart'; import 'package:unit2/screens/profile/components/eligibility/add_modal.dart';
import 'package:unit2/screens/profile/components/eligibility/edit_modal.dart'; import 'package:unit2/screens/profile/components/eligibility/edit_modal.dart';
import 'package:unit2/theme-data.dart/box_shadow.dart'; import 'package:unit2/theme-data.dart/box_shadow.dart';
import 'package:unit2/theme-data.dart/btn-style.dart';
import 'package:unit2/theme-data.dart/colors.dart'; import 'package:unit2/theme-data.dart/colors.dart';
import 'package:unit2/theme-data.dart/form-style.dart';
import 'package:unit2/utils/global.dart'; import 'package:unit2/utils/global.dart';
import 'package:unit2/utils/text_container.dart'; import 'package:unit2/utils/text_container.dart';
import 'package:unit2/widgets/Leadings/add_leading.dart'; import 'package:unit2/widgets/Leadings/add_leading.dart';
@ -19,21 +27,27 @@ import 'package:unit2/widgets/empty_data.dart';
import 'package:unit2/widgets/error_state.dart'; import 'package:unit2/widgets/error_state.dart';
import '../../../bloc/profile/eligibility/eligibility_bloc.dart'; import '../../../bloc/profile/eligibility/eligibility_bloc.dart';
import '../../../utils/alerts.dart'; import '../../../utils/alerts.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
class EligibiltyScreen extends StatelessWidget { class EligibiltyScreen extends StatelessWidget {
const EligibiltyScreen({super.key}); const EligibiltyScreen({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
BuildContext parent = context;
String? token; String? token;
int? profileId; int? profileId;
FilePickerResult? result;
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
return true; return true;
}, },
child: Scaffold( child: Scaffold(
resizeToAvoidBottomInset: true, resizeToAvoidBottomInset: true,
appBar: AppBar( appBar: AppBar(
title: context.watch<EligibilityBloc>().state is AddEligibilityState title: context.watch<EligibilityBloc>().state is AddEligibilityState
? const Text("Add Eligiblity") ? const Text("Add Eligiblity")
@ -42,31 +56,37 @@ class EligibiltyScreen extends StatelessWidget {
: const Text(elibilityScreenTitle), : const Text(elibilityScreenTitle),
centerTitle: true, centerTitle: true,
backgroundColor: primary, backgroundColor: primary,
actions: (context.watch<EligibilityBloc>().state is EligibilityLoaded) actions:
(context.watch<EligibilityBloc>().state is EligibilityLoaded)
? [ ? [
AddLeading(onPressed: () { AddLeading(onPressed: () {
context context
.read<EligibilityBloc>() .read<EligibilityBloc>()
.add(ShowAddEligibilityForm()); .add(ShowAddEligibilityForm());
}) })
] ]
:(context.watch<EligibilityBloc>().state is AddEligibilityState || context.watch<EligibilityBloc>().state is EditEligibilityState)? [ : (context.watch<EligibilityBloc>().state
CloseLeading(onPressed: () { is AddEligibilityState ||
context.read<EligibilityBloc>().add(const LoadEligibility()); context.watch<EligibilityBloc>().state
}) is EditEligibilityState)
]:[], ? [
CloseLeading(onPressed: () {
context
.read<EligibilityBloc>()
.add(const LoadEligibility());
})
]
: [],
), ),
body: BlocBuilder<UserBloc, UserState>( body: BlocBuilder<UserBloc, UserState>(
builder: (context, state) { builder: (context, state) {
if (state is UserLoggedIn) { if (state is UserLoggedIn) {
token = state.userData!.user!.login!.token; token = state.userData!.user!.login!.token;
profileId = profileId = state.userData!.user!.login!.user!.profileId;
state.userData!.user!.login!.user!.profileId;
return BlocBuilder<ProfileBloc, ProfileState>( return BlocBuilder<ProfileBloc, ProfileState>(
builder: (context, state) { builder: (context, state) {
if(state is ProfileLoaded){ if (state is ProfileLoaded) {
return ProgressHUD( return ProgressHUD(
padding: const EdgeInsets.all(24), padding: const EdgeInsets.all(24),
indicatorWidget: const SpinKitFadingCircle( indicatorWidget: const SpinKitFadingCircle(
color: Colors.white, color: Colors.white,
@ -84,8 +104,7 @@ class EligibiltyScreen extends StatelessWidget {
state is DeletedState || state is DeletedState ||
state is EligibilityAddedState || state is EligibilityAddedState ||
state is EligibilityEditedState || state is EligibilityEditedState ||
state is EligibilityErrorState state is EligibilityErrorState) {
) {
final progress = ProgressHUD.of(context); final progress = ProgressHUD.of(context);
progress!.dismiss(); progress!.dismiss();
} }
@ -96,15 +115,17 @@ class EligibiltyScreen extends StatelessWidget {
"Eligibility has been deleted successfully", "Eligibility has been deleted successfully",
() { () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} else { } else {
errorAlert(context, "Deletion Failed", errorAlert(context, "Deletion Failed",
"Error deleting eligibility", () { "Error deleting eligibility", () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} }
} }
@ -114,16 +135,18 @@ class EligibiltyScreen extends StatelessWidget {
successAlert(context, "Adding Successfull!", successAlert(context, "Adding Successfull!",
state.response['message'], () { state.response['message'], () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} else { } else {
errorAlert(context, "Adding Failed", errorAlert(context, "Adding Failed",
"Something went wrong. Please try again.", "Something went wrong. Please try again.",
() { () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} }
} }
@ -133,16 +156,18 @@ class EligibiltyScreen extends StatelessWidget {
successAlert(context, "Update Successfull!", successAlert(context, "Update Successfull!",
state.response['message'], () { state.response['message'], () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} else { } else {
errorAlert(context, "Update Failed", errorAlert(context, "Update Failed",
"Something went wrong. Please try again.", "Something went wrong. Please try again.",
() { () {
Navigator.of(context).pop(); Navigator.of(context).pop();
context.read<EligibilityBloc>().add(const LoadEligibility( context
)); .read<EligibilityBloc>()
.add(const LoadEligibility());
}); });
} }
} }
@ -151,7 +176,11 @@ class EligibiltyScreen extends StatelessWidget {
return BlocBuilder<EligibilityBloc, EligibilityState>( return BlocBuilder<EligibilityBloc, EligibilityState>(
builder: (context, state) { builder: (context, state) {
if (state is EligibilityLoaded) { if (state is EligibilityLoaded) {
for (var cat in state.attachmentCategory) {
if (cat.subclass.id == 3) {
attachmentCategories.add(cat);
}
}
if (state.eligibilities.isNotEmpty) { if (state.eligibilities.isNotEmpty) {
return ListView.builder( return ListView.builder(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -164,6 +193,7 @@ class EligibiltyScreen extends StatelessWidget {
.eligibility! .eligibility!
.title; .title;
return Column( return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.start, MainAxisAlignment.start,
crossAxisAlignment: crossAxisAlignment:
@ -180,6 +210,8 @@ class EligibiltyScreen extends StatelessWidget {
children: [ children: [
Expanded( Expanded(
child: Column( child: Column(
mainAxisSize:
MainAxisSize.min,
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment MainAxisAlignment
.start, .start,
@ -196,9 +228,10 @@ class EligibiltyScreen extends StatelessWidget {
.copyWith( .copyWith(
fontWeight: fontWeight:
FontWeight FontWeight
.w500,color: primary), .w500,
color:
primary),
), ),
const SizedBox( const SizedBox(
height: 5, height: 5,
), ),
@ -212,11 +245,52 @@ class EligibiltyScreen extends StatelessWidget {
height: 3, height: 3,
), ),
Text( Text(
"Rating : ${state.eligibilities[index].rating ?? 'N/A'}.", "Rating : ${state.eligibilities[index].rating ?? 'N/A'}",
style: Theme.of( style: Theme.of(
context) context)
.textTheme .textTheme
.titleSmall) .titleSmall),
const Divider(),
////Show Attachments
SizedBox(
child: state.eligibilities[index].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(DeleteAttachment(attachment: state.eligibilities[index].attachments!.first, moduleId: state.eligibilities[index].attachments!.first.id.toString(), profileId: profileId.toString(), token: token!));
}, "Delete?",
"Confirm Delete?");
},
attachment: state
.eligibilities[index]
.attachments!
.first,
)
////Multiple Attachments View
: MultipleAttachments(
eligibilityName: state
.eligibilities[index]
.eligibility!
.title,
attachments: state
.eligibilities[index]
.attachments!,
))
]), ]),
), ),
AppPopupMenu<int>( AppPopupMenu<int>(
@ -224,29 +298,27 @@ class EligibiltyScreen extends StatelessWidget {
const Offset(-10, -10), const Offset(-10, -10),
elevation: 3, elevation: 3,
onSelected: (value) { onSelected: (value) {
////delete eligibilty-= = = = = = = = =>> ////delete eligibilty-= = = = = = = = =>>
if (value == 2) { if (value == 2) {
confirmAlert(context, confirmAlert(context,
() { () {
final progress = final progress =
ProgressHUD.of( ProgressHUD.of(
context); context);
progress!.showWithText( progress!
"Loading..."); .showWithText(
"Loading...");
BlocProvider.of< BlocProvider.of<
EligibilityBloc>( EligibilityBloc>(
context) context)
.add(DeleteEligibility( .add(DeleteEligibility(
eligibilityId: state eligibilityId: state
.eligibilities[ .eligibilities[
index] index]
.id!, .id!,
profileId: profileId:
profileId.toString(), profileId
.toString(),
token: token:
token!)); token!));
}, "Delete?", }, "Delete?",
@ -254,11 +326,11 @@ class EligibiltyScreen extends StatelessWidget {
} }
if (value == 1) { if (value == 1) {
////edit eligibilty-= = = = = = = = =>> ////edit eligibilty-= = = = = = = = =>>
final progress = final progress =
ProgressHUD.of( ProgressHUD.of(
context); context);
progress!.showWithText( progress!.showWithText(
"Loading..."); "Loading...");
EligibityCert EligibityCert
eligibityCert = eligibityCert =
state.eligibilities[ state.eligibilities[
@ -278,27 +350,247 @@ class EligibiltyScreen extends StatelessWidget {
overseas; overseas;
context context
.read<EligibilityBloc>() .read<
EligibilityBloc>()
.add(ShowEditEligibilityForm( .add(ShowEditEligibilityForm(
eligibityCert: eligibityCert:
eligibityCert)); eligibityCert));
} }
}, ////Attachment
menuItems: [ if (value == 3) {
popMenuItem( showDialog(
text: "Update", context: context,
value: 1, builder:
icon: Icons.edit), (BuildContext
popMenuItem( context) {
text: "Remove", return AlertDialog(
value: 2, contentPadding:
icon: Icons.delete), const EdgeInsets
popMenuItem( .all(0),
text: "Attach", backgroundColor:
value: 2, Colors.grey
icon: Icons.attach_file), .shade100,
icon:
const Icon(
Icons
.file_copy,
size: 32,
color:
primary,
),
title: const Text(
"File Attachment:"),
content: StatefulBuilder(
builder:
(context,
setState) {
return Padding(
padding: const EdgeInsets
.all(
16.0),
child: Column(
mainAxisSize:
MainAxisSize
.min,
mainAxisAlignment:
MainAxisAlignment
.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const Divider(),
Text(
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(() {
if (newResult != null) {
result = newResult;
}
});
},
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: result == null
? const SizedBox()
: Expanded(
child: ListView.builder(
itemCount: result!.files.length,
itemBuilder: (BuildContext context, index) {
final kb = result!.files[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: result!.files[index].extension!.toLowerCase() == 'pdf'
? SvgPicture.asset(
'assets/svgs/pdf.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: result!.files[index].extension!.toLowerCase() == 'png'
? SvgPicture.asset(
'assets/svgs/png.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: result!.files[index].extension!.toLowerCase() == 'jpg' || result!.files[index].extension!.toLowerCase() == 'jpeg'
? SvgPicture.asset(
'assets/svgs/jpg.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: const SizedBox())),
const SizedBox(
width: 12,
),
Flexible(
flex: 4,
child: Text(
result!.files[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))
],
)),
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) {
for (var res in result!.files) {
paths.add(res.path!);
}
Navigator.pop(context);
parent.read<EligibilityBloc>().add(AddAttachment(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( icon: const Icon(
Icons.more_vert, Icons.more_vert,
color: Colors.grey, color: Colors.grey,
@ -310,7 +602,7 @@ class EligibiltyScreen extends StatelessWidget {
), ),
const SizedBox( const SizedBox(
height: 5, height: 5,
) ),
], ],
); );
}); });
@ -322,17 +614,25 @@ class EligibiltyScreen extends StatelessWidget {
} }
if (state is EditEligibilityState) { if (state is EditEligibilityState) {
return EditEligibilityScreen( return EditEligibilityScreen(
profileId: profileId!, profileId: profileId!,
token: token!, token: token!,
eligibityCert: state.eligibityCert); eligibityCert: state.eligibityCert);
} }
if (state is AddEligibilityState) { if (state is AddEligibilityState) {
return AddEligibilityScreen(token: token!,profileId: profileId!,); return AddEligibilityScreen(
token: token!,
profileId: profileId!,
);
} }
if (state is EligibilityErrorState) { if (state is EligibilityErrorState) {
return SomethingWentWrong(message: state.message, onpressed: (){ return SomethingWentWrong(
context.read<EligibilityBloc>().add(GetEligibilities(token: token!,profileId: profileId!)); message: state.message,
}); onpressed: () {
context.read<EligibilityBloc>().add(
GetEligibilities(
token: token!,
profileId: profileId!));
});
} }
return Container( return Container(
color: Colors.grey.shade200, color: Colors.grey.shade200,
@ -342,11 +642,9 @@ class EligibiltyScreen extends StatelessWidget {
}, },
), ),
); );
}
return Container();
} }
); return Container();
});
} }
return Container(); return Container();
}, },

View File

@ -1,11 +1,15 @@
import 'package:app_popup_menu/app_popup_menu.dart'; import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart'; import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/src/widgets/placeholder.dart'; import 'package:flutter/src/widgets/placeholder.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_svg/svg.dart';
import 'package:fluttericon/font_awesome_icons.dart'; import 'package:fluttericon/font_awesome_icons.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart';
@ -19,8 +23,13 @@ import 'package:unit2/widgets/Leadings/add_leading.dart';
import 'package:unit2/widgets/empty_data.dart'; import 'package:unit2/widgets/empty_data.dart';
import 'package:unit2/widgets/error_state.dart'; import 'package:unit2/widgets/error_state.dart';
import '../../../bloc/profile/learningDevelopment/learning_development_bloc.dart'; import '../../../bloc/profile/learningDevelopment/learning_development_bloc.dart';
import '../../../model/profile/attachment.dart';
import '../../../theme-data.dart/btn-style.dart';
import '../../../theme-data.dart/form-style.dart';
import '../../../utils/alerts.dart'; import '../../../utils/alerts.dart';
import '../../../widgets/Leadings/close_leading.dart'; import '../../../widgets/Leadings/close_leading.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
import 'learning_development/add_modal.dart'; import 'learning_development/add_modal.dart';
class LearningAndDevelopmentScreen extends StatelessWidget { class LearningAndDevelopmentScreen extends StatelessWidget {
@ -32,7 +41,11 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
String token; String token;
int profileId; int profileId;
BuildContext parent = context;
DateFormat dteFormat2 = DateFormat.yMMMMd('en_US'); DateFormat dteFormat2 = DateFormat.yMMMMd('en_US');
FilePickerResult? result;
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: context.watch<LearningDevelopmentBloc>().state title: context.watch<LearningDevelopmentBloc>().state
@ -167,9 +180,13 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
// TODO: implement listener // TODO: implement listener
}, },
builder: (context, state) { builder: (context, state) {
print(state);
if (state is LearningDevelopmentLoadedState) {
if (state is LearningDevelopmentLoadedState) {
for (var cat in state.attachmentCategory) {
if (cat.subclass.id == 2) {
attachmentCategories.add(cat);
}
}
if (state.learningsAndDevelopment.isNotEmpty) { if (state.learningsAndDevelopment.isNotEmpty) {
return ListView.builder( return ListView.builder(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -208,140 +225,403 @@ class LearningAndDevelopmentScreen extends StatelessWidget {
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8), horizontal: 12, vertical: 8),
width: screenWidth, width: screenWidth,
child: Row( child: Column(
children: [ children: [
Expanded( Row(
child: Column( children: [
mainAxisAlignment: Expanded(
MainAxisAlignment.start, child: Column(
crossAxisAlignment: mainAxisAlignment:
CrossAxisAlignment MainAxisAlignment.start,
.start, crossAxisAlignment:
children: [ CrossAxisAlignment
Text( .start,
training, children: [
style: Theme.of(context) Text(
.textTheme training,
.titleMedium! style: Theme.of(context)
.copyWith( .textTheme
fontWeight: .titleMedium!
FontWeight .copyWith(
.w600, fontWeight:
color: primary), FontWeight
), .w600,
const SizedBox( color: primary),
height: 8, ),
), const SizedBox(
Text( height: 8,
provider, ),
style: Theme.of(context) Text(
.textTheme provider,
.titleSmall, style: Theme.of(context)
), .textTheme
const SizedBox( .titleSmall,
height: 5, ),
), const SizedBox(
Text( height: 5,
"$duration: $start to $end", ),
style: Theme.of(context) Text(
.textTheme "$duration: $start to $end",
.labelMedium, style: Theme.of(context)
), .textTheme
const SizedBox( .labelMedium,
height: 5, ),
), const SizedBox(
]), height: 5,
), ),
AppPopupMenu<int>( ]),
offset: const Offset(-10, -10), ),
elevation: 3, AppPopupMenu<int>(
onSelected: (value) { offset: const Offset(-10, -10),
////delete -= = = = = = = = =>> elevation: 3,
if (value == 2) { onSelected: (value) {
confirmAlert(context, () { ////delete -= = = = = = = = =>>
final progress = if (value == 2) {
ProgressHUD.of( confirmAlert(context, () {
context); final progress =
progress!.showWithText( ProgressHUD.of(
"Loading..."); context);
BlocProvider.of< progress!.showWithText(
LearningDevelopmentBloc>( "Loading...");
context) BlocProvider.of<
.add(DeleteLearningDevelopment( LearningDevelopmentBloc>(
trainingId: state context)
.learningsAndDevelopment[ .add(DeleteLearningDevelopment(
index] trainingId: state
.conductedTraining! .learningsAndDevelopment[
.id!, index]
hours: state .conductedTraining!
.learningsAndDevelopment[ .id!,
index] hours: state
.conductedTraining! .learningsAndDevelopment[
.totalHours!, index]
sponsorId: state .conductedTraining!
.learningsAndDevelopment[ .totalHours!,
index] sponsorId: state
.sponsoredBy .learningsAndDevelopment[
?.id, index]
profileId: .sponsoredBy
profileId, ?.id,
token: token)); profileId:
}, "Delete?", profileId,
"Confirm Delete?"); token: token));
} }, "Delete?",
if (value == 1) { "Confirm Delete?");
bool isOverseas; }
////edit = = = = = = = =>> if (value == 1) {
final progress = bool isOverseas;
ProgressHUD.of(context); ////edit = = = = = = = =>>
progress!.showWithText( final progress =
"Loading..."); ProgressHUD.of(context);
progress!.showWithText(
"Loading...");
if (state if (state
.learningsAndDevelopment[ .learningsAndDevelopment[
index] index]
.conductedTraining .conductedTraining
?.venue ?.venue
?.cityMunicipality == ?.cityMunicipality ==
null) { null) {
isOverseas = true; isOverseas = true;
} else { } else {
isOverseas = false; isOverseas = false;
} }
context context
.read< .read<
LearningDevelopmentBloc>() LearningDevelopmentBloc>()
.add(ShowEditLearningDevelopmentForm( .add(ShowEditLearningDevelopmentForm(
profileId: profileId:
profileId, profileId,
token: token, token: token,
learningDevelopment: learningDevelopment:
state.learningsAndDevelopment[ state.learningsAndDevelopment[
index], index],
isOverseas: isOverseas:
isOverseas)); isOverseas));
} }
}, if(value == 3){
menuItems: [ showDialog(
popMenuItem( context: context,
text: "Update", builder:
value: 1, (BuildContext
icon: Icons.edit), context) {
popMenuItem( return AlertDialog(
text: "Remove", contentPadding:
value: 2, const EdgeInsets
icon: Icons.delete), .all(0),
popMenuItem( backgroundColor:
text: "Attach", Colors.grey
value: 2, .shade100,
icon: Icons.attach_file), 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) {
result = newResult;
}
});
},
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: result == null
? const SizedBox()
: Expanded(
child: ListView.builder(
itemCount: result!.files.length,
itemBuilder: (BuildContext context, index) {
final kb = result!.files[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: result!.files[index].extension!.toLowerCase() == 'pdf'
? SvgPicture.asset(
'assets/svgs/pdf.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: result!.files[index].extension!.toLowerCase() == 'png'
? SvgPicture.asset(
'assets/svgs/png.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: result!.files[index].extension!.toLowerCase() == 'jpg' || result!.files[index].extension!.toLowerCase() == 'jpeg'
? SvgPicture.asset(
'assets/svgs/jpg.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: const SizedBox())),
const SizedBox(
width: 12,
),
Flexible(
flex: 4,
child: Text(
result!.files[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))
],
)),
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) {
for (var res in result!.files) {
paths.add(res.path!);
}
Navigator.pop(context);
parent.read<LearningDevelopmentBloc>().add(AddAttachment(attachmentModule: state.learningsAndDevelopment[index].conductedTraining!.id.toString(), filePaths: paths, categoryId: selectedAttachmentCategory!.id.toString(), token: token!, profileId: profileId.toString()));
}
},
child: const Text("Submit")),
)
]),
);
}),
);
});
}
},
menuItems: [
popMenuItem(
text: "Update",
value: 1,
icon: Icons.edit),
popMenuItem(
text: "Remove",
value: 2,
icon: Icons.delete),
popMenuItem(
text: "Attach",
value: 3,
icon: Icons.attach_file),
],
icon: const Icon(
Icons.more_vert,
color: Colors.grey,
),
tooltip: "Options",
)
], ],
icon: const Icon( ),
Icons.more_vert, SizedBox(
color: Colors.grey, child: state.learningsAndDevelopment[index].attachments ==
), null ||
tooltip: "Options", 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,
() {
}, "Delete?",
"Confirm Delete?");
},
attachment: state
.learningsAndDevelopment[index]
.attachments!
.first,
)
////Multiple Attachments View
: MultipleAttachments(
eligibilityName: state
.learningsAndDevelopment[index]
.conductedTraining!.title!.title!,
attachments: state
.learningsAndDevelopment[index]
.attachments!,
))
], ],
), ),
), ),

View File

@ -1,10 +1,14 @@
import 'dart:io'; import 'dart:io';
import 'package:app_popup_menu/app_popup_menu.dart'; import 'package:app_popup_menu/app_popup_menu.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_progress_hud/flutter_progress_hud.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_svg/svg.dart';
import 'package:fluttericon/font_awesome_icons.dart'; import 'package:fluttericon/font_awesome_icons.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:unit2/bloc/profile/profile_bloc.dart'; import 'package:unit2/bloc/profile/profile_bloc.dart';
import 'package:unit2/bloc/user/user_bloc.dart'; import 'package:unit2/bloc/user/user_bloc.dart';
@ -19,9 +23,14 @@ import 'package:unit2/widgets/empty_data.dart';
import 'package:unit2/widgets/error_state.dart'; import 'package:unit2/widgets/error_state.dart';
import '../../../bloc/profile/workHistory/workHistory_bloc.dart'; import '../../../bloc/profile/workHistory/workHistory_bloc.dart';
import '../../../model/profile/attachment.dart';
import '../../../model/profile/work_history.dart'; import '../../../model/profile/work_history.dart';
import '../../../theme-data.dart/btn-style.dart';
import '../../../theme-data.dart/form-style.dart';
import '../../../utils/alerts.dart'; import '../../../utils/alerts.dart';
import '../../../utils/global.dart'; import '../../../utils/global.dart';
import '../shared/multiple_attachment.dart';
import '../shared/single_attachment.dart';
class WorkHistoryScreen extends StatelessWidget { class WorkHistoryScreen extends StatelessWidget {
const WorkHistoryScreen({super.key}); const WorkHistoryScreen({super.key});
@ -29,8 +38,12 @@ class WorkHistoryScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
DateFormat dteFormat2 = DateFormat.yMMMMd('en_US'); DateFormat dteFormat2 = DateFormat.yMMMMd('en_US');
BuildContext parent = context;
String? token; String? token;
int profileId; int? profileId;
FilePickerResult? result;
AttachmentCategory? selectedAttachmentCategory;
List<AttachmentCategory> attachmentCategories = [];
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: context.watch<WorkHistoryBloc>().state is AddWorkHistoryState title: context.watch<WorkHistoryBloc>().state is AddWorkHistoryState
@ -160,6 +173,11 @@ class WorkHistoryScreen extends StatelessWidget {
}, },
builder: (context, state) { builder: (context, state) {
if (state is WorkHistoryLoaded) { if (state is WorkHistoryLoaded) {
for (var cat in state.attachmentCategory) {
if (cat.subclass.id == 4) {
attachmentCategories.add(cat);
}
}
if (state.workExperiences.isNotEmpty) { if (state.workExperiences.isNotEmpty) {
return ListView.builder( return ListView.builder(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -183,116 +201,421 @@ class WorkHistoryScreen extends StatelessWidget {
.workExperiences[index] .workExperiences[index]
.toDate!); .toDate!);
return Column( return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [ children: [
Container( Container(
width: screenWidth, width: screenWidth,
decoration: box1(), decoration: box1(),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8), horizontal: 12, vertical: 8),
child: Row(children: [ child: Column(
Expanded( children: [
child: Column( Row(children: [
mainAxisAlignment: Expanded(
MainAxisAlignment.start, child: Column(
crossAxisAlignment: mainAxisAlignment:
CrossAxisAlignment.start, MainAxisAlignment.start,
children: [ crossAxisAlignment:
Text( CrossAxisAlignment.start,
position, children: [
style: Theme.of(context) Text(
.textTheme position,
.titleMedium! style: Theme.of(context)
.copyWith( .textTheme
fontWeight: .titleMedium!
FontWeight.w600, .copyWith(
color: primary), fontWeight:
), FontWeight
const SizedBox( .w600,
height: 8, color: primary),
), ),
Text( const SizedBox(
agency, height: 8,
style: Theme.of(context) ),
.textTheme Text(
.titleSmall! agency,
.copyWith( style: Theme.of(context)
fontWeight: .textTheme
FontWeight.w500), .titleSmall!
), .copyWith(
const SizedBox( fontWeight:
height: 5, FontWeight
), .w500),
Text( ),
"$from - $to ", const SizedBox(
style: Theme.of(context) height: 5,
.textTheme ),
.labelMedium, Text(
), "$from - $to ",
], style: Theme.of(context)
)), .textTheme
AppPopupMenu<int>( .labelMedium,
offset: const Offset(-10, -10), ),
elevation: 3, ],
onSelected: (value) { )),
////delete workhistory-= = = = = = = = =>> AppPopupMenu<int>(
if (value == 2) { offset:
confirmAlert(context, () { const Offset(-10, -10),
final progress = elevation: 3,
ProgressHUD.of(context); onSelected: (value) {
progress!.showWithText( ////delete workhistory-= = = = = = = = =>>
"Loading..."); if (value == 2) {
BlocProvider.of< confirmAlert(context, () {
WorkHistoryBloc>( final progress =
context) ProgressHUD.of(
.add(DeleteWorkHistory( context);
profileId: profileId, progress!.showWithText(
token: token!, "Loading...");
workHistory: BlocProvider.of<
state.workExperiences[ WorkHistoryBloc>(
context)
.add(
DeleteWorkHistory(
profileId: profileId!,
token: token!,
workHistory: state
.workExperiences[
index], index],
)); ));
}, "Delete?", }, "Delete?",
"Confirm Delete?"); "Confirm Delete?");
} }
if (value == 1) { if (value == 1) {
////edit eligibilty-= = = = = = = = =>> ////edit eligibilty-= = = = = = = = =>>
final progress = final progress =
ProgressHUD.of(context); ProgressHUD.of(
progress!.showWithText( context);
"Loading..."); progress!.showWithText(
WorkHistory workHistory = "Loading...");
state.workExperiences[ WorkHistory workHistory =
index]; state.workExperiences[
context index];
.read<WorkHistoryBloc>() context
.add( .read<
ShowEditWorkHistoryForm( WorkHistoryBloc>()
.add(ShowEditWorkHistoryForm(
workHistory: workHistory:
workHistory)); workHistory));
} }
}, ////Attachment
menuItems: [ if (value == 3) {
popMenuItem( showDialog(
text: "Update", context: context,
value: 1, builder: (BuildContext
icon: Icons.edit), context) {
popMenuItem( return AlertDialog(
text: "Remove", contentPadding:
value: 2, const EdgeInsets
icon: Icons.delete), .all(0),
popMenuItem( backgroundColor:
text: "Attach", Colors.grey
value: 2, .shade100,
icon: Icons.attach_file), 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) {
result = newResult;
}
});
},
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: result == null
? const SizedBox()
: Expanded(
child: ListView.builder(
itemCount: result!.files.length,
itemBuilder: (BuildContext context, index) {
final kb = result!.files[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: result!.files[index].extension!.toLowerCase() == 'pdf'
? SvgPicture.asset(
'assets/svgs/pdf.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: result!.files[index].extension!.toLowerCase() == 'png'
? SvgPicture.asset(
'assets/svgs/png.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: result!.files[index].extension!.toLowerCase() == 'jpg' || result!.files[index].extension!.toLowerCase() == 'jpeg'
? SvgPicture.asset(
'assets/svgs/jpg.svg',
height: blockSizeVertical * 3,
allowDrawingOutsideViewBox: true,
)
: const SizedBox())),
const SizedBox(
width: 12,
),
Flexible(
flex: 4,
child: Text(
result!.files[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))
],
)),
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) {
icon: const Icon( for (var res in result!.files) {
Icons.more_vert, paths.add(res.path!);
color: Colors.grey, }
), Navigator.pop(context);
tooltip: "Options", parent.read<WorkHistoryBloc>().add(AddAttachment(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,
() {},
"Delete?",
"Confirm Delete?");
},
attachment: state
.workExperiences[
index]
.attachments!
.first,
)
////Multiple Attachments View
: MultipleAttachments(
eligibilityName: state
.workExperiences[
index]
.position!
.title!,
attachments: state
.workExperiences[
index]
.attachments!,
))
],
),
), ),
const SizedBox( const SizedBox(
height: 5, height: 5,
@ -308,13 +631,13 @@ class WorkHistoryScreen extends StatelessWidget {
} }
if (state is AddWorkHistoryState) { if (state is AddWorkHistoryState) {
return AddWorkHistoryScreen( return AddWorkHistoryScreen(
profileId: profileId, profileId: profileId!,
token: token!, token: token!,
); );
} }
if (state is EditWorkHistoryState) { if (state is EditWorkHistoryState) {
return EditWorkHistoryScreen( return EditWorkHistoryScreen(
profileId: profileId, profileId: profileId!,
token: token!, token: token!,
); );
} }
@ -324,7 +647,8 @@ class WorkHistoryScreen extends StatelessWidget {
onpressed: () { onpressed: () {
context.read<WorkHistoryBloc>().add( context.read<WorkHistoryBloc>().add(
GetWorkHistories( GetWorkHistories(
profileId: profileId, token: token!)); profileId: profileId!,
token: token!));
}); });
} }
return Container(); return Container();

View File

@ -0,0 +1,150 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:fluttericon/entypo_icons.dart';
import '../../../model/profile/attachment.dart';
import '../../../theme-data.dart/box_shadow.dart';
import '../../../theme-data.dart/colors.dart';
import '../../../utils/global.dart';
class MultipleAttachments extends StatelessWidget {
final List<Attachment> attachments;
final String eligibilityName;
const MultipleAttachments({
super.key,
required this.attachments,
required this.eligibilityName
});
@override
Widget build(BuildContext context) {
return Row(
children: [
Flexible(
flex:
2,
child: Container(
padding: const EdgeInsets.all(5),
decoration: box1().copyWith(color: Colors.grey.shade300, boxShadow: []),
child: Text(
attachments.first.filename!,
overflow: TextOverflow.ellipsis,
))),
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(
Entypo.right_open_mini,
color: Colors.black87,
),
onPressed: () {},
),
),
const SizedBox(width: 8,),
Flexible(
child: IconButton(
icon: const Icon(
Icons.delete,
color: primary,
),
onPressed: () {},
),
),
],
),
),
],
),
const Divider()
],
);
}).toList(),
));
});
},
child: Row(
children: const [
Text(" See more.."),
Icon(
Icons.keyboard_arrow_right,
color: Colors.black54,
),
],
),
),
),
)),
],
);
}
}

View File

@ -0,0 +1,49 @@
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:
Text(
attachment.filename!,
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(
width:
8,
),
GestureDetector(
onTap:onpressed,
child: const Icon(Icons.delete,color: primary,))
],
));
}
}

View File

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

View File

@ -0,0 +1,77 @@
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('http://${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;
}
}

View File

@ -167,6 +167,9 @@ class Url {
String getServiceTypes() { String getServiceTypes() {
return "/api/jobnet_app/comm_service_type/"; return "/api/jobnet_app/comm_service_type/";
} }
String attachments(){
return "/api/jobnet_app/profile/attachment/";
}
//// address path //// address path
String addressPath() { String addressPath() {
@ -319,4 +322,7 @@ class Url {
String getAddressCategory() { String getAddressCategory() {
return "/api/jobnet_app/address_categories/"; return "/api/jobnet_app/address_categories/";
} }
String attachmentCategories(){
return "/api/jobnet_app/attachment_categories/";
}
} }

View File

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

View File

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