diff --git a/apps/health_campaign_field_worker_app/lib/pages/beneficiary/household_overview.dart b/apps/health_campaign_field_worker_app/lib/pages/beneficiary/household_overview.dart index ca01b06fd..fc2b85849 100644 --- a/apps/health_campaign_field_worker_app/lib/pages/beneficiary/household_overview.dart +++ b/apps/health_campaign_field_worker_app/lib/pages/beneficiary/household_overview.dart @@ -1,4 +1,5 @@ import 'package:digit_components/digit_components.dart'; +import 'package:digit_components/utils/date_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -8,7 +9,6 @@ import '../../blocs/household_overview/household_overview.dart'; import '../../blocs/search_households/search_households.dart'; import '../../models/entities/beneficiary_type.dart'; import '../../router/app_router.dart'; -import '../../utils/date_conversions.dart'; import '../../utils/i18_key_constants.dart' as i18; import '../../utils/utils.dart'; import '../../widgets/action_card/action_card.dart'; @@ -399,27 +399,25 @@ class _HouseholdOverviewPageState }, name: e.name?.givenName ?? ' - ', years: (e.dateOfBirth == null - ? null - : DateConversions - .getYearsAndMonthsFromDateTime( - DateConversions - .getFormattedDateToDateTime( - e.dateOfBirth!, - ) ?? - DateTime.now(), - false, - )), + ? null + : DigitDateUtils.calculateAge( + DigitDateUtils + .getFormattedDateToDateTime( + e.dateOfBirth!, + ) ?? + DateTime.now(), + ).years) ?? + 0, months: (e.dateOfBirth == null - ? null - : DateConversions - .getYearsAndMonthsFromDateTime( - DateConversions - .getFormattedDateToDateTime( - e.dateOfBirth!, - ) ?? - DateTime.now(), - true, - )), + ? null + : DigitDateUtils.calculateAge( + DigitDateUtils + .getFormattedDateToDateTime( + e.dateOfBirth!, + ) ?? + DateTime.now(), + ).months) ?? + 0, gender: e.gender?.name ?? ' - ', isDelivered: taskdata == null ? false diff --git a/apps/health_campaign_field_worker_app/lib/widgets/beneficiary/view_beneficiary_card.dart b/apps/health_campaign_field_worker_app/lib/widgets/beneficiary/view_beneficiary_card.dart index bbbc426f8..79d326300 100644 --- a/apps/health_campaign_field_worker_app/lib/widgets/beneficiary/view_beneficiary_card.dart +++ b/apps/health_campaign_field_worker_app/lib/widgets/beneficiary/view_beneficiary_card.dart @@ -1,11 +1,11 @@ import 'package:collection/collection.dart'; import 'package:digit_components/digit_components.dart'; import 'package:digit_components/models/digit_table_model.dart'; +import 'package:digit_components/utils/date_utils.dart'; import 'package:flutter/material.dart'; import '../../blocs/search_households/search_households.dart'; import '../../models/entities/beneficiary_type.dart'; -import '../../utils/date_conversions.dart'; import '../../utils/i18_key_constants.dart' as i18; import '../../utils/utils.dart'; import '../localized.dart'; @@ -119,19 +119,17 @@ class _ViewBeneficiaryCardState extends LocalizedState { TableData( e.dateOfBirth == null ? '' - : '${DateConversions.getYearsAndMonthsFromDateTime( - DateConversions.getFormattedDateToDateTime( + : '${DigitDateUtils.calculateAge( + DigitDateUtils.getFormattedDateToDateTime( e.dateOfBirth!, ) ?? DateTime.now(), - false, - )} ${localizations.translate(i18.searchBeneficiary.yearsAbbr)} ${DateConversions.getYearsAndMonthsFromDateTime( - DateConversions.getFormattedDateToDateTime( + ).years} ${localizations.translate(i18.searchBeneficiary.yearsAbbr)} ${DigitDateUtils.calculateAge( + DigitDateUtils.getFormattedDateToDateTime( e.dateOfBirth!, ) ?? DateTime.now(), - true, - )} ${localizations.translate(i18.searchBeneficiary.monthsAbbr)}', + ).months} ${localizations.translate(i18.searchBeneficiary.monthsAbbr)}', cellKey: 'age', ), TableData( diff --git a/apps/health_campaign_field_worker_app/pubspec.yaml b/apps/health_campaign_field_worker_app/pubspec.yaml index c06579c12..ba8128505 100644 --- a/apps/health_campaign_field_worker_app/pubspec.yaml +++ b/apps/health_campaign_field_worker_app/pubspec.yaml @@ -50,7 +50,7 @@ dependencies: pretty_dio_logger: ^1.2.0-beta-1 pluto_grid: ^7.0.1 speech_to_text: ^6.1.1 - flutter_background_service: ^2.4.6 + flutter_background_service: ^3.0.1 flutter_local_notifications: ^14.1.0 device_info_plus: ^9.0.1 battery_plus: ^4.0.1 diff --git a/packages/digit_components/lib/utils/date_utils.dart b/packages/digit_components/lib/utils/date_utils.dart index 540c2bad5..739bee323 100644 --- a/packages/digit_components/lib/utils/date_utils.dart +++ b/packages/digit_components/lib/utils/date_utils.dart @@ -5,19 +5,30 @@ class DigitDateUtils { // Function to calculate age in years and months based on the selected date. static DigitDOBAge calculateAge(DateTime selectedDate) { DateTime currentDate = DateTime.now(); + + // Calculate the difference in years, months, and days int ageInYears = currentDate.year - selectedDate.year; int ageInMonths = currentDate.month - selectedDate.month; + int ageInDays = currentDate.day - selectedDate.day; - if (currentDate.day < selectedDate.day) { + // If the current day is earlier than the selected day in the same month, + // reduce the month count and adjust the days accordingly. + if (ageInDays < 0) { ageInMonths--; + ageInDays += DateTime(selectedDate.year, selectedDate.month + 1, 0).day; } + // If the current month is earlier than the selected month, reduce the year count + // and adjust the month and day counts accordingly. if (ageInMonths < 0) { ageInYears--; ageInMonths += 12; } - return DigitDOBAge(ageInYears, ageInMonths); + return DigitDOBAge( + years: ageInYears >= 0 ? ageInYears : 0, + months: ageInMonths, + days: ageInDays); } // Function to get a formatted date string based on the provided date string and date format. @@ -33,6 +44,39 @@ class DigitDateUtils { } } + static bool isLeapYear(int year) { + // A year is a leap year if it's divisible by 4 but not divisible by 100, + // or if it's divisible by 400. + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); + } + + static int yearsToDays(int years) { + int days = 0; + for (int year = 0; year < years; year++) { + days += isLeapYear(year) ? 366 : 365; + } + return days; + } + + static int yearsMonthsDaysToDays(int years, int months, int days) { + int totalDays = 0; + + // Convert years to days + for (int year = 0; year < years; year++) { + totalDays += isLeapYear(year) ? 366 : 365; + } + + // Convert months to days + for (int month = 0; month < months; month++) { + totalDays += DateTime(DateTime.now().year, month + 2, 0).day; + } + + // Add the given days to the total + totalDays += days; + + return totalDays; + } + // Function to parse the provided date string and return a DateTime object. static DateTime? getFormattedDateToDateTime(String date) { try { @@ -115,6 +159,7 @@ class DigitDateUtils { class DigitDOBAge { final int years; final int months; + final int days; - DigitDOBAge(this.years, this.months); + DigitDOBAge({this.years = 0, this.months = 0, this.days = 0}); } diff --git a/packages/digit_components/lib/widgets/digit_dob_picker.dart b/packages/digit_components/lib/widgets/digit_dob_picker.dart index 5e6a0d8f5..57ef8f1ff 100644 --- a/packages/digit_components/lib/widgets/digit_dob_picker.dart +++ b/packages/digit_components/lib/widgets/digit_dob_picker.dart @@ -81,9 +81,13 @@ class DigitDobPicker extends StatelessWidget { AbstractControl control) { DigitDOBAge age = DigitDateUtils.calculateAge(formControl.value); - return age.years <= 150 && age.years >= 0 - ? null - : {yearsErrorMessage: true}; + DateTime formValue = formControl.value; + return formValue.isAfter(DateTime.now()) || + age.years < 0 || + age.years > 150 || + (age.years >= 150 && age.months > 0) + ? {yearsErrorMessage: true} + : null; } formControl.setValidators([requiredTrue]); @@ -113,9 +117,13 @@ class DigitDobPicker extends StatelessWidget { AbstractControl control) { DigitDOBAge age = DigitDateUtils.calculateAge(formControl.value); - return age.months <= 11 && age.months >= 0 - ? null - : {monthsErrorMessage: true}; + DateTime formValue = formControl.value; + return formValue.isAfter(DateTime.now()) || + age.months < 0 || + age.months > 11 || + (age.years >= 150 && age.months > 0) + ? {monthsErrorMessage: true} + : null; } formControl.setValidators([requiredTrue]); @@ -142,17 +150,24 @@ class DobValueAccessor extends ControlValueAccessor { @override DateTime? viewToModelValue(DigitDOBAge? viewValue) { if (viewValue == null) return null; - final years = viewValue.years; + final years = DigitDateUtils.yearsToDays(viewValue.years); final months = viewValue.months; - final days = years * 365 + months * 30; - - final calculatedDate = DateTime.now().subtract(Duration(days: days)); - - return DateTime( - calculatedDate.year, - calculatedDate.month, - calculatedDate.day, - ); + final days = DigitDateUtils.yearsMonthsDaysToDays( + viewValue.years, viewValue.months, viewValue.days); + + final calculatedDate = DateTime.now().subtract(Duration(days: days + 1)); + + return months > 11 + ? DateTime( + DateTime.now().year, + DateTime.now().month + 1, + DateTime.now().day + 1, + ) + : DateTime( + calculatedDate.year, + calculatedDate.month, + calculatedDate.day, + ); } } @@ -163,19 +178,26 @@ class DobValueAccessorYearsString DobValueAccessorYearsString(this.accessor); String existingMonth = '0'; + String existingDays = '0'; @override String? modelToViewValue(DateTime? modelValue) { final dobAge = accessor.modelToViewValue(modelValue); existingMonth = dobAge != null ? dobAge.months.toString() : '0'; - return dobAge != null ? dobAge.years.toString() : existingMonth; + existingDays = dobAge != null ? dobAge.days.toString() : '0'; + return dobAge != null && dobAge.years >= 0 + ? dobAge.years.toString() + : existingMonth; } @override DateTime? viewToModelValue(String? viewValue) { final years = int.tryParse(viewValue ?? ''); - final dobAge = DigitDOBAge(years ?? 0, int.parse(existingMonth)); + final dobAge = DigitDOBAge( + years: years ?? 0, + months: int.parse(existingMonth), + days: int.parse(existingDays)); return accessor.viewToModelValue(dobAge); } } @@ -187,18 +209,25 @@ class DobValueAccessorMonthString DobValueAccessorMonthString(this.accessor); String existingYear = '0'; + String existingDays = '0'; @override String? modelToViewValue(DateTime? modelValue) { final dobAge = accessor.modelToViewValue(modelValue); - existingYear = dobAge != null ? dobAge.years.toString() : '0'; - return dobAge != null ? dobAge.months.toString() : dobAge?.years.toString(); + existingYear = + dobAge != null && dobAge.years >= 0 ? dobAge.years.toString() : '0'; + existingDays = dobAge != null ? dobAge.days.toString() : '0'; + int months = dobAge != null ? dobAge.months : 0; + return dobAge != null ? months.toString() : existingYear; } @override DateTime? viewToModelValue(String? viewValue) { - final years = int.tryParse(viewValue ?? ''); - final dobAge = DigitDOBAge(int.parse(existingYear), years ?? 0); + final months = int.tryParse(viewValue ?? '0'); + final dobAge = DigitDOBAge( + years: int.parse(existingYear), + months: months ?? 0, + days: int.parse(existingDays)); return accessor.viewToModelValue(dobAge); } } diff --git a/packages/digit_firebase_services/pubspec.yaml b/packages/digit_firebase_services/pubspec.yaml index 064f46870..0917a7bc0 100644 --- a/packages/digit_firebase_services/pubspec.yaml +++ b/packages/digit_firebase_services/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.0.1 homepage: environment: - sdk: '>=3.0.1 <4.0.0' + sdk: '>=3.0.0 <4.0.0' flutter: ">=1.17.0" dependencies: