From 55695ef17633afc89db2da7d888018985c12d04f Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Tue, 30 Sep 2025 19:45:25 +0530 Subject: [PATCH] added faq --- lib/helpers/services/api_endpoints.dart | 2 +- lib/view/auth/login_option_screen.dart | 6 +- lib/view/auth/login_screen.dart | 12 +- lib/view/auth/mpin_auth_screen.dart | 8 +- lib/view/auth/request_demo_bottom_sheet.dart | 22 +- lib/view/directory/contact_detail_screen.dart | 41 +-- lib/view/faq/faq_screen.dart | 280 ++++++++++++++++++ lib/view/layouts/user_profile_right_bar.dart | 37 ++- lib/view/support/support_screen.dart | 226 ++++++++++++++ 9 files changed, 570 insertions(+), 64 deletions(-) create mode 100644 lib/view/faq/faq_screen.dart create mode 100644 lib/view/support/support_screen.dart diff --git a/lib/helpers/services/api_endpoints.dart b/lib/helpers/services/api_endpoints.dart index 960c3a7..b0331b6 100644 --- a/lib/helpers/services/api_endpoints.dart +++ b/lib/helpers/services/api_endpoints.dart @@ -1,5 +1,5 @@ class ApiEndpoints { - static const String baseUrl = "https://stageapi.marcoaiot.com/api"; + static const String baseUrl = "https://mapi.marcoaiot.com/api"; // static const String baseUrl = "https://api.marcoaiot.com/api"; // static const String baseUrl = "https://devapi.marcoaiot.com/api"; diff --git a/lib/view/auth/login_option_screen.dart b/lib/view/auth/login_option_screen.dart index c3364ed..eb2d599 100644 --- a/lib/view/auth/login_option_screen.dart +++ b/lib/view/auth/login_option_screen.dart @@ -55,7 +55,7 @@ class _WelcomeScreenState extends State context: context, barrierDismissible: false, builder: (_) => Dialog( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), insetPadding: const EdgeInsets.all(24), child: SingleChildScrollView( padding: const EdgeInsets.all(24), @@ -199,7 +199,7 @@ class _WelcomeScreenState extends State padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: Colors.orangeAccent, - borderRadius: BorderRadius.circular(6), + borderRadius: BorderRadius.circular(5), ), child: MyText( 'BETA', @@ -232,7 +232,7 @@ class _WelcomeScreenState extends State style: ElevatedButton.styleFrom( backgroundColor: contentTheme.brandRed, foregroundColor: Colors.white, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), elevation: 4, shadowColor: Colors.black26, ), diff --git a/lib/view/auth/login_screen.dart b/lib/view/auth/login_screen.dart index 433e91a..8611672 100644 --- a/lib/view/auth/login_screen.dart +++ b/lib/view/auth/login_screen.dart @@ -49,7 +49,7 @@ class _LoginScreenState extends State with UIMixin { padding: MySpacing.all(24), decoration: BoxDecoration( color: theme.colorScheme.primary.withOpacity(0.02), - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(5), border: Border.all( color: contentTheme.primary.withOpacity(0.5), ), @@ -77,7 +77,7 @@ class _LoginScreenState extends State with UIMixin { margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: Colors.blueAccent, - borderRadius: BorderRadius.circular(4), + borderRadius: BorderRadius.circular(5), ), child: Text( 'BETA', @@ -148,7 +148,7 @@ class _LoginScreenState extends State with UIMixin { value: controller.isChecked.value, onChanged: controller.onChangeCheckBox, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), + borderRadius: BorderRadius.circular(5), ), fillColor: MaterialStateProperty .resolveWith( @@ -192,7 +192,7 @@ class _LoginScreenState extends State with UIMixin { onPressed: controller.onLogin, elevation: 2, padding: MySpacing.xy(24, 16), - borderRadiusAll: 16, + borderRadiusAll: 5, backgroundColor: Colors.blueAccent, child: MyText.labelMedium( 'Login', @@ -242,7 +242,7 @@ class _LoginScreenState extends State with UIMixin { return Material( elevation: 2, shadowColor: contentTheme.secondary.withAlpha(30), - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), child: TextFormField( controller: controller, validator: validator, @@ -255,7 +255,7 @@ class _LoginScreenState extends State with UIMixin { filled: true, fillColor: theme.cardColor, border: OutlineInputBorder( - borderRadius: BorderRadius.circular(2), + borderRadius: BorderRadius.circular(5), borderSide: BorderSide.none, ), prefixIcon: Icon(icon, size: 18), diff --git a/lib/view/auth/mpin_auth_screen.dart b/lib/view/auth/mpin_auth_screen.dart index 32343f7..a229205 100644 --- a/lib/view/auth/mpin_auth_screen.dart +++ b/lib/view/auth/mpin_auth_screen.dart @@ -110,7 +110,7 @@ class _MPINAuthScreenState extends State horizontal: 10, vertical: 4), decoration: BoxDecoration( color: Colors.orangeAccent, - borderRadius: BorderRadius.circular(6), + borderRadius: BorderRadius.circular(5), ), child: MyText( 'BETA', @@ -145,7 +145,7 @@ class _MPINAuthScreenState extends State padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.circular(20), + borderRadius: BorderRadius.circular(5), boxShadow: const [ BoxShadow( color: Colors.black12, @@ -264,7 +264,7 @@ class _MPINAuthScreenState extends State filled: true, fillColor: Colors.grey.shade100, border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), borderSide: BorderSide.none, ), ), @@ -279,7 +279,7 @@ class _MPINAuthScreenState extends State onPressed: controller.isLoading.value ? null : controller.onSubmitMPIN, elevation: 2, padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16), - borderRadiusAll: 10, + borderRadiusAll: 5, backgroundColor: controller.isLoading.value ? contentTheme.brandRed.withOpacity(0.6) : contentTheme.brandRed, diff --git a/lib/view/auth/request_demo_bottom_sheet.dart b/lib/view/auth/request_demo_bottom_sheet.dart index 6977089..27e1e26 100644 --- a/lib/view/auth/request_demo_bottom_sheet.dart +++ b/lib/view/auth/request_demo_bottom_sheet.dart @@ -197,10 +197,10 @@ class _OrganizationFormState extends State<_OrganizationForm> with UIMixin { style: OutlinedButton.styleFrom( side: const BorderSide(color: Colors.red), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), ), padding: const EdgeInsets.symmetric( - horizontal: 20, vertical: 14), + horizontal: 28, vertical: 5), ), ), ElevatedButton.icon( @@ -222,10 +222,10 @@ class _OrganizationFormState extends State<_OrganizationForm> with UIMixin { style: ElevatedButton.styleFrom( backgroundColor: Colors.indigo, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), ), padding: const EdgeInsets.symmetric( - horizontal: 28, vertical: 14), + horizontal: 28, vertical: 5), ), ), ], @@ -291,19 +291,19 @@ class _OrganizationFormState extends State<_OrganizationForm> with UIMixin { contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: Colors.grey[400]!), ), enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: Colors.grey[300]!), ), focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: contentTheme.brandRed, width: 1.5), ), errorBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), borderSide: const BorderSide(color: Colors.red), ), ), @@ -367,15 +367,15 @@ class _OrganizationFormState extends State<_OrganizationForm> with UIMixin { contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 16), border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: Colors.grey[400]!), ), enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: Colors.grey[300]!), ), focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: contentTheme.brandRed, width: 1.5), ), diff --git a/lib/view/directory/contact_detail_screen.dart b/lib/view/directory/contact_detail_screen.dart index e77c747..fe81715 100644 --- a/lib/view/directory/contact_detail_screen.dart +++ b/lib/view/directory/contact_detail_screen.dart @@ -9,7 +9,6 @@ import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/model/directory/contact_model.dart'; import 'package:marco/helpers/widgets/avatar.dart'; import 'package:marco/helpers/utils/launcher_utils.dart'; -import 'package:tab_indicator_styler/tab_indicator_styler.dart'; import 'package:marco/helpers/widgets/Directory/comment_editor_card.dart'; import 'package:flutter_quill_delta_from_html/flutter_quill_delta_from_html.dart'; import 'package:marco/model/directory/add_comment_bottom_sheet.dart'; @@ -190,16 +189,9 @@ class _ContactDetailScreenState extends State { ), ]), TabBar( - labelColor: Colors.red, - unselectedLabelColor: Colors.black, - indicator: MaterialIndicator( - color: Colors.red, - height: 4, - topLeftRadius: 8, - topRightRadius: 8, - bottomLeftRadius: 8, - bottomRightRadius: 8, - ), + labelColor: Colors.black, + unselectedLabelColor: Colors.grey, + indicatorColor: Colors.red, tabs: const [ Tab(text: "Details"), Tab(text: "Notes"), @@ -360,12 +352,6 @@ class _ContactDetailScreenState extends State { [...activeComments, ...inactiveComments].reversed.toList(); final editingId = directoryController.editingCommentId.value; - if (comments.isEmpty) { - return Center( - child: MyText.bodyLarge("No notes yet.", color: Colors.grey), - ); - } - return Stack( children: [ MyRefreshIndicator( @@ -377,14 +363,19 @@ class _ContactDetailScreenState extends State { }, child: Padding( padding: MySpacing.xy(12, 12), - child: ListView.separated( - physics: const AlwaysScrollableScrollPhysics(), - padding: const EdgeInsets.only(bottom: 100), - itemCount: comments.length, - separatorBuilder: (_, __) => MySpacing.height(14), - itemBuilder: (_, index) => - _buildCommentItem(comments[index], editingId, contactId), - ), + child: comments.isEmpty + ? Center( + child: + MyText.bodyLarge("No notes yet.", color: Colors.grey), + ) + : ListView.separated( + physics: const AlwaysScrollableScrollPhysics(), + padding: const EdgeInsets.only(bottom: 100), + itemCount: comments.length, + separatorBuilder: (_, __) => MySpacing.height(14), + itemBuilder: (_, index) => _buildCommentItem( + comments[index], editingId, contactId), + ), ), ), if (editingId == null) diff --git a/lib/view/faq/faq_screen.dart b/lib/view/faq/faq_screen.dart new file mode 100644 index 0000000..452a3a8 --- /dev/null +++ b/lib/view/faq/faq_screen.dart @@ -0,0 +1,280 @@ +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 createState() => _FAQScreenState(); +} + +class _FAQScreenState extends State with UIMixin { + final List> 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 _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 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( + 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), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/view/layouts/user_profile_right_bar.dart b/lib/view/layouts/user_profile_right_bar.dart index 736366d..540049d 100644 --- a/lib/view/layouts/user_profile_right_bar.dart +++ b/lib/view/layouts/user_profile_right_bar.dart @@ -10,7 +10,8 @@ import 'package:marco/helpers/widgets/avatar.dart'; import 'package:marco/model/employees/employee_info.dart'; import 'package:marco/controller/auth/mpin_controller.dart'; import 'package:marco/view/employees/employee_profile_screen.dart'; - +import 'package:marco/view/support/support_screen.dart'; +import 'package:marco/view/faq/faq_screen.dart'; class UserProfileBar extends StatefulWidget { final bool isCondensed; @@ -32,7 +33,6 @@ class _UserProfileBarState extends State _initData(); } - Future _initData() async { employeeInfo = LocalStorage.getEmployeeInfo()!; hasMpin = await LocalStorage.getIsMpin(); @@ -45,7 +45,7 @@ class _UserProfileBarState extends State return Padding( padding: const EdgeInsets.only(left: 14), child: ClipRRect( - borderRadius: BorderRadius.circular(22), + borderRadius: BorderRadius.circular(5), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 18, sigmaY: 18), child: AnimatedContainer( @@ -61,7 +61,7 @@ class _UserProfileBarState extends State begin: Alignment.topLeft, end: Alignment.bottomRight, ), - borderRadius: BorderRadius.circular(22), + borderRadius: BorderRadius.circular(5), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.06), @@ -108,7 +108,6 @@ class _UserProfileBarState extends State ); } - Widget _userProfileSection(bool condensed) { final padding = MySpacing.fromLTRB( condensed ? 16 : 26, @@ -181,13 +180,15 @@ class _UserProfileBarState extends State ), SizedBox(height: spacingHeight), _menuItemRow( - icon: LucideIcons.settings, - label: 'Settings', + icon: LucideIcons.badge_help, + label: 'Support', + onTap: _onSupportTap, ), SizedBox(height: spacingHeight), _menuItemRow( - icon: LucideIcons.badge_help, - label: 'Support', + icon: LucideIcons.info, + label: 'FAQ', // <-- New FAQ menu item + onTap: _onFaqTap, // <-- Handle tap ), SizedBox(height: spacingHeight), _menuItemRow( @@ -202,6 +203,14 @@ class _UserProfileBarState extends State ); } + void _onFaqTap() { + Get.to(() => const FAQScreen()); + } + + void _onSupportTap() { + Get.to(() => const SupportScreen()); + } + Widget _menuItemRow({ required IconData icon, required String label, @@ -211,12 +220,12 @@ class _UserProfileBarState extends State }) { return InkWell( onTap: onTap, - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration( color: Colors.white.withOpacity(0.9), - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey.withOpacity(0.2), width: 1), ), child: Row( @@ -276,7 +285,7 @@ class _UserProfileBarState extends State horizontal: condensed ? 14 : 22, ), shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), ), ), ), @@ -293,7 +302,7 @@ class _UserProfileBarState extends State Widget _buildLogoutDialog(BuildContext context) { return Dialog( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), elevation: 10, backgroundColor: Colors.white, child: Padding( @@ -337,7 +346,7 @@ class _UserProfileBarState extends State foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(14)), + borderRadius: BorderRadius.circular(5)), ), child: const Text("Logout"), ), diff --git a/lib/view/support/support_screen.dart b/lib/view/support/support_screen.dart new file mode 100644 index 0000000..b5606bd --- /dev/null +++ b/lib/view/support/support_screen.dart @@ -0,0 +1,226 @@ +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'; +import 'package:url_launcher/url_launcher.dart'; + +class SupportScreen extends StatefulWidget { + const SupportScreen({super.key}); + + @override + State createState() => _SupportScreenState(); +} + +class _SupportScreenState extends State with UIMixin { + final List> contacts = [ + { + "type": "email", + "label": "info@marcoaiot.com", + "subLabel": "Email us your queries", + "icon": LucideIcons.mail, + "action": "mailto:info@marcoaiot.com?subject=Support Request" + }, + { + "type": "phone", + "label": "+91-8055099750", + "subLabel": "Call our support team", + "icon": LucideIcons.phone, + "action": "tel:+91-8055099750" + }, + ]; + + void _launchAction(String action) async { + final Uri uri = Uri.parse(action); + + if (await canLaunchUrl(uri)) { + // Use LaunchMode.externalApplication for mailto/tel + await launchUrl( + uri, + mode: LaunchMode.externalApplication, + ); + } else { + // Fallback if no app found + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('No app found to open this link.')), + ); + } + } + + Widget _buildAppBar() { + return AppBar( + backgroundColor: const Color(0xFFF5F5F5), + elevation: 0.5, + automaticallyImplyLeading: false, + titleSpacing: 0, + title: Padding( + padding: MySpacing.xy(16, 0), + 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('Support', + fontWeight: 700, color: Colors.black), + ), + ], + ), + ), + ); + } + + Widget _buildContactCard(Map contact) { + return GestureDetector( + onTap: () => _launchAction(contact["action"]), + child: Container( + padding: const EdgeInsets.all(20), + margin: const EdgeInsets.symmetric(horizontal: 24, 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( + children: [ + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.red.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: Icon(contact["icon"], color: Colors.red, size: 24), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyText.bodyMedium( + contact["label"], + fontWeight: 700, + color: Colors.black87, + fontSize: 16, + ), + const SizedBox(height: 4), + MyText.bodySmall( + contact["subLabel"], + color: Colors.black54, + ), + ], + ), + ), + ], + ), + ), + ); + } + + Widget _buildInfoCard(String title, String subtitle, IconData icon) { + return Container( + padding: const EdgeInsets.all(20), + margin: const EdgeInsets.symmetric(horizontal: 24, 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( + children: [ + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.red.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: Icon(icon, color: Colors.red, size: 28), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MyText.bodyMedium(title, + fontWeight: 700, color: Colors.black87, fontSize: 16), + const SizedBox(height: 4), + MyText.bodySmall(subtitle, color: Colors.black54), + ], + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: PreferredSize( + preferredSize: const Size.fromHeight(72), + child: _buildAppBar(), + ), + body: SafeArea( + child: RefreshIndicator( + onRefresh: () async { + // Optional: Implement refresh logic + }, + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MySpacing.height(24), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: MyText.titleLarge( + "Need Help?", + fontWeight: 700, + color: Colors.red, + ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: MyText.bodySmall( + "Our support team is ready to assist you. Reach out via email or phone.", + color: Colors.grey[800], + ), + ), + const SizedBox(height: 24), + + // Contact cards + ...contacts.map((contact) => _buildContactCard(contact)), + + const SizedBox(height: 16), + + // Info card + _buildInfoCard( + "Working Hours", + "Monday - Friday: 9 AM - 6 PM\nSaturday: 10 AM - 2 PM", + LucideIcons.clock, + ), + + const SizedBox(height: 24), + ], + ), + ), + ), + ), + ); + } +}