import 'package:fbla_ui/main.dart'; import 'package:fbla_ui/pages/create_edit_business.dart'; import 'package:fbla_ui/pages/create_edit_listing.dart'; import 'package:fbla_ui/pages/listing_detail.dart'; import 'package:fbla_ui/shared/api_logic.dart'; import 'package:fbla_ui/shared/global_vars.dart'; import 'package:flutter/material.dart'; import 'package:rive/rive.dart'; import 'package:url_launcher/url_launcher.dart'; import '../shared/utils.dart'; class BusinessDetail extends StatefulWidget { final int id; final String name; const BusinessDetail({super.key, required this.id, required this.name}); @override State createState() => _CreateBusinessDetailState(); } class _CreateBusinessDetailState extends State { late Future loadBusiness; @override void initState() { super.initState(); loadBusiness = fetchBusiness(widget.id); } @override Widget build(BuildContext context) { return FutureBuilder( future: loadBusiness, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasData) { if (snapshot.data.runtimeType != String) { return Scaffold( appBar: AppBar( title: Text(snapshot.data.name), actions: _getActions(snapshot.data), ), body: _detailBody(snapshot.data), ); } else { return Scaffold( appBar: AppBar( title: Text(widget.name), ), body: Padding( padding: const EdgeInsets.all(16.0), child: Column(children: [ Center( child: Text(snapshot.data, textAlign: TextAlign.center)), Padding( padding: const EdgeInsets.all(8.0), child: FilledButton( child: const Text('Retry'), onPressed: () { var refreshedData = fetchBusiness(widget.id); setState(() { loadBusiness = refreshedData; }); }, ), ), ]), ), ); } } } else if (snapshot.connectionState == ConnectionState.waiting) { return Scaffold( appBar: AppBar( title: Text(widget.name), ), body: Container( padding: const EdgeInsets.all(8.0), alignment: Alignment.center, child: const SizedBox( width: 75, height: 75, child: RiveAnimation.asset('assets/mdev_triangle_loading.riv'), )), ); } return Padding( padding: const EdgeInsets.all(8.0), child: Scaffold( appBar: AppBar( title: Text(widget.name), ), body: Text( '\nError: ${snapshot.error}', style: const TextStyle(fontSize: 18), textAlign: TextAlign.center, ), ), ); }); } Widget _detailBody(Business business) { return ListView( children: [ // Title, logo, desc, website Center( child: SizedBox( width: 800, child: Column( children: [ Padding( padding: const EdgeInsets.only(top: 4.0), child: Card( clipBehavior: Clip.antiAlias, child: Column( children: [ ListTile( titleAlignment: ListTileTitleAlignment.titleHeight, title: Text(business.name!, style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold)), subtitle: Text( business.description!, ), contentPadding: const EdgeInsets.only(bottom: 8, left: 16), leading: ClipRRect( borderRadius: BorderRadius.circular(6.0), child: Image.network( '$apiAddress/logos/${business.id}', width: 48, height: 48, errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { return Icon( getIconFromBusinessType( business.type ?? BusinessType.other), size: 48); }), ), ), if (business.website != null) ListTile( leading: const Icon(Icons.link), title: const Text('Website'), subtitle: Text( business.website! .replaceAll('https://', '') .replaceAll('http://', '') .replaceAll('www.', ''), style: const TextStyle(color: Colors.blue)), onTap: () { launchUrl( Uri.parse('https://${business.website}')); }, ), ], ), ), ), // Available positions if (business.listings != null) Card( clipBehavior: Clip.antiAlias, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 16, top: 4), child: _GetListingsTitle(business)), _JobList(business: business) ]), ), // Contact info 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!), // maybe replace ! with ?? ''. same is true for below 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}')); }, ), ], ), ), // Location Card( clipBehavior: Clip.antiAlias, child: ListTile( leading: const Icon(Icons.location_on), title: Text(business.locationName), subtitle: Text(business.locationAddress!), onTap: () { launchUrl(Uri.parse(Uri.encodeFull( 'https://www.google.com/maps/search/?api=1&query=${business.locationName} ${business.locationAddress}'))); }, ), ), // Notes if (business.notes != null && business.notes != '') Card( child: ListTile( leading: const Icon(Icons.notes), title: const Text( 'Additional Notes', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold), ), subtitle: Text(business.notes!), ), ), ], ), ), ), ], ); } List? _getActions(Business business) { if (loggedIn) { return [ IconButton( icon: const Icon(Icons.edit), onPressed: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => CreateEditBusiness( inputBusiness: business, ))); }, ), IconButton( icon: const Icon(Icons.delete), onPressed: () { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( backgroundColor: Theme.of(context).colorScheme.surface, title: const Text('Are You Sure?'), content: Text('This will permanently delete ${business.name}.'), actions: [ TextButton( child: const Text('Cancel'), onPressed: () { Navigator.of(context).pop(); }), TextButton( child: const Text('Yes'), onPressed: () async { String? deleteResult = await deleteBusiness(business.id); if (deleteResult != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( width: 300, behavior: SnackBarBehavior.floating, content: Text(deleteResult))); } else { Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => const MainApp())); } }), ], ); }); }, ), ]; } return null; } } class _JobList extends StatelessWidget { final Business business; const _JobList({required this.business}); @override Widget build(BuildContext context) { List<_JobListItem> listItems = []; for (JobListing listing in business.listings!) { listItems.add(_JobListItem( jobListing: listing, fromBusiness: business, )); } return ListView( shrinkWrap: true, children: listItems, ); } } class _JobListItem extends StatelessWidget { final JobListing jobListing; final Business fromBusiness; const _JobListItem({required this.jobListing, required this.fromBusiness}); @override Widget build(BuildContext context) { return ListTile( leading: Icon(getIconFromJobType(jobListing.type!)), title: Text(jobListing.name), subtitle: Text( jobListing.description, style: const TextStyle(overflow: TextOverflow.ellipsis), ), trailing: _getEditIcon(context, fromBusiness, jobListing), onTap: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => JobListingDetail( listing: jobListing, fromBusiness: fromBusiness, ))); }, ); } Widget? _getEditIcon( BuildContext context, Business fromBusiness, JobListing inputListing) { if (loggedIn) { return IconButton( icon: const Icon( Icons.edit, ), onPressed: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => CreateEditJobListing( inputBusiness: fromBusiness, inputJobListing: inputListing, ))); }, ); } return null; } } class _GetListingsTitle extends StatelessWidget { final Business fromBusiness; const _GetListingsTitle(this.fromBusiness); @override Widget build(BuildContext context) { if (!loggedIn) { return const Text('Available Postitions', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)); } else { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('Available Postitions', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)), Padding( padding: const EdgeInsets.only(right: 24.0), child: IconButton( icon: const Icon(Icons.add), onPressed: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => CreateEditJobListing( inputBusiness: fromBusiness, ))); }, ), ) ], ); } } }