From bff2bcf3c2726ca6b42a927a62551f76169944c9 Mon Sep 17 00:00:00 2001 From: Hansen Frenico <16384641+frenicohansen@users.noreply.github.com> Date: Tue, 13 Feb 2024 17:34:50 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor=20api=20to=20deli?= =?UTF-8?q?ver=20transformed=20data?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/src/graphql/monthlyBudgets.sdl.ts | 31 +++++ .../services/monthlyBudgets/monthlyBudgets.ts | 111 ++++++++++++++++++ .../MonthlyBudgetsCell/MonthlyBudgetsCell.tsx | 47 +++----- .../MonthlyBudgetsCell/convertData.ts | 39 ------ web/src/components/Spreadsheet/cells.tsx | 62 +++++++++- web/src/components/Spreadsheet/columns.tsx | 1 + 6 files changed, 217 insertions(+), 74 deletions(-) create mode 100644 api/src/graphql/monthlyBudgets.sdl.ts create mode 100644 api/src/services/monthlyBudgets/monthlyBudgets.ts delete mode 100644 web/src/components/MonthlyBudgetsCell/convertData.ts diff --git a/api/src/graphql/monthlyBudgets.sdl.ts b/api/src/graphql/monthlyBudgets.sdl.ts new file mode 100644 index 0000000..ca39a21 --- /dev/null +++ b/api/src/graphql/monthlyBudgets.sdl.ts @@ -0,0 +1,31 @@ +export const schema = gql` + type MonthlyBudgetCategory { + id: String! + name: String! + month: Int! + year: Int! + assigned: Float! + activity: Float! + available: Float! + } + + type MonthlyBudgetGroup { + id: String! + name: String! + month: Int! + year: Int! + assigned: Float! + activity: Float! + available: Float! + subRows: [MonthlyBudgetCategory!] + } + + type Query { + monthlyBudget( + id: String! + userId: String! + month: Int! + year: Int! + ): [MonthlyBudgetGroup!]! @requireAuth + } +` diff --git a/api/src/services/monthlyBudgets/monthlyBudgets.ts b/api/src/services/monthlyBudgets/monthlyBudgets.ts new file mode 100644 index 0000000..08e78b6 --- /dev/null +++ b/api/src/services/monthlyBudgets/monthlyBudgets.ts @@ -0,0 +1,111 @@ +import type { + MonthlyBudgetGroupRelationResolvers, + QueryResolvers, +} from 'types/graphql' + +import { db } from 'src/lib/db' + +export const monthlyBudget: QueryResolvers['monthlyBudget'] = async ({ + id, + userId, + month, + year, +}) => { + const query = await db.budget.findUnique({ + where: { + id, + userId, + }, + include: { + budgetCategoryGroups: { + orderBy: { + sortOrder: 'asc', + }, + include: { + monthlyCategoryGroupActivities: { + where: { + month, + year, + }, + }, + budgetCategories: { + orderBy: { + sortOrder: 'asc', + }, + include: { + monthlyBudgetPerCategories: { + where: { + month, + year, + }, + include: { + monthlyCategoryActivity: true, + }, + }, + }, + }, + }, + }, + }, + }) + + const res = query.budgetCategoryGroups.map((group) => { + return { + id: group.id, + name: group.name, + month, + year, + assigned: + group.monthlyCategoryGroupActivities[0]?.assigned.toNumber() || 0, + activity: + group.monthlyCategoryGroupActivities[0]?.activity.toNumber() || 0, + available: + group.monthlyCategoryGroupActivities[0]?.available.toNumber() || 0, + } + }) + + return res +} + +export const MonthlyBudgetGroup: MonthlyBudgetGroupRelationResolvers = { + subRows: async (_obj, { root }) => { + const categoryGroups = await db.budgetCategoryGroup.findUnique({ + where: { id: root.id }, + include: { + budgetCategories: { + orderBy: { + sortOrder: 'asc', + }, + include: { + monthlyBudgetPerCategories: { + where: { + month: root.month, + year: root.year, + }, + include: { + monthlyCategoryActivity: true, + }, + }, + }, + }, + }, + }) + + return categoryGroups.budgetCategories.map((category) => { + return { + id: category.id, + name: category.name, + month: root.month, + year: root.year, + assigned: + category.monthlyBudgetPerCategories[0]?.assigned.toNumber() || 0, + activity: + category.monthlyBudgetPerCategories[0]?.monthlyCategoryActivity.activity.toNumber() || + 0, + available: + category.monthlyBudgetPerCategories[0]?.monthlyCategoryActivity.available.toNumber() || + 0, + } + }) + }, +} diff --git a/web/src/components/MonthlyBudgetsCell/MonthlyBudgetsCell.tsx b/web/src/components/MonthlyBudgetsCell/MonthlyBudgetsCell.tsx index 8e7beb5..9e5cb73 100644 --- a/web/src/components/MonthlyBudgetsCell/MonthlyBudgetsCell.tsx +++ b/web/src/components/MonthlyBudgetsCell/MonthlyBudgetsCell.tsx @@ -9,8 +9,6 @@ import { DataTableSkeleton, } from 'src/components/Spreadsheet/data-table' -import { convertBudgetGQLIntoDisplayable } from './convertData' - export const QUERY = gql` query FindBudgetByMonth( $userId: String! @@ -18,30 +16,18 @@ export const QUERY = gql` $month: Int! $year: Int! ) { - budget(id: $budgetId, userId: $userId) { - budgetCategoryGroups { + monthlyBudget(id: $budgetId, userId: $userId, month: $month, year: $year) { + id + category: name + assigned + activity + available + subRows { id - name - sortOrder - monthlyCategoryGroupActivity(month: $month, year: $year) { - assigned - activity - available - } - budgetCategories { - id - name - sortOrder - monthlyBudgetPerCategory(month: $month, year: $year) { - month - year - assigned - monthlyCategoryActivity { - activity - available - } - } - } + category: name + assigned + activity + available } } } @@ -57,11 +43,8 @@ export const Failure = ({ error }: CellFailureProps) => (
Error: {error?.message}
) -export const Success = ({ budget }: CellSuccessProps) => { - return ( - - ) +export const Success = ({ + monthlyBudget, +}: CellSuccessProps) => { + return } diff --git a/web/src/components/MonthlyBudgetsCell/convertData.ts b/web/src/components/MonthlyBudgetsCell/convertData.ts deleted file mode 100644 index 275da90..0000000 --- a/web/src/components/MonthlyBudgetsCell/convertData.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { FindBudgetByMonth } from 'types/graphql' - -import type { MonthlyBudget } from 'src/components/Spreadsheet/columns' - -type MonthlyBudgetGQL = FindBudgetByMonth['budget'] -type MonthlyBudgetGQLIntoDisplayable = ( - budget: MonthlyBudgetGQL -) => MonthlyBudget[] - -// TODO do it on the server side -export const convertBudgetGQLIntoDisplayable: MonthlyBudgetGQLIntoDisplayable = - (budget: MonthlyBudgetGQL) => { - const groups = budget.budgetCategoryGroups - return groups.map((group) => { - const categories = group.budgetCategories - const subRows = categories.map((category) => { - return { - id: category.id, - category: category.name, - assigned: category.monthlyBudgetPerCategory[0]?.assigned || 0, - activity: - category.monthlyBudgetPerCategory[0]?.monthlyCategoryActivity - .activity || 0, - available: - category.monthlyBudgetPerCategory[0]?.monthlyCategoryActivity - .available || 0, - } - }) - - return { - id: group.id, - category: group.name, - assigned: group.monthlyCategoryGroupActivity[0]?.assigned || 0, - activity: group.monthlyCategoryGroupActivity[0]?.activity || 0, - available: group.monthlyCategoryGroupActivity[0]?.available || 0, - subRows, - } - }) - } diff --git a/web/src/components/Spreadsheet/cells.tsx b/web/src/components/Spreadsheet/cells.tsx index 8b0c580..0eeaacc 100644 --- a/web/src/components/Spreadsheet/cells.tsx +++ b/web/src/components/Spreadsheet/cells.tsx @@ -2,9 +2,12 @@ import { useState, useEffect } from 'react' import { type Row, type Getter } from '@tanstack/react-table' import { ChevronDown, ChevronRight } from 'lucide-react' +import type { FindBudgetByMonth } from 'types/graphql' +import { useLocation } from '@redwoodjs/router' import { useMutation } from '@redwoodjs/web' +import { useAuth } from 'src/auth' import { QUERY as FIND_THIS_MONTH_BUDGET } from 'src/components/MonthlyBudgetsCell' import { useSelectedMonth, useSelectedYear } from 'src/lib/store' @@ -93,12 +96,12 @@ export const CEditableCurrency = ({ setValue(initialValue) }, [initialValue]) + const userId = useAuth().currentUser?.id + const budgetId = useLocation().pathname.split('/').pop() const month = useSelectedMonth() const year = useSelectedYear() - const [updateAssignedBudgetForCategory] = useMutation(UPDATE_BUDGET, { - refetchQueries: [FIND_THIS_MONTH_BUDGET], - }) + const [updateAssignedBudgetForCategory] = useMutation(UPDATE_BUDGET) const onBlur = () => { setValue(format(value)) @@ -110,6 +113,59 @@ export const CEditableCurrency = ({ year, input: { assigned: convertToFloat(value) }, }, + update: (cache) => { + const existingData = cache.readQuery({ + query: FIND_THIS_MONTH_BUDGET, + variables: { + month, + year, + budgetId, + userId, + }, + }) + + const { parent, me } = (existingData?.monthlyBudget || []).reduce( + (acc, group) => { + if (!acc.parent) { + const subRow = group.subRows.find( + (subRow) => subRow.id === row.original.id + ) + if (subRow) { + acc.parent = group + acc.me = subRow + } + } + return acc + }, + { parent: null, me: null } + ) + + const changes = convertToFloat(value) - me.assigned + + cache.modify({ + id: cache.identify(me), + fields: { + assigned(cachedAssigned) { + return cachedAssigned + changes + }, + available(cachedAvailable) { + return cachedAvailable + changes + }, + }, + }) + + cache.modify({ + id: cache.identify(parent), + fields: { + assigned(cachedAssigned) { + return cachedAssigned + changes + }, + available(cachedAvailable) { + return cachedAvailable + changes + }, + }, + }) + }, }) } } diff --git a/web/src/components/Spreadsheet/columns.tsx b/web/src/components/Spreadsheet/columns.tsx index e1ecc5f..1da8851 100644 --- a/web/src/components/Spreadsheet/columns.tsx +++ b/web/src/components/Spreadsheet/columns.tsx @@ -12,6 +12,7 @@ import { HExpand, HCheckbox } from './header' // This type is used to define the shape of our data. // You can use a Zod schema here if you want. export type MonthlyBudget = { + __typename?: string id: string category: string assigned: number