feat: Implement emergency contact management feature with UI and BLoC integration

This commit is contained in:
Achintha Isuru
2026-01-24 20:40:02 -05:00
parent caaf972349
commit c124111f46
25 changed files with 819 additions and 29 deletions

View File

@@ -42,4 +42,27 @@ class ProfileRepositoryMock {
// Simulate processing delay
await Future.delayed(const Duration(milliseconds: 300));
}
/// Fetches emergency contacts for the given staff ID.
///
/// Returns a list of [EmergencyContact].
Future<List<EmergencyContact>> getEmergencyContacts(String staffId) async {
await Future.delayed(const Duration(milliseconds: 500));
return [
const EmergencyContact(
name: 'Jane Doe',
phone: '555-987-6543',
relationship: 'Family',
),
];
}
/// Saves emergency contacts for the given staff ID.
Future<void> saveEmergencyContacts(
String staffId,
List<EmergencyContact> contacts,
) async {
await Future.delayed(const Duration(seconds: 1));
// Simulate save
}
}

View File

@@ -13,7 +13,7 @@ extension ProfileNavigator on IModularNavigator {
/// Navigates to the emergency contact page.
void pushEmergencyContact() {
pushNamed('/profile/onboarding/emergency-contact');
pushNamed('./emergency-contact');
}
/// Navigates to the experience page.

View File

@@ -1,13 +0,0 @@
import 'package:flutter/material.dart';
/// NOTE: This is a TEMPORARY class to allow the prototype code to compile
/// without immediate design system integration.
/// It will be replaced by the actual Design System tokens (UiColors) in Step 4.
class AppColors {
static const Color krowBackground = Color(0xFFF9F9F9);
static const Color krowBlue = Color(0xFF0055FF);
static const Color krowYellow = Color(0xFFFFCC00);
static const Color krowBorder = Color(0xFFE0E0E0);
static const Color krowCharcoal = Color(0xFF333333);
static const Color krowMuted = Color(0xFF808080);
}

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:staff_profile_info/staff_profile_info.dart';
import 'package:staff_emergency_contact/staff_emergency_contact.dart';
import 'data/repositories/profile_repository_impl.dart';
import 'domain/repositories/profile_repository.dart';
@@ -53,5 +54,6 @@ class StaffProfileModule extends Module {
void routes(RouteManager r) {
r.child('/', child: (BuildContext context) => const StaffProfilePage());
r.module('/onboarding', module: StaffProfileInfoModule());
r.module('/emergency-contact', module: StaffEmergencyContactModule());
}
}

View File

@@ -32,6 +32,8 @@ dependencies:
# Feature Packages
staff_profile_info:
path: ../profile_sections/onboarding/profile_info
staff_emergency_contact:
path: ../profile_sections/onboarding/emergency_contact
dev_dependencies:
flutter_test:

View File

@@ -0,0 +1,5 @@
# include: package:flutter_lints/flutter.yaml
linter:
rules:
public_member_api_docs: false

View File

@@ -0,0 +1,25 @@
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../domain/repositories/emergency_contact_repository_interface.dart';
/// Implementation of [EmergencyContactRepositoryInterface].
///
/// This repository delegates data operations to the [ProfileRepositoryMock]
/// (or real implementation) from the `data_connect` package.
class EmergencyContactRepositoryImpl
implements EmergencyContactRepositoryInterface {
final ProfileRepositoryMock _profileRepository;
/// Creates an [EmergencyContactRepositoryImpl].
EmergencyContactRepositoryImpl(this._profileRepository);
@override
Future<List<EmergencyContact>> getContacts(String staffId) {
return _profileRepository.getEmergencyContacts(staffId);
}
@override
Future<void> saveContacts(String staffId, List<EmergencyContact> contacts) {
return _profileRepository.saveEmergencyContacts(staffId, contacts);
}
}

View File

@@ -0,0 +1,13 @@
import 'package:krow_core/core.dart';
/// Arguments for getting emergency contacts use case.
class GetEmergencyContactsArguments extends UseCaseArgument {
/// The ID of the staff member.
final String staffId;
/// Creates a [GetEmergencyContactsArguments].
const GetEmergencyContactsArguments({required this.staffId});
@override
List<Object?> get props => [staffId];
}

View File

@@ -0,0 +1,20 @@
import 'package:krow_core/core.dart';
import 'package:krow_domain/krow_domain.dart';
/// Arguments for saving emergency contacts use case.
class SaveEmergencyContactsArguments extends UseCaseArgument {
/// The ID of the staff member.
final String staffId;
/// The list of contacts to save.
final List<EmergencyContact> contacts;
/// Creates a [SaveEmergencyContactsArguments].
const SaveEmergencyContactsArguments({
required this.staffId,
required this.contacts,
});
@override
List<Object?> get props => [staffId, contacts];
}

View File

@@ -0,0 +1,26 @@
import 'package:krow_domain/krow_domain.dart';
/// Extensions for [EmergencyContact] to support UI operations.
extension EmergencyContactExtensions on EmergencyContact {
/// returns a copy of this [EmergencyContact] with the given fields replaced.
EmergencyContact copyWith({
String? name,
String? phone,
String? relationship,
}) {
return EmergencyContact(
name: name ?? this.name,
phone: phone ?? this.phone,
relationship: relationship ?? this.relationship,
);
}
/// Returns an empty [EmergencyContact].
static EmergencyContact empty() {
return const EmergencyContact(
name: '',
phone: '',
relationship: 'family',
);
}
}

View File

@@ -0,0 +1,13 @@
import 'package:krow_domain/krow_domain.dart';
/// Repository interface for managing emergency contacts.
///
/// This interface defines the contract for fetching and saving emergency contact information.
/// It must be implemented by the data layer.
abstract class EmergencyContactRepositoryInterface {
/// Retrieves the list of emergency contacts.
Future<List<EmergencyContact>> getContacts(String staffId);
/// Saves the list of emergency contacts.
Future<void> saveContacts(String staffId, List<EmergencyContact> contacts);
}

View File

@@ -0,0 +1,21 @@
import 'package:krow_core/core.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../domain/arguments/get_emergency_contacts_arguments.dart';
import '../../domain/repositories/emergency_contact_repository_interface.dart';
/// Use case for retrieving emergency contacts.
///
/// This use case encapsulates the business logic for fetching emergency contacts
/// for a specific staff member.
class GetEmergencyContactsUseCase
extends UseCase<GetEmergencyContactsArguments, List<EmergencyContact>> {
final EmergencyContactRepositoryInterface _repository;
/// Creates a [GetEmergencyContactsUseCase].
GetEmergencyContactsUseCase(this._repository);
@override
Future<List<EmergencyContact>> call(GetEmergencyContactsArguments params) {
return _repository.getContacts(params.staffId);
}
}

View File

@@ -0,0 +1,20 @@
import 'package:krow_core/core.dart';
import '../arguments/save_emergency_contacts_arguments.dart';
import '../repositories/emergency_contact_repository_interface.dart';
/// Use case for saving emergency contacts.
///
/// This use case encapsulates the business logic for saving emergency contacts
/// for a specific staff member.
class SaveEmergencyContactsUseCase
extends UseCase<SaveEmergencyContactsArguments, void> {
final EmergencyContactRepositoryInterface _repository;
/// Creates a [SaveEmergencyContactsUseCase].
SaveEmergencyContactsUseCase(this._repository);
@override
Future<void> call(SaveEmergencyContactsArguments params) {
return _repository.saveContacts(params.staffId, params.contacts);
}
}

View File

@@ -0,0 +1,168 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../domain/arguments/get_emergency_contacts_arguments.dart';
import '../../domain/arguments/save_emergency_contacts_arguments.dart';
import '../../domain/usecases/get_emergency_contacts_usecase.dart';
import '../../domain/usecases/save_emergency_contacts_usecase.dart';
// Events
abstract class EmergencyContactEvent extends Equatable {
const EmergencyContactEvent();
@override
List<Object?> get props => [];
}
class EmergencyContactsLoaded extends EmergencyContactEvent {}
class EmergencyContactAdded extends EmergencyContactEvent {}
class EmergencyContactRemoved extends EmergencyContactEvent {
final int index;
const EmergencyContactRemoved(this.index);
@override
List<Object?> get props => [index];
}
class EmergencyContactUpdated extends EmergencyContactEvent {
final int index;
final EmergencyContact contact;
const EmergencyContactUpdated(this.index, this.contact);
@override
List<Object?> get props => [index, contact];
}
class EmergencyContactsSaved extends EmergencyContactEvent {}
// State
enum EmergencyContactStatus { initial, loading, success, saving, failure }
class EmergencyContactState extends Equatable {
final EmergencyContactStatus status;
final List<EmergencyContact> contacts;
final String? errorMessage;
const EmergencyContactState({
this.status = EmergencyContactStatus.initial,
this.contacts = const [],
this.errorMessage,
});
EmergencyContactState copyWith({
EmergencyContactStatus? status,
List<EmergencyContact>? contacts,
String? errorMessage,
}) {
return EmergencyContactState(
status: status ?? this.status,
contacts: contacts ?? this.contacts,
errorMessage: errorMessage ?? this.errorMessage,
);
}
bool get isValid {
if (contacts.isEmpty) return false;
// Check if at least one contact is valid (or all?)
// Usually all added contacts should be valid.
return contacts.every((c) => c.name.isNotEmpty && c.phone.isNotEmpty);
}
@override
List<Object?> get props => [status, contacts, errorMessage];
}
// BLoC
class EmergencyContactBloc
extends Bloc<EmergencyContactEvent, EmergencyContactState> {
final GetEmergencyContactsUseCase getEmergencyContacts;
final SaveEmergencyContactsUseCase saveEmergencyContacts;
final String staffId;
EmergencyContactBloc({
required this.getEmergencyContacts,
required this.saveEmergencyContacts,
required this.staffId,
}) : super(const EmergencyContactState()) {
on<EmergencyContactsLoaded>(_onLoaded);
on<EmergencyContactAdded>(_onAdded);
on<EmergencyContactRemoved>(_onRemoved);
on<EmergencyContactUpdated>(_onUpdated);
on<EmergencyContactsSaved>(_onSaved);
}
Future<void> _onLoaded(
EmergencyContactsLoaded event,
Emitter<EmergencyContactState> emit,
) async {
emit(state.copyWith(status: EmergencyContactStatus.loading));
try {
final contacts = await getEmergencyContacts(
GetEmergencyContactsArguments(staffId: staffId),
);
emit(state.copyWith(
status: EmergencyContactStatus.success,
contacts: contacts.isNotEmpty
? contacts
: [const EmergencyContact(name: '', phone: '', relationship: 'family')],
));
} catch (e) {
emit(state.copyWith(
status: EmergencyContactStatus.failure,
errorMessage: e.toString(),
));
}
}
void _onAdded(
EmergencyContactAdded event,
Emitter<EmergencyContactState> emit,
) {
final updatedContacts = List<EmergencyContact>.from(state.contacts)
..add(const EmergencyContact(name: '', phone: '', relationship: 'family'));
emit(state.copyWith(contacts: updatedContacts));
}
void _onRemoved(
EmergencyContactRemoved event,
Emitter<EmergencyContactState> emit,
) {
final updatedContacts = List<EmergencyContact>.from(state.contacts)
..removeAt(event.index);
emit(state.copyWith(contacts: updatedContacts));
}
void _onUpdated(
EmergencyContactUpdated event,
Emitter<EmergencyContactState> emit,
) {
final updatedContacts = List<EmergencyContact>.from(state.contacts);
updatedContacts[event.index] = event.contact;
emit(state.copyWith(contacts: updatedContacts));
}
Future<void> _onSaved(
EmergencyContactsSaved event,
Emitter<EmergencyContactState> emit,
) async {
emit(state.copyWith(status: EmergencyContactStatus.saving));
try {
await saveEmergencyContacts(
SaveEmergencyContactsArguments(
staffId: staffId,
contacts: state.contacts,
),
);
emit(state.copyWith(status: EmergencyContactStatus.success));
} catch (e) {
emit(state.copyWith(
status: EmergencyContactStatus.failure,
errorMessage: e.toString(),
));
}
}
}

View File

@@ -0,0 +1,92 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_modular/flutter_modular.dart';
import '../blocs/emergency_contact_bloc.dart';
import '../widgets/emergency_contact_add_button.dart';
import '../widgets/emergency_contact_form_item.dart';
import '../widgets/emergency_contact_info_banner.dart';
import '../widgets/emergency_contact_save_button.dart';
/// The Staff Emergency Contact screen.
///
/// This screen allows staff to manage their emergency contacts during onboarding.
/// It uses [EmergencyContactBloc] for state management and follows the
/// composed-widget pattern for UI elements.
class EmergencyContactScreen extends StatelessWidget {
const EmergencyContactScreen({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) =>
Modular.get<EmergencyContactBloc>()..add(EmergencyContactsLoaded()),
child: const _EmergencyContactView(),
);
}
}
class _EmergencyContactView extends StatelessWidget {
const _EmergencyContactView();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
leading: IconButton(
icon: Icon(UiIcons.chevronLeft, color: UiColors.textSecondary),
onPressed: () => Modular.to.pop(),
),
title: Text(
'Emergency Contact',
style: UiTypography.title1m.copyWith(color: UiColors.textPrimary),
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(1.0),
child: Container(color: UiColors.border, height: 1.0),
),
),
body: BlocConsumer<EmergencyContactBloc, EmergencyContactState>(
listener: (context, state) {
if (state.status == EmergencyContactStatus.failure) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.errorMessage ?? 'An error occurred')),
);
}
},
builder: (context, state) {
if (state.status == EmergencyContactStatus.loading) {
return const Center(child: CircularProgressIndicator());
}
return Column(
children: [
Expanded(
child: SingleChildScrollView(
padding: EdgeInsets.all(UiConstants.space6),
child: Column(
children: [
const EmergencyContactInfoBanner(),
SizedBox(height: UiConstants.space6),
...state.contacts.asMap().entries.map(
(entry) => EmergencyContactFormItem(
index: entry.key,
contact: entry.value,
totalContacts: state.contacts.length,
),
),
const EmergencyContactAddButton(),
SizedBox(height: UiConstants.space16),
],
),
),
),
EmergencyContactSaveButton(state: state),
],
);
},
),
);
}
}

