import 'package:concierge/data/remote/models/property_area.dart';
import 'package:concierge/presentation/navigation/app_routes.dart';
import 'package:concierge/presentation/theme/app_colors.dart';
import 'package:concierge/presentation/theme/app_textstyles.dart';
import 'package:concierge/presentation/widgets/round_icon_button.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_svg/flutter_svg.dart';
class HotelOverviewAppBar extends StatelessWidget implements PreferredSizeWidget {
static const double height = 200;
static const double _areaItemWidth = 55;
static const double _areaItemHeight = 46;
final bool shouldShowAppBar;
final bool shouldShowBackButton;
final bool shouldShowProfileButton;
final VoidCallback? onBackPressed;
final VoidCallback? onProfilePressed;
final List<PropertyArea> areas;
final ValueChanged<PropertyArea>? onAreaPressed;
final int? selectedAreaId;
/// Asset paths for the SVG icons.
final String backIconAsset;
final String profileIconAsset;
const HotelOverviewAppBar({
super.key,
this.shouldShowAppBar = true,
this.shouldShowBackButton = true,
this.shouldShowProfileButton = true,
this.onBackPressed,
this.onProfilePressed,
this.areas = const [],
this.onAreaPressed,
this.selectedAreaId,
this.backIconAsset = 'assets/icons/arrow-right.svg',
this.profileIconAsset = 'assets/icons/user-open.svg',
});
bool _isHttpUrl(String value) {
final uri = Uri.tryParse(value);
return uri != null && uri.hasAbsolutePath && (uri.scheme == 'http' || uri.scheme == 'https');
}
String? _areaIconUrl(PropertyArea area) {
// If backend sends the icon as a URL (string), use it.
if (_isHttpUrl(area.icon)) return area.icon;
// Otherwise, fall back to a representative area image if available.
if (area.events.isNotEmpty) {
// Prefer the smallest suitable image.
return area.events.first.heroImage.thumbnail;
}
return null;
}
String? _areaIconAsset(PropertyArea area) {
final name = area.name.trim().toLowerCase();
final icon = area.icon.trim().toUpperCase();
// Primary mapping (by backend icon code)
switch (icon) {
case 'COCKTAIL':
return 'assets/icons/cocktail.svg'; // Bar
case 'BED':
return 'assets/icons/single-bed.svg'; // Room
case 'DROP':
return 'assets/icons/drop.svg'; // Spa
case 'PEOPLE':
return 'assets/icons/group-medium.svg'; // Co-Work
case 'FLOWER':
return 'assets/icons/sun.svg'; // Terrasse
}
// Secondary mapping (by area name)
if (name.contains('bar')) return 'assets/icons/cocktail.svg';
if (name.contains('værelse') || name.contains('room')) {
return 'assets/icons/single-bed.svg';
}
if (name.contains('spa')) return 'assets/icons/drop.svg';
if (name.contains('co-work') || name.contains('cowork')) {
return 'assets/icons/group-medium.svg';
}
if (name.contains('terrasse') || name.contains('terrace')) {
return 'assets/icons/sun.svg';
}
return null;
}
Widget _buildAreaIcon(PropertyArea area, {required Color tintColor}) {
final asset = _areaIconAsset(area);
if (asset != null) {
return SvgPicture.asset(
asset,
package: 'concierge',
width: 24,
height: 24,
fit: BoxFit.contain,
colorFilter: ColorFilter.mode(tintColor, BlendMode.srcIn),
);
}
final iconUrl = _areaIconUrl(area);
if (iconUrl != null) {
return ColorFiltered(
colorFilter: ColorFilter.mode(tintColor, BlendMode.srcIn),
child: Image.network(
iconUrl,
fit: BoxFit.contain,
errorBuilder: (context, _, __) => const SizedBox.shrink(),
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return const Center(
child: SizedBox(
height: 14,
width: 14,
child: CircularProgressIndicator(strokeWidth: 2),
),
);
},
),
);
}
return const SizedBox.shrink();
}
@override
Widget build(BuildContext context) {
if (!shouldShowAppBar) return const SizedBox.shrink();
return Container(
decoration: BoxDecoration(
color: AppColors.sandColor[20]!,
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(24),
bottomRight: Radius.circular(24),
),
),
height: preferredSize.height,
child: Padding(
padding: const EdgeInsets.only(bottom: 16, left: 8, right: 8, top: 50),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Visibility(
visible: shouldShowBackButton,
child: RoundIconButton(
color: Colors.white,
icon: backIconAsset,
onPressed: () {
if (onBackPressed != null) {
onBackPressed!.call();
return;
}
try {
final goRouter = GoRouter.of(context);
if (goRouter.canPop()) {
context.pop();
} else if (goRouter.state.matchedLocation == AppRoutes.hotelOverviewPage) {
context.go("/exit");
} else {
context.go(AppRoutes.hotelOverviewPage);
}
} catch (_) {
context.go(AppRoutes.hotelOverviewPage);
}
},
),
),
Visibility(
visible: shouldShowProfileButton,
child: RoundIconButton(
color: Colors.white,
icon: profileIconAsset,
onPressed: () {
if (onProfilePressed != null) {
onProfilePressed!.call();
}
},
),
),
],
),
const Gap(12),
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
height: _areaItemHeight,
child: LayoutBuilder(
builder: (context, constraints) {
if (areas.isEmpty) return const SizedBox.shrink();
const spacing = 10.0;
const horizontalPadding = 16.0; // 8 left + 8 right
final requiredWidth =
(areas.length * _areaItemWidth) +
((areas.length - 1) * spacing) +
horizontalPadding;
final fitsWithoutScroll = requiredWidth <= constraints.maxWidth;
Widget buildItem(PropertyArea area) {
final isSelected = selectedAreaId != null && area.id == selectedAreaId;
final unselectedColor = AppColors.colorPrimaryText.withValues(alpha: 0.35);
final selectedColor = AppColors.sandColor[100]!;
final tintColor = isSelected ? selectedColor : unselectedColor;
return InkWell(
borderRadius: BorderRadius.circular(12),
onTap: onAreaPressed == null ? null : () => onAreaPressed!(area),
child: SizedBox(
width: _areaItemWidth,
height: _areaItemHeight,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 24,
width: 24,
child: _buildAreaIcon(area, tintColor: tintColor),
),
const Gap(4),
SizedBox(
height: 18,
child: Text(
area.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: AppTextStyles.textRegularSmall.copyWith(
color: tintColor,
),
),
),
],
),
),
);
}
if (fitsWithoutScroll) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
children: [
for (var i = 0; i < areas.length; i++) ...[
buildItem(areas[i]),
if (i != areas.length - 1) const SizedBox(width: spacing),
],
],
),
);
}
return ListView.separated(
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 8),
itemCount: areas.length,
separatorBuilder: (_, __) => const SizedBox(width: spacing),
itemBuilder: (context, index) => buildItem(areas[index]),
);
},
),
),
),
),
],
),
),
);
}
@override
Size get preferredSize => Size.fromHeight(shouldShowAppBar ? height : 0);
}