Updates from idk when...
This commit is contained in:
@@ -11,16 +11,18 @@ import '../../../global/store.dart';
|
||||
import '../../../global/utils.dart';
|
||||
import '../../../global/widgets/ui_button.dart';
|
||||
|
||||
class AddBudgetCategoryDialog extends ConsumerStatefulWidget {
|
||||
const AddBudgetCategoryDialog({super.key});
|
||||
class BudgetCategoryDialog extends ConsumerStatefulWidget {
|
||||
const BudgetCategoryDialog({super.key, this.category});
|
||||
|
||||
final BudgetCategory? category;
|
||||
|
||||
@override
|
||||
ConsumerState<AddBudgetCategoryDialog> createState() =>
|
||||
ConsumerState<BudgetCategoryDialog> createState() =>
|
||||
_AddBudgetCategoryDialogState();
|
||||
}
|
||||
|
||||
class _AddBudgetCategoryDialogState
|
||||
extends ConsumerState<AddBudgetCategoryDialog> {
|
||||
extends ConsumerState<BudgetCategoryDialog> {
|
||||
late final Budget? budget;
|
||||
final categoryNameController = TextEditingController();
|
||||
final amountController = TextEditingController();
|
||||
@@ -32,12 +34,20 @@ class _AddBudgetCategoryDialogState
|
||||
int selectedColorIndex = -1;
|
||||
|
||||
final formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
budget = ref.read(budgetProvider);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
categoryFocusNode.requestFocus();
|
||||
});
|
||||
|
||||
if (widget.category != null) {
|
||||
categoryNameController.text = widget.category!.name;
|
||||
amountController.text = widget.category!.amount.toString();
|
||||
selectedColorIndex = colors.indexOf(widget.category!.color);
|
||||
}
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@@ -66,22 +76,25 @@ class _AddBudgetCategoryDialogState
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(bottom: 18.0),
|
||||
child: Text('Add Category:'),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 18.0),
|
||||
child: Text(widget.category == null
|
||||
? 'Add Category:'
|
||||
: 'Edit Category'),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
const Text('Name:'),
|
||||
const SizedBox(width: 30),
|
||||
Container(
|
||||
width: 120,
|
||||
height: 30,
|
||||
width: 150,
|
||||
height: 40,
|
||||
decoration: Styles.boxLavenderBubble,
|
||||
child: TextFormField(
|
||||
validator: (text) {
|
||||
if (text == null || text.length < 3) {
|
||||
return 'Invalid Category';
|
||||
if (text == null || text.isEmpty) {
|
||||
return 'Cannot be blank';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -99,12 +112,13 @@ class _AddBudgetCategoryDialogState
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
const Text('Amount:'),
|
||||
const SizedBox(width: 30),
|
||||
Container(
|
||||
width: 80,
|
||||
height: 30,
|
||||
width: 150,
|
||||
height: 40,
|
||||
decoration: Styles.boxLavenderBubble,
|
||||
child: TextFormField(
|
||||
validator: (text) {
|
||||
@@ -205,19 +219,53 @@ class _AddBudgetCategoryDialogState
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.category != null && widget.category?.id != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16.0),
|
||||
child: UiButton(
|
||||
showLoading: true,
|
||||
color: Styles.expensesRed,
|
||||
text: 'DELETE',
|
||||
onPressed: () {
|
||||
if (formKey.currentState != null &&
|
||||
formKey.currentState!.validate()) {
|
||||
removeCategory().then((success) {
|
||||
Navigator.pop(context);
|
||||
if (success) {
|
||||
showSnack(
|
||||
ref: ref,
|
||||
text: 'Budget Category Removed',
|
||||
type: SnackType.success,
|
||||
);
|
||||
} else {
|
||||
showSnack(
|
||||
ref: ref,
|
||||
text: 'Unable to Remove Budget Category',
|
||||
type: SnackType.error,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
UiButton(
|
||||
showLoading: true,
|
||||
color: Styles.lavender,
|
||||
text: 'SAVE',
|
||||
onPressed: () =>
|
||||
onPressed: () {
|
||||
if (formKey.currentState != null &&
|
||||
formKey.currentState!.validate()) {
|
||||
submitCategory(colors[selectedColorIndex]).then((_) {
|
||||
Navigator.pop(context);
|
||||
showSnack(
|
||||
ref: ref,
|
||||
text: 'Budget Category Added!',
|
||||
type: SnackType.success,
|
||||
);
|
||||
}),
|
||||
Navigator.pop(context);
|
||||
showSnack(
|
||||
ref: ref,
|
||||
text: 'Budget Category Added!',
|
||||
type: SnackType.success,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -237,24 +285,70 @@ class _AddBudgetCategoryDialogState
|
||||
printPink('Failed validation');
|
||||
return;
|
||||
}
|
||||
final newBudget = BudgetCategory(
|
||||
id: null,
|
||||
amount: double.parse(amountController.text),
|
||||
budgetId: budget!.id!,
|
||||
color: categoryColor,
|
||||
name: categoryNameController.text,
|
||||
);
|
||||
Map<String, dynamic>? budgetData;
|
||||
bool success = false;
|
||||
if (widget.category == null) {
|
||||
final newBudget = BudgetCategory(
|
||||
id: null,
|
||||
amount: double.parse(amountController.text),
|
||||
budgetId: budget!.id!,
|
||||
color: categoryColor,
|
||||
name: categoryNameController.text,
|
||||
);
|
||||
|
||||
final budgetData = await ref
|
||||
budgetData = await ref
|
||||
.read(apiProvider.notifier)
|
||||
.post(path: 'budget_category', data: newBudget.toJson());
|
||||
success = budgetData != null ? budgetData['success'] as bool : false;
|
||||
if (success) {
|
||||
ref
|
||||
.read(dashboardProvider.notifier)
|
||||
.add({'budget_categories': budgetData});
|
||||
}
|
||||
} else {
|
||||
final newBudget =
|
||||
BudgetCategory.copyWith(category: widget.category!, data: {
|
||||
'amount': double.parse(amountController.text),
|
||||
'color': categoryColor,
|
||||
'name': categoryNameController.text
|
||||
});
|
||||
budgetData = await ref
|
||||
.read(apiProvider.notifier)
|
||||
.put(path: 'budget_category', data: newBudget.toJson());
|
||||
success = budgetData != null ? budgetData['success'] as bool : false;
|
||||
if (success) {
|
||||
ref
|
||||
.read(dashboardProvider.notifier)
|
||||
.update({'budget_categories': budgetData});
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
showSnack(
|
||||
ref: ref,
|
||||
text: widget.category == null
|
||||
? 'Added budget category!'
|
||||
: 'Updated category!',
|
||||
type: SnackType.error);
|
||||
} else {
|
||||
showSnack(
|
||||
ref: ref,
|
||||
text: widget.category == null
|
||||
? 'Could not add budget category'
|
||||
: 'Could not update category',
|
||||
type: SnackType.error);
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> removeCategory() async {
|
||||
final res = await ref
|
||||
.read(apiProvider.notifier)
|
||||
.post(path: 'budget_category', data: newBudget.toJson());
|
||||
final success = budgetData != null ? budgetData['success'] as bool : false;
|
||||
.delete(path: 'budget_category', data: {'id': widget.category!.id});
|
||||
final success = res != null ? res['success'] as bool : false;
|
||||
if (success) {
|
||||
ref
|
||||
.read(dashboardProvider.notifier)
|
||||
.add({'budget_categories': budgetData});
|
||||
} else {
|
||||
showSnack(ref: ref, text: 'Could not add budget', type: SnackType.error);
|
||||
.removeWithId('budget_categories', widget.category!.id!);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,21 +10,23 @@ import '../../../global/styles.dart';
|
||||
import '../../../global/widgets/ui_button.dart';
|
||||
import '../../../models/budget_category_model.dart';
|
||||
import '../../../models/transaction_model.dart';
|
||||
import '../../../models/user.dart';
|
||||
|
||||
class AddTransactionDialog extends ConsumerStatefulWidget {
|
||||
const AddTransactionDialog({super.key, this.transaction});
|
||||
class TransactionDialog extends ConsumerStatefulWidget {
|
||||
const TransactionDialog({super.key, this.transaction});
|
||||
|
||||
final Transaction? transaction;
|
||||
|
||||
@override
|
||||
ConsumerState<AddTransactionDialog> createState() =>
|
||||
ConsumerState<TransactionDialog> createState() =>
|
||||
_AddTransactionDialogState();
|
||||
}
|
||||
|
||||
class _AddTransactionDialogState extends ConsumerState<AddTransactionDialog> {
|
||||
class _AddTransactionDialogState extends ConsumerState<TransactionDialog> {
|
||||
late DateTime selectedDate;
|
||||
late final TextEditingController amountController;
|
||||
late final TextEditingController memoController;
|
||||
User? user;
|
||||
|
||||
final amountFocusNode = FocusNode();
|
||||
final memoFocusNode = FocusNode();
|
||||
@@ -49,11 +51,20 @@ class _AddTransactionDialogState extends ConsumerState<AddTransactionDialog> {
|
||||
if (categories.isNotEmpty) {
|
||||
selectedBudgetCategory = categories.first;
|
||||
}
|
||||
final u = ref.read(userProvider);
|
||||
if (u == null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => ref.read(jwtProvider.notifier).revokeToken());
|
||||
} else {
|
||||
user = u;
|
||||
}
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (user == null) return Container();
|
||||
final List<BudgetCategory> budgetCategories =
|
||||
ref.read(budgetCategoriesProvider);
|
||||
return SizedBox(
|
||||
@@ -274,7 +285,7 @@ class _AddTransactionDialogState extends ConsumerState<AddTransactionDialog> {
|
||||
Map<String, dynamic>? data;
|
||||
if (widget.transaction != null) {
|
||||
data = await ref.read(apiProvider.notifier).put(
|
||||
path: 'transactions',
|
||||
path: 'transaction',
|
||||
data: Transaction.copyWith(widget.transaction!, {
|
||||
'memo': memoController.text.isNotEmpty ? memoController.text : null,
|
||||
'amount': double.parse(amountController.text),
|
||||
@@ -284,14 +295,14 @@ class _AddTransactionDialogState extends ConsumerState<AddTransactionDialog> {
|
||||
}).toJson());
|
||||
} else {
|
||||
data = await ref.read(apiProvider.notifier).post(
|
||||
path: 'transactions',
|
||||
path: 'transaction',
|
||||
data: Transaction(
|
||||
amount: double.parse(amountController.text),
|
||||
addedByUserId: 1,
|
||||
createdByUserId: user!.id!,
|
||||
budgetCategoryId: transactionType == TransactionType.income
|
||||
? null
|
||||
: selectedBudgetCategory.id,
|
||||
budgetId: 1,
|
||||
budgetId: user!.budgetId,
|
||||
date: DateTime.now(),
|
||||
type: transactionType,
|
||||
memo: memoController.text.isNotEmpty
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:helpers/helpers/print.dart';
|
||||
import 'package:rluv/features/budget/widgets/add_budget_category_dialog.dart';
|
||||
import 'package:rluv/global/utils.dart';
|
||||
import 'package:rluv/models/budget_category_model.dart';
|
||||
|
||||
@@ -27,18 +28,22 @@ class BudgetCategoryBar extends StatefulWidget {
|
||||
|
||||
class _BudgetCategoryBarState extends State<BudgetCategoryBar> {
|
||||
double percentSpent = 0.0;
|
||||
double setTo = 0.0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
Future.delayed(Duration(milliseconds: min(1600, 200 * widget.index)), () {
|
||||
setState(() =>
|
||||
percentSpent = (widget.currentAmount / widget.budgetCategory.amount));
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Future.delayed(Duration(milliseconds: min(1600, 200 * widget.index)), () {
|
||||
final valToSetTo = widget.currentAmount / widget.budgetCategory.amount;
|
||||
if (valToSetTo != setTo) {
|
||||
setTo = valToSetTo;
|
||||
setState(() => percentSpent = valToSetTo);
|
||||
}
|
||||
});
|
||||
final innerHeight = widget.height - widget.innerPadding * 2;
|
||||
final isBright =
|
||||
getBrightness(widget.budgetCategory.color) == Brightness.light;
|
||||
@@ -50,85 +55,95 @@ class _BudgetCategoryBarState extends State<BudgetCategoryBar> {
|
||||
: isBright
|
||||
? Colors.black87
|
||||
: Colors.white);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SizedBox(
|
||||
width: 90,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
formatBudgetName(widget.budgetCategory.name),
|
||||
style: const TextStyle(fontSize: 18.0),
|
||||
return InkWell(
|
||||
onLongPress: () async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => Dialog(
|
||||
shape: Styles.dialogShape,
|
||||
backgroundColor: Styles.dialogColor,
|
||||
child: BudgetCategoryDialog(category: widget.budgetCategory)));
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SizedBox(
|
||||
width: 90,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
formatBudgetName(widget.budgetCategory.name),
|
||||
style: const TextStyle(fontSize: 18.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 18.0),
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: widget.height,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black,
|
||||
borderRadius: BorderRadius.circular(13.0),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(widget.innerPadding),
|
||||
child: Container(
|
||||
height: innerHeight,
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 18.0),
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: widget.height,
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.emptyBarGrey,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
color: Colors.black,
|
||||
borderRadius: BorderRadius.circular(13.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(widget.innerPadding),
|
||||
child: SizedBox(
|
||||
height: innerHeight,
|
||||
child: AnimatedFractionallySizedBox(
|
||||
curve: Curves.easeOutSine,
|
||||
heightFactor: 1.0,
|
||||
widthFactor: min(1.0, max(0.08, percentSpent)),
|
||||
duration: const Duration(milliseconds: 350),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: widget.budgetCategory.color,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(widget.innerPadding),
|
||||
child: Container(
|
||||
height: innerHeight,
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.emptyBarGrey,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(widget.innerPadding),
|
||||
child: SizedBox(
|
||||
height: innerHeight,
|
||||
child: AnimatedFractionallySizedBox(
|
||||
curve: Curves.easeOutSine,
|
||||
heightFactor: 1.0,
|
||||
widthFactor: min(1.0, max(0.08, percentSpent)),
|
||||
duration: const Duration(milliseconds: 350),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: widget.budgetCategory.color,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: widget.height,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Text(
|
||||
'${widget.currentAmount.currency()} / ${widget.budgetCategory.amount.currency()}',
|
||||
style: textStyle),
|
||||
SizedBox(
|
||||
height: widget.height,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Text(
|
||||
'${widget.currentAmount.currency()} / ${widget.budgetCategory.amount.currency()}',
|
||||
style: textStyle),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,15 @@ import 'package:rluv/global/styles.dart';
|
||||
import 'package:rluv/global/utils.dart';
|
||||
|
||||
class BudgetNetBar extends StatelessWidget {
|
||||
const BudgetNetBar({super.key, required this.isPositive, required this.net});
|
||||
const BudgetNetBar(
|
||||
{super.key,
|
||||
required this.isPositive,
|
||||
required this.net,
|
||||
required this.expected});
|
||||
|
||||
final bool isPositive;
|
||||
final double net;
|
||||
final double expected;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -29,7 +34,7 @@ class BudgetNetBar extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
net.currency(),
|
||||
'${net.currency()} / ${expected.currency()}',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: isPositive ? Styles.incomeGreen : Styles.expensesRed),
|
||||
|
||||
@@ -2,7 +2,9 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:helpers/helpers/misc_build/build_media.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:rluv/features/budget/screens/transactions_listview.dart';
|
||||
import 'package:rluv/features/budget/widgets/add_transaction_dialog.dart';
|
||||
import 'package:rluv/global/api.dart';
|
||||
import 'package:rluv/global/utils.dart';
|
||||
import 'package:rluv/models/transaction_model.dart';
|
||||
|
||||
@@ -26,7 +28,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
|
||||
double cardHeight = 70.0;
|
||||
|
||||
BudgetCategory? budgetCategory;
|
||||
late final Transaction transaction;
|
||||
Transaction? transaction;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -35,12 +37,16 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final transaction = ref.watch(transactionsProvider)[widget.index];
|
||||
transaction =
|
||||
ref.watch(transactionHistoryListProvider).elementAtOrNull(widget.index);
|
||||
if (transaction == null) return Container();
|
||||
final budgetCategories = ref.read(budgetCategoriesProvider);
|
||||
if (transaction.type == TransactionType.expense) {
|
||||
if (transaction!.type == TransactionType.expense) {
|
||||
budgetCategory = budgetCategories.singleWhere(
|
||||
(category) => category.id == transaction.budgetCategoryId,
|
||||
(category) => category.id == transaction!.budgetCategoryId,
|
||||
);
|
||||
} else {
|
||||
budgetCategory = null;
|
||||
}
|
||||
return GestureDetector(
|
||||
onTap: () => toggleDetails(),
|
||||
@@ -67,7 +73,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
|
||||
duration: const Duration(milliseconds: 200),
|
||||
height: cardHeight,
|
||||
width: 6,
|
||||
color: transaction.type == TransactionType.income
|
||||
color: transaction!.type == TransactionType.income
|
||||
? Styles.incomeBlue
|
||||
: Styles.expensesOrange),
|
||||
SizedBox(
|
||||
@@ -79,7 +85,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(DateFormat('EEE MMM d, h:mm a')
|
||||
.format(transaction.date)),
|
||||
.format(transaction!.date)),
|
||||
Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
@@ -94,7 +100,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
|
||||
),
|
||||
],
|
||||
Text(
|
||||
transaction.type == TransactionType.income
|
||||
transaction!.type == TransactionType.income
|
||||
? 'Income'
|
||||
: budgetCategory!.name,
|
||||
style: const TextStyle(fontSize: 20),
|
||||
@@ -103,7 +109,7 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
|
||||
),
|
||||
if (showDetails)
|
||||
Text(
|
||||
transaction.memo ?? '',
|
||||
transaction!.memo ?? '',
|
||||
style: const TextStyle(fontSize: 16),
|
||||
)
|
||||
],
|
||||
@@ -115,14 +121,14 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Text(
|
||||
transaction.amount.currency(),
|
||||
transaction!.amount.currency(),
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: transaction.type == TransactionType.income
|
||||
color: transaction!.type == TransactionType.income
|
||||
? Styles.incomeGreen
|
||||
: Styles.expensesRed),
|
||||
),
|
||||
if (showDetails)
|
||||
if (showDetails) ...[
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.edit_rounded,
|
||||
@@ -133,12 +139,20 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
|
||||
builder: (context) => Dialog(
|
||||
backgroundColor: Styles.dialogColor,
|
||||
shape: Styles.dialogShape,
|
||||
child: AddTransactionDialog(
|
||||
transaction: transaction),
|
||||
child:
|
||||
TransactionDialog(transaction: transaction),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.delete,
|
||||
color: Styles.expensesRed,
|
||||
),
|
||||
onPressed: () => deleteTransaction(),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
@@ -165,4 +179,23 @@ class _TransactionListItemState extends ConsumerState<TransactionListItem> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future deleteTransaction() async {
|
||||
final res = await ref
|
||||
.read(apiProvider.notifier)
|
||||
.delete(path: 'transaction', data: {'id': transaction!.id});
|
||||
|
||||
final success = res != null ? res['success'] as bool : false;
|
||||
if (success) {
|
||||
ref
|
||||
.read(dashboardProvider.notifier)
|
||||
.removeWithId('transactions', transaction!.id!);
|
||||
showSnack(ref: ref, text: 'Transaction removed', type: SnackType.success);
|
||||
} else {
|
||||
showSnack(
|
||||
ref: ref,
|
||||
text: 'Could not delete transaction',
|
||||
type: SnackType.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user