View File

@@ -0,0 +1,34 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../blocs/emergency_contact_bloc.dart';
class EmergencyContactAddButton extends StatelessWidget {
const EmergencyContactAddButton({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: TextButton.icon(
onPressed: () =>
context.read<EmergencyContactBloc>().add(EmergencyContactAdded()),
icon: Icon(UiIcons.add, size: 20.0),
label: Text(
'Add Another Contact',
style: UiTypography.title2b,
),
style: TextButton.styleFrom(
foregroundColor: UiColors.primary,
padding: EdgeInsets.symmetric(
horizontal: UiConstants.space6,
vertical: UiConstants.space3,
),
shape: RoundedRectangleBorder(
borderRadius: UiConstants.radiusFull,
side: BorderSide(color: UiColors.primary),
),
),
),
);
}
}

View File

@@ -0,0 +1,188 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../domain/extensions/emergency_contact_extensions.dart';
import '../blocs/emergency_contact_bloc.dart';
class EmergencyContactFormItem extends StatelessWidget {
final int index;
final EmergencyContact contact;
final int totalContacts;
const EmergencyContactFormItem({
super.key,
required this.index,
required this.contact,
required this.totalContacts,
});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: UiConstants.space4),
padding: EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: UiColors.bgPopup,
borderRadius: UiConstants.radiusLg,
border: Border.all(color: UiColors.border),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(context),
SizedBox(height: UiConstants.space4),
_buildLabel('Full Name'),
_buildTextField(
initialValue: contact.name,
hint: 'Contact name',
icon: UiIcons.user,
onChanged: (val) => context.read<EmergencyContactBloc>().add(
EmergencyContactUpdated(
index,
contact.copyWith(name: val),
),
),
),
SizedBox(height: UiConstants.space4),
_buildLabel('Phone Number'),
_buildTextField(
initialValue: contact.phone,
hint: '+1 (555) 000-0000',
icon: UiIcons.phone,
onChanged: (val) => context.read<EmergencyContactBloc>().add(
EmergencyContactUpdated(
index,
contact.copyWith(phone: val),
),
),
),
SizedBox(height: UiConstants.space4),
_buildLabel('Relationship'),
_buildDropdown(
context,
value: contact.relationship,
items: const ['family', 'friend', 'partner', 'other'],
onChanged: (val) {
if (val != null) {
context.read<EmergencyContactBloc>().add(
EmergencyContactUpdated(
index,
contact.copyWith(relationship: val),
),
);
}
},
),
],
),
);
}
Widget _buildHeader(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Contact ${index + 1}',
style: UiTypography.title2m.copyWith(
color: UiColors.textPrimary,
),
),
if (totalContacts > 1)
IconButton(
icon: Icon(
UiIcons.delete,
color: UiColors.textError,
size: 20.0,
),
onPressed: () => context
.read<EmergencyContactBloc>()
.add(EmergencyContactRemoved(index)),
),
],
);
}
Widget _buildLabel(String label) {
return Padding(
padding: EdgeInsets.only(bottom: UiConstants.space2),
child: Text(
label,
style: UiTypography.body2m.copyWith(
color: UiColors.textSecondary,
),
),
);
}
Widget _buildTextField({
required String initialValue,
required String hint,
required IconData icon,
required Function(String) onChanged,
}) {
return TextFormField(
initialValue: initialValue,
style: UiTypography.body1r.copyWith(
color: UiColors.textPrimary,
),
decoration: InputDecoration(
hintText: hint,
hintStyle: TextStyle(color: UiColors.textPlaceholder),
prefixIcon: Icon(icon, color: UiColors.textSecondary, size: 20.0),
filled: true,
fillColor: UiColors.bgPopup,
contentPadding: EdgeInsets.symmetric(vertical: UiConstants.space4),
border: OutlineInputBorder(
borderRadius: UiConstants.radiusLg,
borderSide: BorderSide(color: UiColors.border),
),
enabledBorder: OutlineInputBorder(
borderRadius: UiConstants.radiusLg,
borderSide: BorderSide(color: UiColors.border),
),
focusedBorder: OutlineInputBorder(
borderRadius: UiConstants.radiusLg,
borderSide: BorderSide(color: UiColors.primary),
),
),
onChanged: onChanged,
);
}
Widget _buildDropdown(
BuildContext context, {
required String value,
required List<String> items,
required Function(String?) onChanged,
}) {
return Container(
padding: EdgeInsets.symmetric(horizontal: UiConstants.space4),
decoration: BoxDecoration(
color: UiColors.bgPopup,
borderRadius: UiConstants.radiusLg,
border: Border.all(color: UiColors.border),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: items.contains(value) ? value : items.first,
isExpanded: true,
icon: Icon(UiIcons.chevronDown, color: UiColors.textSecondary),
items: items.map((String item) {
return DropdownMenuItem<String>(
value: item,
child: Text(
item.toUpperCase(),
style: UiTypography.body1r.copyWith(
color: UiColors.textPrimary,
),
),
);
}).toList(),
onChanged: onChanged,
),
),
);
}
}

