API Rewrite with UI
This commit is contained in:
parent
64e493012a
commit
cfade0e075
@ -22,15 +22,15 @@ class Home extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _HomeState extends State<Home> {
|
class _HomeState extends State<Home> {
|
||||||
late Future refreshBusinessDataFuture;
|
late Future refreshBusinessDataOverviewFuture;
|
||||||
bool _isPreviousData = false;
|
bool _isPreviousData = false;
|
||||||
late List<Business> businesses;
|
late Map<JobType, List<Business>> overviewBusinesses;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
refreshBusinessDataFuture = fetchBusinessData();
|
refreshBusinessDataOverviewFuture = fetchBusinessDataOverview();
|
||||||
initialLogin();
|
initialLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,10 +65,10 @@ class _HomeState extends State<Home> {
|
|||||||
body: RefreshIndicator(
|
body: RefreshIndicator(
|
||||||
edgeOffset: 120,
|
edgeOffset: 120,
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
var refreshedData = fetchBusinessData();
|
var refreshedData = fetchBusinessDataOverview();
|
||||||
await refreshedData;
|
await refreshedData;
|
||||||
setState(() {
|
setState(() {
|
||||||
refreshBusinessDataFuture = refreshedData;
|
refreshBusinessDataOverviewFuture = refreshedData;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
@ -185,8 +185,8 @@ class _HomeState extends State<Home> {
|
|||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) => ExportData(
|
||||||
ExportData(businesses: businesses)));
|
groupedBusinesses: overviewBusinesses)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -245,7 +245,7 @@ class _HomeState extends State<Home> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
FutureBuilder(
|
FutureBuilder(
|
||||||
future: refreshBusinessDataFuture,
|
future: refreshBusinessDataOverviewFuture,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
@ -263,9 +263,11 @@ class _HomeState extends State<Home> {
|
|||||||
child: FilledButton(
|
child: FilledButton(
|
||||||
child: const Text('Retry'),
|
child: const Text('Retry'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
var refreshedData = fetchBusinessData();
|
var refreshedData =
|
||||||
|
fetchBusinessDataOverview();
|
||||||
setState(() {
|
setState(() {
|
||||||
refreshBusinessDataFuture = refreshedData;
|
refreshBusinessDataOverviewFuture =
|
||||||
|
refreshedData;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -274,11 +276,11 @@ class _HomeState extends State<Home> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
businesses = snapshot.data;
|
overviewBusinesses = snapshot.data;
|
||||||
_isPreviousData = true;
|
_isPreviousData = true;
|
||||||
|
|
||||||
return BusinessDisplayPanel(
|
return BusinessDisplayPanel(
|
||||||
businesses: businesses,
|
groupedBusinesses: overviewBusinesses,
|
||||||
widescreen: widescreen,
|
widescreen: widescreen,
|
||||||
selectable: false);
|
selectable: false);
|
||||||
} else if (snapshot.hasError) {
|
} else if (snapshot.hasError) {
|
||||||
@ -293,7 +295,7 @@ class _HomeState extends State<Home> {
|
|||||||
ConnectionState.waiting) {
|
ConnectionState.waiting) {
|
||||||
if (_isPreviousData) {
|
if (_isPreviousData) {
|
||||||
return BusinessDisplayPanel(
|
return BusinessDisplayPanel(
|
||||||
businesses: businesses,
|
groupedBusinesses: overviewBusinesses,
|
||||||
widescreen: widescreen,
|
widescreen: widescreen,
|
||||||
selectable: false);
|
selectable: false);
|
||||||
} else {
|
} else {
|
||||||
@ -339,7 +341,7 @@ class _HomeState extends State<Home> {
|
|||||||
Widget? _getFAB() {
|
Widget? _getFAB() {
|
||||||
if (loggedIn) {
|
if (loggedIn) {
|
||||||
return FloatingActionButton(
|
return FloatingActionButton(
|
||||||
child: const Icon(Icons.add),
|
child: const Icon(Icons.add_business),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@ -4,27 +4,111 @@ import 'package:fbla_ui/pages/create_edit_business.dart';
|
|||||||
import 'package:fbla_ui/pages/signin_page.dart';
|
import 'package:fbla_ui/pages/signin_page.dart';
|
||||||
import 'package:fbla_ui/shared.dart';
|
import 'package:fbla_ui/shared.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:rive/rive.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class BusinessDetail extends StatefulWidget {
|
class BusinessDetail extends StatefulWidget {
|
||||||
final Business inputBusiness;
|
final int id;
|
||||||
|
final String name;
|
||||||
|
final JobType clickFromType;
|
||||||
|
|
||||||
const BusinessDetail({super.key, required this.inputBusiness});
|
const BusinessDetail(
|
||||||
|
{super.key,
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.clickFromType});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<BusinessDetail> createState() => _CreateBusinessDetailState();
|
State<BusinessDetail> createState() => _CreateBusinessDetailState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CreateBusinessDetailState extends State<BusinessDetail> {
|
class _CreateBusinessDetailState extends State<BusinessDetail> {
|
||||||
|
late Future loadBusiness;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
loadBusiness = fetchBusiness(widget.id);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Business business = Business.copy(widget.inputBusiness);
|
return FutureBuilder(
|
||||||
|
future: loadBusiness,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
if (snapshot.data.runtimeType != String) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(business.name),
|
title: Text(snapshot.data.name),
|
||||||
actions: _getActions(business),
|
actions: _getActions(snapshot.data, widget.clickFromType),
|
||||||
),
|
),
|
||||||
body: ListView(
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView _detailBody(Business business) {
|
||||||
|
return ListView(
|
||||||
children: [
|
children: [
|
||||||
// Title, logo, desc, website
|
// Title, logo, desc, website
|
||||||
Card(
|
Card(
|
||||||
@ -46,7 +130,7 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
width: 48,
|
width: 48,
|
||||||
height: 48, errorBuilder: (BuildContext context,
|
height: 48, errorBuilder: (BuildContext context,
|
||||||
Object exception, StackTrace? stackTrace) {
|
Object exception, StackTrace? stackTrace) {
|
||||||
return getIconFromType(business.type, 48,
|
return getIconFromJobType(widget.clickFromType, 48,
|
||||||
Theme.of(context).colorScheme.onSurface);
|
Theme.of(context).colorScheme.onSurface);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@ -54,7 +138,7 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.link),
|
leading: const Icon(Icons.link),
|
||||||
title: const Text('Website'),
|
title: const Text('Website'),
|
||||||
subtitle: Text(business.website,
|
subtitle: Text(business.website!,
|
||||||
style: const TextStyle(color: Colors.blue)),
|
style: const TextStyle(color: Colors.blue)),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
launchUrl(Uri.parse('https://${business.website}'));
|
launchUrl(Uri.parse('https://${business.website}'));
|
||||||
@ -67,13 +151,11 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
Card(
|
Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 16.0, top: 8.0),
|
padding: const EdgeInsets.only(left: 16.0, top: 8.0),
|
||||||
child: Column(
|
child:
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
children: [
|
const Text(
|
||||||
Text(
|
|
||||||
'Available Postitions',
|
'Available Postitions',
|
||||||
style: const TextStyle(
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
fontSize: 20, fontWeight: FontWeight.bold),
|
|
||||||
),
|
),
|
||||||
// Container(
|
// Container(
|
||||||
// height: 400,
|
// height: 400,
|
||||||
@ -110,8 +192,8 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
),
|
),
|
||||||
// Contact info
|
// Contact info
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: (business.contactEmail.isNotEmpty ||
|
visible:
|
||||||
business.contactPhone.isNotEmpty),
|
(business.contactEmail != null || business.contactPhone != null),
|
||||||
child: Card(
|
child: Card(
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -121,9 +203,7 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 16.0, top: 8.0),
|
padding: const EdgeInsets.only(left: 16.0, top: 8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
business.contactName.isEmpty
|
business.contactName ?? 'Contact ${business.name}',
|
||||||
? 'Contact ${business.name}'
|
|
||||||
: business.contactName,
|
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 20, fontWeight: FontWeight.bold),
|
fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
@ -132,10 +212,11 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: business.contactPhone.isNotEmpty,
|
visible: business.contactPhone != null,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(Icons.phone),
|
leading: Icon(Icons.phone),
|
||||||
title: Text(business.contactPhone),
|
title: Text(business.contactPhone!),
|
||||||
|
// maybe replace ! with ?? ''. same is true for below
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -143,10 +224,10 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
Theme.of(context).colorScheme.background,
|
Theme.of(context).colorScheme.background,
|
||||||
title: Text(business.contactName.isEmpty
|
title: Text(business.contactName!.isEmpty
|
||||||
? 'Contact ${business.name}?'
|
? 'Contact ${business.name}?'
|
||||||
: 'Contact ${business.contactName}'),
|
: 'Contact ${business.contactName}'),
|
||||||
content: Text(business.contactName.isEmpty
|
content: Text(business.contactName!.isEmpty
|
||||||
? 'Would you like to call or text ${business.name}?'
|
? 'Would you like to call or text ${business.name}?'
|
||||||
: 'Would you like to call or text ${business.contactName}?'),
|
: 'Would you like to call or text ${business.contactName}?'),
|
||||||
actions: [
|
actions: [
|
||||||
@ -171,10 +252,10 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: business.contactEmail.isNotEmpty,
|
visible: business.contactEmail != null,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: const Icon(Icons.email),
|
leading: const Icon(Icons.email),
|
||||||
title: Text(business.contactEmail),
|
title: Text(business.contactEmail!),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
launchUrl(Uri.parse('mailto:${business.contactEmail}'));
|
launchUrl(Uri.parse('mailto:${business.contactEmail}'));
|
||||||
},
|
},
|
||||||
@ -190,8 +271,8 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: const Icon(Icons.location_on),
|
leading: const Icon(Icons.location_on),
|
||||||
title: Text(business.locationName),
|
title: Text(business.locationName!),
|
||||||
subtitle: Text(business.locationAddress),
|
subtitle: Text(business.locationAddress!),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
launchUrl(Uri.parse(Uri.encodeFull(
|
launchUrl(Uri.parse(Uri.encodeFull(
|
||||||
'https://www.google.com/maps/search/?api=1&query=${business.locationName}')));
|
'https://www.google.com/maps/search/?api=1&query=${business.locationName}')));
|
||||||
@ -201,7 +282,7 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
),
|
),
|
||||||
// Notes
|
// Notes
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: business.notes.isNotEmpty,
|
visible: business.notes != null,
|
||||||
child: Card(
|
child: Card(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: const Icon(Icons.notes),
|
leading: const Icon(Icons.notes),
|
||||||
@ -209,24 +290,25 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
'Additional Notes:',
|
'Additional Notes:',
|
||||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
subtitle: Text(business.notes),
|
subtitle: Text(business.notes!),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget>? _getActions(Business business) {
|
List<Widget>? _getActions(Business business, JobType clickFromType) {
|
||||||
if (loggedIn) {
|
if (loggedIn) {
|
||||||
return [
|
return [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.edit),
|
icon: const Icon(Icons.edit),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
Navigator.of(context).push(MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) => CreateEditBusiness(
|
||||||
CreateEditBusiness(inputBusiness: business)));
|
inputBusiness: business,
|
||||||
|
clickFromType: clickFromType,
|
||||||
|
)));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -250,7 +332,7 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
|
|||||||
child: const Text('Yes'),
|
child: const Text('Yes'),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
String? deleteResult =
|
String? deleteResult =
|
||||||
await deleteBusiness(business, jwt);
|
await deleteBusiness(business.id, jwt);
|
||||||
if (deleteResult != null) {
|
if (deleteResult != null) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
|
|||||||
@ -6,8 +6,9 @@ import 'package:flutter/services.dart';
|
|||||||
|
|
||||||
class CreateEditBusiness extends StatefulWidget {
|
class CreateEditBusiness extends StatefulWidget {
|
||||||
final Business? inputBusiness;
|
final Business? inputBusiness;
|
||||||
|
final JobType? clickFromType;
|
||||||
|
|
||||||
const CreateEditBusiness({super.key, this.inputBusiness});
|
const CreateEditBusiness({super.key, this.inputBusiness, this.clickFromType});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CreateEditBusiness> createState() => _CreateEditBusinessState();
|
State<CreateEditBusiness> createState() => _CreateEditBusinessState();
|
||||||
@ -27,7 +28,6 @@ class _CreateEditBusinessState extends State<CreateEditBusiness> {
|
|||||||
id: 0,
|
id: 0,
|
||||||
name: 'Business',
|
name: 'Business',
|
||||||
description: 'Add details about the business below.',
|
description: 'Add details about the business below.',
|
||||||
type: BusinessType.other,
|
|
||||||
website: '',
|
website: '',
|
||||||
contactName: '',
|
contactName: '',
|
||||||
contactEmail: '',
|
contactEmail: '',
|
||||||
@ -155,7 +155,9 @@ class _CreateEditBusinessState extends State<CreateEditBusiness> {
|
|||||||
'https://logo.clearbit.com/${business.website}',
|
'https://logo.clearbit.com/${business.website}',
|
||||||
errorBuilder: (BuildContext context,
|
errorBuilder: (BuildContext context,
|
||||||
Object exception, StackTrace? stackTrace) {
|
Object exception, StackTrace? stackTrace) {
|
||||||
return getIconFromType(business.type, 48,
|
return getIconFromJobType(
|
||||||
|
widget.clickFromType ?? JobType.other,
|
||||||
|
48,
|
||||||
Theme.of(context).colorScheme.onBackground);
|
Theme.of(context).colorScheme.onBackground);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@ -239,7 +241,8 @@ class _CreateEditBusinessState extends State<CreateEditBusiness> {
|
|||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Business Description (required)',
|
labelText:
|
||||||
|
'Business Description (required)',
|
||||||
),
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value != null && value.isEmpty) {
|
if (value != null && value.isEmpty) {
|
||||||
@ -357,46 +360,49 @@ class _CreateEditBusinessState extends State<CreateEditBusiness> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
// Business Type Dropdown
|
||||||
left: 8.0, right: 8.0, bottom: 8.0),
|
|
||||||
child: Row(
|
// Padding(
|
||||||
mainAxisAlignment:
|
// padding: const EdgeInsets.only(
|
||||||
MainAxisAlignment.spaceBetween,
|
// left: 8.0, right: 8.0, bottom: 8.0),
|
||||||
children: [
|
// child: Row(
|
||||||
const Text('Type of Business',
|
// mainAxisAlignment:
|
||||||
style: TextStyle(fontSize: 16)),
|
// MainAxisAlignment.spaceBetween,
|
||||||
DropdownMenu<BusinessType>(
|
// children: [
|
||||||
initialSelection: business.type,
|
// const Text('Type of Business',
|
||||||
controller: businessTypeController,
|
// style: TextStyle(fontSize: 16)),
|
||||||
label: const Text('Business Type'),
|
// DropdownMenu<BusinessType>(
|
||||||
dropdownMenuEntries: const [
|
// initialSelection: business.type,
|
||||||
DropdownMenuEntry(
|
// controller: businessTypeController,
|
||||||
value: BusinessType.food,
|
// label: const Text('Business Type'),
|
||||||
label: 'Food Related'),
|
// dropdownMenuEntries: const [
|
||||||
DropdownMenuEntry(
|
// DropdownMenuEntry(
|
||||||
value: BusinessType.shop,
|
// value: BusinessType.food,
|
||||||
label: 'Shop'),
|
// label: 'Food Related'),
|
||||||
DropdownMenuEntry(
|
// DropdownMenuEntry(
|
||||||
value: BusinessType.outdoors,
|
// value: BusinessType.shop,
|
||||||
label: 'Outdoors'),
|
// label: 'Shop'),
|
||||||
DropdownMenuEntry(
|
// DropdownMenuEntry(
|
||||||
value: BusinessType.manufacturing,
|
// value: BusinessType.outdoors,
|
||||||
label: 'Manufacturing'),
|
// label: 'Outdoors'),
|
||||||
DropdownMenuEntry(
|
// DropdownMenuEntry(
|
||||||
value: BusinessType.entertainment,
|
// value: BusinessType.manufacturing,
|
||||||
label: 'Entertainment'),
|
// label: 'Manufacturing'),
|
||||||
DropdownMenuEntry(
|
// DropdownMenuEntry(
|
||||||
value: BusinessType.other,
|
// value: BusinessType.entertainment,
|
||||||
label: 'Other'),
|
// label: 'Entertainment'),
|
||||||
],
|
// DropdownMenuEntry(
|
||||||
onSelected: (inputType) {
|
// value: BusinessType.other,
|
||||||
business.type = inputType!;
|
// label: 'Other'),
|
||||||
},
|
// ],
|
||||||
),
|
// onSelected: (inputType) {
|
||||||
],
|
// business.type = inputType!;
|
||||||
),
|
// },
|
||||||
),
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
left: 8.0, right: 8.0, bottom: 8.0),
|
left: 8.0, right: 8.0, bottom: 8.0),
|
||||||
@ -409,8 +415,7 @@ class _CreateEditBusinessState extends State<CreateEditBusiness> {
|
|||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText:
|
labelText: 'Contact Information Name',
|
||||||
'Contact Information Name',
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -16,9 +16,9 @@ bool isBusinessesFiltered = true;
|
|||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
|
|
||||||
class ExportData extends StatefulWidget {
|
class ExportData extends StatefulWidget {
|
||||||
final List<Business> businesses;
|
final Map<JobType, List<Business>> groupedBusinesses;
|
||||||
|
|
||||||
const ExportData({super.key, required this.businesses});
|
const ExportData({super.key, required this.groupedBusinesses});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ExportData> createState() => _ExportDataState();
|
State<ExportData> createState() => _ExportDataState();
|
||||||
@ -31,7 +31,7 @@ class _ExportDataState extends State<ExportData> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
refreshBusinessDataFuture = fetchBusinessData();
|
refreshBusinessDataFuture = fetchBusinessDataOverview();
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
selectedBusinesses = <Business>{};
|
selectedBusinesses = <Business>{};
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ class _ExportDataState extends State<ExportData> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
floatingActionButton: _FAB(businesses: widget.businesses),
|
floatingActionButton: _FAB(groupedBusinesses: widget.groupedBusinesses),
|
||||||
body: CustomScrollView(
|
body: CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
SliverAppBar(
|
SliverAppBar(
|
||||||
@ -196,7 +196,7 @@ class _ExportDataState extends State<ExportData> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
BusinessDisplayPanel(
|
BusinessDisplayPanel(
|
||||||
businesses: widget.businesses,
|
groupedBusinesses: widget.groupedBusinesses,
|
||||||
widescreen: MediaQuery.sizeOf(context).width >= 1000,
|
widescreen: MediaQuery.sizeOf(context).width >= 1000,
|
||||||
selectable: true),
|
selectable: true),
|
||||||
const SliverToBoxAdapter(
|
const SliverToBoxAdapter(
|
||||||
@ -211,15 +211,26 @@ class _ExportDataState extends State<ExportData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _FAB extends StatefulWidget {
|
class _FAB extends StatefulWidget {
|
||||||
final List<Business> businesses;
|
final Map<JobType, List<Business>> groupedBusinesses;
|
||||||
|
|
||||||
const _FAB({required this.businesses});
|
const _FAB({required this.groupedBusinesses});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_FAB> createState() => _FABState();
|
State<_FAB> createState() => _FABState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FABState extends State<_FAB> {
|
class _FABState extends State<_FAB> {
|
||||||
|
List<Business> allBusinesses = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
for (JobType type in widget.groupedBusinesses.keys) {
|
||||||
|
allBusinesses.addAll(widget.groupedBusinesses[type]!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FloatingActionButton(
|
return FloatingActionButton(
|
||||||
@ -273,7 +284,7 @@ class _FABState extends State<_FAB> {
|
|||||||
|
|
||||||
List<pw.TableRow> rows = [];
|
List<pw.TableRow> rows = [];
|
||||||
if (selectedBusinesses.isEmpty) {
|
if (selectedBusinesses.isEmpty) {
|
||||||
selectedBusinesses.addAll(widget.businesses);
|
selectedBusinesses.addAll(allBusinesses);
|
||||||
isBusinessesFiltered = false;
|
isBusinessesFiltered = false;
|
||||||
} else {
|
} else {
|
||||||
isBusinessesFiltered = true;
|
isBusinessesFiltered = true;
|
||||||
@ -284,9 +295,9 @@ class _FABState extends State<_FAB> {
|
|||||||
if (dataTypeFilters.contains(DataType.logo)) {
|
if (dataTypeFilters.contains(DataType.logo)) {
|
||||||
remainingSpace -= 32;
|
remainingSpace -= 32;
|
||||||
}
|
}
|
||||||
if (dataTypeFilters.contains(DataType.type)) {
|
// if (dataTypeFilters.contains(DataType.type)) {
|
||||||
remainingSpace -= 56;
|
// remainingSpace -= 56;
|
||||||
}
|
// }
|
||||||
if (dataTypeFilters.contains(DataType.contactName)) {
|
if (dataTypeFilters.contains(DataType.contactName)) {
|
||||||
remainingSpace -= 72;
|
remainingSpace -= 72;
|
||||||
}
|
}
|
||||||
@ -331,9 +342,9 @@ class _FABState extends State<_FAB> {
|
|||||||
} else if (dataType == DataType.description) {
|
} else if (dataType == DataType.description) {
|
||||||
width = pw.FixedColumnWidth(descriptionWidth);
|
width = pw.FixedColumnWidth(descriptionWidth);
|
||||||
columnNum++;
|
columnNum++;
|
||||||
} else if (dataType == DataType.type) {
|
// } else if (dataType == DataType.type) {
|
||||||
width = const pw.FixedColumnWidth(56);
|
// width = const pw.FixedColumnWidth(56);
|
||||||
columnNum++;
|
// columnNum++;
|
||||||
} else if (dataType == DataType.website) {
|
} else if (dataType == DataType.website) {
|
||||||
width = pw.FixedColumnWidth(websiteWidth);
|
width = pw.FixedColumnWidth(websiteWidth);
|
||||||
columnNum++;
|
columnNum++;
|
||||||
@ -394,18 +405,18 @@ class _FABState extends State<_FAB> {
|
|||||||
),
|
),
|
||||||
padding: const pw.EdgeInsets.all(4.0)));
|
padding: const pw.EdgeInsets.all(4.0)));
|
||||||
}
|
}
|
||||||
if (dataTypeFilters.contains(DataType.type)) {
|
// if (dataTypeFilters.contains(DataType.type)) {
|
||||||
data.add(pw.Padding(
|
// data.add(pw.Padding(
|
||||||
child: pw.Text(
|
// child: pw.Text(
|
||||||
business.type.name,
|
// business.type.name,
|
||||||
// style: const pw.TextStyle(fontSize: 10)
|
// // style: const pw.TextStyle(fontSize: 10)
|
||||||
),
|
// ),
|
||||||
padding: const pw.EdgeInsets.all(4.0)));
|
// padding: const pw.EdgeInsets.all(4.0)));
|
||||||
}
|
// }
|
||||||
if (dataTypeFilters.contains(DataType.website)) {
|
if (dataTypeFilters.contains(DataType.website)) {
|
||||||
data.add(pw.Padding(
|
data.add(pw.Padding(
|
||||||
child: pw.Text(
|
child: pw.Text(
|
||||||
business.website,
|
business.website ?? '',
|
||||||
// style: const pw.TextStyle(fontSize: 10)
|
// style: const pw.TextStyle(fontSize: 10)
|
||||||
),
|
),
|
||||||
padding: const pw.EdgeInsets.all(4.0)));
|
padding: const pw.EdgeInsets.all(4.0)));
|
||||||
@ -413,7 +424,7 @@ class _FABState extends State<_FAB> {
|
|||||||
if (dataTypeFilters.contains(DataType.contactName)) {
|
if (dataTypeFilters.contains(DataType.contactName)) {
|
||||||
data.add(pw.Padding(
|
data.add(pw.Padding(
|
||||||
child: pw.Text(
|
child: pw.Text(
|
||||||
business.contactName,
|
business.contactName ?? '',
|
||||||
// style: const pw.TextStyle(fontSize: 10)
|
// style: const pw.TextStyle(fontSize: 10)
|
||||||
),
|
),
|
||||||
padding: const pw.EdgeInsets.all(4.0)));
|
padding: const pw.EdgeInsets.all(4.0)));
|
||||||
@ -421,7 +432,7 @@ class _FABState extends State<_FAB> {
|
|||||||
if (dataTypeFilters.contains(DataType.contactEmail)) {
|
if (dataTypeFilters.contains(DataType.contactEmail)) {
|
||||||
data.add(pw.Padding(
|
data.add(pw.Padding(
|
||||||
child: pw.Text(
|
child: pw.Text(
|
||||||
business.contactEmail,
|
business.contactEmail ?? '',
|
||||||
// style: const pw.TextStyle(fontSize: 10)
|
// style: const pw.TextStyle(fontSize: 10)
|
||||||
),
|
),
|
||||||
padding: const pw.EdgeInsets.all(4.0)));
|
padding: const pw.EdgeInsets.all(4.0)));
|
||||||
@ -429,7 +440,7 @@ class _FABState extends State<_FAB> {
|
|||||||
if (dataTypeFilters.contains(DataType.contactPhone)) {
|
if (dataTypeFilters.contains(DataType.contactPhone)) {
|
||||||
data.add(pw.Padding(
|
data.add(pw.Padding(
|
||||||
child: pw.Text(
|
child: pw.Text(
|
||||||
business.contactPhone,
|
business.contactPhone ?? '',
|
||||||
// style: const pw.TextStyle(fontSize: 10)
|
// style: const pw.TextStyle(fontSize: 10)
|
||||||
),
|
),
|
||||||
padding: const pw.EdgeInsets.all(4.0)));
|
padding: const pw.EdgeInsets.all(4.0)));
|
||||||
@ -440,7 +451,7 @@ class _FABState extends State<_FAB> {
|
|||||||
style = const pw.TextStyle(fontSize: 8);
|
style = const pw.TextStyle(fontSize: 8);
|
||||||
}
|
}
|
||||||
data.add(pw.Padding(
|
data.add(pw.Padding(
|
||||||
child: pw.Text(business.notes, style: style),
|
child: pw.Text(business.notes ?? '', style: style),
|
||||||
padding: const pw.EdgeInsets.all(4.0)));
|
padding: const pw.EdgeInsets.all(4.0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,10 +472,10 @@ class _FABState extends State<_FAB> {
|
|||||||
} else {
|
} else {
|
||||||
rows.add(pw.TableRow(
|
rows.add(pw.TableRow(
|
||||||
children: [
|
children: [
|
||||||
pw.Padding(
|
// pw.Padding(
|
||||||
child: getPwIconFromType(
|
// child: getPwIconFromType(
|
||||||
business.type, 24, PdfColors.black),
|
// business.type, 24, PdfColors.black),
|
||||||
padding: const pw.EdgeInsets.all(4.0)),
|
// padding: const pw.EdgeInsets.all(4.0)),
|
||||||
...data
|
...data
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:fbla_ui/api_logic.dart';
|
import 'package:fbla_ui/api_logic.dart';
|
||||||
import 'package:fbla_ui/pages/business_detail.dart';
|
import 'package:fbla_ui/pages/business_detail.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -21,7 +20,7 @@ enum DataType {
|
|||||||
logo,
|
logo,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
type,
|
// type,
|
||||||
website,
|
website,
|
||||||
contactName,
|
contactName,
|
||||||
contactEmail,
|
contactEmail,
|
||||||
@ -33,7 +32,7 @@ Map<DataType, int> dataTypeValues = {
|
|||||||
DataType.logo: 0,
|
DataType.logo: 0,
|
||||||
DataType.name: 1,
|
DataType.name: 1,
|
||||||
DataType.description: 2,
|
DataType.description: 2,
|
||||||
DataType.type: 3,
|
// DataType.type: 3,
|
||||||
DataType.website: 4,
|
DataType.website: 4,
|
||||||
DataType.contactName: 5,
|
DataType.contactName: 5,
|
||||||
DataType.contactEmail: 6,
|
DataType.contactEmail: 6,
|
||||||
@ -45,7 +44,7 @@ Map<DataType, String> dataTypeFriendly = {
|
|||||||
DataType.logo: 'Logo',
|
DataType.logo: 'Logo',
|
||||||
DataType.name: 'Name',
|
DataType.name: 'Name',
|
||||||
DataType.description: 'Description',
|
DataType.description: 'Description',
|
||||||
DataType.type: 'Type',
|
// DataType.type: 'Type',
|
||||||
DataType.website: 'Website',
|
DataType.website: 'Website',
|
||||||
DataType.contactName: 'Contact Name',
|
DataType.contactName: 'Contact Name',
|
||||||
DataType.contactEmail: 'Contact Email',
|
DataType.contactEmail: 'Contact Email',
|
||||||
@ -71,47 +70,68 @@ enum BusinessType {
|
|||||||
other,
|
other,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum JobType { cashier, server, mechanic, other }
|
||||||
|
|
||||||
|
class JobListing {
|
||||||
|
String? id;
|
||||||
|
String? businessId;
|
||||||
|
String name;
|
||||||
|
String description;
|
||||||
|
JobType type;
|
||||||
|
String? wage;
|
||||||
|
String? link;
|
||||||
|
|
||||||
|
JobListing(
|
||||||
|
{this.id,
|
||||||
|
this.businessId,
|
||||||
|
required this.name,
|
||||||
|
required this.description,
|
||||||
|
required this.type,
|
||||||
|
this.wage,
|
||||||
|
this.link});
|
||||||
|
}
|
||||||
|
|
||||||
class Business {
|
class Business {
|
||||||
int id;
|
int id;
|
||||||
String name;
|
String name;
|
||||||
String description;
|
String description;
|
||||||
BusinessType type;
|
String? website;
|
||||||
String website;
|
String? contactName;
|
||||||
String contactName;
|
String? contactEmail;
|
||||||
String contactEmail;
|
String? contactPhone;
|
||||||
String contactPhone;
|
String? notes;
|
||||||
String notes;
|
String? locationName;
|
||||||
String locationName;
|
String? locationAddress;
|
||||||
String locationAddress;
|
List<JobListing>? listings;
|
||||||
|
|
||||||
Business({
|
Business(
|
||||||
required this.id,
|
{required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.description,
|
required this.description,
|
||||||
required this.type,
|
this.website,
|
||||||
required this.website,
|
this.contactName,
|
||||||
required this.contactName,
|
this.contactEmail,
|
||||||
required this.contactEmail,
|
this.contactPhone,
|
||||||
required this.contactPhone,
|
this.notes,
|
||||||
required this.notes,
|
this.locationName,
|
||||||
required this.locationName,
|
this.locationAddress,
|
||||||
required this.locationAddress,
|
this.listings});
|
||||||
});
|
|
||||||
|
|
||||||
factory Business.fromJson(Map<String, dynamic> json) {
|
factory Business.fromJson(Map<String, dynamic> json) {
|
||||||
bool typeValid = true;
|
List<JobListing>? listings = [];
|
||||||
try {
|
for (int i = 0; i < json['listings'].length; i++) {
|
||||||
BusinessType.values.byName(json['type']);
|
listings.add(JobListing(
|
||||||
} catch (e) {
|
name: json['listings']['name'],
|
||||||
typeValid = false;
|
description: json['listings']['description'],
|
||||||
|
type: json['listings']['type'],
|
||||||
|
wage: json['listings']['wage'],
|
||||||
|
link: json['listings']['link']));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Business(
|
return Business(
|
||||||
id: json['id'],
|
id: json['id'],
|
||||||
name: json['name'],
|
name: json['name'],
|
||||||
description: json['description'],
|
description: json['description'],
|
||||||
type: typeValid
|
|
||||||
? BusinessType.values.byName(json['type'])
|
|
||||||
: BusinessType.other,
|
|
||||||
website: json['website'],
|
website: json['website'],
|
||||||
contactName: json['contactName'],
|
contactName: json['contactName'],
|
||||||
contactEmail: json['contactEmail'],
|
contactEmail: json['contactEmail'],
|
||||||
@ -119,7 +139,7 @@ class Business {
|
|||||||
notes: json['notes'],
|
notes: json['notes'],
|
||||||
locationName: json['locationName'],
|
locationName: json['locationName'],
|
||||||
locationAddress: json['locationAddress'],
|
locationAddress: json['locationAddress'],
|
||||||
);
|
listings: listings);
|
||||||
}
|
}
|
||||||
|
|
||||||
factory Business.copy(Business input) {
|
factory Business.copy(Business input) {
|
||||||
@ -127,7 +147,6 @@ class Business {
|
|||||||
id: input.id,
|
id: input.id,
|
||||||
name: input.name,
|
name: input.name,
|
||||||
description: input.description,
|
description: input.description,
|
||||||
type: input.type,
|
|
||||||
website: input.website,
|
website: input.website,
|
||||||
contactName: input.contactName,
|
contactName: input.contactName,
|
||||||
contactEmail: input.contactEmail,
|
contactEmail: input.contactEmail,
|
||||||
@ -135,16 +154,16 @@ class Business {
|
|||||||
notes: input.notes,
|
notes: input.notes,
|
||||||
locationName: input.locationName,
|
locationName: input.locationName,
|
||||||
locationAddress: input.locationAddress,
|
locationAddress: input.locationAddress,
|
||||||
);
|
listings: input.listings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<BusinessType, List<Business>> groupBusinesses(List<Business> businesses) {
|
// Map<BusinessType, List<Business>> groupBusinesses(List<Business> businesses) {
|
||||||
Map<BusinessType, List<Business>> groupedBusinesses =
|
// Map<BusinessType, List<Business>> groupedBusinesses =
|
||||||
groupBy<Business, BusinessType>(businesses, (business) => business.type);
|
// groupBy<Business, BusinessType>(businesses, (business) => business.type!);
|
||||||
|
//
|
||||||
return groupedBusinesses;
|
// return groupedBusinesses;
|
||||||
}
|
// }
|
||||||
|
|
||||||
Icon getIconFromType(BusinessType type, double size, Color color) {
|
Icon getIconFromType(BusinessType type, double size, Color color) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -187,6 +206,35 @@ Icon getIconFromType(BusinessType type, double size, Color color) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Icon getIconFromJobType(JobType type, double size, Color color) {
|
||||||
|
switch (type) {
|
||||||
|
case JobType.cashier:
|
||||||
|
return Icon(
|
||||||
|
Icons.shopping_bag,
|
||||||
|
size: size,
|
||||||
|
color: color,
|
||||||
|
);
|
||||||
|
case JobType.server:
|
||||||
|
return Icon(
|
||||||
|
Icons.restaurant,
|
||||||
|
size: size,
|
||||||
|
color: color,
|
||||||
|
);
|
||||||
|
case JobType.mechanic:
|
||||||
|
return Icon(
|
||||||
|
Icons.construction,
|
||||||
|
size: size,
|
||||||
|
color: color,
|
||||||
|
);
|
||||||
|
case JobType.other:
|
||||||
|
return Icon(
|
||||||
|
Icons.work,
|
||||||
|
size: size,
|
||||||
|
color: color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pw.Icon getPwIconFromType(BusinessType type, double size, PdfColor color) {
|
pw.Icon getPwIconFromType(BusinessType type, double size, PdfColor color) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BusinessType.food:
|
case BusinessType.food:
|
||||||
@ -204,6 +252,19 @@ pw.Icon getPwIconFromType(BusinessType type, double size, PdfColor color) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pw.Icon getPwIconFromJobType(JobType type, double size, PdfColor color) {
|
||||||
|
switch (type) {
|
||||||
|
case JobType.cashier:
|
||||||
|
return pw.Icon(const pw.IconData(0xf1cc), size: size, color: color);
|
||||||
|
case JobType.server:
|
||||||
|
return pw.Icon(const pw.IconData(0xe56c), size: size, color: color);
|
||||||
|
case JobType.mechanic:
|
||||||
|
return pw.Icon(const pw.IconData(0xea3c), size: size, color: color);
|
||||||
|
case JobType.other:
|
||||||
|
return pw.Icon(const pw.IconData(0xe8f9), size: size, color: color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Text getNameFromType(BusinessType type, Color color) {
|
Text getNameFromType(BusinessType type, Color color) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BusinessType.food:
|
case BusinessType.food:
|
||||||
@ -221,6 +282,19 @@ Text getNameFromType(BusinessType type, Color color) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text getNameFromJobType(JobType type, Color color) {
|
||||||
|
switch (type) {
|
||||||
|
case JobType.cashier:
|
||||||
|
return Text('Cashier', style: TextStyle(color: color));
|
||||||
|
case JobType.server:
|
||||||
|
return Text('Server', style: TextStyle(color: color));
|
||||||
|
case JobType.mechanic:
|
||||||
|
return Text('Mechanic', style: TextStyle(color: color));
|
||||||
|
case JobType.other:
|
||||||
|
return Text('Other', style: TextStyle(color: color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Icon getIconFromThemeMode(ThemeMode theme) {
|
Icon getIconFromThemeMode(ThemeMode theme) {
|
||||||
switch (theme) {
|
switch (theme) {
|
||||||
case ThemeMode.dark:
|
case ThemeMode.dark:
|
||||||
@ -233,13 +307,13 @@ Icon getIconFromThemeMode(ThemeMode theme) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class BusinessDisplayPanel extends StatefulWidget {
|
class BusinessDisplayPanel extends StatefulWidget {
|
||||||
final List<Business> businesses;
|
final Map<JobType, List<Business>> groupedBusinesses;
|
||||||
final bool widescreen;
|
final bool widescreen;
|
||||||
final bool selectable;
|
final bool selectable;
|
||||||
|
|
||||||
const BusinessDisplayPanel(
|
const BusinessDisplayPanel(
|
||||||
{super.key,
|
{super.key,
|
||||||
required this.businesses,
|
required this.groupedBusinesses,
|
||||||
required this.widescreen,
|
required this.widescreen,
|
||||||
required this.selectable});
|
required this.selectable});
|
||||||
|
|
||||||
@ -253,40 +327,42 @@ class _BusinessDisplayPanelState extends State<BusinessDisplayPanel> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
List<BusinessHeader> headers = [];
|
List<BusinessHeader> headers = [];
|
||||||
List<Business> filteredBusinesses = [];
|
// List<Business> filteredBusinesses = [];
|
||||||
for (var business in widget.businesses) {
|
// for (var business in widget.groupedBusinesses.) {
|
||||||
if (business.name.toLowerCase().contains(searchFilter.toLowerCase())) {
|
// if (business.name.toLowerCase().contains(searchFilter.toLowerCase())) {
|
||||||
filteredBusinesses.add(business);
|
// filteredBusinesses.add(business);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
var groupedBusinesses = groupBusinesses(filteredBusinesses);
|
|
||||||
var businessTypes = groupedBusinesses.keys.toList();
|
|
||||||
|
|
||||||
for (var i = 0; i < businessTypes.length; i++) {
|
if (filters.isNotEmpty) {
|
||||||
if (filters.contains(businessTypes[i])) {
|
|
||||||
isFiltered = true;
|
isFiltered = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// for (var i = 0; i < businessTypes.length; i++) {
|
||||||
|
// if (filters.contains(businessTypes[i])) {
|
||||||
|
// isFiltered = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if (isFiltered) {
|
if (isFiltered) {
|
||||||
for (var i = 0; i < businessTypes.length; i++) {
|
for (JobType jobType in widget.groupedBusinesses.keys) {
|
||||||
if (filters.contains(businessTypes[i])) {
|
if (filters.contains(jobType)) {
|
||||||
headers.add(BusinessHeader(
|
headers.add(BusinessHeader(
|
||||||
type: businessTypes[i],
|
type: jobType,
|
||||||
widescreen: widget.widescreen,
|
widescreen: widget.widescreen,
|
||||||
selectable: widget.selectable,
|
selectable: widget.selectable,
|
||||||
selectedBusinesses: selectedBusinesses,
|
selectedBusinesses: selectedBusinesses,
|
||||||
businesses: groupedBusinesses[businessTypes[i]]!));
|
businesses: widget.groupedBusinesses[jobType]!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (var i = 0; i < businessTypes.length; i++) {
|
for (JobType jobType in widget.groupedBusinesses.keys) {
|
||||||
headers.add(BusinessHeader(
|
headers.add(BusinessHeader(
|
||||||
type: businessTypes[i],
|
type: jobType,
|
||||||
widescreen: widget.widescreen,
|
widescreen: widget.widescreen,
|
||||||
selectable: widget.selectable,
|
selectable: widget.selectable,
|
||||||
selectedBusinesses: selectedBusinesses,
|
selectedBusinesses: selectedBusinesses,
|
||||||
businesses: groupedBusinesses[businessTypes[i]]!));
|
businesses: widget.groupedBusinesses[jobType]!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
headers.sort((a, b) => a.type.index.compareTo(b.type.index));
|
headers.sort((a, b) => a.type.index.compareTo(b.type.index));
|
||||||
@ -295,7 +371,7 @@ class _BusinessDisplayPanelState extends State<BusinessDisplayPanel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class BusinessHeader extends StatefulWidget {
|
class BusinessHeader extends StatefulWidget {
|
||||||
final BusinessType type;
|
final JobType type;
|
||||||
final List<Business> businesses;
|
final List<Business> businesses;
|
||||||
final Set<Business> selectedBusinesses;
|
final Set<Business> selectedBusinesses;
|
||||||
final bool widescreen;
|
final bool widescreen;
|
||||||
@ -343,10 +419,10 @@ class _BusinessHeaderState extends State<BusinessHeader> {
|
|||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 4.0, right: 12.0),
|
padding: const EdgeInsets.only(left: 4.0, right: 12.0),
|
||||||
child: getIconFromType(
|
child: getIconFromJobType(
|
||||||
widget.type, 24, Theme.of(context).colorScheme.onPrimary),
|
widget.type, 24, Theme.of(context).colorScheme.onPrimary),
|
||||||
),
|
),
|
||||||
getNameFromType(
|
getNameFromJobType(
|
||||||
widget.type, Theme.of(context).colorScheme.onPrimary),
|
widget.type, Theme.of(context).colorScheme.onPrimary),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -376,10 +452,11 @@ class _BusinessHeaderState extends State<BusinessHeader> {
|
|||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 4.0, right: 12.0),
|
padding: const EdgeInsets.only(left: 4.0, right: 12.0),
|
||||||
child: getIconFromType(
|
child: getIconFromJobType(
|
||||||
widget.type, 24, Theme.of(context).colorScheme.onPrimary),
|
widget.type, 24, Theme.of(context).colorScheme.onPrimary),
|
||||||
),
|
),
|
||||||
getNameFromType(widget.type, Theme.of(context).colorScheme.onPrimary),
|
getNameFromJobType(
|
||||||
|
widget.type, Theme.of(context).colorScheme.onPrimary),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -404,6 +481,7 @@ class _BusinessHeaderState extends State<BusinessHeader> {
|
|||||||
selectable: selectable,
|
selectable: selectable,
|
||||||
widescreen: widescreen,
|
widescreen: widescreen,
|
||||||
callback: refresh,
|
callback: refresh,
|
||||||
|
type: widget.type,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -418,6 +496,7 @@ class _BusinessHeaderState extends State<BusinessHeader> {
|
|||||||
selectable: selectable,
|
selectable: selectable,
|
||||||
widescreen: widescreen,
|
widescreen: widescreen,
|
||||||
callback: refresh,
|
callback: refresh,
|
||||||
|
type: widget.type,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -431,13 +510,15 @@ class BusinessCard extends StatefulWidget {
|
|||||||
final bool widescreen;
|
final bool widescreen;
|
||||||
final bool selectable;
|
final bool selectable;
|
||||||
final Function callback;
|
final Function callback;
|
||||||
|
final JobType type;
|
||||||
|
|
||||||
const BusinessCard(
|
const BusinessCard(
|
||||||
{super.key,
|
{super.key,
|
||||||
required this.business,
|
required this.business,
|
||||||
required this.widescreen,
|
required this.widescreen,
|
||||||
required this.selectable,
|
required this.selectable,
|
||||||
required this.callback});
|
required this.callback,
|
||||||
|
required this.type});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<BusinessCard> createState() => _BusinessCardState();
|
State<BusinessCard> createState() => _BusinessCardState();
|
||||||
@ -447,27 +528,31 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (widget.widescreen) {
|
if (widget.widescreen) {
|
||||||
return _businessTile(widget.business, widget.selectable);
|
return _businessTile(widget.business, widget.selectable, widget.type);
|
||||||
} else {
|
} else {
|
||||||
return _businessListItem(
|
return _businessListItem(
|
||||||
widget.business, widget.selectable, widget.callback);
|
widget.business, widget.selectable, widget.callback, widget.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _businessTile(Business business, bool selectable) {
|
Widget _businessTile(Business business, bool selectable, JobType type) {
|
||||||
return MouseRegion(
|
return MouseRegion(
|
||||||
cursor: SystemMouseCursors.click,
|
cursor: SystemMouseCursors.click,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
Navigator.of(context).push(MaterialPageRoute(
|
||||||
builder: (context) => BusinessDetail(inputBusiness: business)));
|
builder: (context) => BusinessDetail(
|
||||||
|
id: business.id,
|
||||||
|
name: business.name,
|
||||||
|
clickFromType: type,
|
||||||
|
)));
|
||||||
},
|
},
|
||||||
child: Card(
|
child: Card(
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
_getTileRow(business, selectable, widget.callback),
|
_getTileRow(business, selectable, widget.callback, type),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -490,7 +575,8 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
Uri.parse('https://${business.website}'));
|
Uri.parse('https://${business.website}'));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (business.locationName.isNotEmpty)
|
if ((business.locationName != null) &&
|
||||||
|
(business.locationName != ''))
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.location_on),
|
icon: const Icon(Icons.location_on),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -498,7 +584,8 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
'https://www.google.com/maps/search/?api=1&query=${business.locationName}')));
|
'https://www.google.com/maps/search/?api=1&query=${business.locationName}')));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (business.contactPhone.isNotEmpty)
|
if ((business.contactPhone != null) &&
|
||||||
|
(business.contactPhone != ''))
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.phone),
|
icon: const Icon(Icons.phone),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -509,10 +596,14 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
backgroundColor: Theme.of(context)
|
backgroundColor: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.background,
|
.background,
|
||||||
title: Text(business.contactName.isEmpty
|
title: Text((business.contactName ==
|
||||||
|
null ||
|
||||||
|
business.contactName == '')
|
||||||
? 'Contact ${business.name}?'
|
? 'Contact ${business.name}?'
|
||||||
: 'Contact ${business.contactName}'),
|
: 'Contact ${business.contactName}'),
|
||||||
content: Text(business.contactName.isEmpty
|
content: Text((business.contactName ==
|
||||||
|
null ||
|
||||||
|
business.contactName == '')
|
||||||
? 'Would you like to call or text ${business.name}?'
|
? 'Would you like to call or text ${business.name}?'
|
||||||
: 'Would you like to call or text ${business.contactName}?'),
|
: 'Would you like to call or text ${business.contactName}?'),
|
||||||
actions: [
|
actions: [
|
||||||
@ -535,7 +626,8 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (business.contactEmail.isNotEmpty)
|
if ((business.contactEmail != null) &&
|
||||||
|
(business.contactEmail != ''))
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.email),
|
icon: const Icon(Icons.email),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -553,7 +645,8 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _getTileRow(Business business, bool selectable, Function callback) {
|
Widget _getTileRow(
|
||||||
|
Business business, bool selectable, Function callback, JobType type) {
|
||||||
if (selectable) {
|
if (selectable) {
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
@ -565,8 +658,8 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
child: Image.network('$apiAddress/logos/${business.id}',
|
child: Image.network('$apiAddress/logos/${business.id}',
|
||||||
height: 48, width: 48, errorBuilder: (BuildContext context,
|
height: 48, width: 48, errorBuilder: (BuildContext context,
|
||||||
Object exception, StackTrace? stackTrace) {
|
Object exception, StackTrace? stackTrace) {
|
||||||
return getIconFromType(
|
return getIconFromJobType(
|
||||||
business.type, 48, Theme.of(context).colorScheme.onSurface);
|
type, 48, Theme.of(context).colorScheme.onSurface);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -598,8 +691,8 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
child: Image.network('$apiAddress/logos/${business.id}',
|
child: Image.network('$apiAddress/logos/${business.id}',
|
||||||
height: 48, width: 48, errorBuilder: (BuildContext context,
|
height: 48, width: 48, errorBuilder: (BuildContext context,
|
||||||
Object exception, StackTrace? stackTrace) {
|
Object exception, StackTrace? stackTrace) {
|
||||||
return getIconFromType(business.type, 48,
|
return getIconFromJobType(
|
||||||
Theme.of(context).colorScheme.onSurface);
|
type, 48, Theme.of(context).colorScheme.onSurface);
|
||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
Flexible(
|
Flexible(
|
||||||
@ -620,7 +713,7 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _businessListItem(
|
Widget _businessListItem(
|
||||||
Business business, bool selectable, Function callback) {
|
Business business, bool selectable, Function callback, JobType type) {
|
||||||
return Card(
|
return Card(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: ClipRRect(
|
leading: ClipRRect(
|
||||||
@ -628,8 +721,8 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
child: Image.network('$apiAddress/logos/${business.id}',
|
child: Image.network('$apiAddress/logos/${business.id}',
|
||||||
height: 24, width: 24, errorBuilder: (BuildContext context,
|
height: 24, width: 24, errorBuilder: (BuildContext context,
|
||||||
Object exception, StackTrace? stackTrace) {
|
Object exception, StackTrace? stackTrace) {
|
||||||
return getIconFromType(
|
return getIconFromJobType(
|
||||||
business.type, 24, Theme.of(context).colorScheme.onSurface);
|
type, 24, Theme.of(context).colorScheme.onSurface);
|
||||||
})),
|
})),
|
||||||
title: Text(business.name),
|
title: Text(business.name),
|
||||||
subtitle: Text(business.description,
|
subtitle: Text(business.description,
|
||||||
@ -637,7 +730,11 @@ class _BusinessCardState extends State<BusinessCard> {
|
|||||||
trailing: _getCheckbox(selectable, callback),
|
trailing: _getCheckbox(selectable, callback),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
Navigator.of(context).push(MaterialPageRoute(
|
||||||
builder: (context) => BusinessDetail(inputBusiness: business)));
|
builder: (context) => BusinessDetail(
|
||||||
|
id: business.id,
|
||||||
|
name: business.name,
|
||||||
|
clickFromType: type,
|
||||||
|
)));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -688,7 +785,8 @@ class _FilterChipsState extends State<FilterChips> {
|
|||||||
showCheckmark: false,
|
showCheckmark: false,
|
||||||
shape:
|
shape:
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||||
label: getNameFromType(type, Theme.of(context).colorScheme.onSurface),
|
label:
|
||||||
|
getNameFromType(type, Theme.of(context).colorScheme.onSurface),
|
||||||
selected: selectedChips.contains(type),
|
selected: selectedChips.contains(type),
|
||||||
onSelected: (bool selected) {
|
onSelected: (bool selected) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user