feat: legacy mobile apps created
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
const String getStaffInclusivityInfoSchema = '''
|
||||
query GetPersonalInfo {
|
||||
me {
|
||||
id
|
||||
accessibility {
|
||||
has_car
|
||||
can_relocate
|
||||
requires_accommodations
|
||||
accommodation_details
|
||||
}
|
||||
}
|
||||
}
|
||||
''';
|
||||
|
||||
const String updateStaffInclusivityMutationSchema = '''
|
||||
mutation UpdateStaffAccessibilityInfo(\$input: UpdateStaffAccessibilitiesInput!) {
|
||||
update_staff_accessibilities(input: \$input) {
|
||||
accessibility {
|
||||
requires_accommodations
|
||||
accommodation_details
|
||||
}
|
||||
}
|
||||
}
|
||||
''';
|
||||
@@ -0,0 +1,27 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
@immutable
|
||||
class InclusiveInfoModel {
|
||||
const InclusiveInfoModel({
|
||||
required this.areAccommodationsRequired,
|
||||
required this.accommodationsDetails,
|
||||
});
|
||||
|
||||
factory InclusiveInfoModel.fromJson(Map<String, dynamic> json) {
|
||||
return InclusiveInfoModel(
|
||||
areAccommodationsRequired:
|
||||
json['requires_accommodations'] as bool? ?? false,
|
||||
accommodationsDetails: json['accommodation_details'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
final bool areAccommodationsRequired;
|
||||
final String accommodationsDetails;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'requires_accommodations': areAccommodationsRequired,
|
||||
'accommodation_details': accommodationsDetails,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:krow/core/application/clients/api/api_client.dart';
|
||||
import 'package:krow/features/profile/inclusive/data/gql_shemas.dart';
|
||||
import 'package:krow/features/profile/inclusive/data/models/inclusive_info_model.dart';
|
||||
|
||||
@injectable
|
||||
class StaffInclusivityApiProvider {
|
||||
StaffInclusivityApiProvider(this._client);
|
||||
|
||||
final ApiClient _client;
|
||||
|
||||
Stream<InclusiveInfoModel> getStaffInclusivityInfoWithCache() async* {
|
||||
await for (var response in _client.queryWithCache(
|
||||
schema: getStaffInclusivityInfoSchema,
|
||||
)) {
|
||||
if (response == null || response.data == null) continue;
|
||||
|
||||
if (response.hasException) {
|
||||
throw Exception(response.exception.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
yield InclusiveInfoModel.fromJson(
|
||||
(response.data?['me'] as Map<String, dynamic>?)?['accessibility'] ??
|
||||
{},
|
||||
);
|
||||
} catch (except) {
|
||||
log(
|
||||
'Exception in StaffInclusivityApiProvider '
|
||||
'on getStaffInclusivityInfoWithCache()',
|
||||
error: except,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<InclusiveInfoModel?> updateStaffInclusivityInfoInfo(
|
||||
InclusiveInfoModel data,
|
||||
) async {
|
||||
var result = await _client.mutate(
|
||||
schema: updateStaffInclusivityMutationSchema,
|
||||
body: {
|
||||
'input': data.toJson(),
|
||||
},
|
||||
);
|
||||
|
||||
if (result.hasException) {
|
||||
throw Exception(result.exception.toString());
|
||||
}
|
||||
|
||||
if (result.data == null || result.data!.isEmpty) return null;
|
||||
|
||||
return InclusiveInfoModel.fromJson(
|
||||
(result.data?['update_staff_accessibilities']
|
||||
as Map<String, dynamic>?)?['accessibility'] ??
|
||||
{},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:krow/features/profile/inclusive/data/models/inclusive_info_model.dart';
|
||||
|
||||
abstract class StaffInclusivityRepository {
|
||||
Stream<InclusiveInfoModel> getStaffInclusivityInfo();
|
||||
|
||||
Future<InclusiveInfoModel?> updateStaffMobilityInfo(
|
||||
InclusiveInfoModel data,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:krow/core/application/di/injectable.dart';
|
||||
import 'package:krow/core/data/enums/state_status.dart';
|
||||
import 'package:krow/features/profile/inclusive/data/models/inclusive_info_model.dart';
|
||||
import 'package:krow/features/profile/inclusive/data/staff_inclusivity_repository.dart';
|
||||
|
||||
part 'inclusive_info_event.dart';
|
||||
|
||||
part 'inclusive_info_state.dart';
|
||||
|
||||
class InclusiveInfoBloc extends Bloc<InclusiveInfoEvent, InclusiveInfoState> {
|
||||
InclusiveInfoBloc() : super(const InclusiveInfoState()) {
|
||||
on<InitializeInclusiveInfoEvent>((event, emit) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isInEditMode: event.isInEditMode,
|
||||
status: event.isInEditMode ? StateStatus.loading : StateStatus.idle,
|
||||
),
|
||||
);
|
||||
if (!state.isInEditMode) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
areAccommodationsRequired: true,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await for (final inclusivityData
|
||||
in getIt<StaffInclusivityRepository>().getStaffInclusivityInfo()) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
areAccommodationsRequired:
|
||||
inclusivityData.areAccommodationsRequired,
|
||||
accommodationsDetails: inclusivityData.accommodationsDetails,
|
||||
status: StateStatus.idle,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (except) {
|
||||
log(except.toString());
|
||||
}
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
areAccommodationsRequired: state.areAccommodationsRequired ?? true,
|
||||
status: state.status == StateStatus.loading
|
||||
? StateStatus.idle
|
||||
: state.status,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
on<ToggleRequiresAccommodations>((event, emit) {
|
||||
emit(state.copyWith(areAccommodationsRequired: event.index == 0));
|
||||
});
|
||||
|
||||
on<ChangeAccommodationsDetails>((event, emit) {
|
||||
emit(state.copyWith(accommodationsDetails: event.details));
|
||||
});
|
||||
|
||||
on<SaveInclusiveInfoChanges>((event, emit) async {
|
||||
emit(state.copyWith(status: StateStatus.loading));
|
||||
|
||||
try {
|
||||
await getIt<StaffInclusivityRepository>().updateStaffMobilityInfo(
|
||||
InclusiveInfoModel(
|
||||
areAccommodationsRequired: state.areAccommodationsRequired ?? false,
|
||||
accommodationsDetails: state.accommodationsDetails,
|
||||
),
|
||||
);
|
||||
} catch (except) {
|
||||
emit(state.copyWith(status: StateStatus.idle));
|
||||
|
||||
log(except.toString());
|
||||
}
|
||||
|
||||
emit(state.copyWith(status: StateStatus.success));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
part of 'inclusive_info_bloc.dart';
|
||||
|
||||
@immutable
|
||||
sealed class InclusiveInfoEvent {}
|
||||
|
||||
class InitializeInclusiveInfoEvent extends InclusiveInfoEvent {
|
||||
InitializeInclusiveInfoEvent({required this.isInEditMode});
|
||||
|
||||
final bool isInEditMode;
|
||||
}
|
||||
|
||||
class ToggleRequiresAccommodations extends InclusiveInfoEvent {
|
||||
ToggleRequiresAccommodations(this.index);
|
||||
|
||||
final int index;
|
||||
}
|
||||
|
||||
class ChangeAccommodationsDetails extends InclusiveInfoEvent {
|
||||
ChangeAccommodationsDetails(this.details);
|
||||
|
||||
final String details;
|
||||
}
|
||||
|
||||
class SaveInclusiveInfoChanges extends InclusiveInfoEvent {}
|
||||
@@ -0,0 +1,37 @@
|
||||
part of 'inclusive_info_bloc.dart';
|
||||
|
||||
@immutable
|
||||
class InclusiveInfoState {
|
||||
const InclusiveInfoState({
|
||||
this.areAccommodationsRequired,
|
||||
this.accommodationsDetails = '',
|
||||
this.isInEditMode = true,
|
||||
this.status = StateStatus.idle,
|
||||
});
|
||||
|
||||
final bool? areAccommodationsRequired;
|
||||
final String accommodationsDetails;
|
||||
final bool isInEditMode;
|
||||
final StateStatus status;
|
||||
|
||||
bool get isFilled {
|
||||
return (areAccommodationsRequired != null && !areAccommodationsRequired!) ||
|
||||
accommodationsDetails.isNotEmpty;
|
||||
}
|
||||
|
||||
InclusiveInfoState copyWith({
|
||||
bool? areAccommodationsRequired,
|
||||
String? accommodationsDetails,
|
||||
bool? isInEditMode,
|
||||
StateStatus? status,
|
||||
}) {
|
||||
return InclusiveInfoState(
|
||||
areAccommodationsRequired:
|
||||
areAccommodationsRequired ?? this.areAccommodationsRequired,
|
||||
accommodationsDetails:
|
||||
accommodationsDetails ?? this.accommodationsDetails,
|
||||
isInEditMode: isInEditMode ?? this.isInEditMode,
|
||||
status: status ?? this.status,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:krow/features/profile/inclusive/data/models/inclusive_info_model.dart';
|
||||
import 'package:krow/features/profile/inclusive/data/staff_inclusivity_api_provider.dart';
|
||||
import 'package:krow/features/profile/inclusive/data/staff_inclusivity_repository.dart';
|
||||
|
||||
@Injectable(as: StaffInclusivityRepository)
|
||||
class StaffMobilityRepositoryImpl extends StaffInclusivityRepository {
|
||||
StaffMobilityRepositoryImpl({
|
||||
required StaffInclusivityApiProvider apiProvider,
|
||||
}) : _apiProvider = apiProvider;
|
||||
|
||||
final StaffInclusivityApiProvider _apiProvider;
|
||||
|
||||
@override
|
||||
Stream<InclusiveInfoModel> getStaffInclusivityInfo() {
|
||||
return _apiProvider.getStaffInclusivityInfoWithCache();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<InclusiveInfoModel?> updateStaffMobilityInfo(
|
||||
InclusiveInfoModel data,
|
||||
) {
|
||||
return _apiProvider.updateStaffInclusivityInfoInfo(data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:krow/core/application/common/bool_extension.dart';
|
||||
import 'package:krow/core/application/routing/routes.gr.dart';
|
||||
import 'package:krow/core/data/enums/state_status.dart';
|
||||
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
|
||||
import 'package:krow/core/presentation/styles/theme.dart';
|
||||
import 'package:krow/core/presentation/widgets/scroll_layout_helper.dart';
|
||||
import 'package:krow/core/presentation/widgets/ui_kit/kw_app_bar.dart';
|
||||
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
|
||||
import 'package:krow/core/presentation/widgets/ui_kit/kw_loading_overlay.dart';
|
||||
import 'package:krow/core/presentation/widgets/ui_kit/kw_option_selector.dart';
|
||||
import 'package:krow/features/profile/inclusive/domain/bloc/inclusive_info_bloc.dart';
|
||||
import 'package:krow/features/profile/inclusive/presentation/widgets/accessibility_details_widget.dart';
|
||||
|
||||
@RoutePage()
|
||||
class InclusiveScreen extends StatelessWidget implements AutoRouteWrapper {
|
||||
const InclusiveScreen({
|
||||
super.key,
|
||||
this.isInEditMode = true,
|
||||
});
|
||||
|
||||
final bool isInEditMode;
|
||||
|
||||
@override
|
||||
Widget wrappedRoute(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => InclusiveInfoBloc()
|
||||
..add(InitializeInclusiveInfoEvent(isInEditMode: isInEditMode)),
|
||||
child: this,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: KwAppBar(
|
||||
titleText: 'inclusive'.tr(),
|
||||
showNotification: false,
|
||||
),
|
||||
body: ScrollLayoutHelper(
|
||||
padding: const EdgeInsets.all(16),
|
||||
upperWidget: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Gap(4),
|
||||
Text(
|
||||
'inclusive_information'.tr(),
|
||||
style: AppTextStyles.headingH1,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'providing_optional_information'.tr(),
|
||||
style: AppTextStyles.bodyMediumReg.copyWith(
|
||||
color: AppColors.blackGray,
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16, top: 24),
|
||||
child: Text(
|
||||
'specific_accommodations_question'.tr(),
|
||||
style: AppTextStyles.headingH3,
|
||||
),
|
||||
),
|
||||
BlocSelector<InclusiveInfoBloc, InclusiveInfoState, bool?>(
|
||||
selector: (state) => state.areAccommodationsRequired,
|
||||
builder: (context, areAccommodationsRequired) {
|
||||
return KwOptionSelector(
|
||||
selectedIndex: areAccommodationsRequired?.toInt(),
|
||||
selectedColor: AppColors.blackDarkBgBody,
|
||||
itemBorder: const Border.fromBorderSide(
|
||||
BorderSide(color: AppColors.grayStroke),
|
||||
),
|
||||
items: ['yes'.tr(), 'no'.tr()],
|
||||
onChanged: (index) {
|
||||
context
|
||||
.read<InclusiveInfoBloc>()
|
||||
.add(ToggleRequiresAccommodations(index));
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
const Gap(16),
|
||||
const AccessibilityDetailsWidget(),
|
||||
const Gap(90),
|
||||
],
|
||||
),
|
||||
lowerWidget: BlocConsumer<InclusiveInfoBloc, InclusiveInfoState>(
|
||||
buildWhen: (previous, current) =>
|
||||
previous.status != current.status ||
|
||||
previous.isFilled != current.isFilled,
|
||||
listenWhen: (previous, current) => previous.status != current.status,
|
||||
listener: (context, state) {
|
||||
if (state.status == StateStatus.success) {
|
||||
if (isInEditMode) {
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
context.router.push(
|
||||
AddressRoute(isInEditMode: false),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
return KwLoadingOverlay(
|
||||
shouldShowLoading: state.status == StateStatus.loading,
|
||||
child: KwButton.primary(
|
||||
label: isInEditMode ? 'save_changes'.tr() : 'save_and_continue'.tr(),
|
||||
height: 52,
|
||||
disabled: !state.isFilled,
|
||||
onPressed: () {
|
||||
context
|
||||
.read<InclusiveInfoBloc>()
|
||||
.add(SaveInclusiveInfoChanges());
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:krow/core/data/enums/state_status.dart';
|
||||
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
|
||||
import 'package:krow/core/presentation/styles/theme.dart';
|
||||
import 'package:krow/core/presentation/widgets/ui_kit/kw_input.dart';
|
||||
import 'package:krow/features/profile/inclusive/domain/bloc/inclusive_info_bloc.dart';
|
||||
|
||||
class AccessibilityDetailsWidget extends StatefulWidget {
|
||||
const AccessibilityDetailsWidget({super.key});
|
||||
|
||||
@override
|
||||
State<AccessibilityDetailsWidget> createState() =>
|
||||
_AccessibilityDetailsWidgetState();
|
||||
}
|
||||
|
||||
class _AccessibilityDetailsWidgetState
|
||||
extends State<AccessibilityDetailsWidget> {
|
||||
final _controller = TextEditingController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocConsumer<InclusiveInfoBloc, InclusiveInfoState>(
|
||||
buildWhen: (previous, current) =>
|
||||
previous.areAccommodationsRequired !=
|
||||
current.areAccommodationsRequired ||
|
||||
previous.status != current.status,
|
||||
listenWhen: (previous, current) => previous.status != current.status,
|
||||
listener: (context, state) {
|
||||
_controller.text = state.accommodationsDetails;
|
||||
},
|
||||
builder: (context, state) {
|
||||
return AnimatedOpacity(
|
||||
opacity: state.areAccommodationsRequired ?? false ? 1 : 0,
|
||||
duration: Durations.medium2,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'describe_accommodations'.tr(),
|
||||
style: AppTextStyles.bodyMediumReg.copyWith(
|
||||
color: AppColors.blackGray,
|
||||
),
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
const Gap(16),
|
||||
KwTextInput(
|
||||
enabled: state.areAccommodationsRequired ?? false,
|
||||
controller: _controller,
|
||||
minHeight: 160,
|
||||
maxLength: 300,
|
||||
showCounter: true,
|
||||
radius: 12,
|
||||
title: 'additional_details'.tr(),
|
||||
hintText: 'enter_main_text'.tr(),
|
||||
showError: state.status == StateStatus.error,
|
||||
helperText: state.status == StateStatus.error
|
||||
? 'required_to_fill'.tr()
|
||||
: null,
|
||||
onChanged: (details) {
|
||||
context
|
||||
.read<InclusiveInfoBloc>()
|
||||
.add(ChangeAccommodationsDetails(details));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user