Skip to content

Commit

Permalink
New leave policy changes (#44)
Browse files Browse the repository at this point in the history
* Show urgent leaves to admin and user

* Refactor unit test

* Use shared widget
  • Loading branch information
cp-pratik-k authored Aug 8, 2023
1 parent e6ffe2f commit cc42a13
Show file tree
Hide file tree
Showing 48 changed files with 1,891 additions and 1,533 deletions.
22 changes: 22 additions & 0 deletions lib/data/core/functions/shared_function.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:injectable/injectable.dart';

@Injectable()
class AppFunctions {
bool isUrgentLeave(
{required DateTime startDate,
required DateTime appliedOn,
required double totalLeaves}) {
Duration diff = startDate.difference(appliedOn);
if (totalLeaves <= 1 && diff.inDays >= 2) {
return false;
} else if (totalLeaves <= 3 && diff.inDays >= 7) {
return false;
} else if (totalLeaves <= 5 && diff.inDays >= 14) {
return false;
} else if (totalLeaves > 5 && diff.inDays >= 21) {
return false;
} else {
return true;
}
}
}
411 changes: 207 additions & 204 deletions lib/data/di/service_locator.config.dart

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/data/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"page_not_found_error_title": "page not found!",
"page_not_found_error_message": "It looks like we can't find the page you're looking for!",

"leave_type_placeholder_text": "{leaveType, select, 0{Casual Leave} 1{Sick Leave} 2{Annual Leave} 3{Paternity Leave} 4{Maternity Leave} 5{Marriage Leave} 6{Bereavement Leave} other{other}}",
"leave_type_placeholder_text": "{leaveType, select, 0{Casual Leave} 1{Urgent Leave} other{other}}",
"@leave_type_placeholder_text": {
"description": "get leave type from leave status",
"placeholders": {
Expand Down
7 changes: 1 addition & 6 deletions lib/data/model/leave/leave.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,7 @@ class Leave extends Equatable {
@JsonEnum(valueField: 'value')
enum LeaveType {
casualLeave(0),
sickLeave(1),
annualLeave(2),
paternityLeave(3),
maternityLeave(4),
marriageLeave(5),
bereavementLeave(6);
urgentLeave(1);

final int value;

Expand Down
7 changes: 1 addition & 6 deletions lib/data/model/leave/leave.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions lib/data/model/leave_application.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import 'package:equatable/equatable.dart';
import 'employee/employee.dart';
import 'leave/leave.dart';
import 'leave_count.dart';

class LeaveApplication extends Equatable {
final Employee employee;
final Leave leave;
final LeaveCounts? leaveCounts;

const LeaveApplication(
{required this.employee, required this.leave, this.leaveCounts});
{required this.employee, required this.leave });

@override
List<Object?> get props => [employee, leave, leaveCounts];
List<Object?> get props => [employee, leave];
}
14 changes: 6 additions & 8 deletions lib/data/model/leave_count.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import 'package:equatable/equatable.dart';

class LeaveCounts extends Equatable {
final double remainingLeaveCount;
final double usedLeaveCount;
final int paidLeaveCount;
final double totalUsedLeave;
final double urgentLeaves;
final double casualLeaves;

const LeaveCounts(
{this.remainingLeaveCount = 0.0,
this.usedLeaveCount = 0.0,
this.paidLeaveCount = 0});
{this.casualLeaves = 0.0, this.urgentLeaves = 0.0})
: totalUsedLeave = urgentLeaves + casualLeaves;

@override
List<Object?> get props =>
[remainingLeaveCount, usedLeaveCount, paidLeaveCount];
List<Object?> get props => [totalUsedLeave, urgentLeaves, casualLeaves];
}
3 changes: 2 additions & 1 deletion lib/data/repo/leave_repo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:injectable/injectable.dart';
import 'package:projectunity/data/model/leave/leave.dart';
import 'package:projectunity/data/model/leave_count.dart';
import 'package:projectunity/data/model/pagination/pagination.dart';
import 'package:projectunity/data/provider/user_state.dart';
import 'package:projectunity/data/services/leave_service.dart';
Expand Down Expand Up @@ -85,7 +86,7 @@ class LeaveRepo {
await _leaveService.getUpcomingLeavesOfUser(
uid: uid, spaceId: _userStateNotifier.currentSpaceId!);

Future<double> getUserUsedLeaves({required String uid}) async =>
Future<LeaveCounts> getUserUsedLeaves({required String uid}) async =>
await _leaveService.getUserUsedLeaves(
uid: uid, spaceId: _userStateNotifier.currentSpaceId!);

Expand Down
17 changes: 12 additions & 5 deletions lib/data/services/leave_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:injectable/injectable.dart';
import 'package:projectunity/data/core/extensions/date_time.dart';
import 'package:projectunity/data/core/extensions/leave_extension.dart';
import 'package:projectunity/data/model/leave_count.dart';
import 'package:projectunity/data/model/pagination/pagination.dart';
import '../core/utils/const/firestore.dart';
import '../model/leave/leave.dart';
Expand Down Expand Up @@ -97,7 +98,8 @@ class LeaveService {
}) async {
final leaves = await _leaveDb(spaceId: spaceId)
.where(FireStoreConst.uid, isEqualTo: uid)
.where(FireStoreConst.leaveStatus, isLessThanOrEqualTo: LeaveStatus.approved.value)
.where(FireStoreConst.leaveStatus,
isLessThanOrEqualTo: LeaveStatus.approved.value)
.get();

return leaves.docs.map((doc) => doc.data()).where((leave) {
Expand Down Expand Up @@ -145,7 +147,7 @@ class LeaveService {
return data.docs.map((doc) => doc.data()).toList();
}

Future<double> getUserUsedLeaves(
Future<LeaveCounts> getUserUsedLeaves(
{required String uid, required String spaceId}) async {
DateTime currentTime = DateTime.now();

Expand All @@ -156,15 +158,20 @@ class LeaveService {
.get();

List<Leave> approvedLeaves = data.docs.map((doc) => doc.data()).toList();
double leaveCount = 0.0;
double casualLeaves = 0.0;
double urgentLeaves = 0.0;
approvedLeaves
.where((leave) =>
leave.startDate.isBefore(currentTime) &&
leave.startDate.year == currentTime.year)
.forEach((leave) {
leaveCount += leave.total;
if (leave.type == LeaveType.urgentLeave) {
urgentLeaves += leave.total;
} else {
casualLeaves += leave.total;
}
});
return leaveCount;
return LeaveCounts(urgentLeaves: urgentLeaves, casualLeaves: casualLeaves);
}

Future<Leave?> fetchLeave(
Expand Down
2 changes: 2 additions & 0 deletions lib/ui/admin/leaves/details/admin_leave_detail.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:projectunity/data/provider/user_state.dart';
import 'package:projectunity/ui/admin/leaves/details/widget/admin_leave_details_action_button.dart';
import 'package:projectunity/ui/admin/leaves/details/widget/admin_leave_details_date_content.dart';
import 'package:projectunity/ui/admin/leaves/details/widget/admin_leave_details_response_text_field.dart';
import 'package:projectunity/ui/admin/leaves/details/widget/admin_leave_details_used_leave_count_view.dart';
import 'package:projectunity/ui/widget/widget_validation.dart';
import '../../../../data/configs/colors.dart';
import '../../../../data/configs/space_constant.dart';
Expand Down Expand Up @@ -91,6 +92,7 @@ class _AdminLeaveApplicationDetailScreenState
UserContent(employee: widget.leaveApplication.employee),
AdminLeaveRequestDetailsDateContent(
leave: widget.leaveApplication.leave),
const LeaveCountsView(),
PerDayDurationDateRange(
perDayDurationWithDate:
widget.leaveApplication.leave.getDateAndDuration()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ class AdminLeaveDetailsBloc
Emitter<AdminLeaveDetailsState> emit) async {
emit(state.copyWith(leaveCountStatus: Status.loading));
try {
double usedLeave =
final leaveCounts =
await _leaveRepo.getUserUsedLeaves(uid: event.employeeId);
emit(state.copyWith(
leaveCountStatus: Status.success, usedLeaves: usedLeave));
leaveCountStatus: Status.success, usedLeavesCount: leaveCounts));
} on Exception {
emit(state.copyWith(
error: firestoreFetchDataError, leaveCountStatus: Status.error));
Expand Down
11 changes: 6 additions & 5 deletions lib/ui/admin/leaves/details/bloc/admin_leave_details_state.dart
Original file line number Diff line number Diff line change
@@ -1,37 +1,38 @@
import 'package:equatable/equatable.dart';
import 'package:projectunity/data/model/leave_count.dart';
import '../../../../../data/core/utils/bloc_status.dart';

class AdminLeaveDetailsState extends Equatable {
final Status actionStatus;
final Status leaveCountStatus;
final double usedLeaves;
final LeaveCounts usedLeavesCount;
final String? error;
final String adminReply;

const AdminLeaveDetailsState({
this.adminReply = "",
this.usedLeaves = 0.0,
this.usedLeavesCount = const LeaveCounts(casualLeaves: 0, urgentLeaves: 0),
this.error,
this.actionStatus = Status.initial,
this.leaveCountStatus = Status.initial,
});

AdminLeaveDetailsState copyWith(
{double? usedLeaves,
{LeaveCounts? usedLeavesCount,
String? error,
Status? actionStatus,
Status? leaveCountStatus,
String? adminReply}) {
return AdminLeaveDetailsState(
adminReply: adminReply ?? this.adminReply,
error: error,
usedLeaves: usedLeaves ?? this.usedLeaves,
usedLeavesCount: usedLeavesCount ?? this.usedLeavesCount,
actionStatus: actionStatus ?? this.actionStatus,
leaveCountStatus: leaveCountStatus ?? this.leaveCountStatus,
);
}

@override
List<Object?> get props =>
[error, leaveCountStatus, actionStatus, usedLeaves, adminReply];
[error, leaveCountStatus, actionStatus, usedLeavesCount, adminReply];
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localization.dart';
import 'package:projectunity/data/core/extensions/double_extension.dart';
import '../../../../../data/configs/colors.dart';
import '../../../../../data/configs/space_constant.dart';
import '../../../../../data/configs/text_style.dart';
import '../../../../../data/configs/theme.dart';
import '../../../../../data/core/utils/bloc_status.dart';
import '../../../../../data/core/utils/date_formatter.dart';
import '../../../../../data/model/leave/leave.dart';
import '../../../../widget/circular_progress_indicator.dart';
import '../bloc/admin_leave_details_bloc.dart';
import '../bloc/admin_leave_details_state.dart';

class AdminLeaveRequestDetailsDateContent extends StatelessWidget {
final Leave leave;
Expand All @@ -23,8 +17,8 @@ class AdminLeaveRequestDetailsDateContent extends StatelessWidget {
Widget build(BuildContext context) {
String totalDays = DateFormatter(AppLocalizations.of(context))
.getLeaveDurationPresentationLong(leave.total);
String duration = DateFormatter(AppLocalizations.of(context)).dateInLine(
startDate: leave.startDate, endDate: leave.endDate);
String duration = DateFormatter(AppLocalizations.of(context))
.dateInLine(startDate: leave.startDate, endDate: leave.endDate);

return Container(
padding: const EdgeInsets.all(primaryHorizontalSpacing),
Expand All @@ -35,42 +29,16 @@ class AdminLeaveRequestDetailsDateContent extends StatelessWidget {
borderRadius: AppTheme.commonBorderRadius,
boxShadow: AppTheme.commonBoxShadow,
),
child: Row(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BlocBuilder<AdminLeaveDetailsBloc,
AdminLeaveDetailsState>(
buildWhen: (previous, current) => previous.leaveCountStatus != current.leaveCountStatus,
builder: (context, state) => state.leaveCountStatus == Status.loading
? const AppCircularProgressIndicator(size: 28)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(state.usedLeaves.fixedAt(2).toString(),
style: AppFontStyle.titleDark),
const SizedBox(height: 8),
Text(
AppLocalizations.of(context).user_leave_used_leaves_tag,
style: AppFontStyle.bodyMedium
.copyWith(color: AppColors.primaryBlue),
)
],
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(duration, style: AppFontStyle.titleDark),
const SizedBox(height:8),
Text(
totalDays,
style: AppFontStyle.bodyMedium
.copyWith(color: AppColors.primaryBlue),
),
],
),
Text(duration, style: AppFontStyle.titleDark),
const SizedBox(height: 8),
Text(
totalDays,
style:
AppFontStyle.bodyMedium.copyWith(color: AppColors.primaryBlue),
),
],
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:projectunity/ui/widget/leave_count_view.dart';
import '../../../../../data/configs/colors.dart';
import '../../../../../data/configs/space_constant.dart';
import '../../../../../data/configs/theme.dart';
import '../../../../../data/core/utils/bloc_status.dart';
import '../../../../widget/circular_progress_indicator.dart';
import '../bloc/admin_leave_details_bloc.dart';
import '../bloc/admin_leave_details_state.dart';

class LeaveCountsView extends StatelessWidget {
const LeaveCountsView({super.key});

@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(primaryHorizontalSpacing),
margin: const EdgeInsets.symmetric(
vertical: primaryHalfSpacing, horizontal: primaryHorizontalSpacing),
decoration: BoxDecoration(
color: AppColors.whiteColor,
borderRadius: AppTheme.commonBorderRadius,
boxShadow: AppTheme.commonBoxShadow,
),
child: BlocBuilder<AdminLeaveDetailsBloc, AdminLeaveDetailsState>(
buildWhen: (previous, current) =>
previous.leaveCountStatus != current.leaveCountStatus,
builder: (context, state) => state.leaveCountStatus == Status.loading
? const SizedBox(
height: 60, child: AppCircularProgressIndicator(size: 28))
: UsedLeaveCountsView(leaveCounts: state.usedLeavesCount),
),
);
}
}
10 changes: 5 additions & 5 deletions lib/ui/admin/members/detail/bloc/employee_detail_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ class EmployeeDetailBloc
Emitter<AdminEmployeeDetailState> emit) async {
emit(EmployeeDetailLoadingState());
try {
final double usedLeaves =
final leaveCounts =
await _leaveRepo.getUserUsedLeaves(uid: event.employeeId);
final int totalLeaves = await _spaceService.getPaidLeaves(
final int totalPaidLeavesCount = await _spaceService.getPaidLeaves(
spaceId: _userManager.currentSpaceId!);
double percentage = 0.0;
if (totalLeaves != 0) {
percentage = usedLeaves / totalLeaves;
if (totalPaidLeavesCount != 0) {
percentage = leaveCounts.totalUsedLeave / totalPaidLeavesCount;
}

return emit.forEach(
Expand All @@ -54,7 +54,7 @@ class EmployeeDetailBloc
return EmployeeDetailLoadedState(
employee: employee,
timeOffRatio: percentage,
usedLeaves: usedLeaves);
usedLeaves: leaveCounts);
} else {
return EmployeeDetailFailureState(error: firestoreFetchDataError);
}
Expand Down
Loading

0 comments on commit cc42a13

Please sign in to comment.