init
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../models/models.dart';
|
||||
import '../services/auth_controller.dart';
|
||||
import '../ui/feedback.dart';
|
||||
|
||||
class EventFormScreen extends StatefulWidget {
|
||||
const EventFormScreen({super.key});
|
||||
|
||||
@override
|
||||
State<EventFormScreen> createState() => _EventFormScreenState();
|
||||
}
|
||||
|
||||
class _EventFormScreenState extends State<EventFormScreen> {
|
||||
final _title = TextEditingController();
|
||||
final _description = TextEditingController();
|
||||
final _expense = TextEditingController();
|
||||
final _urls = TextEditingController();
|
||||
String _planType = 'general';
|
||||
int _month = DateTime.now().month;
|
||||
int _year = DateTime.now().year;
|
||||
String? _dealerId;
|
||||
List<Dealer> _dealers = [];
|
||||
bool _loading = true;
|
||||
bool _saving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_prepare();
|
||||
}
|
||||
|
||||
Future<void> _prepare() async {
|
||||
final user = context.read<AuthController>().user;
|
||||
if (user?.role == 'dealer') {
|
||||
setState(() {
|
||||
_dealerId = user?.dealerId;
|
||||
_loading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final dealers = await context.read<AuthController>().api.dealers();
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_dealers = dealers;
|
||||
if (dealers.length == 1) _dealerId = dealers.first.id;
|
||||
_loading = false;
|
||||
});
|
||||
} catch (error) {
|
||||
if (!mounted) return;
|
||||
setState(() => _loading = false);
|
||||
showError(context, error);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_title.dispose();
|
||||
_description.dispose();
|
||||
_expense.dispose();
|
||||
_urls.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _save() async {
|
||||
final expense = double.tryParse(_expense.text.trim());
|
||||
if (_dealerId == null || expense == null) {
|
||||
showError(context, 'Dealer and a numeric expense are required');
|
||||
return;
|
||||
}
|
||||
final urls = _urls.text
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.where((line) => line.isNotEmpty)
|
||||
.toList();
|
||||
setState(() => _saving = true);
|
||||
try {
|
||||
await context.read<AuthController>().api.createEvent({
|
||||
'dealerId': _dealerId,
|
||||
'planType': _planType,
|
||||
'title': _title.text.trim(),
|
||||
'description': _description.text.trim(),
|
||||
'expense': expense,
|
||||
'imageUrls': urls,
|
||||
if (_planType == 'monthlySpecial') 'month': _month,
|
||||
if (_planType == 'monthlySpecial') 'year': _year,
|
||||
});
|
||||
if (mounted) Navigator.pop(context, true);
|
||||
} catch (error) {
|
||||
if (mounted) showError(context, error);
|
||||
} finally {
|
||||
if (mounted) setState(() => _saving = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_loading) {
|
||||
return const Scaffold(body: Center(child: CircularProgressIndicator()));
|
||||
}
|
||||
final isDealer = context.watch<AuthController>().user?.role == 'dealer';
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('New plan')),
|
||||
body: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
SegmentedButton<String>(
|
||||
segments: const [
|
||||
ButtonSegment(value: 'general', label: Text('General')),
|
||||
ButtonSegment(value: 'monthlySpecial', label: Text('Monthly')),
|
||||
],
|
||||
selected: {_planType},
|
||||
onSelectionChanged: (value) => setState(() => _planType = value.first),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(controller: _title, decoration: const InputDecoration(labelText: 'Title')),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _description,
|
||||
minLines: 3,
|
||||
maxLines: 5,
|
||||
decoration: const InputDecoration(labelText: 'Description'),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _expense,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(labelText: 'Expense'),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _urls,
|
||||
minLines: 2,
|
||||
maxLines: 4,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Image URLs',
|
||||
hintText: 'One URL per line',
|
||||
),
|
||||
),
|
||||
if (!isDealer) ...[
|
||||
const SizedBox(height: 12),
|
||||
DropdownButtonFormField<String>(
|
||||
initialValue: _dealerId,
|
||||
decoration: const InputDecoration(labelText: 'Dealer'),
|
||||
items: [
|
||||
for (final dealer in _dealers)
|
||||
DropdownMenuItem(value: dealer.id, child: Text('${dealer.name} (${dealer.code})')),
|
||||
],
|
||||
onChanged: (value) => setState(() => _dealerId = value),
|
||||
),
|
||||
],
|
||||
if (_planType == 'monthlySpecial') ...[
|
||||
const SizedBox(height: 12),
|
||||
DropdownButtonFormField<int>(
|
||||
initialValue: _month,
|
||||
decoration: const InputDecoration(labelText: 'Month'),
|
||||
items: [
|
||||
for (var month = 1; month <= 12; month++)
|
||||
DropdownMenuItem(value: month, child: Text('$month')),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value != null) setState(() => _month = value);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
DropdownButtonFormField<int>(
|
||||
initialValue: _year,
|
||||
decoration: const InputDecoration(labelText: 'Year'),
|
||||
items: [
|
||||
for (var year = DateTime.now().year - 1; year <= DateTime.now().year + 2; year++)
|
||||
DropdownMenuItem(value: year, child: Text('$year')),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value != null) setState(() => _year = value);
|
||||
},
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
FilledButton(
|
||||
onPressed: _saving ? null : _save,
|
||||
child: Text(_saving ? 'Saving' : 'Save plan'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user