Standardize UI to design system tokens

Refactor multiple UI components to use design system tokens and primitives. Added new UiIcons (coffee, wifi, xCircle, ban) and typography color getters (primary, accent). Replaced hardcoded paddings, spacings, radii, borderRadius, and icon imports (lucide_icons -> UiIcons) with UiConstants, UiColors, UiTypography and UiIcons, and switched to UiColors.withValues for opacity. Changes apply across authentication, availability, clock_in (and its widgets), commute tracker, lunch break modal, location map placeholder, attendance card, date selector, and related presentation files to improve visual consistency.
This commit is contained in:
Achintha Isuru
2026-02-10 17:17:56 -05:00
parent bcd973cf64
commit 4c38013c10
58 changed files with 1821 additions and 1832 deletions

View File

@@ -64,10 +64,10 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
Widget _buildStatCard(IconData icon, String value, String label) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 16),
padding: const EdgeInsets.symmetric(vertical: UiConstants.space4),
decoration: BoxDecoration(
color: const Color(0xFFF8FAFC),
borderRadius: BorderRadius.circular(16),
color: UiColors.background,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
border: Border.all(color: UiColors.border),
),
child: Column(
@@ -76,21 +76,19 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
width: 40,
height: 40,
decoration: const BoxDecoration(
color: Colors.white,
color: UiColors.white,
shape: BoxShape.circle,
),
child: Icon(icon, size: 20, color: UiColors.iconSecondary),
),
const SizedBox(height: 8),
const SizedBox(height: UiConstants.space2),
Text(
value,
style: UiTypography.title1m.copyWith(color: UiColors.textPrimary),
style: UiTypography.title1m.textPrimary,
),
Text(
label,
style: UiTypography.footnote2r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.footnote2r.textSecondary,
),
],
),
@@ -99,29 +97,21 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
Widget _buildTimeBox(String label, String time) {
return Container(
padding: const EdgeInsets.all(16),
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: const Color(0xFFF8FAFC),
borderRadius: BorderRadius.circular(16),
color: UiColors.background,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
child: Column(
children: [
Text(
label,
style: const TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: UiColors.textSecondary,
letterSpacing: 0.5,
),
style: UiTypography.titleUppercase4b.textSecondary,
),
const SizedBox(height: 4),
const SizedBox(height: UiConstants.space1),
Text(
_formatTime(time),
style: UiTypography.display2m.copyWith(
fontSize: 20,
color: UiColors.textPrimary,
),
style: UiTypography.headline2m.textPrimary,
),
],
),
@@ -149,7 +139,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.message),
backgroundColor: UiColors.tagSuccess,
backgroundColor: UiColors.success,
),
);
Modular.to.toShifts(selectedDate: state.shiftDate);
@@ -158,7 +148,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.message),
backgroundColor: const Color(0xFFEF4444),
backgroundColor: UiColors.destructive,
),
);
}
@@ -203,7 +193,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
children: [
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(20.0),
padding: const EdgeInsets.all(UiConstants.space5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -211,16 +201,11 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
Text(
"VENDOR",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: UiColors.textSecondary,
letterSpacing: 0.5,
),
style: UiTypography.titleUppercase4b.textSecondary,
),
const SizedBox(height: 8),
const SizedBox(height: UiConstants.space2),
Row(
children: [
SizedBox(
@@ -229,7 +214,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
child: displayShift.logoUrl != null
? ClipRRect(
borderRadius: BorderRadius.circular(
6,
UiConstants.radiusMdValue,
),
child: Image.network(
displayShift.logoUrl!,
@@ -244,33 +229,26 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
),
),
),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
Text(
displayShift.clientName,
style: UiTypography.headline5m.copyWith(
color: UiColors.textPrimary,
),
style: UiTypography.headline5m.textPrimary,
),
],
),
],
),
const SizedBox(height: 24),
const SizedBox(height: UiConstants.space6),
// Date Section
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
Text(
"SHIFT DATE",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: UiColors.textSecondary,
letterSpacing: 0.5,
),
style: UiTypography.titleUppercase4b.textSecondary,
),
const SizedBox(height: 8),
const SizedBox(height: UiConstants.space2),
Row(
children: [
const Icon(
@@ -278,104 +256,44 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
size: 20,
color: UiColors.primary,
),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
Text(
_formatDate(displayShift.date),
style: UiTypography.headline5m.copyWith(
color: UiColors.textPrimary,
),
style: UiTypography.headline5m.textPrimary,
),
],
),
],
),
const SizedBox(height: 24),
const SizedBox(height: UiConstants.space6),
// Worker Capacity / Open Slots
if ((displayShift.requiredSlots ?? 0) > 0)
Container(
padding: const EdgeInsets.all(16),
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: const Color(0xFFF0FDF4), // green-50
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color(0xFFBBF7D0),
), // green-200
color: UiColors.success.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
child: Row(
children: [
const Icon(
Icons.people_alt_outlined,
size: 20,
color: Color(0xFF15803D),
), // green-700, using Material Icon as generic fallback
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"$openSlots spots remaining",
style: UiTypography.body2b.copyWith(
color: const Color(0xFF15803D),
),
),
Text(
"${displayShift.filledSlots ?? 0} filled out of ${displayShift.requiredSlots}",
style: UiTypography.body3r.copyWith(
color: const Color(0xFF166534),
),
),
],
),
UiIcons.users,
size: 16,
color: UiColors.success,
),
SizedBox(
width: 60,
child: LinearProgressIndicator(
value: (displayShift.requiredSlots! > 0)
? (displayShift.filledSlots ?? 0) /
displayShift.requiredSlots!
: 0,
backgroundColor: Colors.white,
color: const Color(0xFF15803D),
minHeight: 6,
borderRadius: BorderRadius.circular(3),
),
const SizedBox(width: UiConstants.space2),
Text(
"$openSlots slots remaining",
style: UiTypography.footnote1m.textSuccess,
),
],
),
),
const SizedBox(height: 24),
// Stats Grid
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 3,
crossAxisSpacing: 12,
childAspectRatio: 0.85,
children: [
_buildStatCard(
UiIcons.dollar,
"\$${estimatedTotal.toStringAsFixed(0)}",
"Total Pay",
),
_buildStatCard(
UiIcons.dollar,
"\$${displayShift.hourlyRate.toInt()}",
"Per Hour",
),
_buildStatCard(
UiIcons.clock,
"${duration.toInt()}h",
"Duration",
),
],
),
const SizedBox(height: 24),
const SizedBox(height: UiConstants.space6),
// Shift Timing
// Time Section
Row(
children: [
Expanded(
@@ -384,7 +302,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
displayShift.startTime,
),
),
const SizedBox(width: 12),
const SizedBox(width: UiConstants.space4),
Expanded(
child: _buildTimeBox(
"END TIME",
@@ -393,129 +311,142 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
),
],
),
const SizedBox(height: 24),
const SizedBox(height: UiConstants.space6),
// Location
Column(
crossAxisAlignment: CrossAxisAlignment.start,
// Quick Info Grid
Row(
children: [
const Text(
"LOCATION",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: UiColors.textSecondary,
letterSpacing: 0.5,
Expanded(
child: _buildStatCard(
UiIcons.dollar,
"\$${displayShift.hourlyRate.toStringAsFixed(0)}/hr",
"Base Rate",
),
),
const SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
displayShift.location.isEmpty
? "TBD"
: displayShift.location,
style: UiTypography.title1m.copyWith(
color: UiColors.textPrimary,
),
),
Text(
displayShift.location.isEmpty
? "TBD"
: displayShift.locationAddress,
style: UiTypography.title1m.copyWith(
color: UiColors.textPrimary,
),
),
],
const SizedBox(width: UiConstants.space4),
Expanded(
child: _buildStatCard(
UiIcons.clock,
"${duration.toInt()} hours",
"Duration",
),
),
const SizedBox(width: UiConstants.space4),
Expanded(
child: _buildStatCard(
UiIcons.wallet,
"\$${estimatedTotal.toStringAsFixed(0)}",
"Est. Total",
),
),
],
),
const SizedBox(height: 24),
const SizedBox(height: UiConstants.space8),
// Additional Info
if (displayShift.description != null) ...[
SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"ADDITIONAL INFO",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: UiColors.textSecondary,
letterSpacing: 0.5,
),
),
const SizedBox(height: 8),
Text(
displayShift.description!,
style: UiTypography.body2m.copyWith(
color: UiColors.textPrimary,
),
),
],
// Location Section
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"LOCATION",
style: UiTypography.titleUppercase4b.textSecondary,
),
),
],
const SizedBox(height: 20),
if (displayShift.status != 'confirmed' &&
displayShift.hasApplied != true &&
(displayShift.requiredSlots == null ||
displayShift.filledSlots == null ||
displayShift.filledSlots! <
displayShift.requiredSlots!))
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => _declineShift(
context,
displayShift!.id,
),
style: OutlinedButton.styleFrom(
foregroundColor: const Color(0xFFEF4444),
side: const BorderSide(
color: Color(0xFFEF4444),
),
padding: const EdgeInsets.symmetric(
vertical: 16,
),
),
child: const Text("Decline"),
),
const SizedBox(height: UiConstants.space3),
Container(
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: UiColors.white,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
border: Border.all(color: UiColors.border),
),
const SizedBox(width: 16),
Expanded(
child: ElevatedButton(
onPressed: () => _bookShift(
context,
displayShift!,
child: Column(
children: [
Row(
children: [
const Icon(
UiIcons.mapPin,
color: UiColors.primary,
size: 20,
),
const SizedBox(width: UiConstants.space3),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
displayShift.location,
style: UiTypography.body2b.textPrimary,
),
Text(
displayShift.locationAddress,
style: UiTypography.body3r.textSecondary,
),
],
),
),
],
),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(
0xFF10B981,
const SizedBox(height: UiConstants.space4),
const Divider(),
const SizedBox(height: UiConstants.space2),
TextButton.icon(
onPressed: () {},
icon: const Icon(
UiIcons.arrowRight,
size: 16,
),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
vertical: 16,
label: const Text("Open in Maps"),
style: TextButton.styleFrom(
foregroundColor: UiColors.primary,
padding: EdgeInsets.zero,
),
),
child: const Text("Book Shift"),
),
],
),
],
),
SizedBox(
height: MediaQuery.of(context).padding.bottom + 10,
),
],
),
const SizedBox(height: UiConstants.space8),
// Description / Instructions
if ((displayShift.description ?? '').isNotEmpty) ...[
Text(
"JOB DESCRIPTION",
style: UiTypography.titleUppercase4b.textSecondary,
),
const SizedBox(height: UiConstants.space2),
Text(
displayShift.description!,
style: UiTypography.body2r.textSecondary,
),
const SizedBox(height: UiConstants.space8),
],
],
),
),
),
// Bottom Action Bar
Container(
padding: EdgeInsets.fromLTRB(
UiConstants.space5,
UiConstants.space4,
UiConstants.space5,
MediaQuery.of(context).padding.bottom + UiConstants.space4,
),
decoration: BoxDecoration(
color: UiColors.white,
border: Border(top: BorderSide(color: UiColors.border)),
boxShadow: [
BoxShadow(
color: UiColors.black.withValues(alpha: 0.05),
blurRadius: 10,
offset: const Offset(0, -4),
),
],
),
child: _buildBottomButton(displayShift, context),
),
],
),
);
@@ -552,7 +483,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
);
},
style: TextButton.styleFrom(
foregroundColor: const Color(0xFF10B981),
foregroundColor: UiColors.success,
),
child: const Text('Book'),
),
@@ -581,7 +512,7 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
).add(DeclineShiftDetailsEvent(id));
},
style: TextButton.styleFrom(
foregroundColor: const Color(0xFFEF4444),
foregroundColor: UiColors.destructive,
),
child: const Text('Decline'),
),
@@ -608,29 +539,23 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
width: 36,
child: CircularProgressIndicator(),
),
const SizedBox(height: 16),
const SizedBox(height: UiConstants.space4),
Text(
shift.title,
style: UiTypography.body2b.copyWith(
color: UiColors.textPrimary,
),
style: UiTypography.body2b.textPrimary,
textAlign: TextAlign.center,
),
const SizedBox(height: 6),
Text(
'${_formatDate(shift.date)}${_formatTime(shift.startTime)} - ${_formatTime(shift.endTime)}',
style: UiTypography.body3r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.body3r.textSecondary,
textAlign: TextAlign.center,
),
if (shift.clientName.isNotEmpty) ...[
const SizedBox(height: 6),
Text(
shift.clientName,
style: UiTypography.body3r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.body3r.textSecondary,
textAlign: TextAlign.center,
),
],
@@ -647,4 +572,150 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
Navigator.of(context, rootNavigator: true).pop();
_actionDialogOpen = false;
}
Widget _buildBottomButton(Shift shift, BuildContext context) {
final String status = shift.status ?? 'open';
if (status == 'confirmed') {
return Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () => _openCancelDialog(context),
style: ElevatedButton.styleFrom(
backgroundColor: UiColors.destructive,
foregroundColor: UiColors.white,
padding: const EdgeInsets.symmetric(vertical: UiConstants.space4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
elevation: 0,
),
child: Text("CANCEL SHIFT", style: UiTypography.body2b.white),
),
),
const SizedBox(width: UiConstants.space4),
Expanded(
child: ElevatedButton(
onPressed: () => Modular.to.toClockIn(),
style: ElevatedButton.styleFrom(
backgroundColor: UiColors.success,
foregroundColor: UiColors.white,
padding: const EdgeInsets.symmetric(vertical: UiConstants.space4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
elevation: 0,
),
child: Text("CLOCK IN", style: UiTypography.body2b.white),
),
),
],
);
}
if (status == 'pending') {
return Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => BlocProvider.of<ShiftDetailsBloc>(context).add(DeclineShiftDetailsEvent(shift.id)),
style: OutlinedButton.styleFrom(
foregroundColor: UiColors.destructive,
padding: const EdgeInsets.symmetric(vertical: UiConstants.space4),
side: const BorderSide(color: UiColors.destructive),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
),
child: Text("DECLINE", style: UiTypography.body2b.textError),
),
),
const SizedBox(width: UiConstants.space4),
Expanded(
child: ElevatedButton(
onPressed: () => BlocProvider.of<ShiftDetailsBloc>(context).add(BookShiftDetailsEvent(shift.id, roleId: shift.roleId)),
style: ElevatedButton.styleFrom(
backgroundColor: UiColors.primary,
foregroundColor: UiColors.white,
padding: const EdgeInsets.symmetric(vertical: UiConstants.space4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
elevation: 0,
),
child: Text("ACCEPT SHIFT", style: UiTypography.body2b.white),
),
),
],
);
}
if (status == 'open' || status == 'available') {
return Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => _declineShift(context, shift.id),
style: OutlinedButton.styleFrom(
foregroundColor: UiColors.textSecondary,
padding: const EdgeInsets.symmetric(vertical: UiConstants.space4),
side: const BorderSide(color: UiColors.border),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
),
child: Text("DECLINE", style: UiTypography.body2b.textSecondary),
),
),
const SizedBox(width: UiConstants.space4),
Expanded(
child: ElevatedButton(
onPressed: () => _bookShift(context, shift),
style: ElevatedButton.styleFrom(
backgroundColor: UiColors.primary,
foregroundColor: UiColors.white,
padding: const EdgeInsets.symmetric(vertical: UiConstants.space4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
elevation: 0,
),
child: Text("APPLY NOW", style: UiTypography.body2b.white),
),
),
],
);
}
return const SizedBox();
}
void _openCancelDialog(BuildContext context) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('Cancel Shift'),
content: const Text('Are you sure you want to cancel this shift?'),
actions: [
TextButton(
onPressed: () => Modular.to.pop(),
child: const Text('No'),
),
TextButton(
onPressed: () {
Modular.to.pop();
BlocProvider.of<ShiftDetailsBloc>(context).add(
DeclineShiftDetailsEvent(widget.shiftId),
);
},
style: TextButton.styleFrom(
foregroundColor: UiColors.destructive,
),
child: const Text('Yes, cancel it'),
),
],
),
);
}
}