View File

@@ -0,0 +1,21 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
class EmergencyContactInfoBanner extends StatelessWidget {
const EmergencyContactInfoBanner({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: UiColors.accent.withOpacity(0.2),
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
child: Text(
'Please provide at least one emergency contact. This information will only be used in case of an emergency during your shifts.',
style: UiTypography.body2r.copyWith(color: UiColors.textPrimary),
),
);
}
}

View File

@@ -0,0 +1,57 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../blocs/emergency_contact_bloc.dart';
class EmergencyContactSaveButton extends StatelessWidget {
final EmergencyContactState state;
const EmergencyContactSaveButton({super.key, required this.state});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: UiColors.bgPopup,
border: Border(top: BorderSide(color: UiColors.border)),
),
child: SafeArea(
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: state.isValid
? () => context
.read<EmergencyContactBloc>()
.add(EmergencyContactsSaved())
: null,
style: ElevatedButton.styleFrom(
backgroundColor: UiColors.primary,
foregroundColor: UiColors.primaryForeground,
disabledBackgroundColor: UiColors.textPlaceholder,
padding: EdgeInsets.symmetric(vertical: UiConstants.space4),
shape: RoundedRectangleBorder(
borderRadius: UiConstants.radiusFull,
),
elevation: 0,
),
child: state.status == EmergencyContactStatus.saving
? SizedBox(
height: 20.0,
width: 20.0,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(UiColors.primaryForeground),
),
)
: Text(
'Save & Continue',
style: UiTypography.title2b,
),
),
),
),
);
}
}

