feat(meezi_app): café profile parity — cover, open badge, gallery, hours (code-only)
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 33s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m5s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 22s
CI/CD / CI · API (dotnet build + test) (push) Successful in 41s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 33s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m5s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 45s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 22s
Enhances the café detail screen toward web-Koja parity. Parsing verified against
the real backend DTOs (CafePublicDto / WorkingHoursPublicDto), still unbuilt (pub blocked).
- Cover image hero (coverImageUrl), open/closed badge (isOpenNow).
- Photo gallery (galleryUrls) horizontal strip.
- Working hours rendered from the day-keyed WorkingHoursPublicDto ({sat..fri} of
{isOpen,open,close}), Sat→Fri with Persian day labels.
This commit is contained in:
@@ -93,11 +93,64 @@ class _CafeDetailScreenState extends ConsumerState<CafeDetailScreen> {
|
|||||||
final description = cafe['description'] as String?;
|
final description = cafe['description'] as String?;
|
||||||
final address = cafe['address'] as String?;
|
final address = cafe['address'] as String?;
|
||||||
final city = cafe['city'] as String?;
|
final city = cafe['city'] as String?;
|
||||||
|
// Defensive parsing — public DTO key names may vary.
|
||||||
|
final cover = (cafe['coverImageUrl'] ?? cafe['coverUrl'] ?? cafe['cover']) as String?;
|
||||||
|
final isOpen = cafe['isOpenNow'] as bool?;
|
||||||
|
final gallery = (cafe['galleryUrls'] ?? cafe['gallery']) is List
|
||||||
|
? ((cafe['galleryUrls'] ?? cafe['gallery']) as List)
|
||||||
|
.map((e) => e.toString())
|
||||||
|
.where((e) => e.isNotEmpty)
|
||||||
|
.toList()
|
||||||
|
: <String>[];
|
||||||
|
// WorkingHoursPublicDto: a day-keyed object {sat..fri}, each {isOpen,open,close}.
|
||||||
|
final hours = cafe['workingHours'] is Map
|
||||||
|
? (cafe['workingHours'] as Map)
|
||||||
|
: const <dynamic, dynamic>{};
|
||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
children: [
|
children: [
|
||||||
Text(name, style: Theme.of(context).textTheme.headlineSmall),
|
if (cover != null && cover.isNotEmpty) ...[
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 16 / 9,
|
||||||
|
child: Image.network(
|
||||||
|
cover,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder: (_, __, ___) =>
|
||||||
|
Container(color: Colors.black12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
],
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(name,
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall),
|
||||||
|
),
|
||||||
|
if (isOpen != null)
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 10, vertical: 4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: (isOpen ? Colors.green : Colors.red)
|
||||||
|
.withValues(alpha: 0.12),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
isOpen ? 'باز است' : 'بسته است',
|
||||||
|
style: TextStyle(
|
||||||
|
color: isOpen ? Colors.green[800] : Colors.red[800],
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -117,6 +170,59 @@ class _CafeDetailScreenState extends ConsumerState<CafeDetailScreen> {
|
|||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Text(description),
|
Text(description),
|
||||||
],
|
],
|
||||||
|
if (gallery.isNotEmpty) ...[
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
SizedBox(
|
||||||
|
height: 110,
|
||||||
|
child: ListView.separated(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
itemCount: gallery.length,
|
||||||
|
separatorBuilder: (_, __) => const SizedBox(width: 8),
|
||||||
|
itemBuilder: (_, i) => ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
child: Image.network(
|
||||||
|
gallery[i],
|
||||||
|
width: 150,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder: (_, __, ___) =>
|
||||||
|
Container(width: 150, color: Colors.black12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
if (hours.isNotEmpty) ...[
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text('ساعات کاری',
|
||||||
|
style: Theme.of(context).textTheme.titleMedium),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
...const [
|
||||||
|
('sat', 'شنبه'),
|
||||||
|
('sun', 'یکشنبه'),
|
||||||
|
('mon', 'دوشنبه'),
|
||||||
|
('tue', 'سهشنبه'),
|
||||||
|
('wed', 'چهارشنبه'),
|
||||||
|
('thu', 'پنجشنبه'),
|
||||||
|
('fri', 'جمعه'),
|
||||||
|
].map((d) {
|
||||||
|
final m = hours[d.$1] is Map
|
||||||
|
? hours[d.$1] as Map
|
||||||
|
: const <dynamic, dynamic>{};
|
||||||
|
final open = (m['open'] ?? '').toString();
|
||||||
|
final close = (m['close'] ?? '').toString();
|
||||||
|
final isOpen = m['isOpen'] == true && open.isNotEmpty;
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(d.$2),
|
||||||
|
Text(isOpen ? '$open - $close' : 'تعطیل'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
Reference in New Issue
Block a user