Skip to content

Commit 173e2e6

Browse files
committed
feat: display and manage sources in a table
- Implemented data table for sources - Added loading and failure states - Implemented pagination - Added edit and delete actions
1 parent b5687c6 commit 173e2e6

File tree

1 file changed

+166
-4
lines changed

1 file changed

+166
-4
lines changed
Lines changed: 166 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,178 @@
1+
import 'package:data_table_2/data_table_2.dart';
12
import 'package:flutter/material.dart';
3+
import 'package:flutter_bloc/flutter_bloc.dart';
4+
import 'package:go_router/go_router.dart';
5+
import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart';
6+
import 'package:ht_dashboard/l10n/app_localizations.dart';
7+
import 'package:ht_dashboard/l10n/l10n.dart';
8+
import 'package:ht_dashboard/router/routes.dart';
9+
import 'package:ht_dashboard/shared/constants/app_spacing.dart';
10+
import 'package:ht_dashboard/shared/widgets/failure_state_widget.dart';
11+
import 'package:ht_dashboard/shared/widgets/loading_state_widget.dart';
12+
import 'package:ht_shared/ht_shared.dart';
213

314
/// {@template sources_page}
4-
/// A placeholder page for Sources.
15+
/// A page for displaying and managing Sources in a tabular format.
516
/// {@endtemplate}
6-
class SourcesPage extends StatelessWidget {
17+
class SourcesPage extends StatefulWidget {
718
/// {@macro sources_page}
819
const SourcesPage({super.key});
920

21+
@override
22+
State<SourcesPage> createState() => _SourcesPageState();
23+
}
24+
25+
class _SourcesPageState extends State<SourcesPage> {
26+
static const int _rowsPerPage = 10;
27+
28+
@override
29+
void initState() {
30+
super.initState();
31+
context.read<ContentManagementBloc>().add(
32+
const LoadSourcesRequested(limit: _rowsPerPage),
33+
);
34+
}
35+
1036
@override
1137
Widget build(BuildContext context) {
12-
return const Center(
13-
child: Text('Sources Page'),
38+
final l10n = context.l10n;
39+
return Padding(
40+
padding: const EdgeInsets.all(AppSpacing.lg),
41+
child: BlocBuilder<ContentManagementBloc, ContentManagementState>(
42+
builder: (context, state) {
43+
if (state.sourcesStatus == ContentManagementStatus.loading &&
44+
state.sources.isEmpty) {
45+
return LoadingStateWidget(
46+
icon: Icons.source,
47+
headline: l10n.loadingSources,
48+
subheadline: l10n.pleaseWait,
49+
);
50+
}
51+
52+
if (state.sourcesStatus == ContentManagementStatus.failure) {
53+
return FailureStateWidget(
54+
message: state.errorMessage ?? l10n.unknownError,
55+
onRetry: () => context.read<ContentManagementBloc>().add(
56+
const LoadSourcesRequested(limit: _rowsPerPage),
57+
),
58+
);
59+
}
60+
61+
if (state.sources.isEmpty) {
62+
return Center(
63+
child: Text(l10n.noSourcesFound),
64+
);
65+
}
66+
67+
return PaginatedDataTable2(
68+
columns: [
69+
DataColumn2(
70+
label: Text(l10n.sourceName),
71+
size: ColumnSize.L,
72+
),
73+
DataColumn2(
74+
label: Text(l10n.sourceType),
75+
size: ColumnSize.M,
76+
),
77+
DataColumn2(
78+
label: Text(l10n.language),
79+
size: ColumnSize.S,
80+
),
81+
DataColumn2(
82+
label: Text(l10n.actions),
83+
size: ColumnSize.S,
84+
),
85+
],
86+
source: _SourcesDataSource(
87+
context: context,
88+
sources: state.sources,
89+
l10n: l10n,
90+
),
91+
rowsPerPage: _rowsPerPage,
92+
availableRowsPerPage: const [_rowsPerPage],
93+
onPageChanged: (pageIndex) {
94+
final newOffset = pageIndex * _rowsPerPage;
95+
if (newOffset >= state.sources.length && state.sourcesHasMore) {
96+
context.read<ContentManagementBloc>().add(
97+
LoadSourcesRequested(
98+
startAfterId: state.sourcesCursor,
99+
limit: _rowsPerPage,
100+
),
101+
);
102+
}
103+
},
104+
empty: Center(child: Text(l10n.noSourcesFound)),
105+
showCheckboxColumn: false,
106+
showFirstLastButtons: true,
107+
fit: FlexFit.tight,
108+
headingRowHeight: 56,
109+
dataRowHeight: 56,
110+
columnSpacing: AppSpacing.md,
111+
horizontalMargin: AppSpacing.md,
112+
);
113+
},
114+
),
14115
);
15116
}
16117
}
118+
119+
class _SourcesDataSource extends DataTableSource {
120+
_SourcesDataSource({
121+
required this.context,
122+
required this.sources,
123+
required this.l10n,
124+
});
125+
126+
final BuildContext context;
127+
final List<Source> sources;
128+
final AppLocalizations l10n;
129+
130+
@override
131+
DataRow? getRow(int index) {
132+
if (index >= sources.length) {
133+
return null;
134+
}
135+
final source = sources[index];
136+
return DataRow2(
137+
cells: [
138+
DataCell(Text(source.name)),
139+
DataCell(Text(source.sourceType?.name ?? l10n.unknown)),
140+
DataCell(Text(source.language ?? l10n.unknown)),
141+
DataCell(
142+
Row(
143+
children: [
144+
IconButton(
145+
icon: const Icon(Icons.edit),
146+
onPressed: () {
147+
// Navigate to edit page
148+
context.goNamed(
149+
Routes.editSourceName, // Assuming an edit route exists
150+
pathParameters: {'id': source.id},
151+
);
152+
},
153+
),
154+
IconButton(
155+
icon: const Icon(Icons.delete),
156+
onPressed: () {
157+
// Dispatch delete event
158+
context.read<ContentManagementBloc>().add(
159+
DeleteSourceRequested(source.id),
160+
);
161+
},
162+
),
163+
],
164+
),
165+
),
166+
],
167+
);
168+
}
169+
170+
@override
171+
bool get isRowCountApproximate => false;
172+
173+
@override
174+
int get rowCount => sources.length;
175+
176+
@override
177+
int get selectedRowCount => 0;
178+
}

0 commit comments

Comments
 (0)