View File

@@ -0,0 +1,46 @@
import 'package:flutter_modular/flutter_modular.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import 'data/repositories/emergency_contact_repository_impl.dart';
import 'domain/repositories/emergency_contact_repository_interface.dart';
import 'domain/usecases/get_emergency_contacts_usecase.dart';
import 'domain/usecases/save_emergency_contacts_usecase.dart';
import 'presentation/blocs/emergency_contact_bloc.dart';
import 'presentation/pages/emergency_contact_screen.dart';
class StaffEmergencyContactModule extends Module {
@override
void binds(Injector i) {
// Repository
// Uses ProfileRepositoryMock from data_connect
i.addLazySingleton<ProfileRepositoryMock>(ProfileRepositoryMock.new);
i.addLazySingleton<EmergencyContactRepositoryInterface>(
() => EmergencyContactRepositoryImpl(i.get<ProfileRepositoryMock>()),
);
// UseCases
i.addLazySingleton<GetEmergencyContactsUseCase>(
() => GetEmergencyContactsUseCase(i.get<EmergencyContactRepositoryInterface>()),
);
i.addLazySingleton<SaveEmergencyContactsUseCase>(
() => SaveEmergencyContactsUseCase(i.get<EmergencyContactRepositoryInterface>()),
);
// BLoC
i.addLazySingleton<EmergencyContactBloc>(
() => EmergencyContactBloc(
getEmergencyContacts: i.get<GetEmergencyContactsUseCase>(),
saveEmergencyContacts: i.get<SaveEmergencyContactsUseCase>(),
staffId: 'mock-staff-id', // TODO: Get direct from auth state
),
);
}
@override
void routes(RouteManager r) {
r.child(
'/',
child: (_) => const EmergencyContactScreen(),
transition: TransitionType.rightToLeft,
);
}
}

