feat: merchant

This commit is contained in:
efrilm
2025-08-29 21:30:57 +07:00
parent 06cc7e3781
commit 89c94c796a
13 changed files with 153 additions and 223 deletions
@@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
import '../../../sample/sample_data.dart';
import '../../components/field/field.dart';
import '../../router/app_router.gr.dart';
import 'widgets/empty_merchant_card.dart';
@@ -113,7 +114,7 @@ class _MerchantPageState extends State<MerchantPage> {
Padding(
padding: const EdgeInsets.only(right: 8),
child: FilterChip(
label: const Text('All'),
label: const Text('Semua'),
selected: _selectedCategory == null,
onSelected: (selected) {
_onCategorySelected(null);
@@ -193,89 +194,6 @@ class _MerchantPageState extends State<MerchantPage> {
}
static List<MerchantModel> _generateMockMerchants() {
return [
MerchantModel(
id: '1',
name: 'Warung Makan Sederhana',
category: 'Food & Beverage',
rating: 4.5,
isOpen: true,
imageUrl: 'https://via.placeholder.com/150',
),
MerchantModel(
id: '2',
name: 'Toko Elektronik',
category: 'Electronics',
rating: 4.2,
isOpen: true,
imageUrl: 'https://via.placeholder.com/150',
),
MerchantModel(
id: '3',
name: 'Apotek Sehat',
category: 'Healthcare',
rating: 4.8,
isOpen: false,
imageUrl: 'https://via.placeholder.com/150',
),
MerchantModel(
id: '4',
name: 'Fashion Store',
category: 'Clothing',
rating: 4.1,
isOpen: true,
imageUrl: 'https://via.placeholder.com/150',
),
MerchantModel(
id: '5',
name: 'Bengkel Motor',
category: 'Automotive',
rating: 4.3,
isOpen: true,
imageUrl: 'https://via.placeholder.com/150',
),
MerchantModel(
id: '6',
name: 'Minimarket 24',
category: 'Retail',
rating: 4.0,
isOpen: true,
imageUrl: 'https://via.placeholder.com/150',
),
MerchantModel(
id: '7',
name: 'Salon Kecantikan',
category: 'Beauty',
rating: 4.6,
isOpen: false,
imageUrl: 'https://via.placeholder.com/150',
),
MerchantModel(
id: '8',
name: 'Laundry Express',
category: 'Service',
rating: 4.4,
isOpen: true,
imageUrl: 'https://via.placeholder.com/150',
),
];
return merchants;
}
}
class MerchantModel {
final String id;
final String name;
final String category;
final double rating;
final bool isOpen;
final String imageUrl;
MerchantModel({
required this.id,
required this.name,
required this.category,
required this.rating,
required this.isOpen,
required this.imageUrl,
});
}
@@ -1,7 +1,7 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import '../../../../../common/theme/theme.dart';
import '../../merchant_page.dart';
import '../../../../../sample/sample_data.dart';
// Models
class ProductCategory {
@@ -295,9 +295,9 @@ class _MerchantDetailPageState extends State<MerchantDetailPage> {
],
),
child: Center(
child: Text(
_getCategoryIcon(widget.merchant.category),
style: TextStyle(fontSize: 36),
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.asset(widget.merchant.imageUrl),
),
),
),
@@ -596,29 +596,6 @@ class _MerchantDetailPageState extends State<MerchantDetailPage> {
),
);
}
String _getCategoryIcon(String category) {
switch (category.toLowerCase()) {
case 'food & beverage':
return '🍽️';
case 'electronics':
return '📱';
case 'healthcare':
return '⚕️';
case 'clothing':
return '👕';
case 'automotive':
return '🚗';
case 'retail':
return '🛍️';
case 'beauty':
return '💄';
case 'service':
return '🔧';
default:
return '🏪';
}
}
}
// Custom delegate for pinned category bar
@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
import '../../../../sample/sample_data.dart';
import '../../../components/image/image.dart';
import '../merchant_page.dart';
class MerchantCard extends StatelessWidget {
final MerchantModel merchant;
@@ -44,35 +44,44 @@ class MerchantCard extends StatelessWidget {
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
child: Image.network(
merchant.imageUrl,
width: double.infinity,
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: AppColor.primary,
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
child: merchant.imageUrl.startsWith('assets')
? Image.asset(
merchant.imageUrl,
fit: BoxFit.fill,
errorBuilder: (context, error, stackTrace) {
return ImagePlaceholder(width: 60, height: 60);
},
)
: Image.network(
merchant.imageUrl,
width: double.infinity,
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: AppColor.primary,
value:
loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
),
);
},
errorBuilder: (context, error, stackTrace) {
return ImagePlaceholder(
width: double.infinity,
height: 100,
showBorderRadius: false,
);
},
),
);
},
errorBuilder: (context, error, stackTrace) {
return ImagePlaceholder(
width: double.infinity,
height: 100,
showBorderRadius: false,
);
},
),
),
),
const SizedBox(height: 10),