diff --git a/package.json b/package.json index 79c2969..eb3ea6c 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "dev": "concurrently -n api,web,codegen -c blue,magenta,yellow 'rails s' 'cd web && bun run watch' 'cd web && bun graphql-codegen --watch'", "dev:test": "cd api && ENV_TYPE=test PORT=4445 bun run bin/dev-test.ts", "deploy": "bun run deploy.js", - "typecheck": "web && bun typecheck", + "typecheck": "cd web && bun typecheck", "lint": "cd web && bun lint" }, "workspaces": ["web"] diff --git a/web/src/components/budgets/BudgetGroup.tsx b/web/src/components/budgets/BudgetGroup.tsx index 99c8ddf..d474097 100644 --- a/web/src/components/budgets/BudgetGroup.tsx +++ b/web/src/components/budgets/BudgetGroup.tsx @@ -3,8 +3,10 @@ import { Component, For, Show } from "solid-js" import { CATEGORY_BACKGROUND_COLORS, CategoryColor } from "../../utils/categoryColors" import { getCssValue } from "../../utils/getCssValue" import CategoryIndicator, { CategoryIndicatorProps } from "../CategoryIndicator" -import { LinkButton } from "../base/Button" +import { Button, LinkButton } from "../base/Button" import { PieChart } from "./PieChart" +import { createSignal } from "solid-js" +import { TransactionsModal } from "./TransactionsModal" interface BudgetGroupProps { title: string @@ -12,15 +14,19 @@ interface BudgetGroupProps { allTransactionsHref: string items: Array<{ indicator: CategoryIndicatorProps + categoryId: string | null name: string color?: CategoryColor budget?: { amountDecimal: number; formatted: string } | null | false total: { amountDecimal: number; formatted: string } - href: string }> } +const NO_CATEGORY = Symbol("NO_CATEGORY") + const BudgetGroup: Component = (props) => { + const [openCategory, setOpenCategory] = createSignal(false) + return (
@@ -44,7 +50,7 @@ const BudgetGroup: Component = (props) => { - {({ indicator, name, color, total, budget, href }) => ( + {({ categoryId, indicator, name, color, total, budget }) => (
@@ -93,16 +99,16 @@ const BudgetGroup: Component = (props) => {
- setOpenCategory(categoryId || NO_CATEGORY)} > - +
)} @@ -116,6 +122,17 @@ const BudgetGroup: Component = (props) => { formattedValue: total.formatted }))} /> + + {(openCategory) => { + const category = openCategory() + return ( + setOpenCategory(false)} + /> + ) + }} +
) } diff --git a/web/src/components/budgets/Budgets.tsx b/web/src/components/budgets/Budgets.tsx index a73b63e..3edb7a6 100644 --- a/web/src/components/budgets/Budgets.tsx +++ b/web/src/components/budgets/Budgets.tsx @@ -50,7 +50,7 @@ export const Budgets: Component<{ color: category?.color as CategoryColor, budget: category?.budget?.budget, total: amountSpent, - href: filteredTransactions({ categoryIds: [category?.id || null] }) + categoryId: category?.id || null }))} /> @@ -72,7 +72,7 @@ export const Budgets: Component<{ color: category?.color as CategoryColor, budget: category?.budget?.budget, total: amountSpent, - href: filteredTransactions({ categoryIds: [category?.id || null] }) + categoryId: category?.id || null }) )} /> @@ -86,7 +86,7 @@ export const Budgets: Component<{ name: transaction.memo, budget: false, total: transaction.amount || { amountDecimal: 0, formatted: "?" }, - href: `/transactions/${transaction.id}` + categoryId: null }))} /> diff --git a/web/src/components/budgets/TransactionsModal.tsx b/web/src/components/budgets/TransactionsModal.tsx new file mode 100644 index 0000000..f99ade8 --- /dev/null +++ b/web/src/components/budgets/TransactionsModal.tsx @@ -0,0 +1,50 @@ +import { Show } from "solid-js" +import { useTransactionsQuery } from "../../graphql/queries/transactionsQuery" +import { Modal, ModalContent, ModalTitle } from "../base/Modal" +import LoadingBar from "../LoadingBar" +import { For } from "solid-js" + +export const TransactionsModal = (props: { categoryId: string | null; onClose: () => void }) => { + const query = useTransactionsQuery(() => ({ + limit: 1000, + filter: { categoryIds: [props.categoryId] } + })) + + const transactionsToShow = () => + query() + ?.transactions.nodes.flatMap((transaction) => { + if (transaction.splitTo) { + return transaction.splitTo + .filter((split) => split.category?.id === props.categoryId) + .map((split) => ({ ...split, shop: transaction.shop })) + } else { + return [transaction] + } + }) + .sort((a, b) => (a.amount?.amountDecimal || 0) - (b.amount?.amountDecimal || 0)) + + return ( + + + Transactions + }> + {(transactionsToShow) => ( +
    + + {(transaction) => ( +
  • + + {transaction.shop}{" "} + – {transaction.memo} + + {transaction.amount?.formatted} +
  • + )} +
    +
+ )} +
+
+
+ ) +}