Skip to content

Commit

Permalink
Add pagination in user leave, refactor test
Browse files Browse the repository at this point in the history
  • Loading branch information
cp-pratik-k committed Jul 31, 2023
1 parent a1a29e3 commit 6c3a72f
Show file tree
Hide file tree
Showing 28 changed files with 370 additions and 164 deletions.
25 changes: 15 additions & 10 deletions lib/data/Repo/leave_repo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,24 @@ class LeaveRepo {
status: LeaveStatus.pending,
spaceId: _userStateNotifier.currentSpaceId!);

Stream<List<Leave>> userLeaves(String uid) => _leavesController.stream
.asyncMap((leaves) => leaves.where((leave) => leave.uid == uid).toList());
Stream<List<Leave>> userLeavesByYear(String uid, int year) =>
_leaveService.userYearlyLeave(
uid: uid, year: year, spaceId: _userStateNotifier.currentSpaceId!);

Stream<List<Leave>> leaveByMonth(DateTime date) =>
Rx.combineLatest2<List<Leave>, List<Leave>, List<Leave>>(
_leaveService.monthlyLeaveByStartDate(
year: date.year,
month: date.month,
spaceId: _userStateNotifier.currentSpaceId!).distinct(),
_leaveService.monthlyLeaveByEndDate(
year: date.year,
month: date.month,
spaceId: _userStateNotifier.currentSpaceId!).distinct(),
_leaveService
.monthlyLeaveByStartDate(
year: date.year,
month: date.month,
spaceId: _userStateNotifier.currentSpaceId!)
.distinct(),
_leaveService
.monthlyLeaveByEndDate(
year: date.year,
month: date.month,
spaceId: _userStateNotifier.currentSpaceId!)
.distinct(),
(leavesByStartDate, leavesByEndDate) {
List<Leave> mergedList = leavesByStartDate;
mergedList.addAll(leavesByEndDate.where((endDateLeave) =>
Expand Down
11 changes: 11 additions & 0 deletions lib/data/services/leave_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ class LeaveService {
.where((leave) => leave.startDate.isBefore(DateTime(year, month)))
.toList());

Stream<List<Leave>> userYearlyLeave(
{required String uid, required int year, required String spaceId}) =>
_leaveDb(spaceId: _userManager.currentSpaceId!)
.where(FireStoreConst.uid, isEqualTo: uid)
.where(FireStoreConst.startLeaveDate,
isGreaterThanOrEqualTo: DateTime(year).timeStampToInt)
.where(FireStoreConst.startLeaveDate,
isLessThanOrEqualTo: DateTime(year, 12, 31).timeStampToInt)
.snapshots()
.map((event) => event.docs.map((leave) => leave.data()).toList());

Stream<List<Leave>> userLeaveByStatus(
{required String uid,
required LeaveStatus status,
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/admin/home/home_screen/admin_home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class AdminHomeScreenPage extends StatelessWidget {
BlocProvider(
create: (context) => getIt.get<AdminHomeBloc>()..add(AdminHomeInitialLoadEvent()),
),
BlocProvider(create: (context) => getIt<WhoIsOutCardBloc>()..add(WhoIsOutInitialLoadEvent())),
BlocProvider(create: (context) => getIt<WhoIsOutCardBloc>()..add(FetchWhoIsOutCardLeaves())),
],
child: const AdminHomeScreen(),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class AdminEmployeeDetailsLeavesBLoc extends Bloc<
emit(state.copyWith(status: Status.loading));
try {
return emit.forEach(
_leaveRepo.userLeaves(event.employeeId),
_leaveRepo.userLeavesByYear(event.employeeId, DateTime.now().year),
onData: (List<Leave> data) {
final userLeaves = data.toList();
userLeaves.sort((a, b) => b.startDate.compareTo(a.startDate));
Expand Down
83 changes: 43 additions & 40 deletions lib/ui/shared/who_is_out_card/bloc/who_is_out_card_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,59 +17,41 @@ import 'who_is_out_card_state.dart';
class WhoIsOutCardBloc extends Bloc<WhoIsOutEvent, WhoIsOutCardState> {
final EmployeeRepo _employeeRepo;
final LeaveRepo _leaveRepo;
StreamSubscription? _subscription;

WhoIsOutCardBloc(
this._employeeRepo,
this._leaveRepo,
) : super(WhoIsOutCardState(
selectedDate: DateTime.now().dateOnly,
focusDay: DateTime.now().dateOnly)) {
on<WhoIsOutInitialLoadEvent>(initialLoad);
on<FetchWhoIsOutCardLeaves>(_fetchWhoIsOutCardLeaves);
on<ChangeCalendarDate>(_changeCalendarDate);
on<ChangeCalendarFormat>(_changeCalendarFormat);
on<FetchMoreLeaves>(_fetchMoreLeavesEvent);
on<ShowCalendarData>(_showCalendarData);
on<ShowCalendarError>(_showCalendarError);
}

FutureOr<void> initialLoad(
WhoIsOutInitialLoadEvent event, Emitter<WhoIsOutCardState> emit) async {
emit(state.copyWith(status: Status.loading));
try {
return emit.forEach(
getLeaveApplicationStream(
leaveStream: _leaveRepo.leaveByMonth(state.focusDay),
membersStream: _employeeRepo.employees),
onData: (List<LeaveApplication> leaveApplications) => state.copyWith(
allAbsences: leaveApplications,
status: Status.success,
selectedDayAbsences: getSelectedDateAbsences(
date: state.selectedDate, allAbsences: leaveApplications)),
onError: (error, stackTrace) => state.copyWith(
status: Status.error, error: firestoreFetchDataError));
} on Exception {
emit(
state.copyWith(status: Status.error, error: firestoreFetchDataError));
}
}

FutureOr<void> _fetchMoreLeavesEvent(
FetchMoreLeaves event, Emitter<WhoIsOutCardState> emit) async {
FutureOr<void> _fetchWhoIsOutCardLeaves(
FetchWhoIsOutCardLeaves event, Emitter<WhoIsOutCardState> emit) async {
emit(state.copyWith(
status: state.selectedDayAbsences == null ? Status.loading : null,
focusDay: event.focusDay));
try {
return emit.forEach(
getLeaveApplicationStream(
leaveStream: _leaveRepo.leaveByMonth(event.date),
membersStream: _employeeRepo.employees),
onData: (List<LeaveApplication> leaveApplications) => state.copyWith(
allAbsences: leaveApplications, focusDay: event.date),
onError: (error, stackTrace) => state.copyWith(
status: Status.error,
error: firestoreFetchDataError,
focusDay: event.date),
);
if (_subscription != null) {
await _subscription?.cancel();
}
_subscription = getLeaveApplicationStream(
leaveStream:
_leaveRepo.leaveByMonth(event.focusDay ?? state.focusDay),
membersStream: _employeeRepo.employees)
.listen((List<LeaveApplication> leaveApplications) {
add(ShowCalendarData(leaveApplications));
}, onError: (error, _) {
add(ShowCalendarError());
});
} on Exception {
emit(state.copyWith(
status: Status.error,
error: firestoreFetchDataError,
focusDay: event.date));
add(ShowCalendarError());
}
}

Expand All @@ -86,6 +68,21 @@ class WhoIsOutCardBloc extends Bloc<WhoIsOutEvent, WhoIsOutCardState> {
emit(state.copyWith(calendarFormat: event.calendarFormat));
}

void _showCalendarData(
ShowCalendarData event, Emitter<WhoIsOutCardState> emit) async {
emit(state.copyWith(
status: Status.success,
allAbsences: event.allAbsence,
selectedDayAbsences: state.selectedDayAbsences ??
getSelectedDateAbsences(
date: state.selectedDate, allAbsences: event.allAbsence)));
}

void _showCalendarError(
ShowCalendarError event, Emitter<WhoIsOutCardState> emit) async {
emit(state.copyWith(status: Status.error, error: firestoreFetchDataError));
}

List<LeaveApplication> getSelectedDateAbsences(
{required DateTime date, required List<LeaveApplication> allAbsences}) {
return allAbsences
Expand All @@ -95,4 +92,10 @@ class WhoIsOutCardBloc extends Bloc<WhoIsOutEvent, WhoIsOutCardState> {
LeaveDayDuration.noLeave)
.toList();
}

@override
Future<void> close() async {
await _subscription?.cancel();
return super.close();
}
}
31 changes: 21 additions & 10 deletions lib/ui/shared/who_is_out_card/bloc/who_is_out_card_event.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
import 'package:equatable/equatable.dart';
import 'package:table_calendar/table_calendar.dart';

import '../../../../data/model/leave_application.dart';

abstract class WhoIsOutEvent extends Equatable {}

class WhoIsOutInitialLoadEvent extends WhoIsOutEvent {
class FetchWhoIsOutCardLeaves extends WhoIsOutEvent {
final DateTime? focusDay;

FetchWhoIsOutCardLeaves({this.focusDay});

@override
List<Object?> get props => [focusDay];
}

class ShowCalendarData extends WhoIsOutEvent {
final List<LeaveApplication> allAbsence;

ShowCalendarData( this.allAbsence);

@override
List<Object?> get props => [allAbsence];
}

class ShowCalendarError extends WhoIsOutEvent {
@override
List<Object?> get props => [];
}
Expand All @@ -25,12 +45,3 @@ class ChangeCalendarDate extends WhoIsOutEvent {
@override
List<Object?> get props => [date];
}

class FetchMoreLeaves extends WhoIsOutEvent {
final DateTime date;

FetchMoreLeaves(this.date);

@override
List<Object?> get props => [date];
}
4 changes: 2 additions & 2 deletions lib/ui/shared/who_is_out_card/bloc/who_is_out_card_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class WhoIsOutCardState extends Equatable {
final DateTime focusDay;
final CalendarFormat calendarFormat;
final List<LeaveApplication> allAbsences;
final List<LeaveApplication> selectedDayAbsences;
final List<LeaveApplication>? selectedDayAbsences;
final String? error;

const WhoIsOutCardState(
Expand All @@ -18,7 +18,7 @@ class WhoIsOutCardState extends Equatable {
required this.focusDay,
this.status = Status.initial,
this.allAbsences = const [],
this.selectedDayAbsences = const [],
this.selectedDayAbsences,
this.error});

WhoIsOutCardState copyWith(
Expand Down
13 changes: 8 additions & 5 deletions lib/ui/shared/who_is_out_card/who_is_out_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class WhoIsOutCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocListener<WhoIsOutCardBloc, WhoIsOutCardState>(
listenWhen: (previous, current) => current.status == Status.error && current.error != null,
listenWhen: (previous, current) =>
current.status == Status.error && current.error != null,
listener: (context, state) {
if (state.status == Status.error && state.error != null) {
showSnackBar(context: context, error: state.error);
Expand Down Expand Up @@ -58,7 +59,7 @@ class WhoIsOutCard extends StatelessWidget {
builder: (context, state) =>
AbsenceEmployeesListWhoIsOutCardView(
status: state.status,
absence: state.selectedDayAbsences,
absence: state.selectedDayAbsences ?? [],
dateOfEmployeeAbsence: state.selectedDate,
),
),
Expand Down Expand Up @@ -91,7 +92,7 @@ class _LeaveCalendarState extends State<LeaveCalendar> {
rangeSelectionMode: RangeSelectionMode.disabled,
onPageChanged: (focusedDay) => context
.read<WhoIsOutCardBloc>()
.add(FetchMoreLeaves(focusedDay)),
.add(FetchWhoIsOutCardLeaves(focusDay: focusedDay)),
onDaySelected: (selectedDay, focusedDay) {
context
.read<WhoIsOutCardBloc>()
Expand All @@ -112,7 +113,8 @@ class _LeaveCalendarState extends State<LeaveCalendar> {
leftChevronMargin: EdgeInsets.zero,
leftChevronPadding: EdgeInsets.zero,
leftChevronIcon: SizedBox(),
headerPadding: EdgeInsets.symmetric(vertical: 10,horizontal: 8),
headerPadding:
EdgeInsets.symmetric(vertical: 10, horizontal: 8),
rightChevronMargin: EdgeInsets.zero,
rightChevronPadding: EdgeInsets.zero,
titleCentered: true,
Expand All @@ -121,7 +123,8 @@ class _LeaveCalendarState extends State<LeaveCalendar> {
titleTextStyle: AppFontStyle.labelRegular),
eventLoader: (day) => context
.read<WhoIsOutCardBloc>()
.getSelectedDateAbsences(date: day, allAbsences: state.allAbsences),
.getSelectedDateAbsences(
date: day, allAbsences: state.allAbsences),
focusedDay: state.focusDay,
);
});
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/user/home/home_screen/user_home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class UserHomeScreenPage extends StatelessWidget {
),
BlocProvider(
create: (_) =>
getIt<WhoIsOutCardBloc>()..add(WhoIsOutInitialLoadEvent())),
getIt<WhoIsOutCardBloc>()..add(FetchWhoIsOutCardLeaves())),
],
child: const UserHomeScreen(),
);
Expand Down
59 changes: 25 additions & 34 deletions lib/ui/user/leaves/leaves_screen/bloc/leaves/user_leave_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:async';
import 'package:collection/collection.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injectable/injectable.dart';
import 'package:projectunity/ui/user/leaves/leaves_screen/bloc/leaves/user_leave_event.dart';
Expand All @@ -11,56 +10,48 @@ import '../../../../../../data/model/leave/leave.dart';
import '../../../../../../data/provider/user_state.dart';

@Injectable()
class UserLeaveBloc extends Bloc<UserLeaveEvents, UserLeaveState> {
class UserLeaveBloc extends Bloc<UserLeavesEvents, UserLeaveState> {
final LeaveRepo _leaveRepo;
final UserStateNotifier _userManager;
late List<Leave> _allLeaves = [];
StreamSubscription? _subscription;

UserLeaveBloc(this._userManager, this._leaveRepo) : super(UserLeaveState()) {
on<FetchUserLeaveEvent>(_fetchLeaves);
on<ChangeYearEvent>(_showLeaveByYear);
on<ListenUserLeaves>(_listenLeaves);
on<ShowUserLeaves>(_showLeaves);
on<ShowError>(_showError);
}

Future<void> _fetchLeaves(
FetchUserLeaveEvent event, Emitter<UserLeaveState> emit) async {
emit(state.copyWith(status: Status.loading));
Future<void> _listenLeaves(
ListenUserLeaves event, Emitter<UserLeaveState> emit) async {
emit(state.copyWith(status: Status.loading, selectedYear: event.year));
try {
return emit.forEach(_leaveRepo.userLeaves(_userManager.employeeId),
onData: (List<Leave> leaves) {
_allLeaves = leaves.toList();
return state.copyWith(
status: Status.success,
leaves:
_getSelectedYearLeaveWithSortByDate(state.selectedYear));
},
onError: (error, _) => state.copyWith(
status: Status.error, error: firestoreFetchDataError));
if (_subscription != null) {
await _subscription?.cancel();
}
_subscription = _leaveRepo
.userLeavesByYear(_userManager.employeeId, event.year)
.listen((List<Leave> leaves) {
add(ShowUserLeaves(leaves));
}, onError: (error, _) {
add(const ShowError());
});
} on Exception {
emit(
state.copyWith(status: Status.error, error: firestoreFetchDataError));
add(const ShowError());
}
}

List<Leave> _getSelectedYearLeaveWithSortByDate(int year) {
final List<Leave> leaves = _allLeaves
.where((leave) =>
leave.startDate.year == year || leave.endDate.year == year)
.whereNotNull()
.toList();
leaves.sort((a, b) => b.startDate.compareTo(a.startDate));
return leaves;
void _showLeaves(ShowUserLeaves event, Emitter<UserLeaveState> emit) {
event.leaves.sort((a, b) => b.startDate.compareTo(a.startDate));
emit(state.copyWith(status: Status.success, leaves: event.leaves));
}

Future<void> _showLeaveByYear(
ChangeYearEvent event, Emitter<UserLeaveState> emit) async {
emit(state.copyWith(
leaves: _getSelectedYearLeaveWithSortByDate(event.year),
selectedYear: event.year));
void _showError(ShowError event, Emitter<UserLeaveState> emit) {
emit(state.copyWith(status: Status.error, error: firestoreFetchDataError));
}

@override
Future<void> close() async {
_allLeaves.clear();
await _subscription?.cancel();
return super.close();
}
}
Loading

0 comments on commit 6c3a72f

Please sign in to comment.