View File

@@ -0,0 +1,5 @@
library staff_emergency_contact;
export 'src/staff_emergency_contact_module.dart';
export 'src/presentation/pages/emergency_contact_screen.dart';
// Export other necessary classes if needed by consumers

View File

@@ -0,0 +1,34 @@
name: staff_emergency_contact
description: Staff Emergency Contact feature.
version: 0.0.1
publish_to: none
resolution: workspace
environment:
sdk: '>=3.10.0 <4.0.0'
flutter: ">=3.0.0"
dependencies:
flutter:
sdk: flutter
flutter_bloc: ^8.1.0
flutter_modular: ^6.3.0
equatable: ^2.0.5
# Architecture Packages
krow_domain:
path: ../../../../../domain
krow_core:
path: ../../../../../core
krow_data_connect:
path: ../../../../../data_connect
design_system:
path: ../../../../../design_system
core_localization:
path: ../../../../../core_localization
dev_dependencies:
flutter_test:
sdk: flutter
bloc_test: ^9.1.0
mocktail: ^1.0.0

View File

@@ -57,6 +57,5 @@ class StaffProfileInfoModule extends Module {
'/personal-info/',
child: (BuildContext context) => const PersonalInfoPage(),
);
// Additional routes will be added as more onboarding pages are implemented
}
}

View File

@@ -1064,20 +1064,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.12.1"
staff_profile:
dependency: transitive
description:
path: "packages/features/staff/profile"
relative: true
source: path
version: "0.0.1"
staff_profile_info:
dependency: transitive
description:
path: "packages/features/staff/profile_sections/onboarding/profile_info"
relative: true
source: path
version: "0.0.1"
stream_channel:
dependency: transitive
description:

View File

@@ -12,6 +12,9 @@ workspace:
- packages/features/staff/authentication
- packages/features/staff/home
- packages/features/staff/staff_main
- packages/features/staff/profile
- packages/features/staff/profile_sections/onboarding/emergency_contact
- packages/features/staff/profile_sections/onboarding/profile_info
- packages/features/client/authentication
- packages/features/client/home
- packages/features/client/settings