import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart'; import 'package:fbla_ui/pages/signin_page.dart'; import 'package:fbla_ui/shared/global_vars.dart'; import 'package:fbla_ui/shared/utils.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:url_launcher/url_launcher.dart'; class BusinessSearchBar extends StatefulWidget { final String searchTextHint; final Widget filterIconButton; final void Function(String) setSearchCallback; const BusinessSearchBar( {super.key, required this.setSearchCallback, required this.searchTextHint, required this.filterIconButton}); @override State createState() => _BusinessSearchBarState(); } class _BusinessSearchBarState extends State { TextEditingController controller = TextEditingController(); @override Widget build(BuildContext context) { return SizedBox( width: 450, height: 50, child: SearchBar( hintText: widget.searchTextHint, controller: controller, backgroundColor: WidgetStateProperty.resolveWith((notNeeded) { return Theme.of(context).colorScheme.surfaceContainer; }), onChanged: (query) { widget.setSearchCallback(query); }, leading: const Padding( padding: EdgeInsets.only(left: 8.0), child: Icon(Icons.search), ), trailing: [ if (controller.text != '') IconButton( icon: const Icon(Icons.clear), onPressed: () { controller.text = ''; widget.setSearchCallback(''); }, ), widget.filterIconButton ]), ); } } class FilterChips extends StatefulWidget { final Set? selectedJobChips; final Set? selectedBusinessChips; const FilterChips( {super.key, this.selectedJobChips, this.selectedBusinessChips}); @override State createState() => _FilterChipsState(); } class _FilterChipsState extends State { List filterChips() { List chips = []; if (widget.selectedJobChips != null) { for (var type in JobType.values) { chips.add(Padding( padding: const EdgeInsets.only(left: 4.0, right: 4.0), child: FilterChip( showCheckmark: false, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20)), label: Text(getNameFromJobType(type)), selected: widget.selectedJobChips!.contains(type), onSelected: (bool selected) { setState(() { if (selected) { widget.selectedJobChips!.add(type); } else { widget.selectedJobChips!.remove(type); } }); }), )); } } else if (widget.selectedBusinessChips != null) { for (var type in BusinessType.values) { chips.add(Padding( padding: const EdgeInsets.only(left: 4.0, right: 4.0), child: FilterChip( showCheckmark: false, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20)), label: Text(getNameFromBusinessType(type)), selected: widget.selectedBusinessChips!.contains(type), onSelected: (bool selected) { setState(() { if (selected) { widget.selectedBusinessChips!.add(type); } else { widget.selectedBusinessChips!.remove(type); } }); }), )); } } return chips; } @override Widget build(BuildContext context) { return Wrap( children: filterChips(), ); } } class MainSliverAppBar extends StatefulWidget { final bool widescreen; final Widget filterIconButton; final void Function(String) setSearch; final void Function() themeCallback; final void Function() generatePDF; final void Function(bool) updateLoggedIn; final String searchHintText; const MainSliverAppBar({ super.key, required this.widescreen, required this.setSearch, required this.searchHintText, required this.themeCallback, required this.filterIconButton, required this.updateLoggedIn, required this.generatePDF, }); @override State createState() => _MainSliverAppBarState(); } class _MainSliverAppBarState extends State { @override Widget build(BuildContext context) { return SliverAppBar( title: widget.widescreen ? Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Flexible( child: BusinessSearchBar( setSearchCallback: widget.setSearch, searchTextHint: widget.searchHintText, filterIconButton: widget.filterIconButton, ), ) // const PreferredSize( // preferredSize: Size(144, 0), child: SizedBox()) ], ) : const Text('Job Link'), toolbarHeight: 70, stretch: false, backgroundColor: Theme.of(context).colorScheme.surface, pinned: true, // floating: true, scrolledUnderElevation: 0, centerTitle: !widget.widescreen, expandedHeight: widget.widescreen ? 70 : 120, bottom: _getBottom(widget.widescreen), leading: !widget.widescreen ? IconButton( icon: Icon(getIconFromThemeMode(themeMode)), onPressed: () { setState(() { widget.themeCallback(); }); }, ) : null, actions: [ IconButton( icon: const Icon(Icons.file_download_outlined), onPressed: widget.generatePDF, ), IconButton( icon: const Icon(Icons.help), onPressed: () { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('About'), backgroundColor: Theme.of(context).colorScheme.surface, content: SizedBox( width: 500, child: IntrinsicHeight( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Welcome to my FBLA 2024 Coding and Programming submission!\n\n' 'MarinoDev Job Link aims to provide comprehensive details of businesses and community partners' ' for Waukesha West High School\'s Career and Technical Education Department.\n\n'), MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( child: const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Git Repo:'), Text( 'https://git.marinodev.com/MarinoDev/FBLA24\n', style: TextStyle(color: Colors.blue)), ], ), onTap: () { launchUrl(Uri.https('git.marinodev.com', '/MarinoDev/FBLA24')); }, ), ), MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( child: const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Please direct any questions to'), Text('drake@marinodev.com', style: TextStyle(color: Colors.blue)), ], ), onTap: () { launchUrl( Uri.parse('mailto:drake@marinodev.com')); }, ), ) ], ), ), ), actions: [ TextButton( child: const Text('OK'), onPressed: () { Navigator.of(context).pop(); }), ], ); }); }, ), Padding( padding: const EdgeInsets.only(right: 8.0), child: IconButton( icon: loggedIn ? const Icon(Icons.account_circle) : const Icon(Icons.login), onPressed: () { if (loggedIn) { var payload = JWT.decode(jwt).payload; showDialog( context: context, builder: (BuildContext context) { return AlertDialog( backgroundColor: Theme.of(context).colorScheme.surface, title: Text('Hi, ${payload['username']}!'), content: Text( 'You are logged in as an admin with username ${payload['username']}.'), actions: [ TextButton( child: const Text('Cancel'), onPressed: () { Navigator.of(context).pop(); }), TextButton( child: const Text('Logout'), onPressed: () async { final prefs = await SharedPreferences.getInstance(); prefs.setBool('rememberMe', false); prefs.setString('username', ''); prefs.setString('password', ''); widget.updateLoggedIn(false); Navigator.of(context).pop(); }), ], ); }); } else { Navigator.push( context, MaterialPageRoute( builder: (context) => SignInPage(refreshAccount: widget.updateLoggedIn))); } }, ), ), ], ); } PreferredSizeWidget? _getBottom(bool widescreen) { if (!widescreen) { return PreferredSize( preferredSize: const Size.fromHeight(0), child: SizedBox( height: 70, child: Padding( padding: const EdgeInsets.all(10), child: BusinessSearchBar( filterIconButton: widget.filterIconButton, setSearchCallback: widget.setSearch, searchTextHint: widget.searchHintText, ), ), ), ); } return null; } } class ContactInformationCard extends StatelessWidget { final Business business; ContactInformationCard({super.key, required this.business}); @override Widget build(BuildContext context) { return Card( clipBehavior: Clip.antiAlias, child: Column( children: [ Row( children: [ Padding( padding: const EdgeInsets.only(left: 16.0, top: 8.0), child: Text( business.contactName!, textAlign: TextAlign.left, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold), ), ), ], ), if (business.contactPhone != null) ListTile( leading: const Icon(Icons.phone), title: Text(business.contactPhone!), onTap: () { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( backgroundColor: Theme.of(context).colorScheme.surface, title: Text('Contact ${business.contactName}'), content: Text( 'Would you like to call or text ${business.contactName}?'), actions: [ TextButton( child: const Text('Text'), onPressed: () { launchUrl( Uri.parse('sms:${business.contactPhone}')); Navigator.of(context).pop(); }), TextButton( child: const Text('Call'), onPressed: () async { launchUrl( Uri.parse('tel:${business.contactPhone}')); Navigator.of(context).pop(); }), ], ); }); }, ), if (business.contactEmail != null) ListTile( leading: const Icon(Icons.email), title: Text(business.contactEmail!), onTap: () { launchUrl(Uri.parse('mailto:${business.contactEmail}')); }, ), ], ), ); } }