2585cce36d
- Wire daySheetsForUserProvider(userId) into ProgrammerDashboard so computeProgrammerStats/computeBadges receive real sheet data instead of the placeholder const <ProgrammerDaySheet>[]. - Monitor tab: watch allDaySheetsProvider and build sheetStatusByUser map for today; pass it to buildMonitorEntries; add "Sheets pending" chip (pending + disapproved today) to the summary row. - ProgrammerDrillDownScreen: add _RecentDaySheetsPanel below the dashboard showing the last 10 sheets (date + status pill) with tap-to-daySheetDetail. - DaySheetDetailScreen (T17 gaps): replace const [] liveRows with programmerDayDataProvider(sheet.workDate) built rows for non-approved sheets; fix _onApprove timer check to filter only the sheet programmer's own tasks (QN-1). - Add test/programmer_drill_down_test.dart (3 tests, all passing). Co-Authored-By: claude-flow <ruv@ruv.net>
129 lines
4.1 KiB
Dart
129 lines
4.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:tasq/models/profile.model.dart';
|
|
import 'package:tasq/models/programmer_day_sheet.model.dart';
|
|
import 'package:tasq/providers/leave_provider.dart';
|
|
import 'package:tasq/providers/programmer_day_data_provider.dart';
|
|
import 'package:tasq/providers/programmer_day_sheets_provider.dart';
|
|
import 'package:tasq/providers/programmer_tasks_provider.dart';
|
|
import 'package:tasq/providers/profile_provider.dart';
|
|
import 'package:tasq/screens/programmer_tasks/programmer_drill_down_screen.dart';
|
|
import 'package:tasq/theme/app_theme.dart';
|
|
import 'package:tasq/utils/app_time.dart';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
ProgrammerDaySheet _sheet({
|
|
required String id,
|
|
required String status,
|
|
required DateTime workDate,
|
|
}) {
|
|
final now = AppTime.now();
|
|
return ProgrammerDaySheet(
|
|
id: id,
|
|
programmerId: 'u1',
|
|
status: status,
|
|
workDate: workDate,
|
|
autoSubmitted: false,
|
|
resubmissions: 0,
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
);
|
|
}
|
|
|
|
Widget _buildApp(String userId, {List<Override> overrides = const []}) {
|
|
return ProviderScope(
|
|
overrides: overrides,
|
|
child: MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: ProgrammerDrillDownScreen(userId: userId),
|
|
),
|
|
);
|
|
}
|
|
|
|
List<Override> _minimalOverrides({
|
|
List<ProgrammerDaySheet> sheets = const [],
|
|
}) {
|
|
final today = DateTime.utc(2026, 9, 28);
|
|
return [
|
|
isStrictAdminProvider.overrideWith((ref) => true),
|
|
profilesProvider.overrideWith((ref) => Stream.value([])),
|
|
currentProfileProvider.overrideWith((ref) => Stream.value(null)),
|
|
programmerTasksProvider.overrideWith((ref) => Stream.value([])),
|
|
programmerRunStatesProvider.overrideWith((ref) => const {}),
|
|
clockTickerProvider.overrideWith((ref) => Stream.value(today)),
|
|
todayKeyProvider.overrideWith((ref) => today),
|
|
leavesProvider.overrideWith((ref) => Stream.value([])),
|
|
programmerDayDataProvider.overrideWith(
|
|
(ref, day) => Future.value(
|
|
DayActivityData(day: day, tasks: [], logsByTask: {}, workLogs: []),
|
|
),
|
|
),
|
|
daySheetsForUserProvider.overrideWith((ref, userId) => Stream.value(sheets)),
|
|
];
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Tests
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void main() {
|
|
setUpAll(AppTime.initialize);
|
|
|
|
group('ProgrammerDrillDownScreen — recent day sheets', () {
|
|
testWidgets('shows Recent day sheets header when there are sheets',
|
|
(tester) async {
|
|
final sheets = [
|
|
_sheet(
|
|
id: 's1',
|
|
status: DaySheetStatus.pending,
|
|
workDate: DateTime.utc(2026, 9, 27),
|
|
),
|
|
_sheet(
|
|
id: 's2',
|
|
status: DaySheetStatus.approved,
|
|
workDate: DateTime.utc(2026, 9, 26),
|
|
),
|
|
];
|
|
|
|
await tester.pumpWidget(
|
|
_buildApp('u1', overrides: _minimalOverrides(sheets: sheets)),
|
|
);
|
|
await tester.pump();
|
|
|
|
// AppSectionHeader renders title in uppercase
|
|
expect(find.text('RECENT DAY SHEETS'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('shows both sheet dates', (tester) async {
|
|
final d1 = DateTime.utc(2026, 9, 27);
|
|
final d2 = DateTime.utc(2026, 9, 26);
|
|
final sheets = [
|
|
_sheet(id: 's1', status: DaySheetStatus.pending, workDate: d1),
|
|
_sheet(id: 's2', status: DaySheetStatus.approved, workDate: d2),
|
|
];
|
|
|
|
await tester.pumpWidget(
|
|
_buildApp('u1', overrides: _minimalOverrides(sheets: sheets)),
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.text(AppTime.formatDate(d1)), findsOneWidget);
|
|
expect(find.text(AppTime.formatDate(d2)), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('shows RECENT DAY SHEETS even with empty sheets list',
|
|
(tester) async {
|
|
await tester.pumpWidget(
|
|
_buildApp('u1', overrides: _minimalOverrides()),
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.text('RECENT DAY SHEETS'), findsOneWidget);
|
|
});
|
|
});
|
|
}
|