FBLA24/fbla_ui/lib/pages/create_edit_business.dart
2024-06-13 16:05:55 -05:00

542 lines
26 KiB
Dart

import 'package:fbla_ui/api_logic.dart';
import 'package:fbla_ui/main.dart';
import 'package:fbla_ui/shared.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CreateEditBusiness extends StatefulWidget {
final Business? inputBusiness;
final JobType? clickFromType;
const CreateEditBusiness({super.key, this.inputBusiness, this.clickFromType});
@override
State<CreateEditBusiness> createState() => _CreateEditBusinessState();
}
class _CreateEditBusinessState extends State<CreateEditBusiness> {
late TextEditingController _nameController;
late TextEditingController _websiteController;
late TextEditingController _descriptionController;
late TextEditingController _contactNameController;
late TextEditingController _contactPhoneController;
late TextEditingController _contactEmailController;
late TextEditingController _notesController;
late TextEditingController _locationNameController;
late TextEditingController _locationAddressController;
Business business = Business(
id: 0,
name: 'Business',
description: 'Add details about the business below.',
website: '',
contactName: '',
contactEmail: '',
contactPhone: '',
notes: '',
locationName: '',
locationAddress: '',
);
bool _isLoading = false;
@override
void initState() {
super.initState();
if (widget.inputBusiness != null) {
business = Business.copy(widget.inputBusiness!);
_nameController = TextEditingController(text: business.name);
_descriptionController =
TextEditingController(text: business.description);
} else {
_nameController = TextEditingController();
_descriptionController = TextEditingController();
}
_websiteController = TextEditingController(text: business.website);
_contactNameController = TextEditingController(text: business.contactName);
_contactPhoneController =
TextEditingController(text: business.contactPhone);
_contactEmailController =
TextEditingController(text: business.contactEmail);
_notesController = TextEditingController(text: business.notes);
_locationNameController =
TextEditingController(text: business.locationName);
_locationAddressController =
TextEditingController(text: business.locationAddress);
}
final formKey = GlobalKey<FormState>();
final TextEditingController businessTypeController = TextEditingController();
@override
Widget build(BuildContext context) {
return PopScope(
canPop: !_isLoading,
onPopInvoked: _handlePop,
child: Form(
key: formKey,
child: Scaffold(
appBar: AppBar(
title: (widget.inputBusiness != null)
? Text('Edit ${widget.inputBusiness?.name}', maxLines: 1)
: const Text('Add New Business'),
),
floatingActionButton: FloatingActionButton(
child: _isLoading
? const Padding(
padding: EdgeInsets.all(16.0),
child: CircularProgressIndicator(
color: Colors.white,
strokeWidth: 3.0,
),
)
: const Icon(Icons.save),
onPressed: () async {
if (formKey.currentState!.validate()) {
formKey.currentState?.save();
setState(() {
_isLoading = true;
});
String? result;
// if (business.contactName == '') {
// business.contactName = 'Contact ${business.name}';
// }
if (widget.inputBusiness != null) {
result = await editBusiness(business, jwt);
} else {
result = await createBusiness(business, jwt);
}
setState(() {
_isLoading = false;
});
if (result != null) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
width: 400,
behavior: SnackBarBehavior.floating,
content: Text(result)));
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const MainApp()));
}
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Check field inputs!'),
width: 200,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
),
);
}
},
),
body: ListView(
children: [
Center(
child: SizedBox(
width: 1000,
child: Column(
children: [
ListTile(
title: Text(business.name,
textAlign: TextAlign.left,
style: const TextStyle(
fontSize: 24, fontWeight: FontWeight.bold)),
subtitle: Text(
business.description,
textAlign: TextAlign.left,
),
leading: ClipRRect(
borderRadius: BorderRadius.circular(6.0),
child: Image.network(
width: 48,
height: 48,
'https://logo.clearbit.com/${business.website}',
errorBuilder: (BuildContext context,
Object exception, StackTrace? stackTrace) {
return getIconFromJobType(
widget.clickFromType ?? JobType.other,
48,
Theme.of(context).colorScheme.onBackground);
}),
),
),
Card(
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0),
child: TextFormField(
controller: _nameController,
autovalidateMode:
AutovalidateMode.onUserInteraction,
maxLength: 30,
onChanged: (inputName) {
setState(() {
business.name = inputName;
});
},
onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).unfocus();
},
decoration: const InputDecoration(
labelText: 'Business Name (required)',
),
validator: (value) {
if (value != null && value.isEmpty) {
return 'Name is required';
}
return null;
},
),
),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0, bottom: 8.0),
child: TextFormField(
controller: _websiteController,
autovalidateMode:
AutovalidateMode.onUserInteraction,
keyboardType: TextInputType.url,
onChanged: (inputUrl) {
setState(() {
business.website = Uri.encodeFull(inputUrl
.toLowerCase()
.replaceAll('https://', '')
.replaceAll('http://', '')
.replaceAll('www.', ''));
});
},
onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).unfocus();
},
decoration: const InputDecoration(
labelText: 'Website (required)',
),
validator: (value) {
if (value != null && value.isEmpty) {
return 'Website is required';
}
return null;
},
),
),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0),
child: TextFormField(
controller: _descriptionController,
autovalidateMode:
AutovalidateMode.onUserInteraction,
maxLength: 500,
maxLines: null,
onChanged: (inputDesc) {
setState(() {
business.description = inputDesc;
});
},
onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).unfocus();
},
decoration: const InputDecoration(
labelText:
'Business Description (required)',
),
validator: (value) {
if (value != null && value.isEmpty) {
return 'Description is required';
}
return null;
},
),
),
// Padding(
// padding: const EdgeInsets.only(
// left: 8.0, right: 8.0, bottom: 16.0),
// child: Row(
// children: [
// ElevatedButton(
// style: ButtonStyle(
// backgroundColor:
// MaterialStateProperty.all(
// Theme.of(context)
// .colorScheme
// .background)),
// child: const Row(
// children: [
// Icon(Icons.search),
// Text('Search For Location'),
// ],
// ),
// onPressed: () {},
// ),
// const Padding(
// padding: EdgeInsets.only(
// left: 32.0, right: 32.0),
// child: Text(
// 'OR',
// style: TextStyle(fontSize: 24),
// ),
// ),
// Expanded(
// child: Column(
// children: [
// TextFormField(
// controller: _locationNameController,
// onChanged: (inputName) {
// setState(() {
// business.locationName =
// inputName;
// });
// },
// onTapOutside:
// (PointerDownEvent event) {
// FocusScope.of(context).unfocus();
// },
// decoration: const InputDecoration(
// labelText:
// 'Location Name (optional)',
// ),
// ),
// TextFormField(
// controller:
// _locationAddressController,
// onChanged: (inputAddr) {
// setState(() {
// business.locationAddress =
// inputAddr;
// });
// },
// onTapOutside:
// (PointerDownEvent event) {
// FocusScope.of(context).unfocus();
// },
// decoration: const InputDecoration(
// labelText:
// 'Location Address (optional)',
// ),
// ),
// ],
// ),
// ),
// ],
// ),
// ),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0, bottom: 8.0),
child: TextFormField(
controller: _locationNameController,
onChanged: (inputName) {
setState(() {
business.locationName = inputName;
});
},
onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).unfocus();
},
decoration: const InputDecoration(
labelText: 'Location Name',
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0, bottom: 16.0),
child: TextFormField(
controller: _locationAddressController,
onChanged: (inputAddr) {
setState(() {
business.locationAddress = inputAddr;
});
},
onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).unfocus();
},
decoration: const InputDecoration(
labelText: 'Location Address',
),
),
),
// Business Type Dropdown
// Padding(
// padding: const EdgeInsets.only(
// left: 8.0, right: 8.0, bottom: 8.0),
// child: Row(
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// const Text('Type of Business',
// style: TextStyle(fontSize: 16)),
// DropdownMenu<BusinessType>(
// initialSelection: business.type,
// controller: businessTypeController,
// label: const Text('Business Type'),
// dropdownMenuEntries: const [
// DropdownMenuEntry(
// value: BusinessType.food,
// label: 'Food Related'),
// DropdownMenuEntry(
// value: BusinessType.shop,
// label: 'Shop'),
// DropdownMenuEntry(
// value: BusinessType.outdoors,
// label: 'Outdoors'),
// DropdownMenuEntry(
// value: BusinessType.manufacturing,
// label: 'Manufacturing'),
// DropdownMenuEntry(
// value: BusinessType.entertainment,
// label: 'Entertainment'),
// DropdownMenuEntry(
// value: BusinessType.other,
// label: 'Other'),
// ],
// onSelected: (inputType) {
// business.type = inputType!;
// },
// ),
// ],
// ),
// ),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0, bottom: 8.0),
child: TextFormField(
controller: _contactNameController,
onSaved: (inputText) {
business.contactName = inputText!;
},
onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).unfocus();
},
decoration: const InputDecoration(
labelText: 'Contact Information Name',
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0, bottom: 8.0),
child: TextFormField(
controller: _contactPhoneController,
inputFormatters: [PhoneFormatter()],
keyboardType: TextInputType.phone,
onSaved: (inputText) {
business.contactPhone = inputText!;
},
onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).unfocus();
},
decoration: const InputDecoration(
labelText: 'Contact Phone # (optional)',
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0, bottom: 8.0),
child: TextFormField(
controller: _contactEmailController,
keyboardType: TextInputType.emailAddress,
onSaved: (inputText) {
business.contactEmail = inputText!;
},
onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).unfocus();
},
decoration: const InputDecoration(
labelText: 'Contact Email',
),
validator: (value) {
if (value != null) {
if (value.isEmpty) {
return null;
} else if (!RegExp(
r'^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
.hasMatch(value)) {
return 'Enter a valid Email';
} else if (value.characters.length > 50) {
return 'Contact Email cannot be longer than 50 characters';
}
}
return null;
},
),
),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0, bottom: 8.0),
child: TextFormField(
controller: _notesController,
maxLength: 300,
maxLines: null,
onSaved: (inputText) {
business.notes = inputText!;
},
onTapOutside: (PointerDownEvent event) {
FocusScope.of(context).unfocus();
},
decoration: const InputDecoration(
labelText: 'Other Notes',
),
),
),
],
),
),
SizedBox(
height: 75,
)
],
),
),
),
],
),
)),
);
}
void _handlePop(bool didPop) {
if (!didPop) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
width: 400,
behavior: SnackBarBehavior.floating,
content: Text('Please wait for it to save.'),
),
);
}
}
}
class PhoneFormatter extends TextInputFormatter {
String phoneFormat(value) {
String input = value.replaceAll(RegExp(r'[\D]'), '');
String phoneFormatted = input.isNotEmpty
? '(${input.substring(0, input.length >= 3 ? 3 : null)}${input.length >= 4 ? ') ' : ''}${input.length > 3 ? input.substring(3, input.length >= 5 ? 6 : null) + (input.length >= 7 ? '-${input.substring(6, input.length >= 10 ? 10 : null)}' : '') : ''}'
: input;
return phoneFormatted;
}
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
String text = newValue.text;
if (newValue.selection.baseOffset == 0) {
return newValue;
}
return newValue.copyWith(
text: phoneFormat(text),
selection: TextSelection.collapsed(offset: phoneFormat(text).length));
}
}