From 18aad2b3d52a1e67fb980050cda164a9953eeb71 Mon Sep 17 00:00:00 2001
From: Nathan Anderson <nathananderson98@gmail.com>
Date: Sat, 22 Jul 2023 21:29:32 -0600
Subject: [PATCH] Added working edit transaction

---
 .../budget/screens/budget_overview.dart       | 474 ++++++++++--------
 .../budget/screens/transactions_listview.dart |  63 +++
 .../widgets/add_budget_category_dialog.dart   | 265 ++++++++++
 .../widgets/add_transaction_dialog.dart       | 441 +++++++++++-----
 .../budget/widgets/budget_category_bar.dart   | 157 ++++++
 .../budget/widgets/budget_net_bar.dart        |   3 +-
 .../budget/widgets/transaction_list_item.dart | 168 +++++++
 lib/features/notes/screens/notes_screen.dart  |  51 ++
 .../settings/screens/settings_screen.dart     |  20 +
 lib/global/api.dart                           | 153 ++++--
 lib/global/store.dart                         | 138 ++++-
 lib/global/styles.dart                        |  58 ++-
 lib/global/utils.dart                         |  61 ++-
 lib/global/widgets/budget_color_circle.dart   |  35 ++
 lib/global/widgets/drawer_button.dart         |  54 ++
 lib/main.dart                                 |  87 +++-
 lib/models/budget.dart                        |   3 +
 lib/models/budget.g.dart                      |   2 +
 lib/models/budget_category_model.dart         |  12 +-
 lib/models/budget_category_model.g.dart       |   4 +
 lib/models/family_model.dart                  |   3 +
 lib/models/family_model.g.dart                |   2 +
 lib/models/shared_note.dart                   |  46 ++
 lib/models/shared_note.g.dart                 |  34 ++
 lib/models/transaction_model.dart             |  35 +-
 lib/models/transaction_model.g.dart           |  15 +-
 lib/models/user.dart                          |   3 +
 lib/models/user.g.dart                        |   2 +
 28 files changed, 1959 insertions(+), 430 deletions(-)
 create mode 100644 lib/features/budget/screens/transactions_listview.dart
 create mode 100644 lib/features/budget/widgets/add_budget_category_dialog.dart
 create mode 100644 lib/features/budget/widgets/transaction_list_item.dart
 create mode 100644 lib/features/notes/screens/notes_screen.dart
 create mode 100644 lib/features/settings/screens/settings_screen.dart
 create mode 100644 lib/global/widgets/budget_color_circle.dart
 create mode 100644 lib/global/widgets/drawer_button.dart
 create mode 100644 lib/models/shared_note.dart
 create mode 100644 lib/models/shared_note.g.dart

diff --git a/lib/features/budget/screens/budget_overview.dart b/lib/features/budget/screens/budget_overview.dart
index 7749807..d02f703 100644
--- a/lib/features/budget/screens/budget_overview.dart
+++ b/lib/features/budget/screens/budget_overview.dart
@@ -1,15 +1,21 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:helpers/helpers.dart';
+import 'package:rluv/features/budget/screens/transactions_listview.dart';
 import 'package:rluv/features/budget/widgets/add_transaction_dialog.dart';
+import 'package:rluv/features/budget/widgets/budget_category_bar.dart';
 import 'package:rluv/features/budget/widgets/budget_net_bar.dart';
 import 'package:rluv/global/styles.dart';
 import 'package:rluv/global/utils.dart';
 
 import '../../../global/store.dart';
