feat: Add support for displaying recurring shift details including start/end dates and recurring days.
This commit is contained in:
@@ -116,8 +116,9 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
||||
);
|
||||
}
|
||||
|
||||
final Shift displayShift =
|
||||
state is ShiftDetailsLoaded ? state.shift : widget.shift;
|
||||
final Shift displayShift = state is ShiftDetailsLoaded
|
||||
? state.shift
|
||||
: widget.shift;
|
||||
final i18n = Translations.of(context).staff_shifts.shift_details;
|
||||
|
||||
final duration = _calculateDuration(displayShift);
|
||||
@@ -154,6 +155,10 @@ class _ShiftDetailsPageState extends State<ShiftDetailsPage> {
|
||||
shiftDateLabel: i18n.shift_date,
|
||||
clockInLabel: i18n.start_time,
|
||||
clockOutLabel: i18n.end_time,
|
||||
startDate: displayShift.startDate,
|
||||
endDate: displayShift.endDate,
|
||||
recurringDays: displayShift.recurringDays,
|
||||
permanentDays: displayShift.permanentDays,
|
||||
),
|
||||
const Divider(height: 1, thickness: 0.5),
|
||||
if (displayShift.breakInfo != null &&
|
||||
|
||||
@@ -342,31 +342,31 @@ class _MyShiftCardState extends State<MyShiftCard> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
UiIcons.clock,
|
||||
size: UiConstants.iconXs,
|
||||
color: UiColors.primary,
|
||||
color: UiColors.iconSecondary,
|
||||
),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
'${schedules.length} schedules',
|
||||
style: UiTypography.footnote2m.copyWith(
|
||||
color: UiColors.primary,
|
||||
),
|
||||
scheduleRange,
|
||||
style:
|
||||
UiTypography.footnote2r.textSecondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: Text(
|
||||
scheduleRange,
|
||||
style: UiTypography.footnote2r.copyWith(
|
||||
color: UiColors.primary,
|
||||
),
|
||||
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
|
||||
Text(
|
||||
'${schedules.length} schedules',
|
||||
style: UiTypography.footnote2m.copyWith(
|
||||
color: UiColors.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
...visibleSchedules.map(
|
||||
(schedule) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
|
||||
@@ -6,19 +6,19 @@ import 'package:intl/intl.dart';
|
||||
class ShiftDateTimeSection extends StatelessWidget {
|
||||
/// The ISO string of the date.
|
||||
final String date;
|
||||
|
||||
|
||||
/// The start time string (HH:mm).
|
||||
final String startTime;
|
||||
|
||||
|
||||
/// The end time string (HH:mm).
|
||||
final String endTime;
|
||||
|
||||
|
||||
/// Localization string for shift date.
|
||||
final String shiftDateLabel;
|
||||
|
||||
|
||||
/// Localization string for clock in time.
|
||||
final String clockInLabel;
|
||||
|
||||
|
||||
/// Localization string for clock out time.
|
||||
final String clockOutLabel;
|
||||
|
||||
@@ -31,8 +31,17 @@ class ShiftDateTimeSection extends StatelessWidget {
|
||||
required this.shiftDateLabel,
|
||||
required this.clockInLabel,
|
||||
required this.clockOutLabel,
|
||||
this.startDate,
|
||||
this.endDate,
|
||||
this.recurringDays,
|
||||
this.permanentDays,
|
||||
});
|
||||
|
||||
final String? startDate;
|
||||
final String? endDate;
|
||||
final List<String>? recurringDays;
|
||||
final List<String>? permanentDays;
|
||||
|
||||
String _formatTime(String time) {
|
||||
if (time.isEmpty) return '';
|
||||
try {
|
||||
@@ -70,34 +79,41 @@ class ShiftDateTimeSection extends StatelessWidget {
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
UiIcons.calendar,
|
||||
size: 20,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
const Icon(UiIcons.calendar, size: 20, color: UiColors.primary),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
Text(
|
||||
_formatDate(date),
|
||||
style: UiTypography.headline5m.textPrimary,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
startDate != null && endDate != null
|
||||
? '${DateFormat('MMM d, y').format(DateTime.parse(startDate!))} – ${DateFormat('MMM d, y').format(DateTime.parse(endDate!))}'
|
||||
: _formatDate(date),
|
||||
style: UiTypography.headline5m.textPrimary,
|
||||
),
|
||||
if (recurringDays != null || permanentDays != null) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
(recurringDays ?? permanentDays ?? [])
|
||||
.map(
|
||||
(d) =>
|
||||
'${d[0].toUpperCase()}${d.substring(1, 3).toLowerCase()}',
|
||||
)
|
||||
.join(', '),
|
||||
style: UiTypography.footnote2r.textSecondary,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildTimeBox(
|
||||
clockInLabel,
|
||||
startTime,
|
||||
),
|
||||
),
|
||||
Expanded(child: _buildTimeBox(clockInLabel, startTime)),
|
||||
const SizedBox(width: UiConstants.space4),
|
||||
Expanded(
|
||||
child: _buildTimeBox(
|
||||
clockOutLabel,
|
||||
endTime,
|
||||
),
|
||||
),
|
||||
Expanded(child: _buildTimeBox(clockOutLabel, endTime)),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user