More fixes

This commit is contained in:
2024-06-25 18:27:53 -05:00
parent 3cdf3b54ed
commit e1f8c15e9a
10 changed files with 454 additions and 239 deletions
+38 -27
View File
@@ -22,6 +22,7 @@ class BusinessDetail extends StatefulWidget {
class _CreateBusinessDetailState extends State<BusinessDetail> {
late Future loadBusiness;
bool _isRetrying = false;
@override
void initState() {
@@ -60,11 +61,17 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
padding: const EdgeInsets.all(8.0),
child: FilledButton(
child: const Text('Retry'),
onPressed: () {
var refreshedData = fetchBusiness(widget.id);
setState(() {
loadBusiness = refreshedData;
});
onPressed: () async {
if (!_isRetrying) {
setState(() {
_isRetrying = true;
});
var refreshedData =
await fetchBusiness(widget.id);
setState(() {
loadBusiness = refreshedData;
});
}
},
),
),
@@ -120,28 +127,32 @@ class _CreateBusinessDetailState extends State<BusinessDetail> {
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);
}),
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: 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)
+9 -3
View File
@@ -40,6 +40,7 @@ class _BusinessesOverviewState extends State<BusinessesOverview> {
ScrollController controller = ScrollController();
bool _extended = true;
double prevPixelPosition = 0;
bool _isRetrying = false;
Map<BusinessType, List<Business>> _filterBySearch(
Map<BusinessType, List<Business>> businesses, String query) {
@@ -138,9 +139,14 @@ class _BusinessesOverviewState extends State<BusinessesOverview> {
padding: const EdgeInsets.all(8.0),
child: FilledButton(
child: const Text('Retry'),
onPressed: () {
widget.updateBusinessesCallback(
businessTypeFilters);
onPressed: () async {
if (!_isRetrying) {
setState(() {
_isRetrying = true;
});
await widget.updateBusinessesCallback(
businessTypeFilters);
}
},
),
),
+57 -24
View File
@@ -103,7 +103,17 @@ class _CreateEditBusinessState extends State<CreateEditBusiness> {
)
: const Icon(Icons.save),
onPressed: () async {
await _saveBusiness(context);
if (!_isLoading) {
await _saveBusiness(context);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
width: 400,
behavior: SnackBarBehavior.floating,
content: Text('Please wait for it to save.'),
),
);
}
},
)
: null,
@@ -114,28 +124,40 @@ class _CreateEditBusinessState extends State<CreateEditBusiness> {
width: 800,
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(
'https://logo.clearbit.com/${business.website}',
width: 48,
height: 48, errorBuilder: (BuildContext context,
Object exception, StackTrace? stackTrace) {
return Icon(
getIconFromBusinessType(
business.type ?? BusinessType.other),
size: 48);
}),
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Card(
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: 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(
'https://logo.clearbit.com/${business.website}',
width: 48,
height: 48, errorBuilder:
(BuildContext context,
Object exception,
StackTrace? stackTrace) {
return Icon(
getIconFromBusinessType(business.type ??
BusinessType.other),
size: 48);
}),
),
),
),
),
),
Card(
@@ -540,7 +562,18 @@ class _CreateEditBusinessState extends State<CreateEditBusiness> {
],
),
onPressed: () async {
await _saveBusiness(context);
if (!_isLoading) {
await _saveBusiness(context);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
width: 400,
behavior: SnackBarBehavior.floating,
content:
Text('Please wait for it to save.'),
),
);
}
},
),
),
+107 -45
View File
@@ -38,6 +38,8 @@ class _CreateEditJobListingState extends State<CreateEditJobListing> {
link: null,
offerType: null);
bool _isLoading = false;
late String businessName;
bool _isRetrying = false;
@override
void initState() {
@@ -57,6 +59,7 @@ class _CreateEditJobListingState extends State<CreateEditJobListing> {
.replaceAll('http://', '')
.replaceAll('www.', ''));
getBusinessNameMapping = fetchBusinessNames();
businessName = widget.inputBusiness?.name ?? 'Offering business';
}
final formKey = GlobalKey<FormState>();
@@ -92,7 +95,17 @@ class _CreateEditJobListingState extends State<CreateEditJobListing> {
)
: const Icon(Icons.save),
onPressed: () async {
await _saveListing(context);
if (!_isLoading) {
await _saveListing(context);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
width: 400,
behavior: SnackBarBehavior.floating,
content: Text('Please wait for it to save.'),
),
);
}
})
: null,
body: FutureBuilder(
@@ -112,11 +125,17 @@ class _CreateEditJobListingState extends State<CreateEditJobListing> {
child: FilledButton(
child: const Text('Retry'),
onPressed: () async {
var refreshedData = fetchBusinessNames();
await refreshedData;
setState(() {
getBusinessNameMapping = refreshedData;
});
if (!_isRetrying) {
setState(() {
_isRetrying = true;
});
var refreshedData = fetchBusinessNames();
await refreshedData;
setState(() {
getBusinessNameMapping = refreshedData;
_isRetrying = false;
});
}
},
),
),
@@ -135,43 +154,55 @@ class _CreateEditJobListingState extends State<CreateEditJobListing> {
width: 800,
child: Column(
children: [
ListTile(
titleAlignment:
ListTileTitleAlignment.titleHeight,
title: Text(listing.name,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold)),
subtitle: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
getNameFromJobType(
listing.type ?? JobType.other),
style: const TextStyle(fontSize: 18),
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Card(
child: Padding(
padding:
const EdgeInsets.only(right: 8.0),
child: ListTile(
titleAlignment: ListTileTitleAlignment
.titleHeight,
title: Text(listing.name,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold)),
subtitle: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
businessName,
style: const TextStyle(
fontSize: 18),
),
Text(
listing.description,
),
],
),
contentPadding:
const EdgeInsets.only(left: 16),
leading: ClipRRect(
borderRadius:
BorderRadius.circular(6.0),
child: Image.network(
'$apiAddress/logos/${listing.businessId}',
width: 48,
height: 48, errorBuilder:
(BuildContext context,
Object exception,
StackTrace?
stackTrace) {
return Icon(
getIconFromJobType(
listing.type ??
JobType.other),
size: 48);
}),
),
),
Text(
listing.description,
),
],
),
contentPadding:
const EdgeInsets.only(left: 16),
leading: ClipRRect(
borderRadius: BorderRadius.circular(6.0),
child: Image.network(
'$apiAddress/logos/${listing.businessId}',
width: 48,
height: 48, errorBuilder:
(BuildContext context,
Object exception,
StackTrace? stackTrace) {
return Icon(
getIconFromJobType(
listing.type ?? JobType.other),
size: 48);
}),
),
),
),
// Business Type Dropdown
@@ -286,6 +317,11 @@ class _CreateEditJobListingState extends State<CreateEditJobListing> {
setState(() {
listing.businessId =
inputType!;
businessName = nameMapping
.where((element) =>
element['id'] ==
listing.businessId)
.first['name'];
businessDropdownErrorText =
null;
});
@@ -435,7 +471,7 @@ class _CreateEditJobListingState extends State<CreateEditJobListing> {
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FilledButton(
child: const Row(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
@@ -443,13 +479,39 @@ class _CreateEditJobListingState extends State<CreateEditJobListing> {
top: 8.0,
right: 8.0,
bottom: 8.0),
child: Icon(Icons.save),
child: _isLoading
? SizedBox(
width: 24,
height: 24,
child:
CircularProgressIndicator(
color:
Theme.of(context)
.colorScheme
.onPrimary,
strokeWidth: 3.0,
),
)
: Icon(Icons.save),
),
Text('Save'),
],
),
onPressed: () async {
await _saveListing(context);
if (!_isLoading) {
await _saveListing(context);
} else {
ScaffoldMessenger.of(context)
.showSnackBar(
const SnackBar(
width: 400,
behavior:
SnackBarBehavior.floating,
content: Text(
'Please wait for it to save.'),
),
);
}
},
),
),
+64 -46
View File
@@ -1,4 +1,5 @@
import 'package:fbla_ui/main.dart';
import 'package:fbla_ui/pages/business_detail.dart';
import 'package:fbla_ui/pages/create_edit_listing.dart';
import 'package:fbla_ui/shared/api_logic.dart';
import 'package:fbla_ui/shared/global_vars.dart';
@@ -44,53 +45,70 @@ class _CreateBusinessDetailState extends State<JobListingDetail> {
clipBehavior: Clip.antiAlias,
child: Column(
children: [
ListTile(
minVerticalPadding: 0,
titleAlignment: ListTileTitleAlignment.titleHeight,
title: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'${listing.name} (${getNameFromOfferType(listing.offerType!)})',
style: const TextStyle(
fontSize: 24, fontWeight: FontWeight.bold)),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
getNameFromJobType(listing.type!),
style: const TextStyle(fontSize: 18),
),
Text(
listing.description,
),
],
),
contentPadding:
const EdgeInsets.only(bottom: 8, left: 16),
leading: Badge(
label: Text(
getLetterFromOfferType(listing.offerType!),
style: const TextStyle(fontSize: 16),
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: ListTile(
minVerticalPadding: 0,
titleAlignment: ListTileTitleAlignment.titleHeight,
title: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'${listing.name} (${getNameFromOfferType(listing.offerType!)})',
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold)),
),
largeSize: 26,
offset: const Offset(15, -5),
textColor: Colors.white,
backgroundColor:
getColorFromOfferType(listing.offerType!),
child: ClipRRect(
borderRadius: BorderRadius.circular(6.0),
child: Image.network(
'$apiAddress/logos/${listing.businessId}',
width: 48,
height: 48, errorBuilder:
(BuildContext context, Object exception,
StackTrace? stackTrace) {
return Icon(
getIconFromJobType(
listing.type ?? JobType.other),
size: 48);
}),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return BusinessDetail(
id: widget.fromBusiness.id,
name: widget.fromBusiness.name!);
}));
},
child: Text(
widget.fromBusiness.name!,
style: const TextStyle(fontSize: 18),
),
),
),
Text(
listing.description,
),
],
),
contentPadding:
const EdgeInsets.only(bottom: 8, left: 16),
leading: Badge(
label: Text(
getLetterFromOfferType(listing.offerType!),
style: const TextStyle(fontSize: 16),
),
largeSize: 24,
offset: const Offset(12, -3),
textColor: Colors.white,
backgroundColor:
getColorFromOfferType(listing.offerType!),
child: ClipRRect(
borderRadius: BorderRadius.circular(6.0),
child: Image.network(
'$apiAddress/logos/${widget.fromBusiness.id}',
width: 48,
height: 48, errorBuilder:
(BuildContext context, Object exception,
StackTrace? stackTrace) {
return Icon(
getIconFromJobType(
listing.type ?? JobType.other),
size: 48);
}),
),
),
),
),
+10 -8
View File
@@ -42,6 +42,7 @@ class _JobsOverviewState extends State<JobsOverview> {
ScrollController controller = ScrollController();
bool _extended = true;
double prevPixelPosition = 0;
bool _isRetrying = false;
Map<JobType, List<Business>> _filterBySearch(
Map<JobType, List<Business>> businesses, String query) {
@@ -145,8 +146,13 @@ class _JobsOverviewState extends State<JobsOverview> {
padding: const EdgeInsets.all(8.0),
child: FilledButton(
child: const Text('Retry'),
onPressed: () {
widget.updateBusinessesCallback(null, null);
onPressed: () async {
if (!_isRetrying) {
setState(() {
_isRetrying = true;
});
await widget.updateBusinessesCallback(null, null);
}
},
),
),
@@ -534,12 +540,8 @@ class _JobHeaderState extends State<_JobHeader> {
business.listings![0].offerType!),
style: const TextStyle(fontSize: 16),
),
largeSize: 26,
padding: business.listings![0].offerType! ==
OfferType.internship
? const EdgeInsets.symmetric(horizontal: 5)
: null,
offset: const Offset(13, -2),
largeSize: 24,
offset: const Offset(12, -3),
textColor: Colors.white,
backgroundColor: getColorFromOfferType(
business.listings![0].offerType!),
+33 -12
View File
@@ -6,8 +6,8 @@ import 'package:fbla_ui/shared/global_vars.dart';
import 'package:fbla_ui/shared/utils.dart';
import 'package:http/http.dart' as http;
var apiAddress = 'https://homelab.marinodev.com/fbla-api';
// var apiAddress = 'http://192.168.0.114:8000/fbla-api';
// var apiAddress = 'https://homelab.marinodev.com/fbla-api';
var apiAddress = 'http://192.168.0.114:8000/fbla-api';
var client = http.Client();
@@ -67,21 +67,40 @@ Future fetchBusinessDataOverviewJobs(
var response = await http.get(uri).timeout(const Duration(seconds: 20));
if (response.statusCode == 200) {
var decodedResponse = json.decode(response.body);
List<Map<String, dynamic>> decodedResponse =
json.decode(response.body).cast<Map<String, dynamic>>();
List<Business> initialBusinesses =
decodedResponse.map((element) => Business.fromJson(element)).toList();
Map<JobType, List<Business>> groupedBusinesses = {};
for (String stringType in decodedResponse.keys) {
List<Business> businesses = [];
for (Map<String, dynamic> map in decodedResponse[stringType]) {
Business business = Business.fromJson(map);
businesses.add(business);
for (Business business in initialBusinesses) {
for (JobListing job in business.listings!) {
List<Business> newBusinesses = groupedBusinesses[job.type!] ?? [];
Business newBusiness = Business.copy(business);
newBusiness.listings =
newBusiness.listings!.where((element) => element == job).toList();
newBusinesses.add(newBusiness);
groupedBusinesses.addAll({job.type!: newBusinesses});
}
groupedBusinesses
.addAll({JobType.values.byName(stringType): businesses});
}
return groupedBusinesses;
// Map<JobType, List<Business>> groupedBusinesses = {};
//
// for (String stringType in decodedResponse.keys) {
// List<Business> businesses = [];
//
// for (Map<String, dynamic> map in decodedResponse[stringType]) {
// Business business = Business.fromJson(map);
// businesses.add(business);
// }
//
// groupedBusinesses
// .addAll({JobType.values.byName(stringType): businesses});
// }
// return groupedBusinesses;
} else {
return 'Error ${response.statusCode}! Please try again later!';
}
@@ -89,6 +108,8 @@ Future fetchBusinessDataOverviewJobs(
return 'Unable to connect to server (timeout).\nPlease try again later.';
} on SocketException {
return 'Unable to connect to server (socket exception).\nPlease check your internet connection.\n';
} catch (e) {
print(e);
}
}
+55 -15
View File
@@ -32,7 +32,17 @@ enum BusinessType {
other,
}
enum JobType { cashier, server, mechanic, other }
enum JobType {
retail,
customerService,
foodService,
finance,
healthcare,
education,
maintenance,
manufacturing,
other,
}
enum OfferType { job, internship, apprenticeship }
@@ -169,12 +179,22 @@ IconData getIconFromBusinessType(BusinessType type) {
IconData getIconFromJobType(JobType type) {
switch (type) {
case JobType.cashier:
case JobType.retail:
return Icons.shopping_bag;
case JobType.server:
case JobType.customerService:
return Icons.support_agent;
case JobType.foodService:
return Icons.restaurant;
case JobType.mechanic:
return Icons.construction;
case JobType.finance:
return Icons.paid;
case JobType.healthcare:
return Icons.medical_services;
case JobType.education:
return Icons.school;
case JobType.maintenance:
return Icons.handyman;
case JobType.manufacturing:
return Icons.factory;
case JobType.other:
return Icons.work;
}
@@ -199,12 +219,22 @@ pw.IconData getPwIconFromBusinessType(BusinessType type) {
pw.IconData getPwIconFromJobType(JobType type) {
switch (type) {
case JobType.cashier:
case JobType.retail:
return const pw.IconData(0xf1cc);
case JobType.server:
case JobType.customerService:
return const pw.IconData(0xf0e2);
case JobType.foodService:
return const pw.IconData(0xe56c);
case JobType.mechanic:
return const pw.IconData(0xea3c);
case JobType.finance:
return const pw.IconData(0xf041);
case JobType.healthcare:
return const pw.IconData(0xf109);
case JobType.education:
return const pw.IconData(0xe80c);
case JobType.maintenance:
return const pw.IconData(0xf10b);
case JobType.manufacturing:
return const pw.IconData(0xebbc);
case JobType.other:
return const pw.IconData(0xe8f9);
}
@@ -229,12 +259,22 @@ String getNameFromBusinessType(BusinessType type) {
String getNameFromJobType(JobType type) {
switch (type) {
case JobType.cashier:
return 'Cashier';
case JobType.server:
return 'Server';
case JobType.mechanic:
return 'Mechanic';
case JobType.retail:
return 'Retail';
case JobType.customerService:
return 'Customer Service';
case JobType.foodService:
return 'Food Service';
case JobType.finance:
return 'Finance';
case JobType.healthcare:
return 'Healthcare';
case JobType.education:
return 'Education';
case JobType.maintenance:
return 'Maintenance';
case JobType.manufacturing:
return 'Manufacturing';
case JobType.other:
return 'Other';
}