Updating user info in db using forms

I have a basic user model
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
password String
username String @unique
role Role @default(user)
accounts Account[]
sessions Session[]
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
password String
username String @unique
role Role @default(user)
accounts Account[]
sessions Session[]
}
I have a form that allows the user to update email, username, etc. I'm using a simple update method
const updateUser = await prisma.user.update({
where: {
username: username,
},
data: {
username: data.username,
},
});
const updateUser = await prisma.user.update({
where: {
username: username,
},
data: {
username: data.username,
},
});
For those using nextjs, is it best to put this function in a server action or make an api route and call it there?
5 Replies
iPheNoMeNaL-oG
iPheNoMeNaL-oG2mo ago
Also is best to update by id instead of username?
Nurul
Nurul2mo ago
You could go with either of the two options. API routes would be more preferable as it can be called from anywhere in your application, whether it’s from a component, a different page, or even an external service. So, if you are looking for reusability then go with API routes. Server Actions makes more sense if the data is required during page rendering, then it can be more straightforward to handle it in the server action. I would recommend updating via id.
iPheNoMeNaL-oG
iPheNoMeNaL-oG2mo ago
@Nurul (Prisma) Here's what I have setup for using server actions. In page.tsx for profile
import { ProfileForm } from "@/components/forms/profile-form";
import { auth } from "@/auth";
import prisma from "@/lib/prisma";

async function updateUser(id: string, data) {
"use server";
await prisma.user.update({
where: {
id: id,
},
data: {
username: data.username,
},
});
}

export default async function Profile() {
const session = await auth();
return (
<div className="flex min-h-screen w-full flex-col">
<main className="flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10">
<div className="mx-auto grid w-full max-w-6xl gap-2">
<h1 className="text-3xl font-semibold">Settings</h1>
</div>

<ProfileForm session={session} />
</main>
</div>
);
}
import { ProfileForm } from "@/components/forms/profile-form";
import { auth } from "@/auth";
import prisma from "@/lib/prisma";

async function updateUser(id: string, data) {
"use server";
await prisma.user.update({
where: {
id: id,
},
data: {
username: data.username,
},
});
}

export default async function Profile() {
const session = await auth();
return (
<div className="flex min-h-screen w-full flex-col">
<main className="flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10">
<div className="mx-auto grid w-full max-w-6xl gap-2">
<h1 className="text-3xl font-semibold">Settings</h1>
</div>

<ProfileForm session={session} />
</main>
</div>
);
}
I need to pass updateUser as a prop to <ProfileForm updateUser={updateUser}/> right? Then inside my <ProfileForm/> client component I have the submit function of the form as the following
async function onSubmit(data: ProfileFormValues) {
console.log("making sure this is original username", username);
toast({
title: "You submitted the following values:",
description: (
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
</pre>
),
});
// update user using data from the form
}
async function onSubmit(data: ProfileFormValues) {
console.log("making sure this is original username", username);
toast({
title: "You submitted the following values:",
description: (
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
</pre>
),
});
// update user using data from the form
}
Nurul
Nurul2mo ago
I believe you can do that 👍 I would recommend trying it out first and ensure everything is working as expected.
iPheNoMeNaL-oG
iPheNoMeNaL-oG2mo ago
const defaultValues: Partial<ProfileFormValues> = {
bio: "Full stack software engineer interested in web3.",
urls: [
{ value: "https://shadcn.com" },
{ value: "http://twitter.com/something" },
],
};

export function ProfileForm({ session, updateUser }) {
const [username, setUsername] = useState(session.user.username);

useEffect(() => {
console.log("current session data", session);
}, []);

const form = useForm<ProfileFormValues>({
resolver: zodResolver(profileSchema),
defaultValues: {
...defaultValues,
username: username,
},
mode: "onChange",
});

const { fields, append } = useFieldArray({
name: "urls",
control: form.control,
});

async function onSubmit(data: ProfileFormValues) {
console.log("making sure this is original username", username);
toast({
title: "You submitted the following values:",
description: (
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
</pre>
),
});
updateUser(session.user.id, data.username);
}
const defaultValues: Partial<ProfileFormValues> = {
bio: "Full stack software engineer interested in web3.",
urls: [
{ value: "https://shadcn.com" },
{ value: "http://twitter.com/something" },
],
};

export function ProfileForm({ session, updateUser }) {
const [username, setUsername] = useState(session.user.username);

useEffect(() => {
console.log("current session data", session);
}, []);

const form = useForm<ProfileFormValues>({
resolver: zodResolver(profileSchema),
defaultValues: {
...defaultValues,
username: username,
},
mode: "onChange",
});

const { fields, append } = useFieldArray({
name: "urls",
control: form.control,
});

async function onSubmit(data: ProfileFormValues) {
console.log("making sure this is original username", username);
toast({
title: "You submitted the following values:",
description: (
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
</pre>
),
});
updateUser(session.user.id, data.username);
}
server action
async function updateUser(id: string, username: string) {
"use server";
console.log("updating user", id, username);
await prisma.user.update({
where: {
id: id,
},
data: {
username: username,
},
});
}

export default async function Profile() {
const session = await auth();
return (
<div className="flex min-h-screen w-full flex-col">
<main className="flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10">
<div className="mx-auto grid w-full max-w-6xl gap-2">
<h1 className="text-3xl font-semibold">Settings</h1>
</div>
{session && <ProfileForm session={session} updateUser={updateUser} />}
</main>
</div>
);
}
async function updateUser(id: string, username: string) {
"use server";
console.log("updating user", id, username);
await prisma.user.update({
where: {
id: id,
},
data: {
username: username,
},
});
}

export default async function Profile() {
const session = await auth();
return (
<div className="flex min-h-screen w-full flex-col">
<main className="flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10">
<div className="mx-auto grid w-full max-w-6xl gap-2">
<h1 className="text-3xl font-semibold">Settings</h1>
</div>
{session && <ProfileForm session={session} updateUser={updateUser} />}
</main>
</div>
);
}
this work correctly for and username is updated in the db