
Next Js Tutorial #12 - Ecommerce App - Edit Profile Page & Api Route
We created edit profile page and api route.

You can also watch the YouTube video:
Next Js Tutorial #12 | Ecommerce App - Edit Profile Page & Api Route
Edit schema.prisma
in prisma
folder:
// We added fullName and address field to our User model
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
password String
fullName String?
address String?
role UserRole @default(USER)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
orders Order[]
}
Push the new schema to our database:
npx prisma db push
Create route.js
in app/api/auth/edit-profile
folder:
import { NextResponse } from "next/server";
import { PrismaClient } from "@prisma/client";
import { cookies } from "next/headers";
import jwt from "jsonwebtoken";
import bcrypt from "bcrypt";
const prisma = new PrismaClient();
export async function PUT(request) {
const body = await request.json();
const { email, password, fullName, address } = body;
if (!email) {
return NextResponse.json(
{ error: "You must enter valid email address!" },
{ status: 200 }
);
}
try {
const tokenCookie = await cookies();
const getToken = tokenCookie.get("token");
if (getToken) {
const token = jwt.verify(getToken.value, "appSecret");
const userId = token.id;
if (!userId) {
return NextResponse.json(
{ error: "Unauthorized request!" },
{ status: 200 }
);
}
const user = await prisma.user.findUnique({ where: { id: userId } });
if (!user) {
return NextResponse.json(
{ error: "Unauthorized request!" },
{ status: 200 }
);
}
let updatedUser;
if (password) {
const hash = await bcrypt.hash(password, 10);
updatedUser = await prisma.user.update({
data: {
email,
password: hash,
fullName,
address,
},
where: {
id: user.id,
},
});
} else {
updatedUser = await prisma.user.update({
data: {
email,
fullName,
address,
},
where: {
id: user.id,
},
});
}
return NextResponse.json(updatedUser, { status: 201 });
}
return NextResponse.json(
{ error: "Unauthorized request!" },
{ status: 200 }
);
} catch (error) {
console.log(error.message);
return NextResponse.json(
{ error: "Failed to update user" },
{ status: 500 }
);
} finally {
await prisma.$disconnect();
}
}
Create page.js
in app/auth/edit-profile
folder:
"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useCurrentUser } from "@/contexts/CurrentUserContext";
import { Loader2 } from "lucide-react";
const EditProfilePage = () => {
const { currentUser } = useCurrentUser();
const [email, setEmail] = useState(currentUser?.email || "");
const [password, setPassword] = useState("");
const [fullName, setFullName] = useState(currentUser?.fullName || "");
const [address, setAddress] = useState(currentUser?.address || "");
const [errorMsg, setErrorMsg] = useState("");
const [loading, setLoading] = useState(false);
const handleSubmit = async () => {
try {
setLoading(true);
const response = await fetch("/api/auth/edit-profile", {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
fullName,
address,
}),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.error) {
setErrorMsg(data.error);
setTimeout(() => {
setErrorMsg("");
}, 4000);
} else {
window.location.reload();
}
return data;
} catch (error) {
console.error("There was a problem with the fetch operation:", error);
} finally {
setLoading(false);
}
};
return (
<section>
<div className="py-8 px-4 mx-auto max-w-2xl lg:py-16">
<h1 className="mb-4 text-2xl font-bold text-gray-900 dark:text-white">
Edit Profile
</h1>
{errorMsg ? (
<div
className="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50"
role="alert"
>
<span className="font-medium">Error:</span>
{errorMsg}
</div>
) : undefined}
<div>
<div className="grid gap-4 sm:grid-cols-2 sm:gap-6">
<div className="sm:col-span-2">
<Label
htmlFor="email"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Email
</Label>
<Input
type="email"
name="email"
id="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
className="input"
placeholder="Email"
required
/>
</div>
<div className="sm:col-span-2">
<Label
htmlFor="password"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Password
</Label>
<Input
type="password"
name="password"
id="password"
value={password}
onChange={(event) => setPassword(event.target.value)}
className="input"
placeholder="Password"
required
/>
<p className="text-xs text-gray-500 mt-1">
You can leave empty if you don't want to change your password.
</p>
</div>
<div className="sm:col-span-2">
<Label
htmlFor="fullName"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Full Name
</Label>
<Input
type="text"
name="fullName"
id="fullName"
value={fullName}
onChange={(event) => setFullName(event.target.value)}
className="input"
placeholder="Full Name"
required
/>
</div>
<div className="sm:col-span-2">
<Label
htmlFor="address"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Address
</Label>
<Input
type="text"
name="address"
id="address"
value={address}
onChange={(event) => setAddress(event.target.value)}
className="input"
placeholder="Address"
required
/>
</div>
</div>
<Button
disabled={loading}
onClick={handleSubmit}
className="btn mt-6"
>
{loading ? <Loader2 className="w-4 h-4 animate-spin" /> : "Edit"}
</Button>
</div>
</div>
</section>
);
};
export default EditProfilePage;
That's it for this tutorial, we created edit profile page and api route.
Next tutorial we'll create bookmarks page and api route.
0
0