rluv_client/lib/features/budget/widgets/add_transaction_dialog.dart

319 lines
14 KiB
Dart
Raw Normal View History

2023-07-19 02:16:13 -06:00
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
2023-07-22 21:29:32 -06:00
import 'package:helpers/helpers/misc_build/build_media.dart';
2023-07-27 01:40:26 -06:00
import 'package:rluv/global/utils.dart';
2023-07-19 02:16:13 -06:00
import '../../../global/api.dart';
import '../../../global/store.dart';
import '../../../global/styles.dart';
2023-07-27 01:40:26 -06:00
import '../../../global/widgets/ui_button.dart';
2023-07-19 02:16:13 -06:00
import '../../../models/budget_category_model.dart';
import '../../../models/transaction_model.dart';
class AddTransactionDialog extends ConsumerStatefulWidget {
2023-07-22 21:29:32 -06:00
const AddTransactionDialog({super.key, this.transaction});
final Transaction? transaction;
2023-07-19 02:16:13 -06:00
@override
ConsumerState<AddTransactionDialog> createState() =>
_AddTransactionDialogState();
}
class _AddTransactionDialogState extends ConsumerState<AddTransactionDialog> {
2023-07-27 01:40:26 -06:00
late DateTime selectedDate;
2023-07-22 21:29:32 -06:00
late final TextEditingController amountController;
late final TextEditingController memoController;
final amountFocusNode = FocusNode();
final memoFocusNode = FocusNode();
TransactionType transactionType = TransactionType.expense;
late BudgetCategory selectedBudgetCategory;
@override
void initState() {
if (widget.transaction != null) {
amountController =
TextEditingController(text: widget.transaction!.amount.toString());
memoController = TextEditingController(text: widget.transaction!.memo);
transactionType = widget.transaction!.type;
2023-07-27 01:40:26 -06:00
selectedDate = widget.transaction!.date;
2023-07-22 21:29:32 -06:00
} else {
amountController = TextEditingController();
memoController = TextEditingController();
2023-07-27 01:40:26 -06:00
selectedDate = DateTime.now();
2023-07-22 21:29:32 -06:00
}
2023-07-27 01:40:26 -06:00
final categories = ref.read(budgetCategoriesProvider);
2023-07-22 21:29:32 -06:00
if (categories.isNotEmpty) {
selectedBudgetCategory = categories.first;
}
super.initState();
}
2023-07-19 02:16:13 -06:00
@override
Widget build(BuildContext context) {
2023-07-22 21:29:32 -06:00
final List<BudgetCategory> budgetCategories =
2023-07-27 01:40:26 -06:00
ref.read(budgetCategoriesProvider);
2023-07-22 21:29:32 -06:00
return SizedBox(
width: BuildMedia(context).width * Styles.dialogScreenWidthFactor,
child: budgetCategories.isEmpty
? const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Add budget categories to sort your transactions',
textAlign: TextAlign.center,
),
)
: Padding(
padding: const EdgeInsets.all(18.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.transaction == null)
Padding(
padding: const EdgeInsets.only(bottom: 8.0, left: 8.0),
child: Row(children: [
if (budgetCategories.isNotEmpty)
InkWell(
onTap: transactionType == TransactionType.expense
? null
: () {
setState(() => transactionType =
TransactionType.expense);
},
child: AnimatedContainer(
height: 38,
width: 80,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8.0),
topRight: Radius.circular(8.0)),
color: transactionType ==
TransactionType.expense
? Styles.lavender
: Styles.washedStone),
duration: const Duration(milliseconds: 300),
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('Expense',
style: TextStyle(fontSize: 16)),
),
),
),
InkWell(
onTap: transactionType == TransactionType.income
? null
: () {
setState(() => transactionType =
TransactionType.income);
},
child: AnimatedContainer(
height: 38,
width: 80,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8.0),
topRight: Radius.circular(8.0)),
color:
transactionType == TransactionType.income
? Styles.lavender
: Styles.washedStone),
duration: const Duration(milliseconds: 300),
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('Income',
style: TextStyle(fontSize: 16)),
),
),
),
]),
2023-07-19 02:16:13 -06:00
),
2023-07-22 21:29:32 -06:00
Row(
children: [
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Amount:',
style: TextStyle(fontSize: 18.0),
),
),
Container(
width: 120,
height: 40,
decoration: Styles.boxLavenderBubble,
child: TextFormField(
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 18.0),
cursorColor: Styles.blushingPink,
decoration: Styles.inputLavenderBubble(),
focusNode: amountFocusNode,
controller: amountController,
onFieldSubmitted: (_) {
memoFocusNode.requestFocus();
},
),
),
],
2023-07-19 02:16:13 -06:00
),
2023-07-22 21:29:32 -06:00
if (budgetCategories.isEmpty)
const Padding(
padding: EdgeInsets.all(18.0),
child: Text(
'Add budget categories to sort your transactions',
textAlign: TextAlign.center,
),
2023-07-19 02:16:13 -06:00
),
2023-07-22 21:29:32 -06:00
if (budgetCategories.isNotEmpty)
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: transactionType == TransactionType.income
? const SizedBox(height: 12.5)
: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Row(
children: [
const Padding(
padding: EdgeInsets.only(right: 28.0),
child: Text(
'Category:',
style: TextStyle(fontSize: 18.0),
),
),
DropdownButton<BudgetCategory>(
dropdownColor: Styles.lavender,
value: selectedBudgetCategory,
items: budgetCategories
.map(
(e) => DropdownMenuItem(
value: e,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 18,
width: 18,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.black,
width: 1.5),
color: e.color,
),
),
const SizedBox(width: 12),
Text(e.name),
],
),
),
)
.toList(),
onChanged: (BudgetCategory? value) {
if (value != null) {
if (kDebugMode) {
print('${value.name} selected');
}
setState(() =>
selectedBudgetCategory = value);
}
},
),
],
),
),
),
const Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: [
Text(
'Memo',
style: TextStyle(fontSize: 18.0),
2023-07-19 02:16:13 -06:00
),
2023-07-22 21:29:32 -06:00
],
2023-07-19 02:16:13 -06:00
),
),
2023-07-22 21:29:32 -06:00
Container(
width: BuildMedia(context).width * 0.65,
height: 100,
decoration: Styles.boxLavenderBubble,
child: TextFormField(
style: const TextStyle(fontSize: 18.0),
maxLines: 4,
focusNode: memoFocusNode,
textAlign: TextAlign.left,
cursorColor: Styles.blushingPink,
controller: memoController,
decoration: Styles.inputLavenderBubble(),
onFieldSubmitted: (_) {},
),
2023-07-19 02:16:13 -06:00
),
2023-07-27 01:40:26 -06:00
UiButton(
showLoading: true,
text: 'ADD',
color: Styles.lavender,
onPressed: () => submitTransaction().then((_) {
Navigator.pop(context);
showSnack(
ref: ref,
text: widget.transaction != null
? 'Transaction updated!'
: 'Transaction added!',
type: SnackType.success,
);
}),
2023-07-19 02:16:13 -06:00
),
],
),
2023-07-22 21:29:32 -06:00
));
}
Future submitTransaction() async {
Map<String, dynamic>? data;
if (widget.transaction != null) {
2023-07-27 01:40:26 -06:00
data = await ref.read(apiProvider.notifier).put(
2023-07-22 21:29:32 -06:00
path: 'transactions',
data: Transaction.copyWith(widget.transaction!, {
'memo': memoController.text.isNotEmpty ? memoController.text : null,
'amount': double.parse(amountController.text),
'budget_category_id': transactionType == TransactionType.income
? null
: selectedBudgetCategory.id,
}).toJson());
} else {
2023-07-27 01:40:26 -06:00
data = await ref.read(apiProvider.notifier).post(
2023-07-22 21:29:32 -06:00
path: 'transactions',
data: Transaction(
amount: double.parse(amountController.text),
addedByUserId: 1,
budgetCategoryId: transactionType == TransactionType.income
? null
: selectedBudgetCategory.id,
budgetId: 1,
date: DateTime.now(),
type: transactionType,
memo: memoController.text.isNotEmpty
? memoController.text
: null)
.toJson());
}
final success = data != null ? data['success'] as bool : false;
if (success) {
if (widget.transaction != null) {
2023-07-27 01:40:26 -06:00
ref.read(dashboardProvider.notifier).update({'transactions': data});
2023-07-22 21:29:32 -06:00
} else {
2023-07-27 01:40:26 -06:00
ref.read(dashboardProvider.notifier).add({'transactions': data});
2023-07-22 21:29:32 -06:00
}
} else {
2023-07-27 01:40:26 -06:00
showSnack(
ref: ref,
text: widget.transaction != null
2023-07-22 21:29:32 -06:00
? 'Failed to edit transaction'
2023-07-27 01:40:26 -06:00
: 'Failed to add transaction',
type: SnackType.error);
2023-07-22 21:29:32 -06:00
}
2023-07-19 02:16:13 -06:00
}
}