+import '../../../models/transaction_model.dart';
+import '../widgets/add_budget_category_dialog.dart';
 
 class BudgetOverviewScreen extends ConsumerStatefulWidget {
-  const BudgetOverviewScreen({super.key});
+  const BudgetOverviewScreen({super.key, required this.initialData});
+
+  final Map<String, dynamic> initialData;
 
   @override
   ConsumerState<BudgetOverviewScreen> createState() =>
@@ -20,234 +26,256 @@ class _BudgetOverviewScreenState extends ConsumerState<BudgetOverviewScreen> {
   final budgetListScrollController = ScrollController();
   @override
   Widget build(BuildContext context) {
-    final budgetCategoriesRef = ref.watch(Store().budgetCategoriesProvider);
+    final budgetCategories = ref.watch(Store().budgetCategoriesProvider);
+    final transactions = ref.watch(Store().transactionsProvider);
     final screen = BuildMedia(context).size;
-    return budgetCategoriesRef.when(
-      data: ((budgetCategories) => RefreshIndicator(
-            onRefresh: () async {
-              final _ = await ref.refresh(Store().dashboardProvider.future);
-            },
+    double netExpense = 0.0;
+    double netIncome = 0.0;
+    Map<int, double> budgetCategoryNetMap = {};
+      netExpense = transactions
+          .where((t) => t.type == TransactionType.expense)
+          .fold(netExpense, (net, t) => net + t.amount);
+      netIncome = transactions
+          .where((t) => t.type == TransactionType.income)
+          .fold(netIncome, (net, t) => net + t.amount);
+      for (final bud in budgetCategories) {
+        double net = 0.0;
+        net = transactions
+            .where((t) => t.budgetCategoryId == bud.id)
+            .fold(net, (net, t) => net + t.amount);
+        budgetCategoryNetMap[bud.id!] = net;
+      }
+    return RefreshIndicator(
+      displacement: 20.0,
+      onRefresh: () async {
+        final family = ref.read(Store().familyProvider).valueOrNull;
+        final _ =
+            ref.read(Store().dashboardProvider.notifier).fetchDashboard(family);
+      },
+      child: Column(
+        children: [
+          /// TOP HALF, TITLE & OVERVIEW
+          Container(
+            height: screen.height * 0.3,
+            width: screen.width,
+            color: Styles.purpleNurple,
             child: Column(
+              crossAxisAlignment: CrossAxisAlignment.center,
               children: [
-                /// TOP HALF, TITLE & OVERVIEW
-                Container(
-                  height: screen.height * 0.33,
-                  width: screen.width,
-                  color: Styles.purpleNurple,
-                  child: Column(
-                    crossAxisAlignment: CrossAxisAlignment.center,
-                    children: [
-                      const Spacer(flex: 2),
-                      Text(
-                        formatDate(DateTime.now()),
-                        style: const TextStyle(
-                            fontSize: 16, color: Styles.electricBlue),
-                      ),
-                      const Spacer(),
-                      const Text('MONTHLY',
-                          style: TextStyle(
-                              fontSize: 42, color: Styles.electricBlue)),
-                      const Spacer(flex: 2),
-                      const BudgetNetBar(isPositive: true, net: 5024.64),
-                      const Spacer(),
-                      const BudgetNetBar(isPositive: false, net: 2004.37),
-                      const Spacer(),
-                    ],
-                  ),
+                const Spacer(flex: 2),
+                Text(
+                  formatDate(DateTime.now()),
+                  style:
+                      const TextStyle(fontSize: 16, color: Styles.electricBlue),
                 ),
-
-                /// BOTTOM HALF, BUDGET BREAKDOWN
-                Expanded(
-                  child: SizedBox(
-                    width: screen.width,
-                    child: Column(
-                      mainAxisSize: MainAxisSize.max,
-                      children: [
-                        Padding(
-                          padding: const EdgeInsets.all(14.0),
-                          child: Container(
-                            decoration: BoxDecoration(
-                              color: Styles.blushingPink,
-                              borderRadius: BorderRadius.circular(16.0),
-                            ),
-                            child: Column(
-                              children: [
-                                const Padding(
-                                  padding: EdgeInsets.all(8.0),
-                                  child: Text(
-                                    'BUDGET',
-                                    style: TextStyle(
-                                        fontSize: 28,
-                                        color: Styles.electricBlue),
-                                  ),
-                                ),
-                                Scrollbar(
-                                  controller: budgetListScrollController,
-                                  thumbVisibility: true,
-                                  child: ListView(
-                                    controller: budgetListScrollController,
-                                    shrinkWrap: true,
-                                    children: [
-                                      for (final budget in budgetCategories)
-                                        Row(
-                                          children: [
-                                            Padding(
-                                              padding:
-                                                  const EdgeInsets.all(8.0),
-                                              child: SizedBox(
-                                                width: 85,
-                                                child: Text(
-                                                  budget.name,
-                                                  style: const TextStyle(
-                                                      fontSize: 16.0),
-                                                ),
-                                              ),
-                                            ),
-                                            AnimatedContainer(
-                                              duration: const Duration(
-                                                  milliseconds: 500),
-                                              child: Expanded(
-                                                  child: Padding(
-                                                padding: const EdgeInsets.only(
-                                                    right: 18.0),
-                                                child: Stack(
-                                                  children: [
-                                                    Container(
-                                                      height: 30,
-                                                      decoration: BoxDecoration(
-                                                        color: Colors.black,
-                                                        borderRadius:
-                                                            BorderRadius
-                                                                .circular(10.0),
-                                                      ),
-                                                    ),
-                                                    Padding(
-                                                      padding:
-                                                          const EdgeInsets.all(
-                                                              2.0),
-                                                      child: Container(
-                                                        height: 26,
-                                                        decoration:
-                                                            BoxDecoration(
-                                                          color: Styles
-                                                              .emptyBarGrey,
-                                                          borderRadius:
-                                                              BorderRadius
-                                                                  .circular(
-                                                                      10.0),
-                                                        ),
-                                                      ),
-                                                    ),
-                                                    Padding(
-                                                      padding:
-                                                          const EdgeInsets.all(
-                                                              2.0),
-                                                      child: SizedBox(
-                                                        height: 26,
-                                                        child:
-                                                            FractionallySizedBox(
-                                                          heightFactor: 1.0,
-                                                          widthFactor: 0.5,
-                                                          child: Container(
-                                                            decoration:
-                                                                BoxDecoration(
-                                                              color:
-                                                                  budget.color,
-                                                              borderRadius:
-                                                                  BorderRadius
-                                                                      .circular(
-                                                                          10.0),
-                                                            ),
-                                                          ),
-                                                        ),
-                                                      ),
-                                                    ),
-                                                  ],
-                                                ),
-                                              )),
-                                            )
-                                          ],
-                                        ),
-                                      const SizedBox(height: 20),
-                                    ],
-                                  ),
-                                ),
-                              ],
-                            ),
-                          ),
-                        ),
-                        const Spacer(),
-                        Padding(
-                          padding: const EdgeInsets.only(bottom: 24.0),
-                          child: Row(
-                            children: [
-                              Expanded(
-                                child: Padding(
-                                  padding: const EdgeInsets.only(
-                                      left: 20.0, right: 15.0),
-                                  child: Container(
-                                    height: 70,
-                                    decoration: BoxDecoration(
-                                      color: Styles.seaweedGreen,
-                                      borderRadius: BorderRadius.circular(15.0),
-                                    ),
-                                    child: InkWell(
-                                      child: const Center(
-                                        child: Padding(
-                                          padding: EdgeInsets.symmetric(
-                                              horizontal: 20.0, vertical: 14.0),
-                                          child: Text(
-                                            'Transaction History',
-                                            textAlign: TextAlign.center,
-                                            style: TextStyle(fontSize: 25),
-                                          ),
-                                        ),
-                                      ),
-                                      onTap: () {
-                                        printRed('FIXME');
-                                      },
-                                    ),
-                                  ),
-                                ),
-                              ),
-                              Padding(
-                                padding: const EdgeInsets.only(right: 20.0),
-                                child: Container(
-                                  decoration: BoxDecoration(
-                                    color: Styles.purpleNurple,
-                                    borderRadius: BorderRadius.circular(40.0),
-                                  ),
-                                  height: 80,
-                                  width: 80,
-                                  child: IconButton(
-                                    icon: const Icon(
-                                      Icons.add,
-                                      size: 48,
-                                      color: Styles.lavender,
-                                    ),
-                                    onPressed: () {
-                                      showDialog(
-                                        context: context,
-                                        builder: (BuildContext context) {
-                                          return const AddTransactionDialog();
-                                        },
-                                      );
-                                    },
-                                  ),
-                                ),
-                              ),
-                            ],
-                          ),
-                        ),
-                      ],
-                    ),
-                  ),
-                )
+                const Spacer(),
+                const Text('MONTHLY',
+                    style: TextStyle(fontSize: 42, color: Styles.electricBlue)),
+                const Spacer(flex: 2),
+                BudgetNetBar(isPositive: true, net: netIncome),
+                const Spacer(),
+                BudgetNetBar(isPositive: false, net: netExpense),
+                const Spacer(),
               ],
             ),
-          )),
-      loading: () => const CircularProgressIndicator(),
-      error: (error, stackTrace) => Text('Error: $error, \n\n$stackTrace'),
+          ),
+
+          /// BOTTOM HALF, BUDGET BREAKDOWN
+          Expanded(
+            child: Container(
+              color: Styles.sunflower,
+              width: screen.width,
+              child: Column(
+                mainAxisSize: MainAxisSize.max,
+                children: [
+                  Padding(
+                    padding: const EdgeInsets.all(14.0),
+                    child: Container(
+                      decoration: BoxDecoration(
+                        color: Styles.blushingPink,
+                        borderRadius: BorderRadius.circular(16.0),
+                      ),
+                      child: Column(
+                        children: [
+                          const Padding(
+                            padding: EdgeInsets.all(8.0),
+                            child: Text(
+                              'BUDGET',
+                              style: TextStyle(
+                                  fontSize: 28, color: Styles.electricBlue),
+                            ),
+                          ),
+                          budgetCategories.isEmpty
+                              ? Padding(
+                                  padding: const EdgeInsets.all(8.0),
+                                  child: SizedBox(
+                                    width: screen.width * 0.8,
+                                    child: Column(
+                                      children: [
+                                        const Padding(
+                                          padding: EdgeInsets.all(8.0),
+                                          child: Text(
+                                              'No budget categories created yet, add some!'),
+                                        ),
+                                        ElevatedButton(
+                                          onPressed: ref.watch(
+                                                      Store().budgetProvider) ==
+                                                  null
+                                              ? null
+                                              : () => showDialog(
+                                                    context: context,
+                                                    builder: (context) => Dialog(
+                                                        shape:
+                                                            Styles.dialogShape,
+                                                        backgroundColor:
+                                                            Styles.dialogColor,
+                                                        child:
+                                                            const AddBudgetCategoryDialog()),
+                                                  ),
+                                          child: const Text('Add Category'),
+                                        ),
+                                      ],
+                                    ),
+                                  ),
+                                )
+                              : Padding(
+                                  padding: const EdgeInsets.symmetric(
+                                      horizontal: 2.0, vertical: 4.0),
+                                  child: SizedBox(
+                                    height: screen.height * 0.36,
+                                    child: Scrollbar(
+                                      controller: budgetListScrollController,
+                                      thumbVisibility: true,
+                                      child: ListView(
+                                        physics: const BouncingScrollPhysics(),
+                                        controller: budgetListScrollController,
+                                        shrinkWrap: true,
+                                        children: [
+                                          ...budgetCategories
+                                              .mapIndexed((i, category) {
+                                            return BudgetCategoryBar(
+                                              budgetCategory: category,
+                                              currentAmount:
+                                                  budgetCategoryNetMap[
+                                                      category.id]!,
+                                              index: i,
+                                            );
+                                          }).toList(),
+                                          const SizedBox(height: 20),
+                                          Row(
+                                            mainAxisAlignment:
+                                                MainAxisAlignment.center,
+                                            children: [
+                                              SizedBox(
+                                                width: 140,
+                                                child: ElevatedButton(
+                                                  onPressed: ref.watch(Store()
+                                                              .budgetProvider) ==
+                                                          null
+                                                      ? null
+                                                      : () => showDialog(
+                                                            context: context,
+                                                            builder: (context) => Dialog(
+                                                                shape: Styles
+                                                                    .dialogShape,
+                                                                backgroundColor:
+                                                                    Styles
+                                                                        .dialogColor,
+                                                                child:
+                                                                    const AddBudgetCategoryDialog()),
+                                                          ),
+                                                  child: const Text(
+                                                      'Add Category'),
+                                                ),
+                                              ),
+                                            ],
+                                          ),
+                                          const SizedBox(height: 20),
+                                        ],
+                                      ),
+                                    ),
+                                  ),
+                                ),
+                        ],
+                      ),
+                    ),
+                  ),
+                  const Spacer(),
+                  Row(
+                    children: [
+                      Expanded(
+                        child: Padding(
+                          padding:
+                              const EdgeInsets.only(left: 20.0, right: 15.0),
+                          child: Container(
+                            height: 70,
+                            decoration: BoxDecoration(
+                              color: Styles.seaweedGreen,
+                              borderRadius: BorderRadius.circular(15.0),
+                            ),
+                            child: InkWell(
+                              child: const Center(
+                                child: Padding(
+                                  padding: EdgeInsets.symmetric(
+                                      horizontal: 20.0, vertical: 14.0),
+                                  child: FittedBox(
+                                    child: Text(
+                                      'Transaction History',
+                                      textAlign: TextAlign.center,
+                                      style: TextStyle(fontSize: 25),
+                                    ),
+                                  ),
+                                ),
+                              ),
+                              onTap: () {
+                                Navigator.push(
+                                    context,
+                                    MaterialPageRoute(
+                                        builder: (context) =>
+                                            const TransactionsListview()));
+                              },
+                            ),
+                          ),
+                        ),
+                      ),
+                      Padding(
+                        padding: const EdgeInsets.only(right: 20.0),
+                        child: Container(
+                          decoration: BoxDecoration(
+                            color: Styles.purpleNurple,
+                            borderRadius: BorderRadius.circular(40.0),
+                          ),
+                          height: 80,
+                          width: 80,
+                          child: IconButton(
+                            icon: const Icon(
+                              Icons.add,
+                              size: 48,
+                              color: Styles.lavender,
+                            ),
+                            onPressed: () {
+                              showDialog(
+                                context: context,
+                                builder: (BuildContext context) {
+                                  return Dialog(
+                                      backgroundColor: Styles.dialogColor,
+                                      shape: Styles.dialogShape,
+                                      child: const AddTransactionDialog());
+                                },
+                              );
+                            },
+                          ),
+                        ),
+                      ),
+                    ],
+                  ),
+                  const Spacer(),
+                ],
+              ),
+            ),
+          )
+        ],
+      ),
     );
   }
 }
diff --git a/lib/features/budget/screens/transactions_listview.dart b/lib/features/budget/screens/transactions_listview.dart
new file mode 100644
index 0000000..8adc0c2
--- /dev/null
+++ b/lib/features/budget/screens/transactions_listview.dart
@@ -0,0 +1,63 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:rluv/features/budget/widgets/transaction_list_item.dart';
+import 'package:rluv/global/styles.dart';
+
+import '../../../global/store.dart';
+
+class TransactionsListview extends ConsumerStatefulWidget {
+  const TransactionsListview({super.key});
+
+  @override
+  ConsumerState<TransactionsListview> createState() =>
+      _TransactionsListviewState();
+}
+
+class _TransactionsListviewState extends ConsumerState<TransactionsListview> {
+  @override
+  Widget build(BuildContext context) {
+    final transactions = ref.watch(Store().transactionsProvider);
+    transactions.sort(
+      (a, b) => b.date.compareTo(a.date),
+    );
+    return Scaffold(
+      backgroundColor: Styles.purpleNurple,
+      body: SafeArea(
+        child: Stack(
+          children: [
+            if (transactions.isEmpty) ...[
+              const Center(
+                child: Text('No transactions'),
+              ),
+            ],
+            if (transactions.isNotEmpty)
+              Column(
+                children: [
+                  const SizedBox(height: 28),
+                  const Text(
+                    'Transaction History',
+                    style: TextStyle(fontSize: 28),
+                    textAlign: TextAlign.center,
+                  ),
+                  Expanded(
+                    child: ListView.builder(
+                      physics: const BouncingScrollPhysics(),
+                      itemCount: transactions.length,
+                      itemBuilder: (BuildContext context, int index) {
+                        return TransactionListItem(
+                          index: index,
+                        );
+                      },
+                    ),
+                  ),
+                ],
+              ),
+            IconButton(
+                icon: const Icon(Icons.chevron_left),
+                onPressed: () => Navigator.pop(context)),
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/features/budget/widgets/add_budget_category_dialog.dart b/lib/features/budget/widgets/add_budget_category_dialog.dart
new file mode 100644
index 0000000..3846bd2
--- /dev/null
+++ b/lib/features/budget/widgets/add_budget_category_dialog.dart
@@ -0,0 +1,265 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:helpers/helpers/misc_build/build_media.dart';
+import 'package:helpers/helpers/print.dart';
+import 'package:rluv/global/styles.dart';
+import 'package:rluv/models/budget.dart';
+import 'package:rluv/models/budget_category_model.dart';
+
+import '../../../global/api.dart';
+import '../../../global/store.dart';
+
+class AddBudgetCategoryDialog extends ConsumerStatefulWidget {
+  const AddBudgetCategoryDialog({super.key});
+
+  @override
+  ConsumerState<AddBudgetCategoryDialog> createState() =>
+      _AddBudgetCategoryDialogState();
+}
+
+class _AddBudgetCategoryDialogState
+    extends ConsumerState<AddBudgetCategoryDialog> {
+  bool loading = false;
+  bool complete = false;
+  late final Budget? budget;
+  final categoryNameController = TextEditingController();
+  final amountController = TextEditingController();
+
+  final categoryFocusNode = FocusNode();
+  final amountFocusNode = FocusNode();
+
+  final colors = Styles.curatedColors;
+  int selectedColorIndex = -1;
+
+  final formKey = GlobalKey<FormState>();
+  @override
+  void initState() {
+    budget = ref.read(Store().budgetProvider);
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      categoryFocusNode.requestFocus();
+    });
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    if (budget == null) {
+      WidgetsBinding.instance.addPostFrameCallback((_) {
+        Navigator.pop(context);
+        ScaffoldMessenger.of(context).showSnackBar(
+          const SnackBar(
+            content: Text('Could not get your budget'),
+          ),
+        );
+      });
+      return Container();
+    } else if (complete) {
+      WidgetsBinding.instance.addPostFrameCallback((_) {
+        Navigator.pop(context);
+        ScaffoldMessenger.of(context).showSnackBar(
+          const SnackBar(
+            content: Text('Budget Category Added!'),
+          ),
+        );
+      });
+      return Container();
+    }
+    return SizedBox(
+      width: BuildMedia(context).width * Styles.dialogScreenWidthFactor,
+      child: Stack(
+        children: [
+          Padding(
+            padding:
+                const EdgeInsets.symmetric(vertical: 18.0, horizontal: 32.0),
+            child: Form(
+              key: formKey,
+              child: Column(
+                mainAxisSize: MainAxisSize.min,
+                children: [
+                  const Padding(
+                    padding: EdgeInsets.only(bottom: 18.0),
+                    child: Text('Add Category:'),
+                  ),
+                  Row(
+                    children: [
+                      const Text('Name:'),
+                      const SizedBox(width: 30),
+                      Container(
+                        width: 120,
+                        height: 30,
+                        decoration: Styles.boxLavenderBubble,
+                        child: TextFormField(
+                          validator: (text) {
+                            if (text == null || text.length < 3) {
+                              return 'Invalid Category';
+                            }
+                            return null;
+                          },
+                          focusNode: categoryFocusNode,
+                          textAlign: TextAlign.center,
+                          cursorColor: Styles.blushingPink,
+                          controller: categoryNameController,
+                          decoration: Styles.inputLavenderBubble(),
+                          onFieldSubmitted: (_) {
+                            amountFocusNode.requestFocus();
+                          },
+                        ),
+                      ),
+                    ],
+                  ),
+                  const SizedBox(height: 18),
+                  Row(
+                    children: [
+                      const Text('Amount:'),
+                      const SizedBox(width: 30),
+                      Container(
+                        width: 80,
+                        height: 30,
+                        decoration: Styles.boxLavenderBubble,
+                        child: TextFormField(
+                          validator: (text) {
+                            try {
+                              if (text == null || text.isEmpty) {
+                                return 'Invalid Amount';
+                              }
+                              final amount = double.tryParse(text);
+                              if (amount == null) {
+                                return 'Not A Number';
+                              }
+                              if (amount < 0) {
+                                return 'Not Positive';
+                              }
+                              return null;
+                            } catch (err) {
+                              return 'Invalid input';
+                            }
+                          },
+                          focusNode: amountFocusNode,
+                          keyboardType: TextInputType.number,
+                          textAlign: TextAlign.center,
+                          cursorColor: Styles.blushingPink,
+                          controller: amountController,
+                          decoration: Styles.inputLavenderBubble(),
+                        ),
+                      ),
+                    ],
+                  ),
+                  Padding(
+                    padding: const EdgeInsets.symmetric(
+                        vertical: 6.0, horizontal: 16.0),
+                    child: SizedBox(
+                      height: 76,
+                      child: ListView.builder(
+                        itemCount: colors.length,
+                        scrollDirection: Axis.horizontal,
+                        itemBuilder: (BuildContext context, int index) {
+                          return GestureDetector(
+                            onTap: () {
+                              if (selectedColorIndex != index) {
+                                setState(() => selectedColorIndex = index);
+                              } else {
+                                setState(() => selectedColorIndex = -1);
+                              }
+                              printBlue(selectedColorIndex);
+                            },
+                            child: Padding(
+                              padding: const EdgeInsets.all(8.0),
+                              child: AnimatedContainer(
+                                decoration: selectedColorIndex == index
+                                    ? BoxDecoration(
+                                        borderRadius:
+                                            BorderRadius.circular(15.0),
+                                        border: Border.all(
+                                          color: Styles.washedStone,
+                                          width: 2.0,
+                                        ),
+                                      )
+                                    : BoxDecoration(
+                                        borderRadius:
+                                            BorderRadius.circular(5.0),
+                                        border: Border.all(
+                                          color: Colors.transparent,
+                                          width: 2.0,
+                                        ),
+                                      ),
+                                duration: const Duration(milliseconds: 400),
+                                child: Padding(
+                                  padding: const EdgeInsets.all(8.0),
+                                  child: Stack(
+                                    alignment: Alignment.center,
+                                    children: [
+                                      Container(
+                                        height: 40,
+                                        width: 40,
+                                        decoration: const BoxDecoration(
+                                          shape: BoxShape.circle,
+                                        ),
+                                      ),
+                                      Container(
+                                        height: 40,
+                                        width: 40,
+                                        decoration: BoxDecoration(
+                                          color: colors[index],
+                                          shape: BoxShape.circle,
+                                          border: Border.all(
+                                              color: Colors.black, width: 1.5),
+                                        ),
+                                      ),
+                                    ],
+                                  ),
+                                ),
+                              ),
+                            ),
+                          );
+                        },
+                      ),
+                    ),
+                  ),
+                  ElevatedButton(
+                    onPressed: () => submitCategory(colors[selectedColorIndex]),
+                    child: const Text('SAVE'),
+                  )
+                ],
+              ),
+            ),
+          ),
+          IconButton(
+            icon: const Icon(Icons.close),
+            onPressed: () => Navigator.pop(context),
+          ),
+          if (loading) const Center(child: CircularProgressIndicator()),
+        ],
+      ),
+    );
+  }
+
+  Future submitCategory(Color categoryColor) async {
+    if (formKey.currentState != null && !formKey.currentState!.validate()) {
+      printPink('Failed validation');
+      return;
+    }
+    setState(
+      () => loading = true,
+    );
+    final newBudget = BudgetCategory(
+      id: null,
+      amount: double.parse(amountController.text),
+      budgetId: budget!.id!,
+      color: categoryColor,
+      name: categoryNameController.text,
+    );
+
+    final budgetData =
+        await Api().post(path: 'budget_category', data: newBudget.toJson());
+    final success = budgetData != null ? budgetData['success'] as bool : false;
+    if (success) {
+      ref
+          .read(Store().dashboardProvider.notifier)
+          .add({'budget_categories': budgetData});
+    }
+    complete = true;
+    setState(() {
+      loading = false;
+    });
+  }
+}
diff --git a/lib/features/budget/widgets/add_transaction_dialog.dart b/lib/features/budget/widgets/add_transaction_dialog.dart
index 47d70f6..92fa676 100644
--- a/lib/features/budget/widgets/add_transaction_dialog.dart
+++ b/lib/features/budget/widgets/add_transaction_dialog.dart
@@ -1,6 +1,7 @@
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:helpers/helpers/misc_build/build_media.dart';
 
 import '../../../global/api.dart';
 import '../../../global/store.dart';
@@ -9,7 +10,9 @@ import '../../../models/budget_category_model.dart';
 import '../../../models/transaction_model.dart';
 
 class AddTransactionDialog extends ConsumerStatefulWidget {
-  const AddTransactionDialog({super.key});
+  const AddTransactionDialog({super.key, this.transaction});
+
+  final Transaction? transaction;
 
   @override
   ConsumerState<AddTransactionDialog> createState() =>
@@ -17,146 +20,310 @@ class AddTransactionDialog extends ConsumerStatefulWidget {
 }
 
 class _AddTransactionDialogState extends ConsumerState<AddTransactionDialog> {
-  final amountController = TextEditingController();
+  bool loading = false;
+  bool complete = false;
+  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;
+    } else {
+      amountController = TextEditingController();
+      memoController = TextEditingController();
+    }
+    final categories = ref.read(Store().budgetCategoriesProvider);
+    if (categories.isNotEmpty) {
+      selectedBudgetCategory = categories.first;
+    }
+    super.initState();
+  }
 
   @override
   Widget build(BuildContext context) {
-    final List<BudgetCategory> budgetCategories =
-        ref.read(Store().budgetCategoriesProvider).requireValue;
-    return Dialog(
-      shape: RoundedRectangleBorder(
-        borderRadius: BorderRadius.circular(10.0),
-        side: const BorderSide(color: Styles.purpleNurple, width: 5.0),
-      ),
-      child: StatefulBuilder(builder: (context, setState) {
-        TransactionType transactionType = TransactionType.expense;
-        BudgetCategory selectedBudgetCategory = budgetCategories.first;
-        return Container(
-          decoration: BoxDecoration(
-            borderRadius: BorderRadius.circular(10.0),
-            color: Styles.purpleNurple,
-          ),
-          child: Padding(
-            padding: const EdgeInsets.all(12.0),
-            child: Column(
-              mainAxisSize: MainAxisSize.min,
-              children: [
-                Row(children: [
-                  InkWell(
-                    onTap: transactionType == TransactionType.expense
-                        ? null
-                        : () {
-                            setState(() =>
-                                transactionType = TransactionType.expense);
-                          },
-                    child: AnimatedContainer(
-                      height: 30,
-                      width: 70,
-                      decoration: BoxDecoration(
-                          borderRadius: const BorderRadius.only(
-                              topLeft: Radius.circular(8.0),
-                              topRight: Radius.circular(8.0)),
-                          color: transactionType == TransactionType.expense
-                              ? Styles.lavender
-                              : Styles.sand),
-                      duration: const Duration(milliseconds: 300),
-                      child: const Padding(
-                        padding: EdgeInsets.all(8.0),
-                        child: Text('Expense'),
-                      ),
-                    ),
-                  ),
-                  InkWell(
-                    onTap: transactionType == TransactionType.income
-                        ? null
-                        : () {
-                            setState(
-                                () => transactionType = TransactionType.income);
-                          },
-                    child: AnimatedContainer(
-                      height: 30,
-                      width: 70,
-                      decoration: BoxDecoration(
-                          borderRadius: const BorderRadius.only(
-                              topLeft: Radius.circular(8.0),
-                              topRight: Radius.circular(8.0)),
-                          color: transactionType == TransactionType.income
-                              ? Styles.lavender
-                              : Styles.sand),
-                      duration: const Duration(milliseconds: 300),
-                      child: const Padding(
-                        padding: EdgeInsets.all(8.0),
-                        child: Text('Income'),
-                      ),
-                    ),
-                  ),
-                ]),
-                Row(
-                  children: [
-                    const Text('Amount:'),
-                    SizedBox(
-                      width: 80,
-                      child: TextField(
-                        controller: amountController,
-                        decoration: InputDecoration(
-                          fillColor: Styles.lavender,
-                          border: OutlineInputBorder(
-                            borderRadius: BorderRadius.circular(10.0),
-                            borderSide:
-                                const BorderSide(color: Colors.transparent),
-                          ),
-                        ),
-                      ),
-                    ),
-                  ],
-                ),
-                Row(
-                  children: [
-                    const Padding(
-                      padding: EdgeInsets.only(right: 28.0),
-                      child: Text('Category:'),
-                    ),
-                    DropdownButton<BudgetCategory>(
-                      value: selectedBudgetCategory,
-                      items: budgetCategories
-                          .map(
-                            (e) => DropdownMenuItem(
-                              value: e,
-                              child: Text(e.name),
-                            ),
-                          )
-                          .toList(),
-                      onChanged: (BudgetCategory? value) {
-                        if (value != null) {
-                          if (kDebugMode) {
-                            print('${value.name} selected');
-                          }
-                          setState(() => selectedBudgetCategory = value);
-                        }
-                      },
-                    ),
-                  ],
-                ),
-                ElevatedButton(
-                  child: const Text('Add'),
-                  onPressed: () {
-                    Api().put(
-                        path: 'transactions',
-                        data: Transaction(
-                            amount: double.parse(amountController.text),
-                            addedByUserId: 1,
-                            budgetCategoryId: 1,
-                            budgetId: 1,
-                            date: DateTime.now(),
-                            transactionType: transactionType));
-                    Navigator.pop(context);
-                  },
-                ),
-              ],
-            ),
+    if (complete) {
+      WidgetsBinding.instance.addPostFrameCallback((_) {
+        Navigator.pop(context);
+        ScaffoldMessenger.of(context).showSnackBar(
+          SnackBar(
+            content: Text(widget.transaction != null
+                ? 'Transaction updated!'
+                : 'Transaction added!'),
           ),
         );
-      }),
-    );
+      });
+      return Container();
+    }
+    final List<BudgetCategory> budgetCategories =
+        ref.read(Store().budgetCategoriesProvider);
+    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)),
+                              ),
+                            ),
+                          ),
+                        ]),
+                      ),
+                    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();
+                            },
+                          ),
+                        ),
+                      ],
+                    ),
+                    if (budgetCategories.isEmpty)
+                      const Padding(
+                        padding: EdgeInsets.all(18.0),
+                        child: Text(
+                          'Add budget categories to sort your transactions',
+                          textAlign: TextAlign.center,
+                        ),
+                      ),
+                    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),
+                          ),
+                        ],
+                      ),
+                    ),
+                    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: (_) {},
+                      ),
+                    ),
+                    ElevatedButton(
+                      onPressed: loading ? null : () => submitTransaction(),
+                      child: const Text('Add'),
+                    ),
+                  ],
+                ),
+              ));
+  }
+
+  Future submitTransaction() async {
+    setState(() {
+      loading = true;
+    });
+    Map<String, dynamic>? data;
+    if (widget.transaction != null) {
+      data = await Api().put(
+          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 {
+      data = await Api().post(
+          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) {
+        ref
+            .read(Store().dashboardProvider.notifier)
+            .update({'transactions': data});
+      } else {
+        ref
+            .read(Store().dashboardProvider.notifier)
+            .add({'transactions': data});
+      }
+      complete = true;
+    } else {
+      ScaffoldMessenger.of(context).showSnackBar(
+        SnackBar(
+          content: Text(widget.transaction != null
+              ? 'Failed to edit transaction'
+              : 'Failed to add transaction'),
+        ),
+      );
+    }
+    setState(() {
+      loading = false;
+    });
   }
 }
diff --git a/lib/features/budget/widgets/budget_category_bar.dart b/lib/features/budget/widgets/budget_category_bar.dart
index e69de29..11d25a7 100644
--- a/lib/features/budget/widgets/budget_category_bar.dart
+++ b/lib/features/budget/widgets/budget_category_bar.dart
@@ -0,0 +1,157 @@
+import 'dart:math';
+
+import 'package:flutter/material.dart';
+import 'package:helpers/helpers/print.dart';
+import 'package:rluv/global/utils.dart';
+import 'package:rluv/models/budget_category_model.dart';
+
+import '../../../global/styles.dart';
+
+class BudgetCategoryBar extends StatefulWidget {
+  const BudgetCategoryBar(
+      {super.key,
+      required this.budgetCategory,
+      required this.currentAmount,
+      required this.index,
+      this.height = 32,
+      this.innerPadding = 1.5});
+
+  final int index;
+  final double currentAmount;
+  final BudgetCategory budgetCategory;
+  final double height;
+  final double innerPadding;
+  @override
+  State<BudgetCategoryBar> createState() => _BudgetCategoryBarState();
+}
+
+class _BudgetCategoryBarState extends State<BudgetCategoryBar> {
+  double percentSpent = 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) {
+    final innerHeight = widget.height - widget.innerPadding * 2;
+    final isBright =
+        getBrightness(widget.budgetCategory.color) == Brightness.light;
+    final textStyle = TextStyle(
+        fontSize: 14,
+        fontWeight: FontWeight.bold,
+        color: widget.currentAmount > widget.budgetCategory.amount
+            ? Styles.expensesRed
+            : 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),
+                ),
+              ),
+            ),
+          ),
+          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(14.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),
+                        ),
+                      ),
+                    ],
+                  ),
+                ),
+              ],
+            ),
+          ))
+        ],
+      ),
+    );
+  }
+
+  String formatBudgetName(String name) {
+    if (name.length < 12) {
+      return name;
+    }
+    if (!name.contains(' ') || name.indexOf(' ') == name.length - 1) {
+      return name;
+    }
+    printLime('here');
+    final words = name.split(' ');
+    int index = 0;
+    String firstLine = words[index];
+    while (true) {
+      index += 1;
+      if (index == words.length) {
+        return '$firstLine\n${words.sublist(index).join(' ')}';
+      }
+      if (firstLine.length + words[index].length > 12) {
+        return '$firstLine\n${words.sublist(index).join(' ')}';
+      }
+      firstLine += ' ${words[index]}';
+    }
+  }
+}
diff --git a/lib/features/budget/widgets/budget_net_bar.dart b/lib/features/budget/widgets/budget_net_bar.dart
index 13d64f9..06e7384 100644
--- a/lib/features/budget/widgets/budget_net_bar.dart
+++ b/lib/features/budget/widgets/budget_net_bar.dart
@@ -1,6 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:helpers/helpers.dart';
 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});
