feat: integrate ClockInPageLoaded event to initialize state on ClockInBloc

This commit is contained in:
Achintha Isuru
2026-01-30 16:49:10 -05:00
parent f1ccc97fae
commit 9038d6533e
2 changed files with 405 additions and 398 deletions

View File

@@ -33,6 +33,8 @@ class ClockInBloc extends Bloc<ClockInEvent, ClockInState> {
on<CheckInRequested>(_onCheckIn);
on<CheckOutRequested>(_onCheckOut);
on<CheckInModeChanged>(_onModeChanged);
add(ClockInPageLoaded());
}
AttendanceStatus _mapToStatus(Map<String, dynamic> map) {

View File

@@ -1,18 +1,19 @@
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 'package:lucide_icons/lucide_icons.dart';
import 'package:intl/intl.dart';
import 'package:krow_domain/krow_domain.dart';
import '../theme/app_colors.dart';
import 'package:lucide_icons/lucide_icons.dart';
import '../bloc/clock_in_bloc.dart';
import '../bloc/clock_in_event.dart';
import '../bloc/clock_in_state.dart';
import '../theme/app_colors.dart';
import '../widgets/attendance_card.dart';
import '../widgets/date_selector.dart';
import '../widgets/swipe_to_check_in.dart';
import '../widgets/lunch_break_modal.dart';
import '../widgets/commute_tracker.dart';
import '../widgets/date_selector.dart';
import '../widgets/lunch_break_modal.dart';
import '../widgets/swipe_to_check_in.dart';
class ClockInPage extends StatefulWidget {
const ClockInPage({super.key});
@@ -28,23 +29,24 @@ class _ClockInPageState extends State<ClockInPage> {
void initState() {
super.initState();
_bloc = Modular.get<ClockInBloc>();
_bloc.add(ClockInPageLoaded());
}
@override
Widget build(BuildContext context) {
return BlocProvider.value(
return BlocProvider<ClockInBloc>.value(
value: _bloc,
child: BlocConsumer<ClockInBloc, ClockInState>(
listener: (context, state) {
if (state.status == ClockInStatus.failure && state.errorMessage != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.errorMessage!)),
);
if (state.status == ClockInStatus.failure &&
state.errorMessage != null) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(state.errorMessage!)));
}
},
builder: (context, state) {
if (state.status == ClockInStatus.loading && state.todayShift == null) {
if (state.status == ClockInStatus.loading &&
state.todayShift == null) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
@@ -64,29 +66,27 @@ class _ClockInPageState extends State<ClockInPage> {
: '--:-- --';
return Scaffold(
backgroundColor: Colors.transparent,
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFF8FAFC), // slate-50
Colors.white,
],
appBar: UiAppBar(
titleWidget: Text(
'Clock In to your Shift',
style: UiTypography.title1m.textPrimary,
),
showBackButton: false,
centerTitle: false,
),
child: SafeArea(
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 100),
padding: const EdgeInsets.only(
bottom: UiConstants.space24,
top: UiConstants.space6,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(),
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Commute Tracker (shows before date selector when applicable)
if (todayShift != null)
@@ -166,43 +166,15 @@ class _ClockInPageState extends State<ClockInPage> {
const SizedBox(height: 24),
// Your Activity Header
// Your Activity Header
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Your Activity",
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColors.krowCharcoal,
),
),
GestureDetector(
onTap: () {
debugPrint('Navigating to shifts...');
},
child: Row(
children: const [
Text(
"View all",
style: TextStyle(
color: AppColors.krowBlue,
fontWeight: FontWeight.w500,
fontSize: 14,
),
),
SizedBox(width: 4),
Icon(
LucideIcons.chevronRight,
size: 16,
color: AppColors.krowBlue,
),
],
),
),
],
),
const SizedBox(height: 12),
// Check-in Mode Toggle
@@ -226,7 +198,12 @@ class _ClockInPageState extends State<ClockInPage> {
),
child: Row(
children: [
_buildModeTab("Swipe", LucideIcons.mapPin, 'swipe', state.checkInMode),
_buildModeTab(
"Swipe",
LucideIcons.mapPin,
'swipe',
state.checkInMode,
),
// _buildModeTab("NFC Tap", LucideIcons.wifi, 'nfc', state.checkInMode),
],
),
@@ -257,7 +234,8 @@ class _ClockInPageState extends State<ClockInPage> {
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const Text(
"TODAY'S SHIFT",
@@ -274,14 +252,18 @@ class _ClockInPageState extends State<ClockInPage> {
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color(0xFF1E293B), // slate-800
color: Color(
0xFF1E293B,
), // slate-800
),
),
Text(
"${todayShift.clientName}${todayShift.location}",
style: const TextStyle(
fontSize: 12,
color: Color(0xFF64748B), // slate-500
color: Color(
0xFF64748B,
), // slate-500
),
),
],
@@ -317,13 +299,17 @@ class _ClockInPageState extends State<ClockInPage> {
SwipeToCheckIn(
isCheckedIn: isCheckedIn,
mode: state.checkInMode,
isLoading: state.status == ClockInStatus.actionInProgress,
isLoading:
state.status ==
ClockInStatus.actionInProgress,
onCheckIn: () async {
// Show NFC dialog if mode is 'nfc'
if (state.checkInMode == 'nfc') {
await _showNFCDialog(context);
} else {
_bloc.add(CheckInRequested(shiftId: todayShift.id));
_bloc.add(
CheckInRequested(shiftId: todayShift.id),
);
}
},
onCheckOut: () {
@@ -331,14 +317,17 @@ class _ClockInPageState extends State<ClockInPage> {
context: context,
builder: (context) => LunchBreakDialog(
onComplete: () {
Navigator.of(context).pop(); // Close dialog first
Navigator.of(
context,
).pop(); // Close dialog first
_bloc.add(const CheckOutRequested());
},
),
);
},
),
] else if (todayShift != null && checkOutTime != null) ...[
] else if (todayShift != null &&
checkOutTime != null) ...[
// Shift Completed State
Container(
padding: const EdgeInsets.all(24),
@@ -430,10 +419,12 @@ class _ClockInPageState extends State<ClockInPage> {
), // emerald-200
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
const Text(
"Checked in at",
@@ -444,7 +435,9 @@ class _ClockInPageState extends State<ClockInPage> {
),
),
Text(
DateFormat('h:mm a').format(checkInTime),
DateFormat(
'h:mm a',
).format(checkInTime),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
@@ -473,7 +466,8 @@ class _ClockInPageState extends State<ClockInPage> {
const SizedBox(height: 16),
// Recent Activity List
if (state.activityLog.isNotEmpty) ...state.activityLog.map(
if (state.activityLog.isNotEmpty)
...state.activityLog.map(
(activity) => Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(12),
@@ -490,7 +484,9 @@ class _ClockInPageState extends State<ClockInPage> {
width: 40,
height: 40,
decoration: BoxDecoration(
color: AppColors.krowBlue.withOpacity(0.1),
color: AppColors.krowBlue.withOpacity(
0.1,
),
borderRadius: BorderRadius.circular(12),
),
child: const Icon(
@@ -502,23 +498,28 @@ class _ClockInPageState extends State<ClockInPage> {
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
DateFormat(
'MMM d',
).format(activity['date'] as DateTime),
DateFormat('MMM d').format(
activity['date'] as DateTime,
),
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Color(0xFF0F172A), // slate-900
color: Color(
0xFF0F172A,
), // slate-900
),
),
Text(
"${activity['start']} - ${activity['end']}",
style: const TextStyle(
fontSize: 12,
color: Color(0xFF64748B), // slate-500
color: Color(
0xFF64748B,
), // slate-500
),
),
],
@@ -544,14 +545,18 @@ class _ClockInPageState extends State<ClockInPage> {
),
),
),
),
);
},
),
);
}
Widget _buildModeTab(String label, IconData icon, String value, String currentMode) {
Widget _buildModeTab(
String label,
IconData icon,
String value,
String currentMode,
) {
final isSelected = currentMode == value;
return Expanded(
child: GestureDetector(