Files
mobile-app/lib/features/home/presentation/widgets/testimonials_section.dart

181 lines
5.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:real_estate_mobile/core/constants/app_colors.dart';
import 'package:real_estate_mobile/features/home/data/models/landing_page_content.dart';
import 'package:real_estate_mobile/features/home/presentation/providers/home_provider.dart';
/// Default testimonials — matches web's hardcoded defaultTestimonials fallback.
const _defaultTestimonials = [
TestimonialItem(
rating: 5,
title: 'No Longer Blood in the Water',
content:
'Using other sites to find a realtor ended with my phone ringing constantly. My number was sold off to multiple lists and it was so overwhelming. RE-Quest gave me confidence that my information was protected and I decided who I was in contact with.',
author: 'Alice T.',
role: '',
),
TestimonialItem(
rating: 5,
title: 'Finding Someone Who Worked with Me',
content:
'RE-Quest let me narrow down my search terms, so I knew before I called that they had experience with the loan program I needed. I loved the in-app chat feature to talk to my short list before committing to a phone call.',
author: 'Kevin R.',
role: '',
),
TestimonialItem(
rating: 5,
title: '',
content:
'The search terms on RE-Quest allowed me to show off my expertise as an agent. Now when leads reach out to me, they already have an idea of what kind of agent I am. Instant connection!',
author: 'Riley S.',
role: '',
),
];
/// Default section content — matches web's hardcoded defaultContent fallback.
const _defaultContent = TestimonialsContent(
title: 'Consumer Protection is Our Foundation',
subtitle:
"Buying or selling your home is one of the largest decisions you will make in your life. Don't let yourself be chased by salesmen. Find the service provider that matches your unique needs.",
ratingInfo:
'Clients rate our real estate services 4.9 out of 5 on average, based on recent client reviews.',
stats: [
StatItem(
iconPath: 'cities',
boldText: '3 states',
normalText: 'and counting',
),
StatItem(
iconPath: 'properties',
boldText: 'Hundreds of',
normalText: 'Professionals',
),
],
testimonials: _defaultTestimonials,
);
class TestimonialsSection extends ConsumerWidget {
const TestimonialsSection({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final homeState = ref.watch(homeProvider);
final cmsTestimonials = homeState.content?.testimonials;
// Use CMS data if available with non-empty testimonials, otherwise fallback
final data =
(cmsTestimonials != null && cmsTestimonials.testimonials.isNotEmpty)
? cmsTestimonials
: _defaultContent;
final testimonials =
data.testimonials.isNotEmpty ? data.testimonials : _defaultTestimonials;
return Column(
children: [
// Testimonial cards carousel (header is in TrustStatsSection above)
SizedBox(
height: 420,
child: ListView.builder(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 24),
itemCount: testimonials.length,
itemBuilder: (context, index) => Padding(
padding: const EdgeInsets.only(right: 16),
child: _buildTestimonialCard(testimonials[index]),
),
),
),
],
);
}
Widget _buildTestimonialCard(TestimonialItem testimonial) {
return Container(
width: 300,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: AppColors.primaryDark.withValues(alpha: 0.1),
width: 1,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Quote icon SVG
SvgPicture.asset(
'assets/icons/quote_icon.svg',
width: 23,
height: 13,
),
const SizedBox(height: 12),
// Title
Text(
testimonial.title,
style: const TextStyle(
fontFamily: 'Fractul',
fontSize: 14,
fontWeight: FontWeight.w700,
color: AppColors.primaryDark,
),
),
const SizedBox(height: 12),
// Content
Expanded(
child: Text(
testimonial.content,
style: const TextStyle(
fontFamily: 'SourceSerif4',
fontSize: 14,
fontWeight: FontWeight.w400,
color: AppColors.primaryDark,
),
),
),
const SizedBox(height: 16),
// Stars (yellow like Figma)
Row(
children: List.generate(
testimonial.rating,
(index) => const Padding(
padding: EdgeInsets.only(right: 4),
child: Icon(
Icons.star,
color: Color(0xFFFFDE21),
size: 18,
),
),
),
),
const SizedBox(height: 12),
// Author name
Text(
testimonial.author,
style: const TextStyle(
fontFamily: 'SourceSerif4',
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.primaryDark,
),
),
const SizedBox(height: 2),
// Role
Text(
testimonial.role,
style: const TextStyle(
fontFamily: 'SourceSerif4',
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.primaryDark,
),
),
],
),
);
}
}