View File

@@ -7,7 +7,6 @@ import '../blocs/shifts/shifts_bloc.dart';
import '../widgets/tabs/my_shifts_tab.dart';
import '../widgets/tabs/find_shifts_tab.dart';
import '../widgets/tabs/history_shifts_tab.dart';
import '../styles/shifts_styles.dart';
class ShiftsPage extends StatefulWidget {
final String? initialTab;
@@ -107,29 +106,25 @@ class _ShiftsPageState extends State<ShiftsPage> {
// Note: Calendar logic moved to MyShiftsTab
return Scaffold(
backgroundColor: AppColors.krowBackground,
backgroundColor: UiColors.background,
body: Column(
children: [
// Header (Blue)
Container(
color: AppColors.krowBlue,
color: UiColors.primary,
padding: EdgeInsets.fromLTRB(
20,
MediaQuery.of(context).padding.top + 10,
20,
20,
UiConstants.space5,
MediaQuery.of(context).padding.top + UiConstants.space2,
UiConstants.space5,
UiConstants.space5,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16,
spacing: UiConstants.space4,
children: [
const Text(
Text(
"Shifts",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
style: UiTypography.display1b.white,
),
// Tabs
@@ -143,17 +138,16 @@ class _ShiftsPageState extends State<ShiftsPage> {
showCount: myShiftsLoaded,
enabled: !blockTabsForFind,
),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
_buildTab(
"find",
"Find Shifts",
UiIcons.search,
availableJobs
.length, // Passed unfiltered count as badge? Or logic inside? Pass availableJobs.
availableJobs.length,
showCount: availableLoaded,
enabled: baseLoaded,
),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
_buildTab(
"history",
"History",
@@ -245,12 +239,15 @@ class _ShiftsPageState extends State<ShiftsPage> {
}
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 8),
padding: const EdgeInsets.symmetric(
vertical: UiConstants.space2,
horizontal: UiConstants.space2,
),
decoration: BoxDecoration(
color: isActive
? Colors.white
: Colors.white.withAlpha((0.2 * 255).round()),
borderRadius: BorderRadius.circular(8),
? UiColors.white
: UiColors.white.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(UiConstants.radiusMdValue),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
@@ -260,23 +257,17 @@ class _ShiftsPageState extends State<ShiftsPage> {
icon,
size: 14,
color: !enabled
? Colors.white.withAlpha((0.5 * 255).round())
? UiColors.white.withValues(alpha: 0.5)
: isActive
? AppColors.krowBlue
: Colors.white,
? UiColors.primary
: UiColors.white,
),
const SizedBox(width: 6),
const SizedBox(width: UiConstants.space1),
Flexible(
child: Text(
label,
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: !enabled
? Colors.white.withAlpha((0.5 * 255).round())
: isActive
? AppColors.krowBlue
: Colors.white,
style: (isActive ? UiTypography.body3m.copyWith(color: UiColors.primary) : UiTypography.body3m.white).copyWith(
color: !enabled ? UiColors.white.withValues(alpha: 0.5) : null,
),
overflow: TextOverflow.ellipsis,
),
@@ -285,23 +276,21 @@ class _ShiftsPageState extends State<ShiftsPage> {
const SizedBox(width: 4),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
horizontal: UiConstants.space1,
vertical: 2,
),
constraints: const BoxConstraints(minWidth: 18),
decoration: BoxDecoration(
color: isActive
? AppColors.krowBlue.withAlpha((0.1 * 255).round())
: Colors.white.withAlpha((0.2 * 255).round()),
borderRadius: BorderRadius.circular(999),
? UiColors.primary.withValues(alpha: 0.1)
: UiColors.white.withValues(alpha: 0.2),
borderRadius: UiConstants.radiusFull,
),
child: Center(
child: Text(
"$count",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: isActive ? AppColors.krowBlue : Colors.white,
style: UiTypography.footnote1b.copyWith(
color: isActive ? UiColors.primary : UiColors.white,
),
),
),

View File

@@ -118,14 +118,14 @@ class _MyShiftCardState extends State<MyShiftCard> {
Modular.to.pushShiftDetails(widget.shift);
},
child: Container(
margin: const EdgeInsets.only(bottom: 12),
margin: const EdgeInsets.only(bottom: UiConstants.space3),
decoration: BoxDecoration(
color: Colors.white,
color: UiColors.white,
borderRadius: UiConstants.radiusLg,
border: Border.all(color: UiColors.border),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
color: UiColors.black.withValues(alpha: 0.05),
blurRadius: 2,
offset: const Offset(0, 1),
),
@@ -142,7 +142,7 @@ class _MyShiftCardState extends State<MyShiftCard> {
// Status Badge
if (statusText.isNotEmpty)
Padding(
padding: const EdgeInsets.only(bottom: 8),
padding: const EdgeInsets.only(bottom: UiConstants.space2),
child: Row(
children: [
if (statusIcon != null)
@@ -173,14 +173,14 @@ class _MyShiftCardState extends State<MyShiftCard> {
),
// Shift Type Badge for available/pending shifts
if (status == 'open' || status == 'pending') ...[
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: BoxDecoration(
color: UiColors.primary.withOpacity(0.1),
color: UiColors.primary.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(4),
),
child: Text(
@@ -205,20 +205,20 @@ class _MyShiftCardState extends State<MyShiftCard> {
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
UiColors.primary.withOpacity(0.09),
UiColors.primary.withOpacity(0.03),
UiColors.primary.withValues(alpha: 0.09),
UiColors.primary.withValues(alpha: 0.03),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(12),
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
border: Border.all(
color: UiColors.primary.withOpacity(0.09),
color: UiColors.primary.withValues(alpha: 0.09),
),
),
child: widget.shift.logoUrl != null
? ClipRRect(
borderRadius: BorderRadius.circular(12),
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
child: Image.network(
widget.shift.logoUrl!,
fit: BoxFit.contain,
@@ -232,7 +232,7 @@ class _MyShiftCardState extends State<MyShiftCard> {
),
),
),
const SizedBox(width: 12),
const SizedBox(width: UiConstants.space3),
// Details
Expanded(
@@ -249,42 +249,34 @@ class _MyShiftCardState extends State<MyShiftCard> {
children: [
Text(
widget.shift.title,
style: UiTypography.body2m.copyWith(
color: UiColors.textPrimary,
),
style: UiTypography.body2m.textPrimary,
overflow: TextOverflow.ellipsis,
),
Text(
widget.shift.clientName,
style: UiTypography.body3r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.body3r.textSecondary,
overflow: TextOverflow.ellipsis,
),
],
),
),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"\$${estimatedTotal.toStringAsFixed(0)}",
style: UiTypography.title1m.copyWith(
color: UiColors.textPrimary,
),
style: UiTypography.title1m.textPrimary,
),
Text(
"\$${widget.shift.hourlyRate.toInt()}/hr · ${duration.toInt()}h",
style: UiTypography.footnote2r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.footnote2r.textSecondary,
),
],
),
],
),
const SizedBox(height: 8),
const SizedBox(height: UiConstants.space2),
// Date & Time - Multi-Day or Single Day
if (widget.shift.durationDays != null &&
@@ -332,11 +324,9 @@ class _MyShiftCardState extends State<MyShiftCard> {
const SizedBox(width: 4),
Text(
_formatDate(widget.shift.date),
style: UiTypography.footnote1r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.footnote1r.textSecondary,
),
const SizedBox(width: 12),
const SizedBox(width: UiConstants.space3),
const Icon(
UiIcons.clock,
size: 12,
@@ -345,9 +335,7 @@ class _MyShiftCardState extends State<MyShiftCard> {
const SizedBox(width: 4),
Text(
"${_formatTime(widget.shift.startTime)} - ${_formatTime(widget.shift.endTime)}",
style: UiTypography.footnote1r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.footnote1r.textSecondary,
),
],
),
@@ -368,9 +356,7 @@ class _MyShiftCardState extends State<MyShiftCard> {
widget.shift.locationAddress.isNotEmpty
? widget.shift.locationAddress
: widget.shift.location,
style: UiTypography.footnote1r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.footnote1r.textSecondary,
overflow: TextOverflow.ellipsis,
),
),

View File

@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:krow_domain/krow_domain.dart';
import 'package:design_system/design_system.dart';
import 'package:core_localization/core_localization.dart';
class ShiftAssignmentCard extends StatelessWidget {
final Shift shift;
@@ -66,12 +65,12 @@ class ShiftAssignmentCard extends StatelessWidget {
return Container(
decoration: BoxDecoration(
color: Colors.white,
color: UiColors.white,
borderRadius: UiConstants.radiusLg,
border: Border.all(color: UiColors.border),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
color: UiColors.black.withValues(alpha: 0.05),
blurRadius: 2,
offset: const Offset(0, 1),
),
@@ -81,7 +80,7 @@ class ShiftAssignmentCard extends StatelessWidget {
children: [
// Header
Padding(
padding: const EdgeInsets.all(16),
padding: const EdgeInsets.all(UiConstants.space4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -97,20 +96,20 @@ class ShiftAssignmentCard extends StatelessWidget {
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
UiColors.primary.withOpacity(0.09),
UiColors.primary.withOpacity(0.03),
UiColors.primary.withValues(alpha: 0.09),
UiColors.primary.withValues(alpha: 0.03),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(12),
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
border: Border.all(
color: UiColors.primary.withOpacity(0.09),
color: UiColors.primary.withValues(alpha: 0.09),
),
),
child: shift.logoUrl != null
? ClipRRect(
borderRadius: BorderRadius.circular(12),
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
child: Image.network(
shift.logoUrl!,
fit: BoxFit.contain,
@@ -124,7 +123,7 @@ class ShiftAssignmentCard extends StatelessWidget {
),
),
),
const SizedBox(width: 12),
const SizedBox(width: UiConstants.space3),
// Details
Expanded(
@@ -140,42 +139,34 @@ class ShiftAssignmentCard extends StatelessWidget {
children: [
Text(
shift.title,
style: UiTypography.body2m.copyWith(
color: UiColors.textPrimary,
),
style: UiTypography.body2m.textPrimary,
overflow: TextOverflow.ellipsis,
),
Text(
shift.clientName,
style: UiTypography.body3r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.body3r.textSecondary,
overflow: TextOverflow.ellipsis,
),
],
),
),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"\$${totalPay.toStringAsFixed(0)}",
style: UiTypography.title1m.copyWith(
color: UiColors.textPrimary,
),
style: UiTypography.title1m.textPrimary,
),
Text(
"\$${shift.hourlyRate.toInt()}/hr · ${hours.toInt()}h",
style: UiTypography.footnote2r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.footnote2r.textSecondary,
),
],
),
],
),
const SizedBox(height: 12),
const SizedBox(height: UiConstants.space3),
// Date & Time
Row(
@@ -188,11 +179,9 @@ class ShiftAssignmentCard extends StatelessWidget {
const SizedBox(width: 4),
Text(
_formatDate(shift.date),
style: UiTypography.footnote1r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.footnote1r.textSecondary,
),
const SizedBox(width: 12),
const SizedBox(width: UiConstants.space3),
const Icon(
UiIcons.clock,
size: 12,
@@ -201,9 +190,7 @@ class ShiftAssignmentCard extends StatelessWidget {
const SizedBox(width: 4),
Text(
"${_formatTime(shift.startTime)} - ${_formatTime(shift.endTime)}",
style: UiTypography.footnote1r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.footnote1r.textSecondary,
),
],
),
@@ -223,9 +210,7 @@ class ShiftAssignmentCard extends StatelessWidget {
shift.locationAddress.isNotEmpty
? shift.locationAddress
: shift.location,
style: UiTypography.footnote1r.copyWith(
color: UiColors.textSecondary,
),
style: UiTypography.footnote1r.textSecondary,
overflow: TextOverflow.ellipsis,
),
),
@@ -240,38 +225,55 @@ class ShiftAssignmentCard extends StatelessWidget {
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
// Actions
Container(
padding: const EdgeInsets.all(UiConstants.space2),
decoration: const BoxDecoration(
color: UiColors.secondary,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(UiConstants.radiusBase),
bottomRight: Radius.circular(UiConstants.radiusBase),
),
),
child: Row(
children: [
Expanded(
child: OutlinedButton(
child: TextButton(
onPressed: onDecline,
style: OutlinedButton.styleFrom(
foregroundColor: UiColors.iconSecondary,
side: const BorderSide(color: UiColors.border),
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
style: TextButton.styleFrom(
foregroundColor: UiColors.destructive,
),
child: Text(
"Decline", // Fallback if translation is broken
style: UiTypography.body2m.textError,
),
child: Text(t.staff_shifts.action.decline),
),
),
const SizedBox(width: 12),
const SizedBox(width: UiConstants.space2),
Expanded(
child: ElevatedButton(
onPressed: onConfirm,
onPressed: isConfirming ? null : onConfirm,
style: ElevatedButton.styleFrom(
backgroundColor: UiColors.primary,
foregroundColor: Colors.white,
foregroundColor: UiColors.white,
elevation: 0,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(UiConstants.radiusMdValue),
),
),
child: Text(t.staff_shifts.action.confirm),
child: isConfirming
? const SizedBox(
height: 16,
width: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
color: UiColors.white,
),
)
: Text(
"Accept", // Fallback
style: UiTypography.body2m.white,
),
),
),
],

View File

@@ -2,7 +2,6 @@ import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../styles/shifts_styles.dart';
import '../my_shift_card.dart';
import '../shared/empty_state_view.dart';
@@ -27,22 +26,21 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
return GestureDetector(
onTap: () => setState(() => _jobType = id),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding: const EdgeInsets.symmetric(
horizontal: UiConstants.space4,
vertical: UiConstants.space2,
),
decoration: BoxDecoration(
color: isSelected ? AppColors.krowBlue : Colors.white,
borderRadius: BorderRadius.circular(999),
color: isSelected ? UiColors.primary : UiColors.white,
borderRadius: UiConstants.radiusFull,
border: Border.all(
color: isSelected ? AppColors.krowBlue : const Color(0xFFE2E8F0),
color: isSelected ? UiColors.primary : UiColors.border,
),
),
child: Text(
label,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: isSelected ? Colors.white : const Color(0xFF64748B),
),
style: (isSelected ? UiTypography.footnote2m.white : UiTypography.footnote2m.textSecondary),
),
),
);
@@ -73,8 +71,11 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
children: [
// Search and Filters
Container(
color: Colors.white,
padding: const EdgeInsets.fromLTRB(20, 16, 20, 16),
color: UiColors.white,
padding: const EdgeInsets.symmetric(
horizontal: UiConstants.space5,
vertical: UiConstants.space4,
),
child: Column(
children: [
// Search Bar
@@ -83,12 +84,12 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
Expanded(
child: Container(
height: 48,
padding: const EdgeInsets.symmetric(horizontal: 12),
padding: const EdgeInsets.symmetric(horizontal: UiConstants.space3),
decoration: BoxDecoration(
color: const Color(0xFFF8FAFC),
borderRadius: BorderRadius.circular(12),
color: UiColors.background,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
border: Border.all(
color: const Color(0xFFE2E8F0),
color: UiColors.border,
),
),
child: Row(
@@ -96,20 +97,17 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
const Icon(
UiIcons.search,
size: 20,
color: Color(0xFF94A3B8),
color: UiColors.textInactive,
),
const SizedBox(width: 10),
const SizedBox(width: UiConstants.space2),
Expanded(
child: TextField(
onChanged: (v) =>
setState(() => _searchQuery = v),
decoration: const InputDecoration(
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Search jobs, location...",
hintStyle: TextStyle(
color: Color(0xFF94A3B8),
fontSize: 14,
),
hintStyle: UiTypography.body2r.textPlaceholder,
),
),
),
@@ -117,37 +115,37 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
),
),
),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
Container(
height: 48,
width: 48,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
color: UiColors.white,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
border: Border.all(
color: const Color(0xFFE2E8F0),
color: UiColors.border,
),
),
child: const Icon(
UiIcons.filter,
size: 18,
color: Color(0xFF64748B),
color: UiColors.textSecondary,
),
),
],
),
const SizedBox(height: 16),
const SizedBox(height: UiConstants.space4),
// Filter Tabs
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
_buildFilterTab('all', 'All Jobs'),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
_buildFilterTab('one-day', 'One Day'),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
_buildFilterTab('multi-day', 'Multi-Day'),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
_buildFilterTab('long-term', 'Long Term'),
],
),
@@ -158,19 +156,19 @@ class _FindShiftsTabState extends State<FindShiftsTab> {
Expanded(
child: filteredJobs.isEmpty
? EmptyStateView(
? const EmptyStateView(
icon: UiIcons.search,
title: "No jobs available",
subtitle: "Check back later",
)
: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.symmetric(horizontal: UiConstants.space5),
child: Column(
children: [
const SizedBox(height: 20),
const SizedBox(height: UiConstants.space5),
...filteredJobs.map(
(shift) => Padding(
padding: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.only(bottom: UiConstants.space3),
child: MyShiftCard(
shift: shift,
),

View File

@@ -17,7 +17,7 @@ class HistoryShiftsTab extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (historyShifts.isEmpty) {
return EmptyStateView(
return const EmptyStateView(
icon: UiIcons.clock,
title: "No shift history",
subtitle: "Completed shifts appear here",
@@ -25,13 +25,13 @@ class HistoryShiftsTab extends StatelessWidget {
}
return SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.symmetric(horizontal: UiConstants.space5),
child: Column(
children: [
const SizedBox(height: 20),
const SizedBox(height: UiConstants.space5),
...historyShifts.map(
(shift) => Padding(
padding: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.only(bottom: UiConstants.space3),
child: GestureDetector(
onTap: () => Modular.to.pushShiftDetails(shift),
child: MyShiftCard(

View File

@@ -1,14 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:design_system/design_system.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../blocs/shifts/shifts_bloc.dart';
import '../my_shift_card.dart';
import '../shift_assignment_card.dart';
import '../shared/empty_state_view.dart';
import '../../styles/shifts_styles.dart';
class MyShiftsTab extends StatefulWidget {
final List<Shift> myShifts;
@@ -118,14 +116,14 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
Navigator.of(context).pop();
context.read<ShiftsBloc>().add(AcceptShiftEvent(id));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Shift confirmed!'),
backgroundColor: Color(0xFF10B981),
SnackBar(
content: const Text('Shift confirmed!'),
backgroundColor: UiColors.success,
),
);
},
style: TextButton.styleFrom(
foregroundColor: const Color(0xFF10B981),
foregroundColor: UiColors.success,
),
child: const Text('Accept'),
),
@@ -152,14 +150,14 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
Navigator.of(context).pop();
context.read<ShiftsBloc>().add(DeclineShiftEvent(id));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Shift declined.'),
backgroundColor: Color(0xFFEF4444),
SnackBar(
content: const Text('Shift declined.'),
backgroundColor: UiColors.destructive,
),
);
},
style: TextButton.styleFrom(
foregroundColor: const Color(0xFFEF4444),
foregroundColor: UiColors.destructive,
),
child: const Text('Decline'),
),
@@ -212,12 +210,15 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
children: [
// Calendar Selector
Container(
color: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16),
color: UiColors.white,
padding: const EdgeInsets.symmetric(
vertical: UiConstants.space4,
horizontal: UiConstants.space4,
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.only(bottom: UiConstants.space3),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -225,7 +226,7 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
icon: const Icon(
UiIcons.chevronLeft,
size: 20,
color: AppColors.krowCharcoal,
color: UiColors.textPrimary,
),
onPressed: () => setState(() {
_weekOffset--;
@@ -237,17 +238,13 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
),
Text(
DateFormat('MMMM yyyy').format(weekStartDate),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.krowCharcoal,
),
style: UiTypography.title1m.textPrimary,
),
IconButton(
icon: const Icon(
UiIcons.chevronRight,
size: 20,
color: AppColors.krowCharcoal,
color: UiColors.textPrimary,
),
onPressed: () => setState(() {
_weekOffset++;
@@ -284,13 +281,13 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
height: 60,
decoration: BoxDecoration(
color: isSelected
? AppColors.krowBlue
: Colors.white,
borderRadius: BorderRadius.circular(12),
? UiColors.primary
: UiColors.white,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
border: Border.all(
color: isSelected
? AppColors.krowBlue
: AppColors.krowBorder,
? UiColors.primary
: UiColors.border,
width: 1,
),
),
@@ -299,31 +296,25 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
children: [
Text(
date.day.toString().padLeft(2, '0'),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: isSelected
? Colors.white
: AppColors.krowCharcoal,
),
style: isSelected
? UiTypography.body1b.white
: UiTypography.body1b.textPrimary,
),
Text(
DateFormat('E').format(date),
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w500,
color: isSelected
? Colors.white.withOpacity(0.8)
: AppColors.krowMuted,
style: (isSelected
? UiTypography.footnote2m.white
: UiTypography.footnote2m.textSecondary).copyWith(
color: isSelected ? UiColors.white.withValues(alpha: 0.8) : null,
),
),
if (hasShifts && !isSelected)
Container(
margin: const EdgeInsets.only(top: 4),
margin: const EdgeInsets.only(top: UiConstants.space1),
width: 4,
height: 4,
decoration: const BoxDecoration(
color: AppColors.krowBlue,
color: UiColors.primary,
shape: BoxShape.circle,
),
),
@@ -338,22 +329,22 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
],
),
),
const Divider(height: 1, color: AppColors.krowBorder),
const Divider(height: 1, color: UiColors.border),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.symmetric(horizontal: UiConstants.space5),
child: Column(
children: [
const SizedBox(height: 20),
const SizedBox(height: UiConstants.space5),
if (widget.pendingAssignments.isNotEmpty) ...[
_buildSectionHeader(
"Awaiting Confirmation",
const Color(0xFFF59E0B),
UiColors.textWarning,
),
...widget.pendingAssignments.map(
(shift) => Padding(
padding: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.only(bottom: UiConstants.space4),
child: ShiftAssignmentCard(
shift: shift,
onConfirm: () => _confirmShift(shift.id),
@@ -362,14 +353,14 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
),
),
),
const SizedBox(height: 12),
const SizedBox(height: UiConstants.space3),
],
if (visibleCancelledShifts.isNotEmpty) ...[
_buildSectionHeader("Cancelled Shifts", AppColors.krowMuted),
_buildSectionHeader("Cancelled Shifts", UiColors.textSecondary),
...visibleCancelledShifts.map(
(shift) => Padding(
padding: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.only(bottom: UiConstants.space4),
child: _buildCancelledCard(
title: shift.title,
client: shift.clientName,
@@ -383,15 +374,15 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
),
),
),
const SizedBox(height: 12),
const SizedBox(height: UiConstants.space3),
],
// Confirmed Shifts
if (visibleMyShifts.isNotEmpty) ...[
_buildSectionHeader("Confirmed Shifts", AppColors.krowMuted),
_buildSectionHeader("Confirmed Shifts", UiColors.textSecondary),
...visibleMyShifts.map(
(shift) => Padding(
padding: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.only(bottom: UiConstants.space3),
child: MyShiftCard(shift: shift),
),
),
@@ -417,7 +408,7 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
Widget _buildSectionHeader(String title, Color dotColor) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.only(bottom: UiConstants.space4),
child: Row(
children: [
Container(
@@ -425,16 +416,12 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
height: 8,
decoration: BoxDecoration(color: dotColor, shape: BoxShape.circle),
),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
Text(
title,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: dotColor == AppColors.krowMuted
? AppColors.krowMuted
: dotColor,
),
style: (dotColor == UiColors.textSecondary
? UiTypography.body2b.textSecondary
: UiTypography.body2b.copyWith(color: dotColor)),
),
],
),
@@ -455,11 +442,11 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.all(16),
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: AppColors.krowBorder),
color: UiColors.white,
borderRadius: BorderRadius.circular(UiConstants.radiusBase + 4),
border: Border.all(color: UiColors.border),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -470,33 +457,25 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
width: 6,
height: 6,
decoration: const BoxDecoration(
color: Color(0xFFEF4444),
color: UiColors.destructive,
shape: BoxShape.circle,
),
),
const SizedBox(width: 6),
const Text(
Text(
"CANCELLED",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: Color(0xFFEF4444),
),
style: UiTypography.footnote2b.textError,
),
if (isLastMinute) ...[
const SizedBox(width: 4),
const Text(
Text(
"• 4hr compensation",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w500,
color: Color(0xFF10B981),
),
style: UiTypography.footnote2m.textSuccess,
),
],
],
),
const SizedBox(height: 12),
const SizedBox(height: UiConstants.space3),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -504,18 +483,18 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
width: 44,
height: 44,
decoration: BoxDecoration(
color: AppColors.krowBlue.withOpacity(0.05),
borderRadius: BorderRadius.circular(12),
color: UiColors.primary.withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
child: const Center(
child: Icon(
LucideIcons.briefcase,
color: AppColors.krowBlue,
UiIcons.briefcase,
color: UiColors.primary,
size: 20,
),
),
),
const SizedBox(width: 12),
const SizedBox(width: UiConstants.space3),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -529,18 +508,11 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
children: [
Text(
title,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.krowCharcoal,
),
style: UiTypography.body2b.textPrimary,
),
Text(
client,
style: const TextStyle(
fontSize: 12,
color: AppColors.krowMuted,
),
style: UiTypography.footnote1r.textSecondary,
),
],
),
@@ -550,52 +522,39 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
children: [
Text(
pay,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColors.krowCharcoal,
),
style: UiTypography.headline4m.textPrimary,
),
Text(
rate,
style: const TextStyle(
fontSize: 10,
color: AppColors.krowMuted,
),
style: UiTypography.footnote2r.textSecondary,
),
],
),
],
),
const SizedBox(height: 8),
const SizedBox(height: UiConstants.space2),
Row(
children: [
const Icon(
LucideIcons.calendar,
UiIcons.calendar,
size: 12,
color: AppColors.krowMuted,
color: UiColors.textSecondary,
),
const SizedBox(width: 4),
Text(
date,
style: const TextStyle(
fontSize: 12,
color: AppColors.krowMuted,
),
style: UiTypography.footnote1r.textSecondary,
),
const SizedBox(width: 12),
const SizedBox(width: UiConstants.space3),
const Icon(
LucideIcons.clock,
UiIcons.clock,
size: 12,
color: AppColors.krowMuted,
color: UiColors.textSecondary,
),
const SizedBox(width: 4),
Text(
time,
style: const TextStyle(
fontSize: 12,
color: AppColors.krowMuted,
),
style: UiTypography.footnote1r.textSecondary,
),
],
),
@@ -603,18 +562,15 @@ class _MyShiftsTabState extends State<MyShiftsTab> {
Row(
children: [
const Icon(
LucideIcons.mapPin,
UiIcons.mapPin,
size: 12,
color: AppColors.krowMuted,
color: UiColors.textSecondary,
),
const SizedBox(width: 4),
Expanded(
child: Text(
address,
style: const TextStyle(
fontSize: 12,
color: AppColors.krowMuted,
),
style: UiTypography.footnote1r.textSecondary,
overflow: TextOverflow.ellipsis,
),
),