Merge branch 'dev' into feature/centralized-data-error-handling and resolve conflicts
This commit is contained in:
@@ -46,10 +46,8 @@ class HomeRepositoryImpl
|
||||
.dayEnd(_toTimestamp(end))
|
||||
.execute());
|
||||
|
||||
// Filter for ACCEPTED applications (same logic as shifts_repository_impl)
|
||||
// Filter for CONFIRMED applications (same logic as shifts_repository_impl)
|
||||
final apps = response.data.applications.where((app) =>
|
||||
(app.status is Known &&
|
||||
(app.status as Known).value == ApplicationStatus.ACCEPTED) ||
|
||||
(app.status is Known &&
|
||||
(app.status as Known).value == ApplicationStatus.CONFIRMED));
|
||||
|
||||
@@ -145,4 +143,3 @@ class HomeRepositoryImpl
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ 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:staff_home/src/presentation/blocs/home_cubit.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
import 'package:staff_home/src/presentation/blocs/home_cubit.dart';
|
||||
import 'package:staff_home/src/presentation/widgets/home_page/empty_state_widget.dart';
|
||||
import 'package:staff_home/src/presentation/widgets/home_page/home_header.dart';
|
||||
import 'package:staff_home/src/presentation/widgets/home_page/placeholder_banner.dart';
|
||||
@@ -84,28 +84,28 @@ class WorkerHomePage extends StatelessWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: QuickActionItem(
|
||||
icon: LucideIcons.search,
|
||||
icon: UiIcons.search,
|
||||
label: quickI18n.find_shifts,
|
||||
onTap: () => Modular.to.toShifts(),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: QuickActionItem(
|
||||
icon: LucideIcons.calendar,
|
||||
icon: UiIcons.calendar,
|
||||
label: quickI18n.availability,
|
||||
onTap: () => Modular.to.toAvailability(),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: QuickActionItem(
|
||||
icon: LucideIcons.dollarSign,
|
||||
icon: UiIcons.dollar,
|
||||
label: quickI18n.earnings,
|
||||
onTap: () => Modular.to.toPayments(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
|
||||
// Today's Shifts
|
||||
BlocBuilder<HomeCubit, HomeState>(
|
||||
@@ -124,9 +124,11 @@ class WorkerHomePage extends StatelessWidget {
|
||||
if (state.status == HomeStatus.loading)
|
||||
const Center(
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
width: 40,
|
||||
child: CircularProgressIndicator(),
|
||||
height: UiConstants.space10,
|
||||
width: UiConstants.space10,
|
||||
child: CircularProgressIndicator(
|
||||
color: UiColors.primary,
|
||||
),
|
||||
),
|
||||
)
|
||||
else if (shifts.isEmpty)
|
||||
@@ -150,7 +152,7 @@ class WorkerHomePage extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
|
||||
// Tomorrow's Shifts
|
||||
BlocBuilder<HomeCubit, HomeState>(
|
||||
@@ -178,7 +180,7 @@ class WorkerHomePage extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
|
||||
// Recommended Shifts
|
||||
SectionHeader(
|
||||
@@ -198,7 +200,8 @@ class WorkerHomePage extends StatelessWidget {
|
||||
itemCount: state.recommendedShifts.length,
|
||||
clipBehavior: Clip.none,
|
||||
itemBuilder: (context, index) => Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
padding: const EdgeInsets.only(
|
||||
right: UiConstants.space3),
|
||||
child: RecommendedShiftCard(
|
||||
shift: state.recommendedShifts[index],
|
||||
),
|
||||
@@ -207,7 +210,7 @@ class WorkerHomePage extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -28,23 +28,20 @@ class HomeHeader extends StatelessWidget {
|
||||
spacing: UiConstants.space3,
|
||||
children: [
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
width: UiConstants.space12,
|
||||
height: UiConstants.space12,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: UiColors.primary.withOpacity(0.2),
|
||||
color: UiColors.primary.withValues(alpha: 0.2),
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
child: CircleAvatar(
|
||||
backgroundColor: UiColors.primary.withOpacity(0.1),
|
||||
backgroundColor: UiColors.primary.withValues(alpha: 0.1),
|
||||
child: Text(
|
||||
initial,
|
||||
style: const TextStyle(
|
||||
color: UiColors.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
style: UiTypography.body1b.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
@@ -42,7 +42,7 @@ class PendingPaymentCard extends StatelessWidget {
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
LucideIcons.dollarSign,
|
||||
UiIcons.dollar,
|
||||
color: UiColors.primary,
|
||||
size: 20,
|
||||
),
|
||||
@@ -76,7 +76,7 @@ class PendingPaymentCard extends StatelessWidget {
|
||||
),
|
||||
SizedBox(width: UiConstants.space2),
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
UiIcons.chevronRight,
|
||||
color: UiColors.mutedForeground,
|
||||
size: 20,
|
||||
),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
|
||||
import 'package:design_system/design_system.dart';
|
||||
|
||||
@@ -29,19 +29,19 @@ class PlaceholderBanner extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: bg,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(color: accent.withOpacity(0.3)),
|
||||
border: Border.all(color: accent.withValues(alpha: 0.3)),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
width: UiConstants.space10,
|
||||
height: UiConstants.space10,
|
||||
padding: const EdgeInsets.all(UiConstants.space2),
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.bgBanner,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(LucideIcons.sparkles, color: accent, size: 20),
|
||||
child: Icon(UiIcons.sparkles, color: accent, size: UiConstants.space5),
|
||||
),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
@@ -59,7 +59,7 @@ class PlaceholderBanner extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
Icon(LucideIcons.chevronRight, color: accent),
|
||||
Icon(UiIcons.chevronRight, color: accent),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -22,8 +22,8 @@ class QuickActionItem extends StatelessWidget {
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
width: UiConstants.space16,
|
||||
height: UiConstants.space16,
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.bgBanner,
|
||||
@@ -31,13 +31,13 @@ class QuickActionItem extends StatelessWidget {
|
||||
border: Border.all(color: UiColors.bgSecondary),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: UiColors.foreground.withOpacity(0.05),
|
||||
color: UiColors.foreground.withValues(alpha: 0.05),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Icon(icon, color: UiColors.primary, size: 24),
|
||||
child: Icon(icon, color: UiColors.primary, size: UiConstants.space6),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Text(
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
class RecommendedShiftCard extends StatelessWidget {
|
||||
@@ -14,8 +14,6 @@ class RecommendedShiftCard extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final recI18n = t.staff.home.recommended_card;
|
||||
final duration = 8;
|
||||
final totalPay = duration * shift.hourlyRate;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
@@ -23,14 +21,14 @@ class RecommendedShiftCard extends StatelessWidget {
|
||||
},
|
||||
child: Container(
|
||||
width: 300,
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(color: UiColors.border),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.02),
|
||||
color: UiColors.black.withValues(alpha: 0.02),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -45,51 +43,43 @@ class RecommendedShiftCard extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
recI18n.act_now,
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFFDC2626),
|
||||
),
|
||||
style: UiTypography.body3m.copyWith(color: UiColors.textError),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
horizontal: UiConstants.space2,
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFE8F0FF),
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
color: UiColors.tagInProgress,
|
||||
borderRadius: UiConstants.radiusFull,
|
||||
),
|
||||
child: Text(
|
||||
recI18n.one_day,
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF0047FF),
|
||||
),
|
||||
style: UiTypography.body3m.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 44,
|
||||
height: 44,
|
||||
width: UiConstants.space10,
|
||||
height: UiConstants.space10,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFE8F0FF),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.tagInProgress,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
),
|
||||
child: const Icon(
|
||||
LucideIcons.calendar,
|
||||
color: Color(0xFF0047FF),
|
||||
size: 20,
|
||||
UiIcons.calendar,
|
||||
color: UiColors.primary,
|
||||
size: UiConstants.space5,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -97,25 +87,16 @@ class RecommendedShiftCard extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
Flexible(
|
||||
child: Text(
|
||||
shift.title,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16,
|
||||
color: UiColors.foreground,
|
||||
),
|
||||
maxLines: 1,
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'\$${totalPay.round()}',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: UiColors.foreground,
|
||||
),
|
||||
'\$${shift.hourlyRate}/h',
|
||||
style: UiTypography.headline4m.textPrimary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -125,17 +106,11 @@ class RecommendedShiftCard extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
shift.clientName,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
Text(
|
||||
'\$${shift.hourlyRate.toStringAsFixed(0)}/hr • ${duration}h',
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
'\$${shift.hourlyRate.toStringAsFixed(0)}/hr',
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -144,57 +119,48 @@ class RecommendedShiftCard extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
LucideIcons.calendar,
|
||||
size: 14,
|
||||
UiIcons.calendar,
|
||||
size: UiConstants.space3,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
recI18n.today,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
const Icon(
|
||||
LucideIcons.clock,
|
||||
size: 14,
|
||||
UiIcons.clock,
|
||||
size: UiConstants.space3,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
recI18n.time_range(
|
||||
start: shift.startTime,
|
||||
end: shift.endTime,
|
||||
),
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
LucideIcons.mapPin,
|
||||
size: 14,
|
||||
UiIcons.mapPin,
|
||||
size: UiConstants.space3,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Expanded(
|
||||
child: Text(
|
||||
shift.locationAddress,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
|
||||
import 'package:design_system/design_system.dart';
|
||||
|
||||
|
||||
/// Section header widget for home page sections, using design system tokens.
|
||||
class SectionHeader extends StatelessWidget {
|
||||
/// Section title
|
||||
@@ -23,43 +22,58 @@ class SectionHeader extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: UiTypography.headline4m,
|
||||
),
|
||||
if (action != null)
|
||||
if (onAction != null)
|
||||
GestureDetector(
|
||||
onTap: onAction,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
action!,
|
||||
style: UiTypography.body2m.copyWith(color: UiColors.primary),
|
||||
),
|
||||
const Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.primary.withOpacity(0.08),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: UiColors.primary.withOpacity(0.2),
|
||||
Expanded(
|
||||
child: action != null
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
if (onAction != null)
|
||||
GestureDetector(
|
||||
onTap: onAction,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
action ?? '',
|
||||
style: UiTypography.body3r.textPrimary,
|
||||
),
|
||||
const Icon(
|
||||
UiIcons.chevronRight,
|
||||
size: UiConstants.space4,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space2,
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.primary.withValues(alpha: 0.08),
|
||||
borderRadius:
|
||||
BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(
|
||||
color: UiColors.primary.withValues(alpha: 0.2),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
action!,
|
||||
style: UiTypography.body3r.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
title,
|
||||
style: UiTypography.body2m.textPrimary,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
action!,
|
||||
style: UiTypography.body3r.copyWith(color: UiColors.primary),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import 'package:design_system/design_system.dart';
|
||||
@@ -77,15 +77,15 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
Modular.to.pushShiftDetails(widget.shift);
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
padding: const EdgeInsets.all(16),
|
||||
margin: const EdgeInsets.only(bottom: UiConstants.space3),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(color: UiColors.border),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.05),
|
||||
color: UiColors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
@@ -94,27 +94,28 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
width: UiConstants.space12,
|
||||
height: UiConstants.space12,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: widget.shift.logoUrl != null
|
||||
? ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius:
|
||||
BorderRadius.circular(UiConstants.radiusBase),
|
||||
child: Image.network(
|
||||
widget.shift.logoUrl!,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
)
|
||||
: const Icon(
|
||||
LucideIcons.building2,
|
||||
: Icon(
|
||||
UiIcons.building,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -125,28 +126,18 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
Flexible(
|
||||
child: Text(
|
||||
widget.shift.title,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: UiColors.foreground,
|
||||
),
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
text: '\$${widget.shift.hourlyRate}',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
color: UiColors.foreground,
|
||||
),
|
||||
children: const [
|
||||
style: UiTypography.body1b.textPrimary,
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '/h',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 12,
|
||||
),
|
||||
style: UiTypography.body3r,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -155,19 +146,13 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
),
|
||||
Text(
|
||||
widget.shift.clientName,
|
||||
style: const TextStyle(
|
||||
color: UiColors.mutedForeground,
|
||||
fontSize: 13,
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
'${_formatTime(widget.shift.startTime)} • ${widget.shift.location}',
|
||||
style: const TextStyle(
|
||||
color: UiColors.mutedForeground,
|
||||
fontSize: 12,
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -179,14 +164,14 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
margin: const EdgeInsets.only(bottom: UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(color: UiColors.border),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.05),
|
||||
color: UiColors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -195,7 +180,7 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
child: Column(
|
||||
children: [
|
||||
// Header
|
||||
@@ -203,48 +188,45 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
width: 56,
|
||||
height: 56,
|
||||
width: UiConstants.space14,
|
||||
height: UiConstants.space14,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: widget.shift.logoUrl != null
|
||||
? ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius:
|
||||
BorderRadius.circular(UiConstants.radiusBase),
|
||||
child: Image.network(
|
||||
widget.shift.logoUrl!,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
)
|
||||
: const Icon(
|
||||
LucideIcons.building2,
|
||||
: Icon(
|
||||
UiIcons.building,
|
||||
size: 28,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: 6,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.primary,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
borderRadius: UiConstants.radiusFull,
|
||||
),
|
||||
child: Text(
|
||||
'Assigned ${_getTimeAgo(widget.shift.createdDate).replaceAll('Pending ', '')}',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
style: UiTypography.body3m.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
|
||||
// Title and Rate
|
||||
Row(
|
||||
@@ -257,18 +239,11 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
children: [
|
||||
Text(
|
||||
widget.shift.title,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: UiColors.foreground,
|
||||
),
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
),
|
||||
Text(
|
||||
widget.shift.clientName,
|
||||
style: const TextStyle(
|
||||
color: UiColors.mutedForeground,
|
||||
fontSize: 14,
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -276,31 +251,24 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
text: '\$${widget.shift.hourlyRate}',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
color: UiColors.foreground,
|
||||
),
|
||||
children: const [
|
||||
style: UiTypography.headline3m.textPrimary,
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '/h',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 16,
|
||||
),
|
||||
style: UiTypography.body1r,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
|
||||
// Location and Date
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
LucideIcons.mapPin,
|
||||
Icon(
|
||||
UiIcons.mapPin,
|
||||
size: 16,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
@@ -308,30 +276,24 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.shift.location,
|
||||
style: const TextStyle(
|
||||
color: UiColors.mutedForeground,
|
||||
fontSize: 14,
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
const Icon(
|
||||
LucideIcons.calendar,
|
||||
const SizedBox(width: UiConstants.space4),
|
||||
Icon(
|
||||
UiIcons.calendar,
|
||||
size: 16,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'${_formatDate(widget.shift.date)}, ${_formatTime(widget.shift.startTime)}',
|
||||
style: const TextStyle(
|
||||
color: UiColors.mutedForeground,
|
||||
fontSize: 14,
|
||||
),
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
|
||||
// Tags
|
||||
Wrap(
|
||||
@@ -339,21 +301,21 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
_buildTag(
|
||||
LucideIcons.zap,
|
||||
UiIcons.zap,
|
||||
'Immediate start',
|
||||
UiColors.accent.withValues(alpha: 0.3),
|
||||
UiColors.foreground,
|
||||
),
|
||||
_buildTag(
|
||||
LucideIcons.timer,
|
||||
UiIcons.timer,
|
||||
'No experience',
|
||||
const Color(0xFFFEE2E2),
|
||||
const Color(0xFFDC2626),
|
||||
UiColors.tagError,
|
||||
UiColors.textError,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -361,46 +323,48 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
// Actions
|
||||
if (!widget.compact)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space5,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 48,
|
||||
height: UiConstants.space12,
|
||||
child: ElevatedButton(
|
||||
onPressed: widget.onApply,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: UiColors.foreground,
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: UiColors.primary,
|
||||
foregroundColor: UiColors.white,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius:
|
||||
BorderRadius.circular(UiConstants.radiusBase),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'Accept shift',
|
||||
style: TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
child: const Text('Accept shift'),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 48,
|
||||
height: UiConstants.space12,
|
||||
child: OutlinedButton(
|
||||
onPressed: widget.onDecline,
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: const Color(0xFFEF4444),
|
||||
side: const BorderSide(color: Color(0xFFFCA5A5)),
|
||||
foregroundColor: UiColors.destructive,
|
||||
side: BorderSide(
|
||||
color: UiColors.destructive.withValues(alpha: 0.3),
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius:
|
||||
BorderRadius.circular(UiConstants.radiusBase),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'Decline shift',
|
||||
style: TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
child: const Text('Decline shift'),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space5),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -414,7 +378,7 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: bg,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
borderRadius: UiConstants.radiusFull,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -424,11 +388,7 @@ class _ShiftCardState extends State<ShiftCard> {
|
||||
Flexible(
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: text,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
style: UiTypography.body3m.copyWith(color: text),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
|
||||
@@ -17,29 +18,33 @@ class AutoMatchToggle extends StatefulWidget {
|
||||
State<AutoMatchToggle> createState() => _AutoMatchToggleState();
|
||||
}
|
||||
|
||||
class _AutoMatchToggleState extends State<AutoMatchToggle> with SingleTickerProviderStateMixin {
|
||||
class _AutoMatchToggleState extends State<AutoMatchToggle>
|
||||
with SingleTickerProviderStateMixin {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.staff.home.auto_match;
|
||||
final Color primary = Theme.of(context).colorScheme.primary;
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
gradient: widget.enabled
|
||||
? LinearGradient(
|
||||
colors: [primary, primary.withOpacity(0.8)],
|
||||
colors: [
|
||||
UiColors.primary,
|
||||
UiColors.primary.withValues(alpha: 0.8),
|
||||
],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
)
|
||||
: null,
|
||||
color: widget.enabled ? null : Colors.white,
|
||||
border: widget.enabled ? null : Border.all(color: Colors.grey.shade200),
|
||||
color: widget.enabled ? null : UiColors.white,
|
||||
border:
|
||||
widget.enabled ? null : Border.all(color: UiColors.border),
|
||||
boxShadow: widget.enabled
|
||||
? [
|
||||
BoxShadow(
|
||||
color: primary.withOpacity(0.3),
|
||||
color: UiColors.primary.withValues(alpha: 0.3),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
@@ -54,36 +59,39 @@ class _AutoMatchToggleState extends State<AutoMatchToggle> with SingleTickerProv
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
width: UiConstants.space10,
|
||||
height: UiConstants.space10,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.enabled
|
||||
? Colors.white.withOpacity(0.2)
|
||||
: primary.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
? UiColors.white.withValues(alpha: 0.2)
|
||||
: UiColors.primary.withValues(alpha: 0.1),
|
||||
borderRadius:
|
||||
BorderRadius.circular(UiConstants.radiusBase),
|
||||
),
|
||||
child: Icon(
|
||||
LucideIcons.zap,
|
||||
color: widget.enabled ? Colors.white : primary,
|
||||
UiIcons.zap,
|
||||
color: widget.enabled ? UiColors.white : UiColors.primary,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: UiConstants.space3),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
i18n.title,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: widget.enabled ? Colors.white : const Color(0xFF0F172A),
|
||||
style: UiTypography.body1b.copyWith(
|
||||
color: widget.enabled
|
||||
? UiColors.white
|
||||
: UiColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
widget.enabled ? i18n.finding_shifts : i18n.get_matched,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: widget.enabled ? const Color(0xFFF8E08E) : Colors.grey.shade500,
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: widget.enabled
|
||||
? UiColors.accent
|
||||
: UiColors.textInactive,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -93,10 +101,10 @@ class _AutoMatchToggleState extends State<AutoMatchToggle> with SingleTickerProv
|
||||
Switch(
|
||||
value: widget.enabled,
|
||||
onChanged: widget.onToggle,
|
||||
activeThumbColor: Colors.white,
|
||||
activeTrackColor: Colors.white.withValues(alpha: 0.3),
|
||||
inactiveThumbColor: Colors.white,
|
||||
inactiveTrackColor: Colors.grey.shade300,
|
||||
activeThumbColor: UiColors.white,
|
||||
activeTrackColor: UiColors.white.withValues(alpha: 0.3),
|
||||
inactiveThumbColor: UiColors.white,
|
||||
inactiveTrackColor: UiColors.border,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -106,29 +114,28 @@ class _AutoMatchToggleState extends State<AutoMatchToggle> with SingleTickerProv
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Container(
|
||||
height: 1,
|
||||
color: Colors.white.withValues(alpha: 0.2),
|
||||
color: UiColors.white.withValues(alpha: 0.2),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Text(
|
||||
i18n.matching_based_on,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFF8E08E),
|
||||
fontSize: 12,
|
||||
style: UiTypography.body3r.copyWith(
|
||||
color: UiColors.accent,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
children: [
|
||||
_buildChip(LucideIcons.mapPin, i18n.chips.location),
|
||||
_buildChip(UiIcons.mapPin, i18n.chips.location),
|
||||
_buildChip(
|
||||
LucideIcons.clock,
|
||||
UiIcons.clock,
|
||||
i18n.chips.availability,
|
||||
),
|
||||
_buildChip(LucideIcons.briefcase, i18n.chips.skills),
|
||||
_buildChip(UiIcons.briefcase, i18n.chips.skills),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -144,17 +151,17 @@ class _AutoMatchToggleState extends State<AutoMatchToggle> with SingleTickerProv
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: UiColors.white.withValues(alpha: 0.2),
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusMdValue),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(icon, size: 12, color: Colors.white),
|
||||
Icon(icon, size: 12, color: UiColors.white),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 12),
|
||||
style: UiTypography.body3r.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
@@ -15,14 +16,14 @@ class BenefitsWidget extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.staff.home.benefits;
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: Theme.of(context).dividerColor),
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(color: UiColors.border),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context).colorScheme.onBackground.withOpacity(0.05),
|
||||
color: UiColors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
@@ -35,7 +36,7 @@ class BenefitsWidget extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
i18n.title,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
style: UiTypography.title1m.textPrimary,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => Modular.to.pushNamed('/benefits'),
|
||||
@@ -43,19 +44,19 @@ class BenefitsWidget extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
i18n.view_all,
|
||||
style: Theme.of(context).textTheme.labelLarge?.copyWith(color: Theme.of(context).colorScheme.primary),
|
||||
style: UiTypography.buttonL.textPrimary,
|
||||
),
|
||||
Icon(
|
||||
LucideIcons.chevronRight,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
UiIcons.chevronRight,
|
||||
size: UiConstants.space4,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@@ -63,19 +64,19 @@ class BenefitsWidget extends StatelessWidget {
|
||||
label: i18n.items.sick_days,
|
||||
current: 10,
|
||||
total: 40,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
_BenefitItem(
|
||||
label: i18n.items.vacation,
|
||||
current: 40,
|
||||
total: 40,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
_BenefitItem(
|
||||
label: i18n.items.holidays,
|
||||
current: 24,
|
||||
total: 24,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -104,13 +105,13 @@ class _BenefitItem extends StatelessWidget {
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 56,
|
||||
height: 56,
|
||||
width: UiConstants.space14,
|
||||
height: UiConstants.space14,
|
||||
child: CustomPaint(
|
||||
painter: _CircularProgressPainter(
|
||||
progress: current / total,
|
||||
color: color,
|
||||
backgroundColor: const Color(0xFFE5E7EB),
|
||||
backgroundColor: UiColors.border,
|
||||
strokeWidth: 4,
|
||||
),
|
||||
child: Center(
|
||||
@@ -119,32 +120,21 @@ class _BenefitItem extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
'${current.toInt()}/${total.toInt()}',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1E293B),
|
||||
),
|
||||
style: UiTypography.body3m.textPrimary,
|
||||
),
|
||||
Text(
|
||||
i18n.hours_label,
|
||||
style: const TextStyle(
|
||||
fontSize: 8,
|
||||
color: Color(0xFF94A3B8),
|
||||
),
|
||||
style: UiTypography.footnote1r.textTertiary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF475569),
|
||||
),
|
||||
style: UiTypography.body3m.textSecondary,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
@@ -32,9 +33,9 @@ class ImproveYourselfWidget extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
i18n.title,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
style: UiTypography.title1m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
clipBehavior: Clip.none,
|
||||
@@ -51,14 +52,14 @@ class ImproveYourselfWidget extends StatelessWidget {
|
||||
onTap: () => Modular.to.pushNamed(item['page']!),
|
||||
child: Container(
|
||||
width: 160,
|
||||
margin: const EdgeInsets.only(right: 12),
|
||||
margin: const EdgeInsets.only(right: UiConstants.space3),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: Theme.of(context).dividerColor),
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(color: UiColors.border),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context).colorScheme.onBackground.withOpacity(0.05),
|
||||
color: UiColors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
@@ -69,36 +70,33 @@ class ImproveYourselfWidget extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 96,
|
||||
height: UiConstants.space24,
|
||||
width: double.infinity,
|
||||
child: Image.network(
|
||||
item['image']!,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) => Container(
|
||||
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||
child: const Icon(
|
||||
Icons.image_not_supported,
|
||||
color: Colors.grey,
|
||||
color: UiColors.background,
|
||||
child: Icon(
|
||||
UiIcons.zap,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
padding: const EdgeInsets.all(UiConstants.space3),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
item['title']!,
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
item['description']!,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFF64748B),
|
||||
),
|
||||
style: UiTypography.body3r.textSecondary,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
|
||||
|
||||
/// Widget for displaying more ways to use Krow, using design system tokens.
|
||||
class MoreWaysToUseKrowWidget extends StatelessWidget {
|
||||
/// Creates a [MoreWaysToUseKrowWidget].
|
||||
@@ -31,9 +31,9 @@ class MoreWaysToUseKrowWidget extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
i18n.title,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
style: UiTypography.title1m.textPrimary,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
clipBehavior: Clip.none,
|
||||
@@ -50,14 +50,14 @@ class MoreWaysToUseKrowWidget extends StatelessWidget {
|
||||
onTap: () => Modular.to.pushNamed(item['page']!),
|
||||
child: Container(
|
||||
width: 160,
|
||||
margin: const EdgeInsets.only(right: 12),
|
||||
margin: const EdgeInsets.only(right: UiConstants.space3),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: Theme.of(context).dividerColor),
|
||||
color: UiColors.white,
|
||||
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
|
||||
border: Border.all(color: UiColors.border),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context).colorScheme.onBackground.withOpacity(0.05),
|
||||
color: UiColors.black.withValues(alpha: 0.05),
|
||||
blurRadius: 2,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
@@ -68,25 +68,25 @@ class MoreWaysToUseKrowWidget extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 96,
|
||||
height: UiConstants.space24,
|
||||
width: double.infinity,
|
||||
child: Image.network(
|
||||
item['image']!,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) => Container(
|
||||
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||
child: const Icon(
|
||||
Icons.image_not_supported,
|
||||
color: Colors.grey,
|
||||
color: UiColors.background,
|
||||
child: Icon(
|
||||
UiIcons.zap,
|
||||
color: UiColors.mutedForeground,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
padding: const EdgeInsets.all(UiConstants.space3),
|
||||
child: Text(
|
||||
item['title']!,
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user