clemwo
clemwo
TTCTheo's Typesafe Cult
Created by clemwo on 9/28/2023 in #questions
How to call mutate only once on page visit? (For Change Email Confirmation Links)
I'm struggling to get a mutation to fire exactly once in my application. Here's the scenario: when a user decides to reset their email, a token with a random UUID is generated and stored in our database. The new email then receives a confirmation link like base-url.com/email-reset?token={token_uuid}. The user clicks the link and lands on a page that shows a modal, which varies based on whether it's loading, successful, or encounters an error. My goal is to trigger the resetEmail mutation only once, as soon as the token from the URL becomes available. However, I've noticed that the mutation often gets triggered multiple times. This is an issue because the first successful mutation deletes the token from the backend, causing any subsequent mutations to fail and display the error modal although the email change is successful. Here's a code snippet for context:
// By default, a loading modal is displayed
const resetEmail = api.emailReset.resetEmail.useMutation({
onSuccess: () => showSuccessModal(),
onError: () => showErrorModal(),
});
useEffect(() => {
if (query.token && resetEmail.isIdle) {
resetEmail.mutate({ id: query.token });
}
}, [query.token, resetEmail]);
// By default, a loading modal is displayed
const resetEmail = api.emailReset.resetEmail.useMutation({
onSuccess: () => showSuccessModal(),
onError: () => showErrorModal(),
});
useEffect(() => {
if (query.token && resetEmail.isIdle) {
resetEmail.mutate({ id: query.token });
}
}, [query.token, resetEmail]);
I've tried using useState to set a resetEmailTried flag, but that hasn't solved the problem. I suspect this is because React's state doesn't update instantly. Any help or insights would be much appreciated 🙏
12 replies
TTCTheo's Typesafe Cult
Created by clemwo on 9/21/2023 in #questions
How to customize zod union error message?
I have a zod schema like so:
const schema = z.object({
customer: z.union([z.string().uuid(), z.literal("allCustomers"])
})
const schema = z.object({
customer: z.union([z.string().uuid(), z.literal("allCustomers"])
})
How can I customize the error message when customer is undefined?
5 replies
TTCTheo's Typesafe Cult
Created by clemwo on 7/6/2023 in #questions
How to implement redirect based on user role
Hi, I would love to implement redirections based on the user role. I want to implement it so that on every single page, I can explicitly define which roles are allowed to view the current page and the redirect url to which the user will be redirected if he isn't authorized to view the page. Now I have implemented a simple hook which works but the content of the page still flashes before the user gets redirected. What is the recommended way to protect routes in t3-app based on roles?
My implementation: useRoleRedirect.ts:
import { type Role } from "@prisma/client";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { useEffect } from "react";

const useRoleRedirect = (allowedRoles: Role[], redirect: string) => {
const userRole = useSession().data?.user.role;
const router = useRouter();

useEffect(() => {
if (userRole && !allowedRoles.includes(userRole)) {
void router.push(redirect);
}
}, [router, userRole, redirect, allowedRoles]);
};

export default useRoleRedirect;
import { type Role } from "@prisma/client";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { useEffect } from "react";

const useRoleRedirect = (allowedRoles: Role[], redirect: string) => {
const userRole = useSession().data?.user.role;
const router = useRouter();

useEffect(() => {
if (userRole && !allowedRoles.includes(userRole)) {
void router.push(redirect);
}
}, [router, userRole, redirect, allowedRoles]);
};

export default useRoleRedirect;
Usage of hook in other component:
const Page: NextPage = () => {
useRoleRedirect([Role.ADMIN, Role.MANAGER], "/");
...
const Page: NextPage = () => {
useRoleRedirect([Role.ADMIN, Role.MANAGER], "/");
...
Now this thing works but the original content from "Page" still gets flashed which I would like to prevent. I'm also just curious what the standard way of handling this type of problem is. I greatly appreciate any advice 🙂
11 replies
TTCTheo's Typesafe Cult
Created by clemwo on 6/29/2023 in #questions
What's the reason for having the prisma singleton in the context?
On the t3 Stack homepage it says the following:
We include the Prisma Client in Context by default and recommend using this instead of importing it separately in each file.
On the app I'm currently working on I'm implementing a repository pattern so I'm only actually using the prisma object in a handful of repository files. To me this feels like the most sane way of handling database connections that's why I'm wondering why it is included in the context. I'm sure there are good reasons
1 replies
TTCTheo's Typesafe Cult
Created by clemwo on 5/9/2023 in #questions
How to create an object with a mutation. Getting React error `Invalid hook call`
Hi, would be great if I could some help here 🙂 Here is my userRouter, getAll already works without issues. However I dont manage to create objects in my database.
import { createTRPCRouter, publicProcedure } from "../trpc";

export const userRouter = createTRPCRouter({
create: publicProcedure.mutation(async ({ ctx }) => {
return await ctx.prisma.user.create({
data: {
firstName: "Peter",
lastName: "Hansen",
role: "MANAGER",
clientId: "clhg7tzgz0000nhp0zwfmc0jm",
},
});
}),

getAll: publicProcedure.query(({ ctx }) => {
return ctx.prisma.user.findMany();
}),
});
import { createTRPCRouter, publicProcedure } from "../trpc";

export const userRouter = createTRPCRouter({
create: publicProcedure.mutation(async ({ ctx }) => {
return await ctx.prisma.user.create({
data: {
firstName: "Peter",
lastName: "Hansen",
role: "MANAGER",
clientId: "clhg7tzgz0000nhp0zwfmc0jm",
},
});
}),

getAll: publicProcedure.query(({ ctx }) => {
return ctx.prisma.user.findMany();
}),
});
I have a "Create" Page where I get an error when I try to use the mutation to create a User in the database.
import { type NextPage } from "next";
import Header from "~/components/Header/Header";
import { api } from "~/utils/api";

const Create: NextPage = () => {
const createUser = () => {
api.users.create.useMutation();
};
return (
<>
<Header header="Create" />
<p>Create new Users here!</p>
<button onClick={() => createUser()}>Click Me</button>
</>
);
};

export default Create;
import { type NextPage } from "next";
import Header from "~/components/Header/Header";
import { api } from "~/utils/api";

const Create: NextPage = () => {
const createUser = () => {
api.users.create.useMutation();
};
return (
<>
<Header header="Create" />
<p>Create new Users here!</p>
<button onClick={() => createUser()}>Click Me</button>
</>
);
};

export default Create;
The error I get is
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
I appreciate any help I can get, thank you!
3 replies