import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/view_models/ai_recommendations_view_model.dart'; import '../strings/tenders_strings.dart'; import 'main_tenders_slider.dart'; /// The "Recommended" tab body. Handles loading, empty/"still learning", /// error+retry and the recommended tender list for [AiRecommendationsViewModel]. class RecommendedTendersView extends StatefulWidget { const RecommendedTendersView({super.key, this.isDesktop = false}); final bool isDesktop; @override State createState() => _RecommendedTendersViewState(); } class _RecommendedTendersViewState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { context.read().loadIfNeeded(); } }); } @override Widget build(BuildContext context) { return Consumer( builder: (context, vm, child) { if (vm.isLoading) { return const _LoadingSkeleton(); } if (vm.errorMessage != null) { return _MessageState( title: TendersStrings.recommendedError, onRetry: vm.refresh, ); } if (vm.stillLearning) { return _MessageState( title: TendersStrings.recommendedStillLearningTitle, body: TendersStrings.recommendedStillLearningBody, onRetry: vm.refresh, ); } if (vm.recommendedTenders.isNotEmpty) { if (widget.isDesktop) { return Padding( padding: EdgeInsets.symmetric(vertical: 4.0.h()), child: MainTendersSlider( tenders: vm.recommendedTenders, isDesktop: true, ), ); } return SingleChildScrollView( child: Padding( padding: EdgeInsets.symmetric(vertical: 18.0.h()), child: MainTendersSlider(tenders: vm.recommendedTenders), ), ); } return _MessageState( title: TendersStrings.recommendedEmptyTitle, body: TendersStrings.recommendedEmptyBody, onRetry: vm.refresh, ); }, ); } } /// Centered title/body message with an optional retry button. Wrapped in a /// scroll view so pull-to-refresh works even when empty. class _MessageState extends StatelessWidget { const _MessageState({required this.title, this.body, this.onRetry}); final String title; final String? body; final Future Function()? onRetry; @override Widget build(BuildContext context) { final content = Padding( padding: EdgeInsets.symmetric(horizontal: 32.0.w(), vertical: 48.0.h()), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( title, textAlign: TextAlign.center, style: TextStyle( fontSize: 16.0.sp(), fontWeight: FontWeight.w600, color: AppColors.grey70, ), ), if (body != null) ...[ SizedBox(height: 12.0.h()), Text( body!, textAlign: TextAlign.center, style: TextStyle( fontSize: 14.0.sp(), fontWeight: FontWeight.w400, color: AppColors.grey60, height: 1.5, ), ), ], if (onRetry != null) ...[ SizedBox(height: 24.0.h()), TextButton( onPressed: onRetry, child: Text( TendersStrings.retry, style: TextStyle( fontSize: 14.0.sp(), fontWeight: FontWeight.w600, color: AppColors.mainBlue, ), ), ), ], ], ), ); if (onRetry == null) { return Center(child: content); } return RefreshIndicator( color: AppColors.jellyBean, onRefresh: onRetry!, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: ConstrainedBox( constraints: BoxConstraints(minHeight: SizeConfig.screenHeight * 0.6), child: Center(child: content), ), ), ); } } /// Simple placeholder list shown while recommendations load. class _LoadingSkeleton extends StatelessWidget { const _LoadingSkeleton(); @override Widget build(BuildContext context) { return ListView.separated( padding: EdgeInsets.all(16.0.h()), itemCount: 4, separatorBuilder: (_, __) => SizedBox(height: 12.0.h()), itemBuilder: (context, index) => Container( height: 120.0.h(), decoration: BoxDecoration( color: AppColors.grey0, borderRadius: BorderRadius.circular(12.0.w()), border: Border.all(color: AppColors.grey30), ), ), ); } }