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:
@@ -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'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user