Skip to content

Commit

Permalink
wrap all data mutations in error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
buckhalt committed Oct 30, 2023
1 parent 4b44c04 commit 72c0db5
Show file tree
Hide file tree
Showing 26 changed files with 335 additions and 179 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ const ActiveProtocolSwitch = ({

const { data: isActive } = api.protocol.getActive.useQuery(hash, {
initialData,
onError: (err) => {
throw new Error(err.message);
},
});

const { mutateAsync: setActive } = api.protocol.setActive.useMutation({
Expand All @@ -33,8 +36,7 @@ const ActiveProtocolSwitch = ({
},
onError: (err, _newState, previousState) => {
utils.protocol.getActive.setData(hash, previousState);
// eslint-disable-next-line no-console
console.error(err);
throw new Error(err.message);
},
onSuccess: () => {
router.refresh();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const AnonymousRecruitmentSwitch = ({
const { data: allowAnonymousRecruitment } =
api.appSettings.get.allowAnonymousRecruitment.useQuery(undefined, {
initialData,
onError(error) {
throw new Error(error.message);
},
});

const { mutateAsync: updateAnonymousRecruitment } =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import { useState } from 'react';
import { DeleteInterviewsDialog } from '../../interviews/_components/DeleteInterviewsDialog';

export const InterviewsTable = () => {
const interviews = api.interview.get.all.useQuery();
const interviews = api.interview.get.all.useQuery(undefined, {
onError(error) {
throw new Error(error.message);
},
});

const [interviewsToDelete, setInterviewsToDelete] = useState<Interview[]>();
const [showDeleteModal, setShowDeleteModal] = useState(false);
Expand Down
16 changes: 0 additions & 16 deletions app/(dashboard)/dashboard/_components/ParticipantsTable/Loader.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ export const ParticipantsTable = ({
initialData,
refetchOnMount: false,
onError(error) {
// eslint-disable-next-line no-console
console.error(error);
throw new Error(error.message);
},
},
Expand Down
10 changes: 8 additions & 2 deletions app/(dashboard)/dashboard/_components/ProtocolUploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,14 @@ export default function ProtocolUploader({
setOpen(false);
}

const { data: lastUploadedProtocol } =
api.protocol.get.lastUploaded.useQuery();
const { data: lastUploadedProtocol } = api.protocol.get.lastUploaded.useQuery(
undefined,
{
onError(error) {
throw new Error(error.message);
},
},
);

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ export const ProtocolsTable = ({
initialData,
refetchOnMount: false,
onError(error) {
// eslint-disable-next-line no-console
console.error(error);
throw new Error(error.message);
},
},
);
Expand Down
6 changes: 5 additions & 1 deletion app/(dashboard)/dashboard/_components/ResetButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import { Button } from '~/components/ui/Button';
const ResetButton = () => {
const [loading, setLoading] = useState(false);
const router = useRouter();
const { mutateAsync: resetConfigured } = api.appSettings.reset.useMutation();
const { mutateAsync: resetConfigured } = api.appSettings.reset.useMutation({
onError(error) {
throw new Error(error.message);
},
});

const reset = async () => {
setLoading(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ export const DeleteInterviewsDialog = ({
}: DeleteInterviewsDialog) => {
const [hasUnexported, setHasUnexported] = useState<boolean>(false);
const { mutateAsync: deleteInterviews, isLoading: isDeleting } =
api.interview.delete.useMutation();
api.interview.delete.useMutation({
onError(error) {
throw new Error(error.message);
},
});
const utils = api.useUtils();

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export const DeleteAllParticipantsButton = () => {
await utils.participant.get.all.refetch();
setShowAlertDialog(false);
},
onError(error) {
throw new Error(error.message);
},
});
return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ export const DeleteParticipantsDialog = ({
});
}, [participantsToDelete]);
const { mutateAsync: deleteParticipants, isLoading: isDeleting } =
api.participant.delete.byId.useMutation();
api.participant.delete.byId.useMutation({
onError(error) {
throw new Error(error.message);
},
});
const utils = api.useUtils();

const handleConfirm = async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ const ImportCSVModal = ({
const methods = useZodForm({ schema: formSchema, shouldUnregister: true });
const utils = api.useUtils();
const { mutateAsync: importParticipants } =
api.participant.create.useMutation();
api.participant.create.useMutation({
onError(error) {
throw new Error(error.message);
},
});
const isSubmitting = methods.formState.isSubmitting;
const [showImportDialog, setShowImportDialog] = useState(false);
const selectedCSV = methods.watch('csvFile');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ export const DeleteProtocolsDialog = ({
});
}, [protocolsToDelete]);
const { mutateAsync: deleteProtocols, isLoading: isDeleting } =
api.protocol.delete.byHash.useMutation();
api.protocol.delete.byHash.useMutation({
onError(error) {
throw new Error(error.message);
},
});

const utils = api.useUtils();
const handleConfirm = async () => {
Expand Down
26 changes: 15 additions & 11 deletions app/(dashboard)/dashboard/protocols/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ import { ProtocolsTable } from '~/app/(dashboard)/dashboard/_components/Protocol
import { api } from '~/trpc/server';

const ProtocolsPage = async () => {
const protocols = await api.protocol.get.all.query(undefined, {
context: {
revalidate: 0,
},
});
return (
<div className="rounded-lg bg-white p-6">
<h2 className="mb-6 text-2xl font-bold">Protocols management view</h2>
<ProtocolsTable initialData={protocols} />
</div>
);
try {
const protocols = await api.protocol.get.all.query(undefined, {
context: {
revalidate: 0,
},
});
return (
<div className="rounded-lg bg-white p-6">
<h2 className="mb-6 text-2xl font-bold">Protocols management view</h2>
<ProtocolsTable initialData={protocols} />
</div>
);
} catch (error) {
throw new Error('An error occurred while fetching protocols');
}
};

export default ProtocolsPage;
14 changes: 5 additions & 9 deletions app/(onboard)/_components/OnboardWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,12 @@ function OnboardWizard() {
const step = searchParams.get('step');
const stepInt = parseInt(step ?? '1', 10);

const { data: expired, error } = api.appSettings.get.expired.useQuery(
undefined,
{
refetchInterval: 1000 * 10,
const { data: expired } = api.appSettings.get.expired.useQuery(undefined, {
refetchInterval: 1000 * 10,
onError(error) {
throw new Error(error.message);
},
);

if (error) {
throw new Error(error.message);
}
});

useEffect(() => {
if (expired) {
Expand Down
3 changes: 3 additions & 0 deletions app/(onboard)/expired/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export default function Page() {

window.location.replace('/setup');
},
onError(error) {
throw new Error(error.message);
},
},
);

Expand Down
32 changes: 32 additions & 0 deletions app/api/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use client'; // Error components must be Client components

import { useEffect } from 'react';
import { Button } from '~/components/ui/Button';
import { AlertTriangle } from 'lucide-react';

export default function Error({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
useEffect(() => {
// Log the error to an error reporting service
// eslint-disable-next-line no-console
console.error(error);
}, [error]);

return (
<div className="mx-auto my-4 flex max-w-md flex-col items-center rounded-lg border border-destructive p-4 text-center">
<AlertTriangle className="mb-2 h-12 w-12 text-destructive" />
<h2 className="mb-2 text-2xl font-semibold text-destructive">
API Error
</h2>
<p className="text-sm">{error.message}</p>
<div className="mt-4">
<Button onClick={() => reset()}>Try Again</Button>
</div>
</div>
);
}
32 changes: 32 additions & 0 deletions app/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use client'; // Error components must be Client components

import { useEffect } from 'react';
import { Button } from '~/components/ui/Button';
import { AlertTriangle } from 'lucide-react';

export default function Error({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
useEffect(() => {
// Log the error to an error reporting service
// eslint-disable-next-line no-console
console.error(error);
}, [error]);

return (
<div className="mx-auto my-4 flex max-w-md flex-col items-center rounded-lg border border-destructive p-4 text-center">
<AlertTriangle className="mb-2 h-12 w-12 text-destructive" />
<h2 className="mb-2 text-2xl font-semibold text-destructive">
Root Layout Error
</h2>
<p className="text-sm">{error.message}</p>
<div className="mt-4">
<Button onClick={() => reset()}>Try Again</Button>
</div>
</div>
);
}
37 changes: 20 additions & 17 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,26 @@ export const dynamic = 'force-dynamic';
async function RootLayout({ children }: { children: React.ReactNode }) {
const session = await getServerSession();

const { configured, expired } =
await api.appSettings.get.allappSettings.query();

return (
<html lang="en">
<body>
<RedirectWrapper
configured={configured}
expired={expired}
session={session}
>
<Providers initialSession={session}>{children}</Providers>
<Toaster />
</RedirectWrapper>
</body>
</html>
);
try {
const { configured, expired } =
await api.appSettings.get.allappSettings.query();
return (
<html lang="en">
<body>
<RedirectWrapper
configured={configured}
expired={expired}
session={session}
>
<Providers initialSession={session}>{children}</Providers>
<Toaster />
</RedirectWrapper>
</body>
</html>
);
} catch (error) {
throw new Error('Failed to fetch app settings');
}
}

export default RootLayout;
5 changes: 2 additions & 3 deletions app/not-found.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ export default function NotFound() {
};
return (
<div className="flex h-screen flex-col items-center justify-center bg-gray-100">
<FileWarning className="mb-4 h-12 w-12 text-violet-600" />
<FileWarning className="mb-4 h-12 w-12 text-violet-700" />
<h1 className="text-3xl font-extrabold text-violet-700">404</h1>
<p className="text-lg text-gray-700">Page not found</p>
<Button
variant="outline"
className="mt-4 bg-violet-600 text-white hover:bg-violet-700"
className="mt-4 bg-violet-600 hover:bg-violet-800"
onClick={redirectToDashboard}
>
Back to Dashboard
Expand Down
6 changes: 5 additions & 1 deletion providers/InterviewProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ function InterviewProvider({
);
const [initialized, setInitialized] = useState(false);
const { network, networkHandlers } = useNetwork(initialNetwork);
const { mutate: updateNetwork } = api.interview.updateNetwork.useMutation();
const { mutate: updateNetwork } = api.interview.updateNetwork.useMutation({
onError: (error) => {
throw new Error(error.message);
},
});

const stages = protocol.stages;
const protocolStageCount = stages.length;
Expand Down
8 changes: 5 additions & 3 deletions providers/SessionProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ export const SessionProvider = ({
setSession(null);
}
},
onError: (error) => {
throw new Error(error.message);
},
});

// If we have an initial session, we don't need to fetch it again.
Expand All @@ -56,10 +59,9 @@ export const SessionProvider = ({
return;
}

getSession().catch((err) => {
// eslint-disable-next-line no-console
console.error(err);
getSession().catch((err: { message: string | undefined }) => {
setSession(null);
throw new Error(err.message);
});
}, [initialSession, getSession]);

Expand Down
Loading

0 comments on commit 72c0db5

Please sign in to comment.