Skip to content

Commit

Permalink
feat: 34 - 35 - better feedback after actions (#65)
Browse files Browse the repository at this point in the history
* feat: 43 - updated policies

* feat: 34 - 35 - better feedback after actions
  • Loading branch information
dsaltares committed Jul 15, 2023
1 parent 44359cb commit b70fe01
Show file tree
Hide file tree
Showing 20 changed files with 259 additions and 10 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"next-auth": "^4.22.1",
"node-fetch": "2",
"nodemailer": "^6.9.3",
"notistack": "^3.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.45.1",
Expand Down
4 changes: 2 additions & 2 deletions src/components/AccountList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { useMemo } from 'react';
import useDialogForId from '@lib/useDialogForId';
import useDialogFromUrl from '@lib/useDialogFromUrl';
import type { Account } from '@server/account/types';
import useDeleteAccount from '@lib/accounts/useDeleteCategory';
import useUpdateAccount from '@lib/accounts/useUpdateCategory';
import useDeleteAccount from '@lib/accounts/useDeleteAccount';
import useUpdateAccount from '@lib/accounts/useUpdateAccount';
import type { CSVImportPreset } from '@server/csvImportPreset/types';
import ConfirmationDialog from './ConfirmationDialog';
import AccountListItem from './AccountListItem';
Expand Down
6 changes: 4 additions & 2 deletions src/components/TransactionTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,12 @@ const TransactionTable = ({
useDeleteTransactions();
const handleSingleDelete = () =>
deleteOpenFor ? deleteTransactions({ ids: [deleteOpenFor] }) : undefined;
const handleMultiDelete = () =>
deleteTransactions({
const handleMultiDelete = async () => {
await deleteTransactions({
ids: table.getSelectedRowModel().flatRows.map((row) => row.original.id),
});
onRowSelectionChange({});
};
const { mutateAsync: updateTransactions, isLoading: isMultiUpdating } =
useUpdateTransactions();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.createAccount.useMutation>[0];
Expand All @@ -8,6 +9,20 @@ const useCreateAccount = (options?: Options) => {
const queryClient = useQueryClient();
return client.createAccount.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: 'Account created.',
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: 'Failed to create account.',
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.deleteAccount.useMutation>[0];
Expand All @@ -8,6 +9,20 @@ const useDeleteAccount = (options?: Options) => {
const queryClient = useQueryClient();
return client.deleteAccount.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: 'Account deleted.',
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: 'Failed to delete account.',
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.updateAccount.useMutation>[0];
Expand All @@ -8,6 +9,20 @@ const useUpdateAccount = (options?: Options) => {
const queryClient = useQueryClient();
return client.updateAccount.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: 'Account updated.',
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: 'Failed to update account.',
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
15 changes: 15 additions & 0 deletions src/lib/categories/useCreateCategory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.createCategory.useMutation>[0];
Expand All @@ -8,6 +9,20 @@ const useCreateCategory = (options?: Options) => {
const queryClient = useQueryClient();
return client.createCategory.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: 'Category created.',
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: 'Failed to create category.',
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
15 changes: 15 additions & 0 deletions src/lib/categories/useDeleteCategory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.deleteCategory.useMutation>[0];
Expand All @@ -8,6 +9,20 @@ const useDeleteCategory = (options?: Options) => {
const queryClient = useQueryClient();
return client.deleteCategory.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: 'Category deleted.',
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: 'Failed to delete category.',
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
15 changes: 15 additions & 0 deletions src/lib/categories/useUpdateCategory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.updateCategory.useMutation>[0];
Expand All @@ -8,6 +9,20 @@ const useUpdateCategory = (options?: Options) => {
const queryClient = useQueryClient();
return client.updateCategory.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: 'Category updated.',
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: 'Failed to update category.',
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
15 changes: 15 additions & 0 deletions src/lib/csvImportPresets/useCreateCSVImportPreset.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.createCSVImportPreset.useMutation>[0];
Expand All @@ -8,6 +9,20 @@ const useCreateCSVImportPreset = (options?: Options) => {
const queryClient = useQueryClient();
return client.createCSVImportPreset.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: 'Import preset created.',
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: 'Failed to create import preset.',
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
15 changes: 15 additions & 0 deletions src/lib/csvImportPresets/useDeleteCSVImportPreset.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.deleteCSVImportPreset.useMutation>[0];
Expand All @@ -8,6 +9,20 @@ const useDeleteCSVImportPreset = (options?: Options) => {
const queryClient = useQueryClient();
return client.deleteCSVImportPreset.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: 'Import preset deleted.',
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: 'Failed to delete import preset.',
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
15 changes: 15 additions & 0 deletions src/lib/csvImportPresets/useUpdateCSVImportPreset.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.updateCSVImportPreset.useMutation>[0];
Expand All @@ -8,6 +9,20 @@ const useUpdateCSVImportPreset = (options?: Options) => {
const queryClient = useQueryClient();
return client.updateCSVImportPreset.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: 'Import preset updated.',
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: 'Failed to update import preset.',
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
15 changes: 15 additions & 0 deletions src/lib/transactions/useCreateTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.createTransaction.useMutation>[0];
Expand All @@ -8,6 +9,20 @@ const useCreateTransaction = (options?: Options) => {
const queryClient = useQueryClient();
return client.createTransaction.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: 'Transaction created.',
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: 'Failed to create transaction.',
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
19 changes: 19 additions & 0 deletions src/lib/transactions/useDeleteTransactions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/api';

type Options = Parameters<typeof client.deleteTransactions.useMutation>[0];
Expand All @@ -8,6 +9,24 @@ const useDeleteTransactions = (options?: Options) => {
const queryClient = useQueryClient();
return client.deleteTransactions.useMutation({
...options,
onSuccess: (...args) => {
enqueueSnackbar({
message: `Deleted ${args[1].ids.length} ${
args[1].ids.length > 1 ? 'transactions' : 'transaction'
}.`,
variant: 'success',
});
return options?.onSuccess?.apply(this, args);
},
onError: (...args) => {
enqueueSnackbar({
message: `Failed to delete ${args[1].ids.length} ${
args[1].ids.length > 1 ? 'transactions' : 'transaction'
}.`,
variant: 'error',
});
return options?.onError?.apply(this, args);
},
onSettled: (...args) =>
Promise.all([
options?.onSettled?.apply(this, args),
Expand Down
31 changes: 27 additions & 4 deletions src/lib/transactions/useImportTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,35 @@ import { type ChangeEventHandler, useCallback, useMemo, useRef } from 'react';
import { parse } from 'csv-parse/sync';
import parseDate from 'date-fns/parse';
import { useRouter } from 'next/router';
import { enqueueSnackbar } from 'notistack';
import { TRPCClientError } from '@trpc/client';
import Routes from '@lib/routes';
import type { Account } from '@server/account/types';
import useCreateTransactions from '@lib/transactions/useCreateTransactions';
import client from '../api';

const useImportTransactions = (account: Account) => {
const router = useRouter();
const { mutateAsync: createTransactions, isLoading } =
useCreateTransactions();
const { mutateAsync: createTransactions, isLoading } = useCreateTransactions({
onSuccess: (numTransactions: number) => {
enqueueSnackbar({
message: `Imported ${numTransactions} transactions.`,
variant: 'success',
});
},
onError: (e) => {
const isBadlyFormedRequest =
e instanceof TRPCClientError && e.data.cause === 'BAD_REQUEST';
enqueueSnackbar({
message: `Failed to import transactions.${
isBadlyFormedRequest
? ' Either the import preset or the file are invalid.'
: ''
}`,
variant: 'error',
});
},
});
const { data: presets } = client.getCSVImportPresets.useQuery();
const { data: categories } = client.getCategories.useQuery();
const preset = useMemo(
Expand Down Expand Up @@ -79,8 +99,11 @@ const useImportTransactions = (account: Account) => {
});
void router.push(Routes.transactionsForAccount(account.id));
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
enqueueSnackbar({
message:
'Failed to process file. Check the import preset and the file.',
variant: 'error',
});
}
},
[preset, categories, createTransactions, account.id, router]
Expand Down
Loading

0 comments on commit b70fe01

Please sign in to comment.