@@ -28,7 +29,7 @@ class BudgetNetBar extends StatelessWidget {
             ),
           ),
           Text(
-            '\$$net',
+            net.currency(),
             style: TextStyle(
                 fontSize: 20,
                 color: isPositive ? Styles.incomeGreen : Styles.expensesRed),
diff --git a/lib/features/budget/widgets/transaction_list_item.dart b/lib/features/budget/widgets/transaction_list_item.dart
new file mode 100644
index 0000000..8bbb406
--- /dev/null
+++ b/lib/features/budget/widgets/transaction_list_item.dart
@@ -0,0 +1,168 @@
+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/widgets/add_transaction_dialog.dart';
+import 'package:rluv/global/utils.dart';
+import 'package:rluv/models/transaction_model.dart';
+
+import '../../../global/store.dart';
+import '../../../global/styles.dart';
+import '../../../global/widgets/budget_color_circle.dart';
+import '../../../models/budget_category_model.dart';
+
+class TransactionListItem extends ConsumerStatefulWidget {
+  const TransactionListItem({super.key, required this.index});
+
+  final int index;
+
+  @override
+  ConsumerState<TransactionListItem> createState() =>
+      _TransactionListItemState();
+}
+
+class _TransactionListItemState extends ConsumerState<TransactionListItem> {
+  bool showDetails = false;
+  double cardHeight = 70.0;
+
+  BudgetCategory? budgetCategory;
+  late final Transaction transaction;
+
+  @override
+  void initState() {
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final transaction = ref.watch(Store().transactionsProvider)[widget.index];
+    final budgetCategories = ref.read(Store().budgetCategoriesProvider);
+    if (transaction.type == TransactionType.expense) {
+      budgetCategory = budgetCategories.singleWhere(
+        (category) => category.id == transaction.budgetCategoryId,
+      );
+    }
+    return GestureDetector(
+      onTap: () => toggleDetails(),
+      child: Padding(
+        padding: const EdgeInsets.only(top: 8.0, left: 8.0, bottom: 8.0),
+        child: ClipRRect(
+          borderRadius: const BorderRadius.only(
+              topLeft: Radius.circular(10.0),
+              bottomLeft: Radius.circular(10.0)),
+          child: AnimatedContainer(
+            curve: Curves.easeOut,
+            duration: const Duration(milliseconds: 200),
+            height: cardHeight,
+            decoration: const BoxDecoration(
+              borderRadius: BorderRadius.only(
+                  topLeft: Radius.circular(10.0),
+                  bottomLeft: Radius.circular(10.0)),
+              color: Styles.washedStone,
+            ),
+            child: Row(
+              children: [
+                AnimatedContainer(
+                    curve: Curves.easeOut,
+                    duration: const Duration(milliseconds: 200),
+                    height: cardHeight,
+                    width: 6,
+                    color: transaction.type == TransactionType.income
+                        ? Styles.incomeBlue
+                        : Styles.expensesOrange),
+                SizedBox(
+                  width: BuildMedia(context).width * 0.65,
+                  child: Padding(
+                    padding: const EdgeInsets.only(left: 8.0),
+                    child: Column(
+                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Text(DateFormat('EEE MMM d, h:mm a')
+                            .format(transaction.date)),
+                        Row(
+                          children: [
+                            const SizedBox(
+                              width: 6,
+                            ),
+                            if (budgetCategory != null) ...[
+                              BudgetColorCircle(
+                                color: budgetCategory!.color,
+                              ),
+                              const SizedBox(
+                                width: 8,
+                              ),
+                            ],
+                            Text(
+                              transaction.type == TransactionType.income
+                                  ? 'Income'
+                                  : budgetCategory!.name,
+                              style: const TextStyle(fontSize: 20),
+                            ),
+                          ],
+                        ),
+                        if (showDetails)
+                          Text(
+                            transaction.memo ?? '',
+                            style: const TextStyle(fontSize: 16),
+                          )
+                      ],
+                    ),
+                  ),
+                ),
+                const Spacer(),
+                Column(
+                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                  children: [
+                    Text(
+                      transaction.amount.currency(),
+                      style: TextStyle(
+                          fontSize: 24,
+                          color: transaction.type == TransactionType.income
+                              ? Styles.incomeGreen
+                              : Styles.expensesRed),
+                    ),
+                    if (showDetails)
+                      IconButton(
+                        icon: const Icon(
+                          Icons.edit_rounded,
+                        ),
+                        onPressed: () {
+                          showDialog(
+                            context: context,
+                            builder: (context) => Dialog(
+                              backgroundColor: Styles.dialogColor,
+                              shape: Styles.dialogShape,
+                              child: AddTransactionDialog(
+                                  transaction: transaction),
+                            ),
+                          );
+                        },
+                      ),
+                  ],
+                ),
+                const SizedBox(
+                  width: 14,
+                ),
+              ],
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+
+  void toggleDetails() {
+    if (showDetails) {
+      setState(() {
+        showDetails = false;
+        cardHeight = 70;
+      });
+    } else {
+      setState(() {
+        showDetails = true;
+        cardHeight = 120;
+      });
+    }
+  }
+}
diff --git a/lib/features/notes/screens/notes_screen.dart b/lib/features/notes/screens/notes_screen.dart
new file mode 100644
index 0000000..02add73
--- /dev/null
+++ b/lib/features/notes/screens/notes_screen.dart
@@ -0,0 +1,51 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:helpers/helpers/misc_build/build_media.dart';
+
+import '../../../global/store.dart';
+
+class SharedNotesScreen extends ConsumerStatefulWidget {
+  const SharedNotesScreen({super.key, required this.initialData});
+
+  final Map<String, dynamic> initialData;
+  @override
+  ConsumerState<SharedNotesScreen> createState() => _SharedNotesScreenState();
+}
+
+class _SharedNotesScreenState extends ConsumerState<SharedNotesScreen> {
+  @override
+  Widget build(BuildContext context) {
+    final sharedNotes = ref.watch(Store().sharedNotesProvider);
+    return Column(
+      children: [
+        const Padding(
+          padding: EdgeInsets.all(18.0),
+          child: Text(
+            'Notes:',
+            style: TextStyle(fontSize: 20),
+            textAlign: TextAlign.center,
+          ),
+        ),
+        if (sharedNotes.isEmpty) const Text('Add notes to get started:'),
+        if (sharedNotes.isNotEmpty)
+          GridView.builder(
+            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
+              crossAxisCount: 2,
+            ),
+            itemBuilder: (BuildContext context, int index) {
+              final note = sharedNotes[index];
+              return SizedBox(
+                width: BuildMedia(context).width * 0.4,
+                child: Card(
+                  child: Padding(
+                    padding: const EdgeInsets.all(8.0),
+                    child: Text(note.content),
+                  ),
+                ),
+              );
+            },
+          ),
+      ],
+    );
+  }
+}
diff --git a/lib/features/settings/screens/settings_screen.dart b/lib/features/settings/screens/settings_screen.dart
new file mode 100644
index 0000000..c42ce36
--- /dev/null
+++ b/lib/features/settings/screens/settings_screen.dart
@@ -0,0 +1,20 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+class SettingsScreen extends ConsumerStatefulWidget {
+  const SettingsScreen({super.key});
+
+  @override
+  ConsumerState<SettingsScreen> createState() => _SettingsScreenState();
+}
+
+class _SettingsScreenState extends ConsumerState<SettingsScreen> {
+  @override
+  Widget build(BuildContext context) {
+    return const Column(
+      children: [
+        Text('Settings'),
+      ],
+    );
+  }
+}
diff --git a/lib/global/api.dart b/lib/global/api.dart
index 04795e8..c4e2878 100644
--- a/lib/global/api.dart
+++ b/lib/global/api.dart
@@ -1,4 +1,7 @@
+import 'dart:convert';
+
 import 'package:dio/dio.dart';
+import 'package:flutter/foundation.dart';
 import 'package:helpers/helpers/print.dart';
 
 class Api {
@@ -10,38 +13,40 @@ class Api {
     _instance.initDone = true;
     _instance.dio = Dio();
     _instance.dio.options.baseUrl = "http://localhost:8081/";
+    // _instance.dio.options.baseUrl = "https://rluv.fosscat.com/";
     _instance.dio.interceptors.add(
-      InterceptorsWrapper(
-        onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
-          // Do something before request is sent.
-          // If you want to resolve the request with custom data,
-          // you can resolve a `Response` using `handler.resolve(response)`.
-          // If you want to reject the request with a error message,
-          // you can reject with a `DioException` using `handler.reject(dioError)`.
-          return handler.next(options);
-        },
-        onResponse: (Response response, ResponseInterceptorHandler handler) {
-          if (response.statusCode != null &&
-              response.statusCode! < 500 &&
-              response.statusCode! >= 400) {
-            return handler.reject(DioException.badResponse(
-                requestOptions: RequestOptions(),
-                response: response,
-                statusCode: response.statusCode!));
-          }
-          // Do something with response data.
-          // If you want to reject the request with a error message,
-          // you can reject a `DioException` object using `handler.reject(dioError)`.
-          return handler.next(response);
-        },
-        onError: (DioException e, ErrorInterceptorHandler handler) {
-          printPink(e);
-          // Do something with response error.
-          // If you want to resolve the request with some custom data,
-          // you can resolve a `Response` object using `handler.resolve(response)`.
-          return handler.next(e);
-        },
-      ),
+      LoggingInterceptor(),
+      // InterceptorsWrapper(
+      //   onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
+      //     // Do something before request is sent.
+      //     // If you want to resolve the request with custom data,
+      //     // you can resolve a `Response` using `handler.resolve(response)`.
+      //     // If you want to reject the request with a error message,
+      //     // you can reject with a `DioException` using `handler.reject(dioError)`.
+      //     return handler.next(options);
+      //   },
+      //   onResponse: (Response response, ResponseInterceptorHandler handler) {
+      //     if (response.statusCode != null &&
+      //         response.statusCode! < 500 &&
+      //         response.statusCode! >= 400) {
+      //       return handler.reject(DioException.badResponse(
+      //           requestOptions: RequestOptions(),
+      //           response: response,
+      //           statusCode: response.statusCode!));
+      //     }
+      //     // Do something with response data.
+      //     // If you want to reject the request with a error message,
+      //     // you can reject a `DioException` object using `handler.reject(dioError)`.
+      //     return handler.next(response);
+      //   },
+      //   onError: (DioException e, ErrorInterceptorHandler handler) {
+      //     printPink(e);
+      //     // Do something with response error.
+      //     // If you want to resolve the request with some custom data,
+      //     // you can resolve a `Response` object using `handler.resolve(response)`.
+      //     return handler.next(e);
+      //   },
+      // ),
     );
     return _instance;
   }
@@ -79,6 +84,21 @@ class Api {
     }
   }
 
+  Future<Map<String, dynamic>?> post(
+      {required String path, Object? data}) async {
+    try {
+      final res = await dio.post(path, data: data);
+
+      if (res.data != null) {
+        return res.data as Map<String, dynamic>;
+      }
+      return null;
+    } catch (err) {
+      printRed('Error in put: $err');
+      return null;
+    }
+  }
+
   Future<Map<String, dynamic>?> delete(
       {required String path, Object? data}) async {
     try {
@@ -94,3 +114,74 @@ class Api {
     }
   }
 }
+
+class LoggingInterceptor extends Interceptor {
+  LoggingInterceptor();
+
+  @override
+  Future onRequest(
+      RequestOptions options, RequestInterceptorHandler handler) async {
+    logPrint('///*** REQUEST ***\\\\\\');
+    printKV('URI', options.uri);
+    printKV('METHOD', options.method);
+    logPrint('HEADERS:');
+    options.headers.forEach((key, v) => printKV(' - $key', v));
+    logPrint('BODY:');
+    printJson(options.data);
+
+    return handler.next(options);
+  }
+
+  @override
+  void onError(DioException err, ErrorInterceptorHandler handler) {
+    logPrint('///*** ERROR RESPONSE ***\\\\\\');
+    logPrint('URI: ${err.requestOptions.uri}');
+    if (err.response != null) {
+      logPrint('STATUS CODE: ${err.response?.statusCode?.toString()}');
+    }
+    logPrint('$err');
+    if (err.response != null) {
+      printKV('REDIRECT', err.response?.realUri ?? '');
+      logPrint('BODY:');
+      printJson(err.response?.data);
+    }
+    return handler.next(err);
+  }
+
+  @override
+  Future onResponse(
+      Response response, ResponseInterceptorHandler handler) async {
+    logPrint('///*** RESPONSE ***\\\\\\');
+    printKV('URI', response.requestOptions.uri);
+    printKV('STATUS CODE', response.statusCode ?? '');
+    // printKV('REDIRECT', response.isRedirect);
+    logPrint('BODY:');
+    printJson(response.data);
+
+    return handler.next(response);
+  }
+
+  void printKV(String key, Object v) {
+    if (kDebugMode) {
+      printOrange('$key: $v');
+    }
+  }
+
+  void printJson(Map<String, dynamic>? s) {
+    if (kDebugMode) {
+      if (s == null) {
+        printAmber({});
+        return;
+      }
+      JsonEncoder encoder = const JsonEncoder.withIndent('  ');
+      String prettyprint = encoder.convert(s);
+      printAmber(prettyprint);
+    }
+  }
+
+  void logPrint(String s) {
+    if (kDebugMode) {
+      printOrange(s);
+    }
+  }
+}
diff --git a/lib/global/store.dart b/lib/global/store.dart
index 9a8fbc3..99de3e2 100644
--- a/lib/global/store.dart
+++ b/lib/global/store.dart
@@ -1,43 +1,70 @@
+import 'dart:convert';
+
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:helpers/helpers/print.dart';
 import 'package:rluv/global/api.dart';
 import 'package:rluv/models/budget.dart';
 import 'package:rluv/models/budget_category_model.dart';
+import 'package:shared_preferences/shared_preferences.dart';
 
 import '../models/family_model.dart';
+import '../models/shared_note.dart';
 import '../models/transaction_model.dart';
 import '../models/user.dart';
 
 class Store {
   static final Store _instance = Store._internal();
   bool _initDone = false;
+  SharedPreferences? prefs;
 
   factory Store() {
     if (_instance._initDone) {
       return _instance;
     }
     _instance._initDone = true;
-    _instance.dashboardProvider = FutureProvider<Map<String, dynamic>?>(
-      (ref) async {
-        final family = await ref.watch(_instance.familyProvider.future);
-        return Api().get("dashboard/${family.id}");
+    SharedPreferences.getInstance().then(
+      (value) => _instance.prefs = value,
+    );
+    _instance.dashboardProvider =
+        StateNotifierProvider<DashBoardStateNotifier, Map<String, dynamic>?>(
+      (ref) {
+        final family = ref.watch(_instance.familyProvider).valueOrNull;
+        return DashBoardStateNotifier(family);
       },
     );
-    _instance.budgetCategoriesProvider =
-        FutureProvider<List<BudgetCategory>>((ref) async {
-      final dash = await ref.watch(_instance.dashboardProvider.future);
-      printAmber(dash);
+    // _instance.dashboardProvider = FutureProvider<Map<String, dynamic>?>(
+    //   (ref) async {
+    //     final family = await ref.watch(_instance.familyProvider.future);
+    //     return Api().get("dashboard/${family.id}");
+    //   },
+    // );
+    _instance.budgetProvider = Provider<Budget?>(
+      (ref) {
+        final dash = ref.watch(_instance.dashboardProvider);
+        if (dash == null) return null;
+        final budgetData = dash['budget'] as Map<String, dynamic>?;
+        if (budgetData == null) return null;
+        return Budget.fromJson(budgetData);
+      },
+    );
+    _instance.budgetCategoriesProvider = Provider<List<BudgetCategory>>((ref) {
+      final dash = ref.watch(_instance.dashboardProvider);
       if (dash == null) return [];
-      final categories = dash['budget_categories'] as List<dynamic>;
-      return categories
+      final categoriesData = dash['budget_categories'] as List<dynamic>;
+      final categories = categoriesData
           .map(
             (e) => BudgetCategory.fromJson(e as Map<String, dynamic>),
           )
           .toList();
+      if (_instance.prefs != null) {
+        final budgetJson = jsonEncode({'budget_categories': categoriesData});
+        printBlue('updated prefs stored categories');
+        _instance.prefs!.setString('budget_categories', budgetJson);
+      }
+      return categories;
     });
-    _instance.transactionsProvider =
-        FutureProvider<List<Transaction>>((ref) async {
-      final dash = await ref.watch(_instance.dashboardProvider.future);
+    _instance.transactionsProvider = Provider<List<Transaction>>((ref) {
+      final dash = ref.watch(_instance.dashboardProvider);
       if (dash == null) return [];
       final transactions = dash['transactions'] as List<dynamic>;
       return transactions
@@ -72,10 +99,87 @@ class Store {
           createdAt: DateTime.now(),
           updatedAt: DateTime.now()));
 
-  late final FutureProvider<List<BudgetCategory>> budgetCategoriesProvider;
-  late final FutureProvider<Budget> budgetProvider;
-  late final FutureProvider<List<Transaction>> transactionsProvider;
-  late final FutureProvider<Map<String, dynamic>?> dashboardProvider;
+  late final Provider<List<BudgetCategory>> budgetCategoriesProvider;
+  late final Provider<Budget?> budgetProvider;
+  late final Provider<List<Transaction>> transactionsProvider;
+  late final Provider<List<SharedNote>> sharedNotesProvider;
+  // late final FutureProvider<Map<String, dynamic>?> dashboardProvider;
 
+  late final StateNotifierProvider<DashBoardStateNotifier,
+      Map<String, dynamic>?> dashboardProvider;
   void fetchDashboard() {}
 }
+
+class DashBoardStateNotifier extends StateNotifier<Map<String, dynamic>?> {
+  DashBoardStateNotifier(FamilyModel? family) : super(null) {
+    fetchDashboard(family);
+  }
+
+  Future fetchDashboard(FamilyModel? family) async {
+    if (family == null) {
+      printPink('Unable to get dashboard');
+      return;
+    }
+    printAmber('Fetching dashboard');
+    state = await Api().get("dashboard/${family.id}");
+  }
+
+  void update(Map<String, dynamic> data) {
+    if (state == null) {
+      printPink('Cant update data, state is null');
+      return;
+    }
+    if (data.keys.length != 1 || data.values.length != 1) {
+      throw Exception('Only one key/val used in update');
+    }
+    final key = data.keys.first;
+    switch (key) {
+      case 'transactions':
+      case 'budget_categories':
+        final subStateList = state![key] as List<dynamic>;
+        final subStateListObj = subStateList
+            .map(
+              (e) => e as Map<String, dynamic>,
+            )
+            .toList();
+        subStateListObj.removeWhere(
+          (element) =>
+              element['id'] ==
+              (data.values.first as Map<String, dynamic>)['id'],
+        );
+        subStateListObj.add(data.values.first);
+
+        final newState = state;
+        newState![key] = subStateListObj;
+        state = {...newState};
+        // printBlue(state);
+        break;
+      default:
+        break;
+    }
+  }
+
+  void add(Map<String, dynamic> data) {
+    if (state == null) {
+      printPink('Cant add data, state is null');
+      return;
+    }
+    if (data.keys.length != 1 || data.values.length != 1) {
+      throw Exception('Only one key/val used in add');
+    }
+    final key = data.keys.first;
+    switch (key) {
+      case 'transactions':
+      case 'budget_categories':
+        final subStateList = state![key] as List<dynamic>;
+        final newState = state;
+        subStateList.add(data.values.first);
+        newState![key] = subStateList;
+        state = {...newState};
+        // printBlue(state);
+        break;
+      default:
+        break;
+    }
+  }
+}
diff --git a/lib/global/styles.dart b/lib/global/styles.dart
index 4b71883..b8cce2c 100644
--- a/lib/global/styles.dart
+++ b/lib/global/styles.dart
@@ -1,4 +1,4 @@
-import 'dart:ui';
+import 'package:flutter/material.dart';
 
 class Styles {
   // Theme Colors
@@ -9,7 +9,7 @@ class Styles {
   static const Color seaweedGreen = Color(0xFF86BA90);
   static const Color emptyBarGrey = Color(0xFFC8C8C8);
   static const Color lavender = Color(0xFFB8B8FF);
-  static const Color sand = Color(0xFFD9D9D9);
+  static const Color washedStone = Color(0xFFD9D9D9);
 
   // Income Colors
   static const Color incomeBlue = Color(0xFFB8B8FF);
@@ -17,5 +17,57 @@ class Styles {
 
   // Expenses Colors
   static const Color expensesOrange = Color(0xFFFA824C);
-  static const Color expensesRed = Color(0xFF9E0000);
+  static const Color expensesRed = Color(0xFFC73E1D);
+
+  static const List<Color> curatedColors = [
+    Color(0xFF6D326D),
+    Color(0xFFE58F65),
+    Color(0xFFD3E298),
+    Color(0xFFFD96A9),
+    Color(0xFF4F7CAC),
+    Color(0xFFE4B4C2),
+    Color(0xFFFFB8D1),
+    Color(0xFFDDFDFE),
+    Color(0xFFD7BE82),
+    Color(0xFFD4C5C7),
+    Color(0xFF8EB8E5),
+    Color(0xFF9893DA),
+    Color(0xFF99AA38),
+    Color(0xFFA7E2E3),
+    Color(0xFFF7B2BD),
+    Color(0xFFFEDC97),
+    Color(0xFFC28CAE),
+    Color(0xFFF1BF98),
+    Color(0xFFD1BCE3),
+    Color(0xFFBDC667),
+    Color(0xFFFFB563)
+  ];
+
+  // Widget Styles
+  static BoxDecoration boxLavenderBubble = BoxDecoration(
+    color: Styles.lavender,
+    borderRadius: BorderRadius.circular(20.0),
+  );
+
+  static InputDecoration inputLavenderBubble({String? labelText}) =>
+      InputDecoration(
+        contentPadding:
+            const EdgeInsets.symmetric(vertical: 8.0, horizontal: 8.0),
+        labelText: labelText,
+        focusColor: Styles.blushingPink,
+        hoverColor: Styles.blushingPink,
+        fillColor: Styles.lavender,
+        border: const OutlineInputBorder(
+          borderSide: BorderSide.none,
+        ),
+      );
+
+  static const Color dialogColor = Styles.purpleNurple;
+
+  static RoundedRectangleBorder dialogShape = RoundedRectangleBorder(
+    borderRadius: BorderRadius.circular(20.0),
+  );
+
+  // Sizing Styles
+  static const dialogScreenWidthFactor = 0.75;
 }
diff --git a/lib/global/utils.dart b/lib/global/utils.dart
index 1a30b0c..341a61d 100644
--- a/lib/global/utils.dart
+++ b/lib/global/utils.dart
@@ -1,5 +1,8 @@
-import 'dart:ui';
+import 'dart:math';
 
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:helpers/helpers/print.dart';
 import 'package:intl/intl.dart';
 
 String formatDate(DateTime time) {
@@ -8,10 +11,62 @@ String formatDate(DateTime time) {
 
 DateTime dateFromJson(int value) => DateTime.fromMillisecondsSinceEpoch(value);
 
-int dateToJson(DateTime? value) =>
-    value == null ? 0 : value.millisecondsSinceEpoch;
+int? dateToJson(DateTime? value) => value?.millisecondsSinceEpoch;
+
+bool boolFromJson(int value) => value == 1;
+
+int boolToJson(bool hide) => hide ? 1 : 0;
 
 String colorToJson(Color color) =>
     color.toString().split('(0x')[1].split(')')[0];
 
 Color colorFromJson(String hex) => Color(int.parse(hex, radix: 16));
+
+String? optionalColorToJson(Color? optionalColor) => optionalColor == null
+    ? null
+    : optionalColor.toString().split('(0x')[1].split(')')[0];
+
+Color? optionalColorFromJson(String? hex) =>
+    hex == null ? null : Color(int.parse(hex, radix: 16));
+
+Brightness getBrightness(Color color) =>
+    ThemeData.estimateBrightnessForColor(color);
+
+List<Color> generateColorList() {
+  List<Color> colors = [];
+  for (int i = 100; i <= 255; i += 30) {
+    // Red value variations
+    for (int j = 100; j <= 255; j += 30) {
+      // Green value variations
+      for (int k = 100; k <= 255; k += 30) {
+        // Blue value variations
+        final alpha = Random().nextInt(256) + 50 % 255;
+        colors.add(Color.fromARGB(alpha, i, j, k));
+      }
+    }
+  }
+  colors.shuffle();
+  return colors;
+}
+
+extension MonetaryExtension on double {
+  String currency() {
+    final numStr = toStringAsFixed(2);
+    final pieces = numStr.split(".");
+    if (pieces.length == 1) {
+      return "\$${pieces.first}.00";
+    } else {
+      if (pieces.length > 2) {
+        printBlue(pieces);
+      }
+      return '\$${pieces[0]}.${pieces[1].padRight(2, "0")}';
+    }
+  }
+}
+
+void setDevicePortraitOrientation() {
+  SystemChrome.setPreferredOrientations([
+    DeviceOrientation.portraitUp,
+    DeviceOrientation.portraitDown,
+  ]);
+}
diff --git a/lib/global/widgets/budget_color_circle.dart b/lib/global/widgets/budget_color_circle.dart
new file mode 100644
index 0000000..61cfe75
--- /dev/null
+++ b/lib/global/widgets/budget_color_circle.dart
@@ -0,0 +1,35 @@
+import 'package:flutter/material.dart';
+
+class BudgetColorCircle extends StatelessWidget {
+  const BudgetColorCircle(
+      {super.key, required this.color, this.height = 18, this.width = 18});
+
+  final double height;
+  final double width;
+  final Color color;
+
+  @override
+  Widget build(BuildContext context) {
+    return Stack(
+      children: [
+        Container(
+          height: height,
+          width: width,
+          decoration: const BoxDecoration(
+            shape: BoxShape.circle,
+            color: Colors.white,
+          ),
+        ),
+        Container(
+          height: height,
+          width: width,
+          decoration: BoxDecoration(
+            shape: BoxShape.circle,
+            border: Border.all(color: Colors.black, width: 1.5),
+            color: color,
+          ),
+        ),
+      ],
+    );
+  }
+}
diff --git a/lib/global/widgets/drawer_button.dart b/lib/global/widgets/drawer_button.dart
new file mode 100644
index 0000000..ed8dd29
--- /dev/null
+++ b/lib/global/widgets/drawer_button.dart
@@ -0,0 +1,54 @@
+import 'package:flutter/material.dart';
+import 'package:rluv/global/styles.dart';
+
+class CuteDrawerButton extends StatelessWidget {
+  const CuteDrawerButton(
+      {super.key,
+      required this.text,
+      required this.color,
+      required this.onPressed});
+
+  final String text;
+  final Function onPressed;
+  final Color color;
+  final double borderRadius = 12.0;
+  @override
+  Widget build(BuildContext context) {
+    return Padding(
+      padding: const EdgeInsets.all(8.0),
+      child: InkWell(
+        borderRadius: BorderRadius.circular(borderRadius),
+        onTap: () => onPressed(),
+        child: Container(
+          decoration: BoxDecoration(
+            color: color,
+            boxShadow: const [
+              BoxShadow(
+                color: Colors.black26,
+                blurRadius: 2.0,
+                spreadRadius: 2.0,
+                offset: Offset(2.5, 2.5),
+              )
+            ],
+            borderRadius: BorderRadius.circular(borderRadius),
+          ),
+          child: Row(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: [
+              Padding(
+                padding: const EdgeInsets.all(8.0),
+                child: Text(
+                  text,
+                  style: const TextStyle(
+                    fontSize: 14,
+                    color: Styles.washedStone,
+                  ),
+                ),
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/main.dart b/lib/main.dart
index f7a4a4b..7b417de 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,9 +1,17 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:helpers/helpers/misc_build/build_media.dart';
 import 'package:rluv/features/budget/screens/budget_overview.dart';
+import 'package:rluv/features/notes/screens/notes_screen.dart';
+import 'package:rluv/features/settings/screens/settings_screen.dart';
 import 'package:rluv/global/styles.dart';
+import 'package:rluv/global/utils.dart';
+import 'package:rluv/global/widgets/drawer_button.dart';
 
-void main() {
+import 'global/store.dart';
+
+void main() async {
+  final _ = Store().prefs;
   runApp(const MyApp());
 }
 
@@ -34,12 +42,70 @@ class Home extends ConsumerStatefulWidget {
 }
 
 class _HomeState extends ConsumerState<Home> {
+  Map<String, dynamic> initData = {};
+  final drawerColors = Styles.curatedColors;
+  @override
+  void initState() {
+    setDevicePortraitOrientation();
+    super.initState();
+  }
+
   @override
   Widget build(BuildContext context) {
+    if (ref.watch(currentHomePageProvider).toString() ==
+        "BudgetOverviewScreen") {
+      initData = {};
+    }
     return Scaffold(
+      key: ref.read(scaffoldKeyProvider),
       resizeToAvoidBottomInset: false,
-      drawer: const Drawer(
+      drawer: Drawer(
         backgroundColor: Styles.purpleNurple,
+        child: SafeArea(
+          child: Column(
+            children: [
+              SizedBox(height: BuildMedia(context).height * 0.15),
+              CuteDrawerButton(
+                text: 'Budget',
+                color: drawerColors[4],
+                onPressed: () {
+                  if (ref.read(currentHomePageProvider).toString() !=
+                      "BudgetOverviewScreen") {
+                    ref.read(currentHomePageProvider.notifier).state =
+                        BudgetOverviewScreen(initialData: initData);
+                  }
+                  toggleDrawer();
+                },
+              ),
+              CuteDrawerButton(
+                text: 'Notes',
+                color: drawerColors[5],
+                onPressed: () {
+                  if (ref.read(currentHomePageProvider).toString() !=
+                      "SharedNotesScreen") {
+                    ref.read(currentHomePageProvider.notifier).state =
+                        SharedNotesScreen(initialData: initData);
+                  }
+                  toggleDrawer();
+                },
+              ),
+              const Spacer(),
+              CuteDrawerButton(
+                text: 'Settings',
+                color: drawerColors[0],
+                onPressed: () {
+                  if (ref.read(currentHomePageProvider).toString() !=
+                      "SettingsScreen") {
+                    ref.read(currentHomePageProvider.notifier).state =
+                        const SettingsScreen();
+                  }
+                  toggleDrawer();
+                },
+              ),
+              const SizedBox(height: 24),
+            ],
+          ),
+        ),
       ),
       appBar: AppBar(
         backgroundColor: Styles.purpleNurple,
@@ -50,10 +116,23 @@ class _HomeState extends ConsumerState<Home> {
       body: ref.watch(currentHomePageProvider),
     );
   }
+
+  toggleDrawer() async {
+    final key = ref.read(scaffoldKeyProvider);
+    if (key.currentState != null && key.currentState!.isDrawerOpen) {
+      key.currentState!.openEndDrawer();
+    } else if (key.currentState != null) {
+      key.currentState!.openDrawer();
+    }
+  }
 }
 
+final scaffoldKeyProvider = Provider<GlobalKey<ScaffoldState>>(
+  (ref) => GlobalKey<ScaffoldState>(),
+);
+
 final currentHomePageProvider = StateProvider<Widget>(
-  (ref) => const BudgetOverviewScreen(),
+  (ref) => const BudgetOverviewScreen(initialData: {}),
 );
 
 final appBarTitleProvider = Provider<String>(
@@ -62,6 +141,8 @@ final appBarTitleProvider = Provider<String>(
     switch (currentPageName) {
       case 'BudgetOverviewScreen':
         return 'Budget';
+      case 'SharedNotesScreen':
+        return 'Notes';
       default:
         return '';
     }
diff --git a/lib/models/budget.dart b/lib/models/budget.dart
index b28db81..afeffe9 100644
--- a/lib/models/budget.dart
+++ b/lib/models/budget.dart
@@ -11,11 +11,14 @@ class Budget {
     required this.name,
     required this.createdAt,
     required this.updatedAt,
+    this.hide = false,
   });
 
   final int? id;
   final String name;
 
+  @JsonKey(fromJson: boolFromJson, toJson: boolToJson)
+  final bool hide;
   @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
   final DateTime createdAt;
   @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
diff --git a/lib/models/budget.g.dart b/lib/models/budget.g.dart
index 1fba5c4..3087ba4 100644
--- a/lib/models/budget.g.dart
+++ b/lib/models/budget.g.dart
@@ -11,11 +11,13 @@ Budget _$BudgetFromJson(Map<String, dynamic> json) => Budget(
       name: json['name'] as String,
       createdAt: dateFromJson(json['created_at'] as int),
       updatedAt: dateFromJson(json['updated_at'] as int),
+      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
     );
 
 Map<String, dynamic> _$BudgetToJson(Budget instance) => <String, dynamic>{
       'id': instance.id,
       'name': instance.name,
+      'hide': boolToJson(instance.hide),
       'created_at': dateToJson(instance.createdAt),
       'updated_at': dateToJson(instance.updatedAt),
     };
diff --git a/lib/models/budget_category_model.dart b/lib/models/budget_category_model.dart
index 90a6e34..635f1bc 100644
--- a/lib/models/budget_category_model.dart
+++ b/lib/models/budget_category_model.dart
@@ -13,8 +13,10 @@ class BudgetCategory {
     required this.budgetId,
     required this.name,
     required this.color,
-    required this.createdAt,
+    this.createdAt,
+    this.updatedAt,
     required this.amount,
+    this.hide = false,
   });
 
   final int budgetId;
@@ -22,11 +24,17 @@ class BudgetCategory {
   final String name;
   final double amount;
 
+  @JsonKey(fromJson: boolFromJson, toJson: boolToJson)
+  final bool hide;
+
   @JsonKey(fromJson: colorFromJson, toJson: colorToJson)
   final Color color;
 
   @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
-  final DateTime createdAt;
+  final DateTime? createdAt;
+
+  @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
+  final DateTime? updatedAt;
 
   factory BudgetCategory.fromJson(Map<String, dynamic> json) =>
       _$BudgetCategoryFromJson(json);
diff --git a/lib/models/budget_category_model.g.dart b/lib/models/budget_category_model.g.dart
index a47efe8..d7498c1 100644
--- a/lib/models/budget_category_model.g.dart
+++ b/lib/models/budget_category_model.g.dart
@@ -13,7 +13,9 @@ BudgetCategory _$BudgetCategoryFromJson(Map<String, dynamic> json) =>
       name: json['name'] as String,
       color: colorFromJson(json['color'] as String),
       createdAt: dateFromJson(json['created_at'] as int),
+      updatedAt: dateFromJson(json['updated_at'] as int),
       amount: (json['amount'] as num).toDouble(),
+      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
     );
 
 Map<String, dynamic> _$BudgetCategoryToJson(BudgetCategory instance) =>
@@ -22,6 +24,8 @@ Map<String, dynamic> _$BudgetCategoryToJson(BudgetCategory instance) =>
       'id': instance.id,
       'name': instance.name,
       'amount': instance.amount,
+      'hide': boolToJson(instance.hide),
       'color': colorToJson(instance.color),
       'created_at': dateToJson(instance.createdAt),
+      'updated_at': dateToJson(instance.updatedAt),
     };
diff --git a/lib/models/family_model.dart b/lib/models/family_model.dart
index 8c9be80..91720e2 100644
--- a/lib/models/family_model.dart
+++ b/lib/models/family_model.dart
@@ -11,10 +11,13 @@ class FamilyModel {
     required this.budgetId,
     required this.createdAt,
     required this.updatedAt,
+    this.hide = false,
   });
 
   final int id, budgetId;
 
+  @JsonKey(fromJson: boolFromJson, toJson: boolToJson)
+  final bool hide;
   @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
   final DateTime createdAt;
   @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
diff --git a/lib/models/family_model.g.dart b/lib/models/family_model.g.dart
index e411dbf..6c36909 100644
--- a/lib/models/family_model.g.dart
+++ b/lib/models/family_model.g.dart
@@ -11,12 +11,14 @@ FamilyModel _$FamilyModelFromJson(Map<String, dynamic> json) => FamilyModel(
       budgetId: json['budget_id'] as int,
       createdAt: dateFromJson(json['created_at'] as int),
       updatedAt: dateFromJson(json['updated_at'] as int),
+      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
     );
 
 Map<String, dynamic> _$FamilyModelToJson(FamilyModel instance) =>
     <String, dynamic>{
       'id': instance.id,
       'budget_id': instance.budgetId,
+      'hide': boolToJson(instance.hide),
       'created_at': dateToJson(instance.createdAt),
       'updated_at': dateToJson(instance.updatedAt),
     };
diff --git a/lib/models/shared_note.dart b/lib/models/shared_note.dart
new file mode 100644
index 0000000..6cedf0e
--- /dev/null
+++ b/lib/models/shared_note.dart
@@ -0,0 +1,46 @@
+import 'dart:ui';
+
+import 'package:json_annotation/json_annotation.dart';
+
+import '../global/utils.dart';
+
+part 'shared_note.g.dart';
+
+@JsonSerializable()
+class SharedNote {
+  const SharedNote({
+    this.id,
+    required this.familyId,
+    required this.createdByUserId,
+    required this.content,
+    this.color,
+    this.createdAt,
+    this.updatedAt,
+    this.isMarkdown = false,
+    this.hide = false,
+  });
+
+  final int? id;
+  final int familyId, createdByUserId;
+  final String content;
+
+  @JsonKey(fromJson: optionalColorFromJson, toJson: optionalColorToJson)
+  final Color? color;
+
+  @JsonKey(fromJson: boolFromJson, toJson: boolToJson)
+  final bool isMarkdown;
+
+  @JsonKey(fromJson: boolFromJson, toJson: boolToJson)
+  final bool hide;
+
+  @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
+  final DateTime? createdAt;
+
+  @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
+  final DateTime? updatedAt;
+
+  factory SharedNote.fromJson(Map<String, dynamic> json) =>
+      _$SharedNoteFromJson(json);
+
+  Map<String, dynamic> toJson() => _$SharedNoteToJson(this);
+}
diff --git a/lib/models/shared_note.g.dart b/lib/models/shared_note.g.dart
new file mode 100644
index 0000000..fb5e067
--- /dev/null
+++ b/lib/models/shared_note.g.dart
@@ -0,0 +1,34 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'shared_note.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SharedNote _$SharedNoteFromJson(Map<String, dynamic> json) => SharedNote(
+      id: json['id'] as int?,
+      familyId: json['family_id'] as int,
+      createdByUserId: json['created_by_user_id'] as int,
+      content: json['content'] as String,
+      color: optionalColorFromJson(json['color'] as String?),
+      createdAt: dateFromJson(json['created_at'] as int),
+      updatedAt: dateFromJson(json['updated_at'] as int),
+      isMarkdown: json['is_markdown'] == null
+          ? false
+          : boolFromJson(json['is_markdown'] as int),
+      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
+    );
+
+Map<String, dynamic> _$SharedNoteToJson(SharedNote instance) =>
+    <String, dynamic>{
+      'id': instance.id,
+      'family_id': instance.familyId,
+      'created_by_user_id': instance.createdByUserId,
+      'content': instance.content,
+      'color': optionalColorToJson(instance.color),
+      'is_markdown': boolToJson(instance.isMarkdown),
+      'hide': boolToJson(instance.hide),
+      'created_at': dateToJson(instance.createdAt),
+      'updated_at': dateToJson(instance.updatedAt),
+    };
diff --git a/lib/models/transaction_model.dart b/lib/models/transaction_model.dart
index b2fc6a9..244867b 100644
--- a/lib/models/transaction_model.dart
+++ b/lib/models/transaction_model.dart
@@ -14,18 +14,25 @@ class Transaction {
   const Transaction({
     this.id,
     required this.amount,
-    required this.transactionType,
+    required this.type,
     required this.budgetId,
-    required this.budgetCategoryId,
+    this.budgetCategoryId,
     required this.addedByUserId,
     required this.date,
+    this.memo,
     this.createdAt,
+    this.updatedAt,
+    this.hide = false,
   });
 
-  final int? id;
-  final int budgetId, budgetCategoryId, addedByUserId;
+  final int? id, budgetCategoryId;
+  final int budgetId, addedByUserId;
   final double amount;
-  final TransactionType transactionType;
+  final String? memo;
+  final TransactionType type;
+
+  @JsonKey(fromJson: boolFromJson, toJson: boolToJson)
+  final bool hide;
 
   @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
   final DateTime date;
@@ -33,8 +40,26 @@ class Transaction {
   @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
   final DateTime? createdAt;
 
+  @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
+  final DateTime? updatedAt;
+
   factory Transaction.fromJson(Map<String, dynamic> json) =>
       _$TransactionFromJson(json);
 
+  factory Transaction.copyWith(Transaction trans, Map<String, dynamic> data) =>
+      Transaction(
+        id: data['id'] ?? trans.id,
+        amount: data['amount'] ?? trans.amount,
+        type: data['type'] ?? trans.type,
+        budgetId: data['budget_id'] ?? trans.budgetId,
+        budgetCategoryId: data['budget_category_id'] ?? trans.budgetCategoryId,
+        addedByUserId: data['added_by_user_id'] ?? trans.addedByUserId,
+        date: data['date'] ?? trans.date,
+        memo: data['memo'] ?? trans.memo,
+        createdAt: data['created_at'] ?? trans.createdAt,
+        updatedAt: data['updated_at'] ?? trans.updatedAt,
+        hide: data['hide'] ?? trans.hide,
+      );
+
   Map<String, dynamic> toJson() => _$TransactionToJson(this);
 }
diff --git a/lib/models/transaction_model.g.dart b/lib/models/transaction_model.g.dart
index 573be33..0f0b6b4 100644
--- a/lib/models/transaction_model.g.dart
+++ b/lib/models/transaction_model.g.dart
@@ -9,25 +9,30 @@ part of 'transaction_model.dart';
 Transaction _$TransactionFromJson(Map<String, dynamic> json) => Transaction(
       id: json['id'] as int?,
       amount: (json['amount'] as num).toDouble(),
-      transactionType:
-          $enumDecode(_$TransactionTypeEnumMap, json['transaction_type']),
+      type: $enumDecode(_$TransactionTypeEnumMap, json['type']),
       budgetId: json['budget_id'] as int,
-      budgetCategoryId: json['budget_category_id'] as int,
+      budgetCategoryId: json['budget_category_id'] as int?,
       addedByUserId: json['added_by_user_id'] as int,
       date: dateFromJson(json['date'] as int),
+      memo: json['memo'] as String?,
       createdAt: dateFromJson(json['created_at'] as int),
+      updatedAt: dateFromJson(json['updated_at'] as int),
+      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
     );
 
 Map<String, dynamic> _$TransactionToJson(Transaction instance) =>
     <String, dynamic>{
       'id': instance.id,
-      'budget_id': instance.budgetId,
       'budget_category_id': instance.budgetCategoryId,
+      'budget_id': instance.budgetId,
       'added_by_user_id': instance.addedByUserId,
       'amount': instance.amount,
-      'transaction_type': _$TransactionTypeEnumMap[instance.transactionType]!,
+      'memo': instance.memo,
+      'type': _$TransactionTypeEnumMap[instance.type]!,
+      'hide': boolToJson(instance.hide),
       'date': dateToJson(instance.date),
       'created_at': dateToJson(instance.createdAt),
+      'updated_at': dateToJson(instance.updatedAt),
     };
 
 const _$TransactionTypeEnumMap = {
diff --git a/lib/models/user.dart b/lib/models/user.dart
index dd2ca16..79eebcb 100644
--- a/lib/models/user.dart
+++ b/lib/models/user.dart
@@ -14,12 +14,15 @@ class User {
     this.createdAt,
     this.updatedAt,
     this.lastActivityAt,
+    this.hide = false,
   });
 
   final int? id;
   final int familyId, budgetId;
   final String name;
 
+  @JsonKey(fromJson: boolFromJson, toJson: boolToJson)
+  final bool hide;
   @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
   final DateTime? createdAt;
   @JsonKey(fromJson: dateFromJson, toJson: dateToJson)
diff --git a/lib/models/user.g.dart b/lib/models/user.g.dart
index acd57a0..cbb3fd8 100644
--- a/lib/models/user.g.dart
+++ b/lib/models/user.g.dart
@@ -14,6 +14,7 @@ User _$UserFromJson(Map<String, dynamic> json) => User(
       createdAt: dateFromJson(json['created_at'] as int),
       updatedAt: dateFromJson(json['updated_at'] as int),
       lastActivityAt: dateFromJson(json['last_activity_at'] as int),
+      hide: json['hide'] == null ? false : boolFromJson(json['hide'] as int),
     );
 
 Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
@@ -21,6 +22,7 @@ Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
       'family_id': instance.familyId,
       'budget_id': instance.budgetId,
       'name': instance.name,
+      'hide': boolToJson(instance.hide),
       'created_at': dateToJson(instance.createdAt),
       'updated_at': dateToJson(instance.updatedAt),
       'last_activity_at': dateToJson(instance.lastActivityAt),