From 836eb9742cabc91afa3b5246a47b1f4b5b4aa1b1 Mon Sep 17 00:00:00 2001 From: Ian C Date: Tue, 26 Nov 2024 13:03:56 -0500 Subject: [PATCH] refactored the error class --- .excalidraw | 11 ++ actions/budget/budgetActions.ts | 61 ++++++----- actions/categories/categoriesActions.ts | 46 ++++---- .../categoryGroups/categoryGroupsActions.ts | 19 ++-- actions/helpers/calculateAvailableFunds.ts | 78 +++++++------- .../monthlyBudgets/monthlyBudgetsActions.ts | 32 +++--- .../monthlyCategoryDetailsActions.ts | 101 +++++++++++------- actions/transactions/transactionsActions.ts | 77 +++++++------ app/dashboard/debug/displayForm.tsx | 16 +-- app/dashboard/debug/page.tsx | 17 ++- app/dashboard/debug/updateBox.tsx | 10 +- errors/AppError.ts | 48 ++++++--- errors/index.ts | 2 +- 13 files changed, 304 insertions(+), 214 deletions(-) create mode 100644 .excalidraw diff --git a/.excalidraw b/.excalidraw new file mode 100644 index 0000000..11c9e04 --- /dev/null +++ b/.excalidraw @@ -0,0 +1,11 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", + "elements": [], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/actions/budget/budgetActions.ts b/actions/budget/budgetActions.ts index 63a686f..fdf4f18 100644 --- a/actions/budget/budgetActions.ts +++ b/actions/budget/budgetActions.ts @@ -5,7 +5,6 @@ import { MonthlyBudget, Budget } from "@/types"; import { createServersideClient } from "@/utils/supabase/server"; import { revalidatePath } from "next/cache"; - export async function getDefaultBudget(): Promise { const supabase = createServersideClient(); const { @@ -16,11 +15,13 @@ export async function getDefaultBudget(): Promise { // Return our custom error type if there is an auth error from Supabase if (authError || !user?.id) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code || "AUTH_FAILURE", + status: authError?.status || 401, + hint: { hint: "Try logging in again." }, + }).toPlainObject(); } const { data: budget, error } = await supabase @@ -41,16 +42,19 @@ export async function getDefaultBudget(): Promise { return await createDefaultBudget(budgetName); } console.error("Error fetching budgets: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + status: 500, + details: error.details, + }).toPlainObject(); } - // revalidatePath("/dashboard"); return budget; } -export async function createDefaultBudget( - name: string = "My Budget", -): Promise { +export async function createDefaultBudget(budgetName: string): Promise { const supabase = createServersideClient(); const { data: { user }, @@ -58,25 +62,34 @@ export async function createDefaultBudget( } = await supabase.auth.getUser(); if (authError || !user?.id) { - console.error("Error authenticating user: ", authError); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - authError?.status, - ).toPlainObject(); + console.error("Error authenticating user: ", authError?.message); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code || "AUTH_FAILURE", + status: authError?.status || 401, + hint: { hint: "Try logging in again." }, + }).toPlainObject(); } - const { data, error } = await supabase + const { data: newBudget, error } = await supabase .from("budgets") - .insert({ name, user_id: user.id }) - .select() + .insert([{ name: budgetName, user_id: user.id }]) .single(); if (error) { - console.error("Error creating budget: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + console.error("Error creating default budget: ", error); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + status: 500, + details: error.details, + }).toPlainObject(); } - return data; + // Revalidate the path to ensure the new budget is reflected in the UI + revalidatePath("/dashboard"); + + return newBudget; } \ No newline at end of file diff --git a/actions/categories/categoriesActions.ts b/actions/categories/categoriesActions.ts index 13119d2..435a5ba 100644 --- a/actions/categories/categoriesActions.ts +++ b/actions/categories/categoriesActions.ts @@ -22,26 +22,33 @@ export async function getCategoriesWithDetails( if (authError || !user) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - authError?.status, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + status: authError?.status, + }).toPlainObject(); } const { data: categoriesWithDetails, error } = await supabase .from("categories") - .select(` + .select( + ` *, monthly_category_details ( * ) - `) + `, + ) + .eq("monthly_category_details.monthly_budget_id", monthlyBudgetID); if (error || !categoriesWithDetails) { - console.error("Error fetching catories with details: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + console.error("Error fetching categories with details: ", error); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + }).toPlainObject(); } // Map over the data to flatten `monthly_category_details` to a single object @@ -71,12 +78,12 @@ export async function addCategory( if (authError || !user) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - authError?.status, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + status: authError?.status, + }).toPlainObject(); } const { error } = await supabase @@ -85,7 +92,11 @@ export async function addCategory( if (error) { console.error("Error adding category: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + }).toPlainObject(); } revalidatePath("/dashboard"); @@ -93,4 +104,3 @@ export async function addCategory( } // Update a category in the categories table - diff --git a/actions/categoryGroups/categoryGroupsActions.ts b/actions/categoryGroups/categoryGroupsActions.ts index 7e8648e..1d89a64 100644 --- a/actions/categoryGroups/categoryGroupsActions.ts +++ b/actions/categoryGroups/categoryGroupsActions.ts @@ -16,12 +16,12 @@ export async function getCategoryGroups( if (authError || !user?.id) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - authError?.status, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + status: authError?.status, + }).toPlainObject(); } const { data, error } = await supabase @@ -32,7 +32,12 @@ export async function getCategoryGroups( if (error || !data) { console.error("Error fetching category groups: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + status: 500, + }).toPlainObject(); } return data; diff --git a/actions/helpers/calculateAvailableFunds.ts b/actions/helpers/calculateAvailableFunds.ts index 64e44f7..cbc35a1 100644 --- a/actions/helpers/calculateAvailableFunds.ts +++ b/actions/helpers/calculateAvailableFunds.ts @@ -25,17 +25,20 @@ export async function getAvailableAmount( if (authError || !user?.id) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - authError?.status, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + status: authError?.status, + }).toPlainObject(); } // Validate currMonth if (!(month instanceof Date) || isNaN(month.getTime())) { - return new AppError("VALIDATION_ERROR", "Invalid date provided").toPlainObject(); + return new AppError({ + name: "VALIDATION_ERROR", + message: "Invalid date provided" + }).toPlainObject(); } // Get all transactions up to the current month @@ -57,11 +60,11 @@ export async function getAvailableAmount( if (transactionsError) { console.error("Error fetching transactions: ", transactionsError); - return new AppError( - "DB_ERROR", - transactionsError?.message, - transactionsError?.code, - ).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: transactionsError?.message, + code: transactionsError?.code, + }).toPlainObject(); } else if (!transactions) { return null; } @@ -79,11 +82,11 @@ export async function getAvailableAmount( // TODO: Check if this is true and remove the second if statement. if (bugdetsError) { console.error("Error fetching monthly budgets: ", bugdetsError); - return new AppError( - "DB_ERROR", - bugdetsError.message, - bugdetsError.code, - ).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: bugdetsError.message, + code: bugdetsError.code, + }).toPlainObject(); } else if (!monthlyBudgets) { return null; } @@ -102,11 +105,11 @@ export async function getAvailableAmount( // TODO: Same here. if (categoryError) { console.error("Error fetching monthly category details: ", categoryError); - return new AppError( - "DB_ERROR", - categoryError.message, - categoryError.code, - ).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: categoryError.message, + code: categoryError.code, + }).toPlainObject(); } else if (!monthlyCategoryDetails) { return null; } @@ -138,11 +141,6 @@ export async function getAvailableAmount( return availableAmount; } - -// ************************* - - - // I don't think we need to export this. Just use it in other server actions // to recalulate the total available amount after a transaction is added. export async function calculateAvailableAmount( @@ -157,11 +155,11 @@ export async function calculateAvailableAmount( if (authError || !user) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - ); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + }); } const { data: transactions, error: transactionError } = await supabase @@ -172,11 +170,11 @@ export async function calculateAvailableAmount( if (transactionError) { console.error("Error fetching transactions: ", transactionError); - return new AppError( - "DB_ERROR", - transactionError.message, - transactionError.code, - ); + return new AppError({ + name: "DB_ERROR", + message: transactionError.message, + code: transactionError.code, + }); } else if (!transactions) { return 0; } @@ -189,7 +187,11 @@ export async function calculateAvailableAmount( if (categoryError || !monthlyCategoryDetails) { console.error("Error fetching monthly category details: ", categoryError); - return new AppError("DB_ERROR", categoryError.message, categoryError.code); + return new AppError({ + name: "DB_ERROR", + message: categoryError.message, + code: categoryError.code, + }); } const totalInflow = transactions diff --git a/actions/monthlyBudgets/monthlyBudgetsActions.ts b/actions/monthlyBudgets/monthlyBudgetsActions.ts index a49575e..55509c6 100644 --- a/actions/monthlyBudgets/monthlyBudgetsActions.ts +++ b/actions/monthlyBudgets/monthlyBudgetsActions.ts @@ -24,11 +24,11 @@ export async function getTodaysMonthlyBudget( if (authError || !user) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + }).toPlainObject(); } const today = new Date(); @@ -55,7 +55,11 @@ export async function getTodaysMonthlyBudget( return createMonthlyBudget(budgetId, new Date()); } console.error("Error fetching current monthly budgets: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + }).toPlainObject(); } // revalidatePath("/dashboard"); @@ -76,11 +80,11 @@ export async function createMonthlyBudget( if (authError || !user) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + }).toPlainObject(); } const firstDayOfMonth = new Date(month.getFullYear(), month.getMonth(), 1); @@ -99,7 +103,11 @@ export async function createMonthlyBudget( if (error || !data) { console.error("Error fetching monthly budgets: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + }).toPlainObject(); } return data; diff --git a/actions/monthlyCategoryDetails/monthlyCategoryDetailsActions.ts b/actions/monthlyCategoryDetails/monthlyCategoryDetailsActions.ts index fcedae8..fbf03ad 100644 --- a/actions/monthlyCategoryDetails/monthlyCategoryDetailsActions.ts +++ b/actions/monthlyCategoryDetails/monthlyCategoryDetailsActions.ts @@ -10,7 +10,7 @@ export async function updateAssigned( monthlyBudgetId: number, categoryId: number, amountAssigned: number, -): Promise { +): Promise { const supabase = createServersideClient(); const { data: { user }, @@ -19,22 +19,22 @@ export async function updateAssigned( if (authError || !user?.id) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - authError?.status, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + status: authError?.status, + }).toPlainObject(); } if (amountAssigned < 0) { - return new AppError( - "VALIDATION_ERROR", - "Assigned amount must be non-negative", - ).toPlainObject(); + return new AppError({ + name: "VALIDATION_ERROR", + message: "Assigned amount must be non-negative", + }).toPlainObject(); } - const { data: updateData, error: updateError } = await supabase + const { data: upsertData, error: upsertError } = await supabase .from("monthly_category_details") .upsert( { @@ -43,25 +43,36 @@ export async function updateAssigned( category_id: categoryId, amount_assigned: amountAssigned, }, - { onConflict: "monthly_budget_id,category_id" }, // Specify the conflict target - ); - - if (updateError) { - console.error("Error updating assigned amount: ", updateError); - return new AppError( - "DB_ERROR", - updateError.message, - updateError.code, - ).toPlainObject(); + { onConflict: "monthly_budget_id,category_id" }, + ) + .select() + .single(); + + if (upsertError) { + console.error("Error upserting assigned amount: ", upsertError); + return new AppError({ + name: "DB_ERROR", + message: upsertError.message, + code: upsertError.code, + status: 500, + details: upsertError.details, + hint: { + attemptedUpsert: { + user_id: user.id, + monthly_budget_id: monthlyBudgetId, + category_id: categoryId, + amount_assigned: amountAssigned, + }, + }, + }).toPlainObject(); } revalidatePath("/dashboard"); - return null; + return upsertData; } export async function getMonthlyCategoryDetails( - budgetId: number, - month: string, + monthlyBudgetId: number, ): Promise { const supabase = createServersideClient(); const { @@ -71,22 +82,25 @@ export async function getMonthlyCategoryDetails( if (authError || !user) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + }).toPlainObject(); } const { data: details, error } = await supabase .from("monthly_category_details") .select("*") - .eq("budget_id", budgetId) - .eq("month", month); + .eq("monthly_budget_id", monthlyBudgetId); if (error) { console.error("Error fetching monthly category details: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + }).toPlainObject(); } return details; @@ -105,11 +119,11 @@ export async function createMonthlyCategoryDetails( if (authError || !user) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + }).toPlainObject(); } const { data, error } = await supabase @@ -124,11 +138,18 @@ export async function createMonthlyCategoryDetails( if (error) { console.error("Error creating monthly category details: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + }).toPlainObject(); } if (!data) { - return new AppError("NOT_FOUND", "No data returned").toPlainObject(); + return new AppError({ + name: "NOT_FOUND", + message: "No data returned", + }).toPlainObject(); } return data[0]; diff --git a/actions/transactions/transactionsActions.ts b/actions/transactions/transactionsActions.ts index 43502f4..c918bbe 100644 --- a/actions/transactions/transactionsActions.ts +++ b/actions/transactions/transactionsActions.ts @@ -32,11 +32,11 @@ export async function addTransaction( budgetId: number, amount: number, transactionType: "inflow" | "outflow", - categoryId?: number, - date?: Date, - note?: string, - cleared?: boolean, - payee?: string, + categoryId?: number | null, + date?: Date | null, + note?: string | null, + cleared?: boolean | undefined, + payee?: string | null, ): Promise { const supabase = createServersideClient(); const { @@ -44,36 +44,19 @@ export async function addTransaction( error: authError, } = await supabase.auth.getUser(); - // Return our custom error type if there is an auth error from Supabase - if (authError || !user?.id) { + if (authError || !user) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - ).toPlainObject(); - } - - // Validate amount - if (amount < 0 || isNaN(amount)) { - return new AppError( - "VALIDATION_ERROR", - "Transaction amount must be non-negative", - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + status: authError?.status, + }).toPlainObject(); } - // Validate transaction type - if (transactionType !== "inflow" && transactionType !== "outflow") { - return new AppError( - "VALIDATION_ERROR", - "Invalid transaction type", - ).toPlainObject(); - } - - const { error } = await supabase.from("transactions").insert({ + const { data, error } = await supabase.from("transactions").insert({ budget_id: budgetId, - user_id: user.id, - amount: parseFloat(amount.toFixed(2)), + amount, transaction_type: transactionType, category_id: categoryId || null, date: date @@ -82,11 +65,18 @@ export async function addTransaction( note: note || "", cleared: cleared !== undefined ? cleared : true, payee: payee || null, + user_id: user.id, }); if (error) { console.error("Error inserting transaction: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + status: 500, + details: error.details, + }).toPlainObject(); } revalidatePath("/dashboard"); @@ -104,24 +94,29 @@ export async function getTransactions( if (authError || !user) { console.error("Error authenticating user: ", authError?.message); - return new AppError( - "AUTH_ERROR", - "User authentication failed or user not found", - authError?.code, - ).toPlainObject(); + return new AppError({ + name: "AUTH_ERROR", + message: "User authentication failed or user not found", + code: authError?.code, + status: authError?.status, + }).toPlainObject(); } const { data: transactions, error } = await supabase .from("transactions") .select("*") - .eq("budget_id", budgetId) - .order("date", { ascending: false }); + .eq("budget_id", budgetId); if (error) { console.error("Error fetching transactions: ", error); - return new AppError("DB_ERROR", error.message, error.code).toPlainObject(); + return new AppError({ + name: "DB_ERROR", + message: error.message, + code: error.code, + status: 500, + details: error.details, + }).toPlainObject(); } - // revalidatePath("/dashboard"); return transactions; } \ No newline at end of file diff --git a/app/dashboard/debug/displayForm.tsx b/app/dashboard/debug/displayForm.tsx index e151bef..69ee448 100644 --- a/app/dashboard/debug/displayForm.tsx +++ b/app/dashboard/debug/displayForm.tsx @@ -14,7 +14,7 @@ import { isPlainAppError, PlainAppError } from "@/errors"; import { addCategory, addTransaction } from "@/actions"; import { Button } from "@/components/button"; import { RadioField, RadioGroup } from "@/components/radio"; -import { Radio } from "../../../components/radio"; +import { Radio } from "@/components/radio"; import { Label } from "@headlessui/react"; import { DescriptionDetails, @@ -25,15 +25,7 @@ import { Divider } from "@/components/divider"; import { Select } from "@/components/select"; import { Input, InputGroup } from "@/components/input"; import { CurrencyDollarIcon } from "@heroicons/react/24/outline"; -import { DateType } from "../../../components/input"; -import { - Dialog, - DialogActions, - DialogBody, - DialogDescription, - DialogTitle, -} from "@/components/dialog"; -import { Field } from "@/components/fieldset"; +import { DateType } from "@/components/input"; import { updateAssigned } from "@/actions/monthlyCategoryDetails"; import UpdateBox from "./updateBox"; @@ -177,7 +169,7 @@ export default function DisplayForm({ categoryDetailsId, amount, ); - if (res?.error) { + if (isPlainAppError(res)) { const errStr = `Error adding category: ${res.error.message}`; toast.error(errStr, { className: "bg-rose-500" }); setLoading(false); @@ -241,7 +233,7 @@ export default function DisplayForm({ return (
{c.name}
diff --git a/app/dashboard/debug/page.tsx b/app/dashboard/debug/page.tsx index 37285e6..6f7b473 100644 --- a/app/dashboard/debug/page.tsx +++ b/app/dashboard/debug/page.tsx @@ -6,7 +6,7 @@ import { MonthlyBudget, Transaction, } from "@/types/types"; -import { AppError, isPlainAppError, PlainAppError } from "@/errors"; +import { isPlainAppError, PlainAppError } from "@/errors"; import { getDefaultBudget, getTodaysMonthlyBudget, @@ -16,6 +16,8 @@ import { } from "@/actions"; import DisplayForm from "./displayForm"; import { Toaster } from "sonner"; +import { updateAssigned } from "@/actions/monthlyCategoryDetails"; + // app/debug/page.tsx export default async function DebugPage() { @@ -32,6 +34,7 @@ export default async function DebugPage() { return
TX Fetch Error: {txs.error.message}
; } + // Todo: Fetch monthly budget from query params. If no params exist, default to current month. const currMonthlyBudget: MonthlyBudget | PlainAppError = await getTodaysMonthlyBudget(budget.id); @@ -41,6 +44,7 @@ export default async function DebugPage() { ); } + const categoryWithDetails: CategoryWithDetails[] | PlainAppError = await getCategoriesWithDetails(budget.id); @@ -48,12 +52,19 @@ export default async function DebugPage() { return
Category Fetch Error: {categoryWithDetails.error.message}
; } - const categoryGroups: CategoryGroup[] | PlainAppError = await getCategoryGroups(budget.id); + + + const categoryGroups: CategoryGroup[] | PlainAppError = + await getCategoryGroups(budget.id); if (isPlainAppError(categoryGroups)) { - return
Category Groups Fetch Error: {categoryGroups.error.message}
; + return ( +
Category Groups Fetch Error: {categoryGroups.error.message}
+ ); } + const testSupabase = await updateAssigned(13, 3, 300); + console.log("testSupabase: ", testSupabase); return ( <> diff --git a/app/dashboard/debug/updateBox.tsx b/app/dashboard/debug/updateBox.tsx index a1d6e2b..bc7f35e 100644 --- a/app/dashboard/debug/updateBox.tsx +++ b/app/dashboard/debug/updateBox.tsx @@ -20,12 +20,18 @@ export default function UpdateBox({ }) { const [isOpen, setIsOpen] = useState(false); const [assignedAmount, setAssignedAmount] = useState( - c.monthly_category_details?.amount_assigned, + c.monthly_category_details?.amount_assigned ); return ( <> - diff --git a/errors/AppError.ts b/errors/AppError.ts index 20d4108..c6c5c8d 100644 --- a/errors/AppError.ts +++ b/errors/AppError.ts @@ -5,7 +5,25 @@ type ErrorName = | "VALIDATION_ERROR" | "UNKNOWN_ERROR"; -export type PlainAppError = ReturnType; +export interface PlainAppError { + error: { + name: ErrorName; + message: string; + code: string; + status: number; + details: string; + hint: Record; + }; +} + +export interface AppErrorOptions { + name: ErrorName; + message: string; + code?: string; + status?: number; + details?: string; + hint?: Record; +} // Our custom error class. Use this to pinpoint what kind of error is being returned // from our server actions. @@ -14,31 +32,29 @@ export class AppError extends Error { message: string; code: string; status: number; + details: string; + hint: {}; - constructor( - name: ErrorName, - message: string, - code: string = "UNKNOWN_CODE", - status: number = 500, - ) { - super(message); - this.name = name; - this.message = message; - this.code = code; - this.status = status; + constructor(options: AppErrorOptions) { + super(options.message); + this.name = options.name; + this.message = options.message; + this.code = options.code || "UNKNOWN_CODE"; + this.status = options.status || 500; + this.details = options.details || ""; + this.hint = options.hint || {}; } - toPlainObject(): { - error: { name: ErrorName; message: string; code: string; status: number }; - } { + toPlainObject(): PlainAppError { return { error: { name: this.name, message: this.message, code: this.code, status: this.status, + details: this.details, + hint: this.hint, }, }; } } - diff --git a/errors/index.ts b/errors/index.ts index 89a9f76..8f148f5 100644 --- a/errors/index.ts +++ b/errors/index.ts @@ -3,4 +3,4 @@ export { AppError } from './AppError'; // export { AuthenticationError } from './AuthenticationError'; // export { ResourceNotFoundError } from './ResourceNotFoundError'; export { isPlainAppError } from './typeGuards'; -export type { PlainAppError } from './AppError'; \ No newline at end of file +export type { PlainAppError, AppErrorOptions } from './AppError'; \ No newline at end of file