chore: add localization to benefits overview page (en & es)
This commit is contained in:
@@ -536,6 +536,21 @@
|
|||||||
"sick_days": "Sick Days",
|
"sick_days": "Sick Days",
|
||||||
"vacation": "Vacation",
|
"vacation": "Vacation",
|
||||||
"holidays": "Holidays"
|
"holidays": "Holidays"
|
||||||
|
},
|
||||||
|
"overview": {
|
||||||
|
"title": "Your Benefits Overview",
|
||||||
|
"subtitle": "Manage and track your earned benefits here",
|
||||||
|
"request_payment": "Request Payment for $benefit",
|
||||||
|
"request_submitted": "Request submitted for $benefit",
|
||||||
|
"sick_leave_subtitle": "You need at least 8 hours to request sick leave",
|
||||||
|
"vacation_subtitle": "You need 40 hours to claim vacation pay",
|
||||||
|
"holidays_subtitle": "Pay holidays: Thanksgiving, Christmas, New Year",
|
||||||
|
"sick_leave_history": "SICK LEAVE HISTORY",
|
||||||
|
"compliance_banner": "Listed certificates are mandatory for employees. If the employee does not have the complete certificates, they can't proceed with their registration.",
|
||||||
|
"status": {
|
||||||
|
"pending": "Pending",
|
||||||
|
"submitted": "Submitted"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"auto_match": {
|
"auto_match": {
|
||||||
|
|||||||
@@ -536,6 +536,21 @@
|
|||||||
"sick_days": "D\u00edas de Enfermedad",
|
"sick_days": "D\u00edas de Enfermedad",
|
||||||
"vacation": "Vacaciones",
|
"vacation": "Vacaciones",
|
||||||
"holidays": "Festivos"
|
"holidays": "Festivos"
|
||||||
|
},
|
||||||
|
"overview": {
|
||||||
|
"title": "Resumen de tus Beneficios",
|
||||||
|
"subtitle": "Gestiona y sigue tus beneficios ganados aqu\u00ed",
|
||||||
|
"request_payment": "Solicitar pago por $benefit",
|
||||||
|
"request_submitted": "Solicitud enviada para $benefit",
|
||||||
|
"sick_leave_subtitle": "Necesitas al menos 8 horas para solicitar d\u00edas de enfermedad",
|
||||||
|
"vacation_subtitle": "Necesitas 40 horas para reclamar el pago de vacaciones",
|
||||||
|
"holidays_subtitle": "D\u00edas festivos pagados: Acci\u00f3n de Gracias, Navidad, A\u00f1o Nuevo",
|
||||||
|
"sick_leave_history": "HISTORIAL DE D\u00cdAS DE ENFERMEDAD",
|
||||||
|
"compliance_banner": "Los certificados listados son obligatorios para los empleados. Si el empleado no tiene los certificados completos, no puede proceder con su registro.",
|
||||||
|
"status": {
|
||||||
|
"pending": "Pendiente",
|
||||||
|
"submitted": "Enviado"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"auto_match": {
|
"auto_match": {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:flutter_modular/flutter_modular.dart';
|
import 'package:flutter_modular/flutter_modular.dart';
|
||||||
import 'package:krow_core/core.dart';
|
import 'package:krow_core/core.dart';
|
||||||
import 'package:krow_domain/krow_domain.dart';
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
import 'package:core_localization/core_localization.dart';
|
||||||
import 'package:staff_home/src/presentation/blocs/home_cubit.dart';
|
import 'package:staff_home/src/presentation/blocs/home_cubit.dart';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
@@ -58,186 +59,189 @@ class BenefitsOverviewPage extends StatelessWidget {
|
|||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Your Benefits Overview',
|
t.staff.home.benefits.overview.title,
|
||||||
style: UiTypography.title2b.textPrimary,
|
style: UiTypography.title2b.textPrimary,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(
|
||||||
|
t.staff.home.benefits.overview.subtitle,
|
||||||
|
style: UiTypography.footnote2r.textSecondary,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
bottom: PreferredSize(
|
||||||
Text(
|
preferredSize: const Size.fromHeight(1),
|
||||||
'Manage and track your earned benefits here',
|
child: Container(color: UiColors.border.withOpacity(0.5), height: 1),
|
||||||
style: UiTypography.footnote2r.textSecondary,
|
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
),
|
}
|
||||||
bottom: PreferredSize(
|
}
|
||||||
preferredSize: const Size.fromHeight(1),
|
|
||||||
child: Container(color: UiColors.border.withOpacity(0.5), height: 1),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _BenefitCard extends StatelessWidget {
|
class _BenefitCard extends StatelessWidget {
|
||||||
final Benefit benefit;
|
final Benefit benefit;
|
||||||
|
|
||||||
const _BenefitCard({required this.benefit});
|
const _BenefitCard({required this.benefit});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final bool isSickLeave = benefit.title.toLowerCase().contains('sick');
|
final bool isSickLeave = benefit.title.toLowerCase().contains('sick');
|
||||||
final bool isVacation = benefit.title.toLowerCase().contains('vacation');
|
final bool isVacation = benefit.title.toLowerCase().contains('vacation');
|
||||||
final bool isHolidays = benefit.title.toLowerCase().contains('holiday');
|
final bool isHolidays = benefit.title.toLowerCase().contains('holiday');
|
||||||
|
|
||||||
return Container(
|
final i18n = t.staff.home.benefits.overview;
|
||||||
padding: const EdgeInsets.all(UiConstants.space6),
|
|
||||||
decoration: BoxDecoration(
|
return Container(
|
||||||
color: Colors.white,
|
padding: const EdgeInsets.all(UiConstants.space6),
|
||||||
borderRadius: UiConstants.radiusLg,
|
decoration: BoxDecoration(
|
||||||
border: Border.all(color: UiColors.border.withOpacity(0.5)),
|
color: Colors.white,
|
||||||
boxShadow: [
|
borderRadius: UiConstants.radiusLg,
|
||||||
BoxShadow(
|
border: Border.all(color: UiColors.border.withOpacity(0.5)),
|
||||||
color: UiColors.black.withOpacity(0.02),
|
boxShadow: [
|
||||||
blurRadius: 10,
|
BoxShadow(
|
||||||
offset: const Offset(0, 4),
|
color: UiColors.black.withOpacity(0.02),
|
||||||
|
blurRadius: 10,
|
||||||
|
offset: const Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
child: Column(
|
||||||
),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
children: [
|
||||||
_buildProgressCircle(),
|
Row(
|
||||||
const SizedBox(width: UiConstants.space4),
|
children: [
|
||||||
Expanded(
|
_buildProgressCircle(),
|
||||||
child: Column(
|
const SizedBox(width: UiConstants.space4),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Expanded(
|
||||||
children: [
|
child: Column(
|
||||||
Row(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Row(
|
||||||
benefit.title,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
style: UiTypography.body1b.textPrimary,
|
children: [
|
||||||
|
Text(
|
||||||
|
benefit.title,
|
||||||
|
style: UiTypography.body1b.textPrimary,
|
||||||
|
),
|
||||||
|
const Icon(UiIcons.info, size: 18, color: Color(0xFFE2E8F0)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
_getSubtitle(benefit.title),
|
||||||
|
style: UiTypography.footnote2r.textSecondary,
|
||||||
),
|
),
|
||||||
const Icon(UiIcons.info, size: 18, color: Color(0xFFE2E8F0)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
),
|
||||||
Text(
|
],
|
||||||
_getSubtitle(benefit.title),
|
),
|
||||||
style: UiTypography.footnote2r.textSecondary,
|
const SizedBox(height: UiConstants.space6),
|
||||||
|
if (isSickLeave) ...[
|
||||||
|
_AccordionHistory(label: i18n.sick_leave_history),
|
||||||
|
const SizedBox(height: UiConstants.space6),
|
||||||
|
],
|
||||||
|
if (isVacation || isHolidays) ...[
|
||||||
|
_buildComplianceBanner(i18n.compliance_banner),
|
||||||
|
const SizedBox(height: UiConstants.space6),
|
||||||
|
],
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: UiButton.primary(
|
||||||
|
text: i18n.request_payment(benefit: benefit.title),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: const Color(0xFF0038A8),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Implement payment request
|
||||||
|
UiSnackbar.show(context, message: i18n.request_submitted(benefit: benefit.title), type: UiSnackbarType.success);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: UiConstants.space6),
|
);
|
||||||
if (isSickLeave) ...[
|
}
|
||||||
const _AccordionHistory(label: 'SICK LEAVE HISTORY'),
|
|
||||||
const SizedBox(height: UiConstants.space6),
|
Widget _buildProgressCircle() {
|
||||||
],
|
final double progress = benefit.entitlementHours > 0
|
||||||
if (isVacation || isHolidays) ...[
|
? (benefit.remainingHours / benefit.entitlementHours)
|
||||||
_buildComplianceBanner(),
|
: 0.0;
|
||||||
const SizedBox(height: UiConstants.space6),
|
|
||||||
],
|
final bool isSickLeave = benefit.title.toLowerCase().contains('sick');
|
||||||
SizedBox(
|
final Color circleColor = isSickLeave ? const Color(0xFF2563EB) : const Color(0xFF10B981);
|
||||||
width: double.infinity,
|
|
||||||
child: UiButton.primary(
|
return SizedBox(
|
||||||
text: 'Request Payment for ${benefit.title}',
|
width: 72,
|
||||||
style: ElevatedButton.styleFrom(
|
height: 72,
|
||||||
backgroundColor: const Color(0xFF0038A8),
|
child: CustomPaint(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
painter: _CircularProgressPainter(
|
||||||
shape: RoundedRectangleBorder(
|
progress: progress,
|
||||||
borderRadius: BorderRadius.circular(8),
|
color: circleColor,
|
||||||
),
|
backgroundColor: const Color(0xFFE2E8F0),
|
||||||
|
strokeWidth: 6,
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${benefit.remainingHours.toInt()}/${benefit.entitlementHours.toInt()}',
|
||||||
|
style: UiTypography.body2b.textPrimary.copyWith(fontSize: 14),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
t.client_billing.hours_suffix,
|
||||||
|
style: UiTypography.footnote2r.textTertiary.copyWith(fontSize: 9),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
onPressed: () {
|
|
||||||
// TODO: Implement payment request
|
|
||||||
UiSnackbar.show(context, message: 'Request submitted for ${benefit.title}', type: UiSnackbarType.success);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
),
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildProgressCircle() {
|
String _getSubtitle(String title) {
|
||||||
final double progress = benefit.entitlementHours > 0
|
final i18n = t.staff.home.benefits.overview;
|
||||||
? (benefit.remainingHours / benefit.entitlementHours)
|
if (title.toLowerCase().contains('sick')) {
|
||||||
: 0.0;
|
return i18n.sick_leave_subtitle;
|
||||||
|
} else if (title.toLowerCase().contains('vacation')) {
|
||||||
|
return i18n.vacation_subtitle;
|
||||||
|
} else if (title.toLowerCase().contains('holiday')) {
|
||||||
|
return i18n.holidays_subtitle;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
final bool isSickLeave = benefit.title.toLowerCase().contains('sick');
|
Widget _buildComplianceBanner(String text) {
|
||||||
final Color circleColor = isSickLeave ? const Color(0xFF2563EB) : const Color(0xFF10B981);
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
return SizedBox(
|
decoration: BoxDecoration(
|
||||||
width: 72,
|
color: const Color(0xFFECFDF5),
|
||||||
height: 72,
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: CustomPaint(
|
),
|
||||||
painter: _CircularProgressPainter(
|
child: Row(
|
||||||
progress: progress,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
color: circleColor,
|
|
||||||
backgroundColor: const Color(0xFFE2E8F0),
|
|
||||||
strokeWidth: 6,
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
const Icon(UiIcons.checkCircle, size: 16, color: Color(0xFF10B981)),
|
||||||
'${benefit.remainingHours.toInt()}/${benefit.entitlementHours.toInt()}',
|
const SizedBox(width: 8),
|
||||||
style: UiTypography.body2b.textPrimary.copyWith(fontSize: 14),
|
Expanded(
|
||||||
),
|
child: Text(
|
||||||
Text(
|
text,
|
||||||
'hours',
|
style: UiTypography.footnote1r.copyWith(
|
||||||
style: UiTypography.footnote2r.textTertiary.copyWith(fontSize: 9),
|
color: const Color(0xFF065F46),
|
||||||
|
fontSize: 11,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
),
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
String _getSubtitle(String title) {
|
|
||||||
if (title.toLowerCase().contains('sick')) {
|
|
||||||
return 'You need at least 8 hours to request sick leave';
|
|
||||||
} else if (title.toLowerCase().contains('vacation')) {
|
|
||||||
return 'You need 40 hours to claim vacation pay';
|
|
||||||
} else if (title.toLowerCase().contains('holiday')) {
|
|
||||||
return 'Pay holidays: Thanksgiving, Christmas, New Year';
|
|
||||||
}
|
}
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildComplianceBanner() {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.all(12),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: const Color(0xFFECFDF5),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
const Icon(UiIcons.checkCircle, size: 16, color: Color(0xFF10B981)),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
'Listed certificates are mandatory for employees. If the employee does not have the complete certificates, they can\'t proceed with their registration.',
|
|
||||||
style: UiTypography.footnote1r.copyWith(
|
|
||||||
color: const Color(0xFF065F46),
|
|
||||||
fontSize: 11,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CircularProgressPainter extends CustomPainter {
|
class _CircularProgressPainter extends CustomPainter {
|
||||||
final double progress;
|
final double progress;
|
||||||
|
|||||||
Reference in New Issue
Block a user