Skip to content

Commit fe09c63

Browse files
committed
feat: display and manage categories in table
- Implemented data table for categories - Added loading and failure states - Implemented delete functionality - Implemented edit functionality
1 parent f154623 commit fe09c63

File tree

1 file changed

+162
-4
lines changed

1 file changed

+162
-4
lines changed
Lines changed: 162 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,174 @@
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 categories_page}
4-
/// A placeholder page for Categories.
15+
/// A page for displaying and managing Categories in a tabular format.
516
/// {@endtemplate}
6-
class CategoriesPage extends StatelessWidget {
17+
class CategoriesPage extends StatefulWidget {
718
/// {@macro categories_page}
819
const CategoriesPage({super.key});
920

21+
@override
22+
State<CategoriesPage> createState() => _CategoriesPageState();
23+
}
24+
25+
class _CategoriesPageState extends State<CategoriesPage> {
26+
static const int _rowsPerPage = 10;
27+
28+
@override
29+
void initState() {
30+
super.initState();
31+
context.read<ContentManagementBloc>().add(
32+
const LoadCategoriesRequested(limit: _rowsPerPage),
33+
);
34+
}
35+
1036
@override
1137
Widget build(BuildContext context) {
12-
return const Center(
13-
child: Text('Categories 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.categoriesStatus == ContentManagementStatus.loading &&
44+
state.categories.isEmpty) {
45+
return LoadingStateWidget(
46+
icon: Icons.category,
47+
headline: l10n.loadingCategories,
48+
subheadline: l10n.pleaseWait,
49+
);
50+
}
51+
52+
if (state.categoriesStatus == ContentManagementStatus.failure) {
53+
return FailureStateWidget(
54+
message: state.errorMessage ?? l10n.unknownError,
55+
onRetry: () => context.read<ContentManagementBloc>().add(
56+
const LoadCategoriesRequested(limit: _rowsPerPage),
57+
),
58+
);
59+
}
60+
61+
if (state.categories.isEmpty) {
62+
return Center(
63+
child: Text(l10n.noCategoriesFound),
64+
);
65+
}
66+
67+
return PaginatedDataTable2(
68+
columns: [
69+
DataColumn2(
70+
label: Text(l10n.categoryName),
71+
size: ColumnSize.L,
72+
),
73+
DataColumn2(
74+
label: Text(l10n.description),
75+
size: ColumnSize.M,
76+
),
77+
DataColumn2(
78+
label: Text(l10n.actions),
79+
size: ColumnSize.S,
80+
),
81+
],
82+
source: _CategoriesDataSource(
83+
context: context,
84+
categories: state.categories,
85+
l10n: l10n,
86+
),
87+
rowsPerPage: _rowsPerPage,
88+
availableRowsPerPage: const [_rowsPerPage],
89+
onPageChanged: (pageIndex) {
90+
final newOffset = pageIndex * _rowsPerPage;
91+
if (newOffset >= state.categories.length &&
92+
state.categoriesHasMore) {
93+
context.read<ContentManagementBloc>().add(
94+
LoadCategoriesRequested(
95+
startAfterId: state.categoriesCursor,
96+
limit: _rowsPerPage,
97+
),
98+
);
99+
}
100+
},
101+
empty: Center(child: Text(l10n.noCategoriesFound)),
102+
showCheckboxColumn: false,
103+
showFirstLastButtons: true,
104+
fit: FlexFit.tight,
105+
headingRowHeight: 56,
106+
dataRowHeight: 56,
107+
columnSpacing: AppSpacing.md,
108+
horizontalMargin: AppSpacing.md,
109+
);
110+
},
111+
),
14112
);
15113
}
16114
}
115+
116+
class _CategoriesDataSource extends DataTableSource {
117+
_CategoriesDataSource({
118+
required this.context,
119+
required this.categories,
120+
required this.l10n,
121+
});
122+
123+
final BuildContext context;
124+
final List<Category> categories;
125+
final AppLocalizations l10n;
126+
127+
@override
128+
DataRow? getRow(int index) {
129+
if (index >= categories.length) {
130+
return null;
131+
}
132+
final category = categories[index];
133+
return DataRow2(
134+
cells: [
135+
DataCell(Text(category.name)),
136+
DataCell(Text(category.description ?? l10n.notAvailable)),
137+
DataCell(
138+
Row(
139+
children: [
140+
IconButton(
141+
icon: const Icon(Icons.edit),
142+
onPressed: () {
143+
// Navigate to edit page
144+
context.goNamed(
145+
Routes.editCategoryName, // Assuming an edit route exists
146+
pathParameters: {'id': category.id},
147+
);
148+
},
149+
),
150+
IconButton(
151+
icon: const Icon(Icons.delete),
152+
onPressed: () {
153+
// Dispatch delete event
154+
context.read<ContentManagementBloc>().add(
155+
DeleteCategoryRequested(category.id),
156+
);
157+
},
158+
),
159+
],
160+
),
161+
),
162+
],
163+
);
164+
}
165+
166+
@override
167+
bool get isRowCountApproximate => false;
168+
169+
@override
170+
int get rowCount => categories.length;
171+
172+
@override
173+
int get selectedRowCount => 0;
174+
}

0 commit comments

Comments
 (0)