add auth, format

This commit is contained in:
Phuoc Nguyen
2025-11-07 11:52:06 +07:00
parent 24a8508fce
commit 3803bd26e0
173 changed files with 8505 additions and 7116 deletions

View File

@@ -74,12 +74,16 @@ class ProductsLocalDataSourceImpl implements ProductsLocalDataSource {
{
'product_id': 'prod_001',
'name': 'Gạch Cát Tường 1200x1200',
'description': 'Gạch men bóng kiếng cao cấp, chống trượt, độ bền cao. Phù hợp cho phòng khách, phòng ngủ.',
'description':
'Gạch men bóng kiếng cao cấp, chống trượt, độ bền cao. Phù hợp cho phòng khách, phòng ngủ.',
'base_price': 450000.0,
'unit': '',
'images': ['https://www.eurotile.vn/pictures/catalog/product/0-gachkholon/cat-tuong/CAT-S01G-1.jpg'],
'images': [
'https://www.eurotile.vn/pictures/catalog/product/0-gachkholon/cat-tuong/CAT-S01G-1.jpg',
],
'image_captions': {},
'link_360': 'https://design.eurotile.vn/pub/tool/panorama/show?obsPlanId=3FO3H1VE59R5&locale=en_US',
'link_360':
'https://design.eurotile.vn/pub/tool/panorama/show?obsPlanId=3FO3H1VE59R5&locale=en_US',
'specifications': {},
'category': 'floor_tiles',
'brand': 'Eurotile',
@@ -92,12 +96,16 @@ class ProductsLocalDataSourceImpl implements ProductsLocalDataSource {
{
'product_id': 'prod_002',
'name': 'Gạch granite nhập khẩu',
'description': 'Gạch granite nhập khẩu Tây Ban Nha, vân đá tự nhiên, sang trọng. Kích thước 80x80cm.',
'description':
'Gạch granite nhập khẩu Tây Ban Nha, vân đá tự nhiên, sang trọng. Kích thước 80x80cm.',
'base_price': 680000.0,
'unit': '',
'images': ['https://images.unsplash.com/photo-1565193566173-7a0ee3dbe261?w=300&h=300&fit=crop'],
'images': [
'https://images.unsplash.com/photo-1565193566173-7a0ee3dbe261?w=300&h=300&fit=crop',
],
'image_captions': {},
'link_360': 'https://design.eurotile.vn/pub/tool/panorama/show?obsPlanId=3FO3H1VE59R&locale=en_US',
'link_360':
'https://design.eurotile.vn/pub/tool/panorama/show?obsPlanId=3FO3H1VE59R&locale=en_US',
'specifications': {},
'category': 'floor_tiles',
'brand': 'Vasta Stone',
@@ -110,12 +118,16 @@ class ProductsLocalDataSourceImpl implements ProductsLocalDataSource {
{
'product_id': 'prod_003',
'name': 'Gạch mosaic trang trí',
'description': 'Gạch mosaic thủy tinh màu sắc đa dạng, tạo điểm nhấn cho không gian. Kích thước 30x30cm.',
'description':
'Gạch mosaic thủy tinh màu sắc đa dạng, tạo điểm nhấn cho không gian. Kích thước 30x30cm.',
'base_price': 320000.0,
'unit': '',
'images': ['https://images.unsplash.com/photo-1615971677499-5467cbab01c0?w=300&h=300&fit=crop'],
'images': [
'https://images.unsplash.com/photo-1615971677499-5467cbab01c0?w=300&h=300&fit=crop',
],
'image_captions': {},
'link_360': 'https://design.eurotile.vn/pub/tool/panorama/show?obsPlanId=3FO3H1VE59R5&locale=en_US',
'link_360':
'https://design.eurotile.vn/pub/tool/panorama/show?obsPlanId=3FO3H1VE59R5&locale=en_US',
'specifications': {},
'category': 'decorative_tiles',
'brand': 'Eurotile',
@@ -128,12 +140,16 @@ class ProductsLocalDataSourceImpl implements ProductsLocalDataSource {
{
'product_id': 'prod_004',
'name': 'Gạch 3D họa tiết',
'description': 'Gạch 3D với họa tiết nổi độc đáo, tạo hiệu ứng thị giác ấn tượng cho tường phòng khách.',
'description':
'Gạch 3D với họa tiết nổi độc đáo, tạo hiệu ứng thị giác ấn tượng cho tường phòng khách.',
'base_price': 750000.0,
'unit': '',
'images': ['https://images.unsplash.com/photo-1600566753190-17f0baa2a6c3?w=300&h=300&fit=crop'],
'images': [
'https://images.unsplash.com/photo-1600566753190-17f0baa2a6c3?w=300&h=300&fit=crop',
],
'image_captions': {},
'link_360': 'https://design.eurotile.vn/pub/tool/panorama/show?obsPlanId=3FO3H1VE59R5&locale=en_US',
'link_360':
'https://design.eurotile.vn/pub/tool/panorama/show?obsPlanId=3FO3H1VE59R5&locale=en_US',
'specifications': {},
'category': 'wall_tiles',
'brand': 'Vasta Stone',
@@ -146,12 +162,16 @@ class ProductsLocalDataSourceImpl implements ProductsLocalDataSource {
{
'product_id': 'prod_005',
'name': 'Gạch ceramic chống trượt',
'description': 'Gạch ceramic chống trượt cấp độ R11, an toàn cho phòng tắm và ban công. Kích thước 40x40cm.',
'description':
'Gạch ceramic chống trượt cấp độ R11, an toàn cho phòng tắm và ban công. Kích thước 40x40cm.',
'base_price': 380000.0,
'unit': '',
'images': ['https://images.unsplash.com/photo-1615874694520-474822394e73?w=300&h=300&fit=crop'],
'images': [
'https://images.unsplash.com/photo-1615874694520-474822394e73?w=300&h=300&fit=crop',
],
'image_captions': {},
'link_360': 'https://design.eurotile.vn/pub/tool/panorama/show?obsPlanId=3FO3H1VE59R5&locale=en_US',
'link_360':
'https://design.eurotile.vn/pub/tool/panorama/show?obsPlanId=3FO3H1VE59R5&locale=en_US',
'specifications': {},
'category': 'outdoor_tiles',
'brand': 'Eurotile',
@@ -164,10 +184,13 @@ class ProductsLocalDataSourceImpl implements ProductsLocalDataSource {
{
'product_id': 'prod_006',
'name': 'Gạch terrazzo đá mài',
'description': 'Gạch terrazzo phong cách retro, đá mài hạt màu, độc đáo và bền đẹp theo thời gian.',
'description':
'Gạch terrazzo phong cách retro, đá mài hạt màu, độc đáo và bền đẹp theo thời gian.',
'base_price': 890000.0,
'unit': '',
'images': ['https://images.unsplash.com/photo-1564013799919-ab600027ffc6?w=300&h=300&fit=crop'],
'images': [
'https://images.unsplash.com/photo-1564013799919-ab600027ffc6?w=300&h=300&fit=crop',
],
'image_captions': {},
'link_360': null,
'specifications': {},
@@ -186,9 +209,7 @@ class ProductsLocalDataSourceImpl implements ProductsLocalDataSource {
// Simulate network delay
await Future.delayed(const Duration(milliseconds: 500));
return _productsJson
.map((json) => ProductModel.fromJson(json))
.toList();
return _productsJson.map((json) => ProductModel.fromJson(json)).toList();
}
@override
@@ -245,8 +266,6 @@ class ProductsLocalDataSourceImpl implements ProductsLocalDataSource {
// Simulate network delay
await Future.delayed(const Duration(milliseconds: 300));
return _categoriesJson
.map((json) => CategoryModel.fromJson(json))
.toList();
return _categoriesJson.map((json) => CategoryModel.fromJson(json)).toList();
}
}

View File

@@ -139,11 +139,13 @@ class ProductModel extends HiveObject {
'description': description,
'base_price': basePrice,
'images': images != null ? jsonDecode(images!) : null,
'image_captions':
imageCaptions != null ? jsonDecode(imageCaptions!) : null,
'image_captions': imageCaptions != null
? jsonDecode(imageCaptions!)
: null,
'link_360': link360,
'specifications':
specifications != null ? jsonDecode(specifications!) : null,
'specifications': specifications != null
? jsonDecode(specifications!)
: null,
'category': category,
'brand': brand,
'unit': unit,

View File

@@ -16,9 +16,7 @@ import 'package:worker/features/products/domain/repositories/products_repository
class ProductsRepositoryImpl implements ProductsRepository {
final ProductsLocalDataSource localDataSource;
const ProductsRepositoryImpl({
required this.localDataSource,
});
const ProductsRepositoryImpl({required this.localDataSource});
@override
Future<List<Product>> getAllProducts() async {
@@ -43,7 +41,9 @@ class ProductsRepositoryImpl implements ProductsRepository {
@override
Future<List<Product>> getProductsByCategory(String categoryId) async {
try {
final productModels = await localDataSource.getProductsByCategory(categoryId);
final productModels = await localDataSource.getProductsByCategory(
categoryId,
);
return productModels.map((model) => model.toEntity()).toList();
} catch (e) {
throw Exception('Failed to get products by category: $e');

View File

@@ -26,10 +26,7 @@ import 'package:worker/features/products/presentation/widgets/product_detail/sti
class ProductDetailPage extends ConsumerStatefulWidget {
final String productId;
const ProductDetailPage({
super.key,
required this.productId,
});
const ProductDetailPage({super.key, required this.productId});
@override
ConsumerState<ProductDetailPage> createState() => _ProductDetailPageState();
@@ -70,9 +67,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
_isFavorite
? 'Đã thêm vào yêu thích'
: 'Đã xóa khỏi yêu thích',
_isFavorite ? 'Đã thêm vào yêu thích' : 'Đã xóa khỏi yêu thích',
),
duration: const Duration(seconds: 1),
),
@@ -109,10 +104,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
// Title
const Text(
'Chia sẻ sản phẩm',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
),
const SizedBox(height: AppSpacing.lg),
@@ -144,9 +136,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
Navigator.pop(context);
// TODO: Copy to clipboard
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Đã sao chép link sản phẩm!'),
),
const SnackBar(content: Text('Đã sao chép link sản phẩm!')),
);
},
),
@@ -269,9 +259,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
);
},
loading: () => const Center(
child: CircularProgressIndicator(
color: AppColors.primaryBlue,
),
child: CircularProgressIndicator(color: AppColors.primaryBlue),
),
error: (error, stack) => Center(
child: Padding(
@@ -287,10 +275,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
const SizedBox(height: AppSpacing.lg),
const Text(
'Không thể tải thông tin sản phẩm',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
textAlign: TextAlign.center,
),
const SizedBox(height: AppSpacing.sm),

View File

@@ -55,7 +55,10 @@ class ProductsPage extends ConsumerWidget {
backgroundColor: AppColors.danger,
textColor: AppColors.white,
isLabelVisible: cartItemCount > 0,
child: const Icon(Icons.shopping_cart_outlined, color: Colors.black),
child: const Icon(
Icons.shopping_cart_outlined,
color: Colors.black,
),
),
onPressed: () => context.push(RouteNames.cart),
),
@@ -74,9 +77,7 @@ class ProductsPage extends ConsumerWidget {
data: (categories) => CategoryFilterChips(categories: categories),
loading: () => const SizedBox(
height: 48.0,
child: Center(
child: CircularProgressIndicator(strokeWidth: 2.0),
),
child: Center(child: CircularProgressIndicator(strokeWidth: 2.0)),
),
error: (error, stack) => const SizedBox.shrink(),
),
@@ -115,7 +116,8 @@ class ProductsPage extends ConsumerWidget {
);
},
loading: () => _buildLoadingState(),
error: (error, stack) => _buildErrorState(context, l10n, error, ref),
error: (error, stack) =>
_buildErrorState(context, l10n, error, ref),
),
),
],
@@ -146,10 +148,7 @@ class ProductsPage extends ConsumerWidget {
const SizedBox(height: AppSpacing.sm),
Text(
l10n.noResults,
style: const TextStyle(
fontSize: 14.0,
color: AppColors.grey500,
),
style: const TextStyle(fontSize: 14.0, color: AppColors.grey500),
),
],
),
@@ -159,9 +158,7 @@ class ProductsPage extends ConsumerWidget {
/// Build loading state
Widget _buildLoadingState() {
return const Center(
child: CircularProgressIndicator(
color: AppColors.primaryBlue,
),
child: CircularProgressIndicator(color: AppColors.primaryBlue),
);
}
@@ -195,10 +192,7 @@ class ProductsPage extends ConsumerWidget {
const SizedBox(height: AppSpacing.sm),
Text(
error.toString(),
style: const TextStyle(
fontSize: 14.0,
color: AppColors.grey500,
),
style: const TextStyle(fontSize: 14.0, color: AppColors.grey500),
textAlign: TextAlign.center,
),
const SizedBox(height: AppSpacing.lg),

View File

@@ -17,10 +17,7 @@ import 'package:worker/features/products/presentation/providers/selected_categor
class CategoryFilterChips extends ConsumerWidget {
final List<Category> categories;
const CategoryFilterChips({
super.key,
required this.categories,
});
const CategoryFilterChips({super.key, required this.categories});
@override
Widget build(BuildContext context, WidgetRef ref) {
@@ -32,7 +29,8 @@ class CategoryFilterChips extends ConsumerWidget {
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
itemCount: categories.length,
separatorBuilder: (context, index) => const SizedBox(width: AppSpacing.sm),
separatorBuilder: (context, index) =>
const SizedBox(width: AppSpacing.sm),
itemBuilder: (context, index) {
final category = categories[index];
final isSelected = selectedCategory == category.id;
@@ -49,7 +47,9 @@ class CategoryFilterChips extends ConsumerWidget {
selected: isSelected,
onSelected: (selected) {
if (selected) {
ref.read(selectedCategoryProvider.notifier).updateCategory(category.id);
ref
.read(selectedCategoryProvider.notifier)
.updateCategory(category.id);
}
},
backgroundColor: AppColors.white,

View File

@@ -70,9 +70,7 @@ class ProductCard extends ConsumerWidget {
placeholder: (context, url) => Shimmer.fromColors(
baseColor: AppColors.grey100,
highlightColor: AppColors.grey50,
child: Container(
color: AppColors.grey100,
),
child: Container(color: AppColors.grey100),
),
errorWidget: (context, url, error) => Container(
color: AppColors.grey100,
@@ -182,8 +180,12 @@ class ProductCard extends ConsumerWidget {
],
),
child: Icon(
isFavorited ? Icons.favorite : Icons.favorite_border,
color: isFavorited ? AppColors.danger : AppColors.grey500,
isFavorited
? Icons.favorite
: Icons.favorite_border,
color: isFavorited
? AppColors.danger
: AppColors.grey500,
size: 20,
),
),
@@ -244,7 +246,9 @@ class ProductCard extends ConsumerWidget {
disabledForegroundColor: AppColors.grey500,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.button),
borderRadius: BorderRadius.circular(
AppRadius.button,
),
),
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.sm,
@@ -272,7 +276,9 @@ class ProductCard extends ConsumerWidget {
// For now, show a message
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Đang phát triển tính năng xem 360°'),
content: Text(
'Đang phát triển tính năng xem 360°',
),
duration: Duration(seconds: 2),
),
);
@@ -285,7 +291,9 @@ class ProductCard extends ConsumerWidget {
),
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.button),
borderRadius: BorderRadius.circular(
AppRadius.button,
),
),
padding: const EdgeInsets.symmetric(
horizontal: AppSpacing.sm,

View File

@@ -20,10 +20,7 @@ import 'package:worker/features/products/domain/entities/product.dart';
class ImageGallerySection extends StatefulWidget {
final Product product;
const ImageGallerySection({
super.key,
required this.product,
});
const ImageGallerySection({super.key, required this.product});
@override
State<ImageGallerySection> createState() => _ImageGallerySectionState();
@@ -232,9 +229,8 @@ class _ImageGallerySectionState extends State<ImageGallerySection> {
child: CachedNetworkImage(
imageUrl: images[index],
fit: BoxFit.cover,
placeholder: (context, url) => Container(
color: AppColors.grey100,
),
placeholder: (context, url) =>
Container(color: AppColors.grey100),
errorWidget: (context, url, error) => Container(
color: AppColors.grey100,
child: const Icon(
@@ -321,10 +317,7 @@ class _ImageLightboxState extends State<_ImageLightbox> {
),
title: Text(
'${_currentIndex + 1} / ${widget.images.length}',
style: const TextStyle(
color: AppColors.white,
fontSize: 16,
),
style: const TextStyle(color: AppColors.white, fontSize: 16),
),
),
body: Stack(
@@ -414,18 +407,12 @@ class _ImageLightboxState extends State<_ImageLightbox> {
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
Colors.black.withAlpha(128),
Colors.transparent,
],
colors: [Colors.black.withAlpha(128), Colors.transparent],
),
),
child: Text(
widget.imageCaptions[widget.images[_currentIndex]] ?? '',
style: const TextStyle(
color: AppColors.white,
fontSize: 16,
),
style: const TextStyle(color: AppColors.white, fontSize: 16),
textAlign: TextAlign.center,
),
),

View File

@@ -19,10 +19,7 @@ import 'package:worker/features/products/domain/entities/product.dart';
class ProductInfoSection extends StatelessWidget {
final Product product;
const ProductInfoSection({
super.key,
required this.product,
});
const ProductInfoSection({super.key, required this.product});
String _formatPrice(double price) {
final formatter = NumberFormat('#,###', 'vi_VN');
@@ -40,10 +37,7 @@ class ProductInfoSection extends StatelessWidget {
// SKU
Text(
'SKU: ${product.erpnextItemCode ?? product.productId}',
style: const TextStyle(
fontSize: 12,
color: AppColors.grey500,
),
style: const TextStyle(fontSize: 12, color: AppColors.grey500),
),
const SizedBox(height: 8),
@@ -168,18 +162,11 @@ class _QuickInfoCard extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
Icon(
icon,
color: AppColors.primaryBlue,
size: 24,
),
Icon(icon, color: AppColors.primaryBlue, size: 24),
const SizedBox(height: 4),
Text(
label,
style: const TextStyle(
fontSize: 12,
color: AppColors.grey500,
),
style: const TextStyle(fontSize: 12, color: AppColors.grey500),
textAlign: TextAlign.center,
),
const SizedBox(height: 2),

View File

@@ -17,10 +17,7 @@ import 'package:worker/features/products/domain/entities/product.dart';
class ProductTabsSection extends StatefulWidget {
final Product product;
const ProductTabsSection({
super.key,
required this.product,
});
const ProductTabsSection({super.key, required this.product});
@override
State<ProductTabsSection> createState() => _ProductTabsSectionState();
@@ -52,10 +49,7 @@ class _ProductTabsSectionState extends State<ProductTabsSection>
Container(
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: Color(0xFFe0e0e0),
width: 1,
),
bottom: BorderSide(color: Color(0xFFe0e0e0), width: 1),
),
),
child: TabBar(
@@ -152,29 +146,31 @@ class _DescriptionTab extends StatelessWidget {
'Màu sắc bền đẹp theo thời gian',
'Dễ dàng vệ sinh và bảo trì',
'Thân thiện với môi trường',
].map((feature) => Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(
Icons.check_circle,
size: 18,
color: AppColors.success,
),
const SizedBox(width: 12),
Expanded(
child: Text(
feature,
style: const TextStyle(
fontSize: 14,
color: AppColors.grey900,
),
].map(
(feature) => Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(
Icons.check_circle,
size: 18,
color: AppColors.success,
),
const SizedBox(width: 12),
Expanded(
child: Text(
feature,
style: const TextStyle(
fontSize: 14,
color: AppColors.grey900,
),
),
],
),
)),
),
],
),
),
),
const SizedBox(height: 20),
@@ -242,9 +238,7 @@ class _SpecificationsTab extends StatelessWidget {
border: isLast
? null
: const Border(
bottom: BorderSide(
color: Color(0xFFe0e0e0),
),
bottom: BorderSide(color: Color(0xFFe0e0e0)),
),
),
child: Row(
@@ -335,9 +329,7 @@ class _ReviewsTab extends StatelessWidget {
children: List.generate(
5,
(index) => Icon(
index < 4
? Icons.star
: Icons.star_half,
index < 4 ? Icons.star : Icons.star_half,
color: const Color(0xFFffc107),
size: 18,
),
@@ -349,10 +341,7 @@ class _ReviewsTab extends StatelessWidget {
// Review count
const Text(
'125 đánh giá',
style: TextStyle(
fontSize: 14,
color: AppColors.grey500,
),
style: TextStyle(fontSize: 14, color: AppColors.grey500),
),
],
),
@@ -382,11 +371,7 @@ class _ReviewItem extends StatelessWidget {
padding: const EdgeInsets.only(bottom: 16),
margin: const EdgeInsets.only(bottom: 16),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: Color(0xFFe0e0e0),
),
),
border: Border(bottom: BorderSide(color: Color(0xFFe0e0e0))),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -482,6 +467,7 @@ final _mockReviews = [
'name': 'Trần Thị B',
'date': '1 tháng trước',
'rating': 4,
'text': 'Gạch đẹp, vân gỗ rất chân thực. Giao hàng nhanh chóng và đóng gói cẩn thận.',
'text':
'Gạch đẹp, vân gỗ rất chân thực. Giao hàng nhanh chóng và đóng gói cẩn thận.',
},
];

View File

@@ -37,10 +37,7 @@ class StickyActionBar extends StatelessWidget {
decoration: BoxDecoration(
color: AppColors.white,
border: Border(
top: BorderSide(
color: const Color(0xFFe0e0e0),
width: 1,
),
top: BorderSide(color: const Color(0xFFe0e0e0), width: 1),
),
boxShadow: [
BoxShadow(
@@ -58,9 +55,7 @@ class StickyActionBar extends StatelessWidget {
// Quantity Controls
Container(
decoration: BoxDecoration(
border: Border.all(
color: const Color(0xFFe0e0e0),
),
border: Border.all(color: const Color(0xFFe0e0e0)),
borderRadius: BorderRadius.circular(8),
),
child: Row(
@@ -81,9 +76,7 @@ class StickyActionBar extends StatelessWidget {
fontWeight: FontWeight.w600,
),
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
],
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
@@ -101,10 +94,7 @@ class StickyActionBar extends StatelessWidget {
),
// Increase Button
_QuantityButton(
icon: Icons.add,
onPressed: onIncrease,
),
_QuantityButton(icon: Icons.add, onPressed: onIncrease),
],
),
),
@@ -151,10 +141,7 @@ class _QuantityButton extends StatelessWidget {
final IconData icon;
final VoidCallback? onPressed;
const _QuantityButton({
required this.icon,
this.onPressed,
});
const _QuantityButton({required this.icon, this.onPressed});
@override
Widget build(BuildContext context) {

View File

@@ -104,9 +104,7 @@ class _ProductSearchBarState extends ConsumerState<ProductSearchBar> {
vertical: AppSpacing.md,
),
),
style: const TextStyle(
fontSize: InputFieldSpecs.fontSize,
),
style: const TextStyle(fontSize: InputFieldSpecs.fontSize),
),
);
}