Skip to content

Commit db11d3f

Browse files
committed
feat(content-management): add create category page
- Creates new page for category creation - Integrates with CreateCategoryBloc - Handles form input and submission - Displays success and error messages - Refreshes category list on success
1 parent 8edfa8e commit db11d3f

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_bloc/flutter_bloc.dart';
3+
import 'package:go_router/go_router.dart';
4+
import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart';
5+
import 'package:ht_dashboard/content_management/bloc/create_category/create_category_bloc.dart';
6+
import 'package:ht_dashboard/l10n/l10n.dart';
7+
import 'package:ht_dashboard/shared/shared.dart';
8+
import 'package:ht_data_repository/ht_data_repository.dart';
9+
import 'package:ht_shared/ht_shared.dart';
10+
11+
/// {@template create_category_page}
12+
/// A page for creating a new category.
13+
/// It uses a [BlocProvider] to create and provide a [CreateCategoryBloc].
14+
/// {@endtemplate}
15+
class CreateCategoryPage extends StatelessWidget {
16+
/// {@macro create_category_page}
17+
const CreateCategoryPage({super.key});
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
return BlocProvider(
22+
create: (context) => CreateCategoryBloc(
23+
categoriesRepository: context.read<HtDataRepository<Category>>(),
24+
),
25+
child: const _CreateCategoryView(),
26+
);
27+
}
28+
}
29+
30+
class _CreateCategoryView extends StatefulWidget {
31+
const _CreateCategoryView();
32+
33+
@override
34+
State<_CreateCategoryView> createState() => _CreateCategoryViewState();
35+
}
36+
37+
class _CreateCategoryViewState extends State<_CreateCategoryView> {
38+
final _formKey = GlobalKey<FormState>();
39+
40+
@override
41+
Widget build(BuildContext context) {
42+
final l10n = context.l10n;
43+
return Scaffold(
44+
appBar: AppBar(
45+
title: Text(l10n.createCategory),
46+
actions: [
47+
BlocBuilder<CreateCategoryBloc, CreateCategoryState>(
48+
builder: (context, state) {
49+
if (state.status == CreateCategoryStatus.submitting) {
50+
return const Padding(
51+
padding: EdgeInsets.only(right: AppSpacing.lg),
52+
child: SizedBox(
53+
width: 24,
54+
height: 24,
55+
child: CircularProgressIndicator(strokeWidth: 3),
56+
),
57+
);
58+
}
59+
return IconButton(
60+
icon: const Icon(Icons.save),
61+
tooltip: l10n.saveChanges,
62+
onPressed: state.isFormValid
63+
? () => context.read<CreateCategoryBloc>().add(
64+
const CreateCategorySubmitted(),
65+
)
66+
: null,
67+
);
68+
},
69+
),
70+
],
71+
),
72+
body: BlocConsumer<CreateCategoryBloc, CreateCategoryState>(
73+
listenWhen: (previous, current) => previous.status != current.status,
74+
listener: (context, state) {
75+
if (state.status == CreateCategoryStatus.success &&
76+
ModalRoute.of(context)!.isCurrent) {
77+
ScaffoldMessenger.of(context)
78+
..hideCurrentSnackBar()
79+
..showSnackBar(
80+
SnackBar(
81+
content: Text(l10n.categoryCreatedSuccessfully),
82+
),
83+
);
84+
context.read<ContentManagementBloc>().add(
85+
const LoadCategoriesRequested(),
86+
);
87+
context.pop();
88+
}
89+
if (state.status == CreateCategoryStatus.failure) {
90+
ScaffoldMessenger.of(context)
91+
..hideCurrentSnackBar()
92+
..showSnackBar(
93+
SnackBar(
94+
content: Text(state.errorMessage ?? l10n.unknownError),
95+
backgroundColor: Theme.of(context).colorScheme.error,
96+
),
97+
);
98+
}
99+
},
100+
builder: (context, state) {
101+
return SingleChildScrollView(
102+
child: Padding(
103+
padding: const EdgeInsets.all(AppSpacing.lg),
104+
child: Form(
105+
key: _formKey,
106+
child: Column(
107+
crossAxisAlignment: CrossAxisAlignment.start,
108+
children: [
109+
TextFormField(
110+
initialValue: state.name,
111+
decoration: InputDecoration(
112+
labelText: l10n.categoryName,
113+
border: const OutlineInputBorder(),
114+
),
115+
onChanged: (value) => context
116+
.read<CreateCategoryBloc>()
117+
.add(CreateCategoryNameChanged(value)),
118+
),
119+
const SizedBox(height: AppSpacing.lg),
120+
TextFormField(
121+
initialValue: state.description,
122+
decoration: InputDecoration(
123+
labelText: l10n.description,
124+
border: const OutlineInputBorder(),
125+
),
126+
maxLines: 3,
127+
onChanged: (value) => context
128+
.read<CreateCategoryBloc>()
129+
.add(CreateCategoryDescriptionChanged(value)),
130+
),
131+
const SizedBox(height: AppSpacing.lg),
132+
TextFormField(
133+
initialValue: state.iconUrl,
134+
decoration: InputDecoration(
135+
labelText: l10n.iconUrl,
136+
border: const OutlineInputBorder(),
137+
),
138+
onChanged: (value) => context
139+
.read<CreateCategoryBloc>()
140+
.add(CreateCategoryIconUrlChanged(value)),
141+
),
142+
],
143+
),
144+
),
145+
),
146+
);
147+
},
148+
),
149+
);
150+
}
151+
}

0 commit comments

Comments
 (0)