marco.pms.mobileapp/lib/view/faq/faq_screen.dart
2025-09-30 19:45:25 +05:30

281 lines
9.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_lucide/flutter_lucide.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
class FAQScreen extends StatefulWidget {
const FAQScreen({super.key});
@override
State<FAQScreen> createState() => _FAQScreenState();
}
class _FAQScreenState extends State<FAQScreen> with UIMixin {
final List<Map<String, String>> faqs = [
{
"question": "How do I perform Check-in and Check-out?",
"answer":
"To Check-in, go to the Dashboard and tap the 'Check-in' button. For Check-out, return to the Dashboard and tap 'Check-out'. Ensure GPS and internet are enabled."
},
{
"question": "How do I login to the app?",
"answer":
"Enter your registered email and password on the login screen. If you forget your password, use the 'Forgot Password' option to reset it."
},
{
"question": "What is MPIN and how do I use it?",
"answer":
"MPIN is a 4-digit security PIN used for quick login and authorization. Set it under 'Settings > Security'. Use it instead of typing your password every time."
},
{
"question": "How do I log expenses?",
"answer":
"Go to the 'Expenses' section, click 'Add Expense', fill in the details like amount, category, and description, and then save. You can view all past expenses in the same section."
},
{
"question": "Can I edit or delete an expense?",
"answer":
"Yes, tap on an expense from the list and choose 'Edit' or 'Delete'. Changes are synced automatically with your account."
},
{
"question": "What if I face login issues?",
"answer":
"Ensure your internet is working and the app is updated. If problems persist, contact support via email or phone."
},
];
late List<bool> _expanded;
final TextEditingController searchController = TextEditingController();
String _searchQuery = "";
@override
void initState() {
super.initState();
_expanded = List.generate(faqs.length, (_) => false);
}
Widget _buildAppBar() {
return AppBar(
backgroundColor: const Color(0xFFF5F5F5),
elevation: 0.5,
automaticallyImplyLeading: false,
titleSpacing: 0,
title: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
IconButton(
icon: const Icon(Icons.arrow_back_ios_new,
color: Colors.black, size: 20),
onPressed: () => Navigator.pop(context),
),
MySpacing.width(8),
Expanded(
child: MyText.titleLarge('FAQ',
fontWeight: 700, color: Colors.black),
),
],
),
),
);
}
Widget _buildFAQCard(int index, Map<String, String> faq) {
final isExpanded = _expanded[index];
return GestureDetector(
onTap: () {
setState(() {
_expanded[index] = !isExpanded;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
padding: const EdgeInsets.all(20),
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
boxShadow: const [
BoxShadow(
color: Colors.black12,
blurRadius: 12,
offset: Offset(0, 6),
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(LucideIcons.badge_help,
color: Colors.blue, size: 24),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.bodyMedium(
faq["question"] ?? "",
fontWeight: 600,
color: Colors.black87,
fontSize: 14,
),
const SizedBox(height: 8),
AnimatedCrossFade(
firstChild: const SizedBox.shrink(),
secondChild: MyText.bodySmall(
faq["answer"] ?? "",
color: Colors.black54,
),
crossFadeState: isExpanded
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
duration: const Duration(milliseconds: 300),
),
],
),
),
Icon(
isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
color: Colors.grey[600],
),
],
),
),
);
}
Widget _buildEmptyState() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.help_outline, size: 60, color: Colors.grey),
MySpacing.height(18),
MyText.titleMedium(
'No matching FAQs found.',
fontWeight: 600,
color: Colors.grey,
),
MySpacing.height(10),
MyText.bodySmall(
'Try adjusting your search or clear the search bar.',
color: Colors.grey,
),
],
),
);
}
@override
Widget build(BuildContext context) {
final filteredFaqs = faqs
.asMap()
.entries
.where((entry) =>
entry.value["question"]!
.toLowerCase()
.contains(_searchQuery.toLowerCase()) ||
entry.value["answer"]!
.toLowerCase()
.contains(_searchQuery.toLowerCase()))
.toList();
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: PreferredSize(
preferredSize: const Size.fromHeight(72),
child: _buildAppBar(),
),
body: Column(
children: [
// Search bar
Padding(
padding: const EdgeInsets.all(12.0),
child: SizedBox(
height: 40,
child: TextField(
controller: searchController,
onChanged: (value) {
setState(() {
_searchQuery = value;
});
},
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 0),
prefixIcon:
const Icon(Icons.search, size: 20, color: Colors.grey),
suffixIcon: ValueListenableBuilder<TextEditingValue>(
valueListenable: searchController,
builder: (context, value, _) {
if (value.text.isEmpty) return const SizedBox.shrink();
return IconButton(
icon: const Icon(Icons.clear,
size: 20, color: Colors.grey),
onPressed: () {
searchController.clear();
setState(() {
_searchQuery = "";
});
},
);
},
),
hintText: 'Search FAQs...',
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey.shade300),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: Colors.grey.shade300),
),
),
),
),
),
Expanded(
child: filteredFaqs.isEmpty
? _buildEmptyState()
: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Introductory text
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16, vertical: 12),
child: MyText.bodyMedium(
'Here are some frequently asked questions to help you get started:',
fontWeight: 500,
color: Colors.black87,
),
),
...filteredFaqs
.map((entry) =>
_buildFAQCard(entry.key, entry.value))
.toList(),
const SizedBox(height: 24),
],
),
),
),
],
),
);
}
}