I am having trouble registering and the problem occurs when uploading an image file using Multer in my Express.js application in the form.
I am getting an error "MulterError: Unexpected field" when trying to upload an image file from the frontend. The problem occurs only the first time, and when I submit the same image again, the registering is successful.
the error:
[server] Multer Error: MulterError: Unexpected field
[server] at wrappedFileFilter (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\multer\index.js:40:19)
[server] at Multipart.<anonymous> (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\multer\lib\make-middleware.js:107:7)
[server] at Multipart.emit (node:events:518:28)
[server] at HeaderParser.cb (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\busboy\lib\types\multipart.js:358:14)
[server] at HeaderParser.push (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\busboy\lib\types\multipart.js:162:20)
[server] at SBMH.ssCb [as _cb] (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\busboy\lib\types\multipart.js:394:37)
[server] at feed (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\streamsearch\lib\sbmh.js:248:10)
[server] at SBMH.push (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\streamsearch\lib\sbmh.js:104:16)
[server] at Multipart._write (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\busboy\lib\types\multipart.js:567:19)
[server] at writeOrBuffer (node:internal/streams/writable:572:12) {
[server] code: 'LIMIT_UNEXPECTED_FILE',
[server] field: 'avatar',
[server] storageErrors: []
[server] }
my files:
store.ts:
/* eslint-disable @typescript-eslint/no-explicit-any */
import { create } from "zustand";
import { persist } from "zustand/middleware";
// import axios from "axios";
import { ProductProps } from "../../type";
import { config } from "../config";
import { getDataWithToken, loginpostData, regpostData } from ".";
interface APIResponse {
token?: string;
errors?: { msg: string }[]; //user.js - 23
}
interface CartProduct extends ProductProps {
quantity: number;
}
interface UserType {
firstName: string;
lastName: string;
password: string;
email: string;
avatar: string;
id: string;
}
interface StoreType {
// user
currentUser: UserType | null;
isLoading: boolean;
// isAuthonticated: null;
// token: localStorage.getItem("token");
// registerUser: (userData: FormData) => Promise<void>;
registerUser: (userData: FormData) => Promise<APIResponse>; // ✅ تحديث التوقيع ليعيد APIResponse
loginUser: (userData: FormData) => Promise<APIResponse>; // ✅ تحديث التوقيع ليعيد APIResponse
logoutUser: () => void;
// getUserInfo: (userId: string) => Promise<void>;
getUserInfo: () => Promise<void>;
// cart
cartProduct: CartProduct[];
addToCart: (product: ProductProps) => void;
decreaseQuantity: (productId: string) => void;
removeFromCart: (productId: string) => void;
resetCart: () => void;
// favorite
favoriteProduct: CartProduct[];
addToFavorite: (product: ProductProps) => void;
removeFromFavourite: (productId: string) => void;
resetFavorite: () => void;
}
const customStorage = {
getItem: (name: string) => {
const item = localStorage.getItem(name);
return item ? JSON.parse(item) : null;
},
setItem: (name: string, value: any) => {
localStorage.setItem(name, JSON.stringify(value));
},
removeItem: (name: string) => {
localStorage.removeItem(name);
},
};
export const Store = create<StoreType>()(
persist(
(set) => ({
currentUser: null,
isLoading: true,
cartProduct: [],
favoriteProduct: [],
registerUser: async (userData: FormData): Promise<APIResponse> => {
try {
set({ isLoading: true });
const data = await regpostData(
`${config.baseUrl}/api/users/register`,
userData
);
set({ currentUser: data, isLoading: false });
return data; // ✅ إرجاع البيانات بعد التسجيل
} catch (error: any) {
console.error("Error registering user", error);
set({ currentUser: null, isLoading: false });
console.error("error.response?.data", error.response?.data);
return error.response?.data;
}
},
loginUser: async (userData: FormData): Promise<APIResponse> => {
try {
set({ isLoading: true });
const data = await loginpostData(
`${config.baseUrl}/api/users/login`,
userData
);
if (data.token) {
localStorage.setItem("token", data.token);
set({ currentUser: data, isLoading: false });
}
// set({ currentUser: data, isLoading: false });
console.log(data);
return data; // ✅ إرجاع البيانات بعد التسجيل
} catch (error: any) {
set({ currentUser: null, isLoading: false });
console.error("error.response?.data", error.response?.data);
return error.response?.data;
}
},
logoutUser: () => {
set({ currentUser: null }); // مسح معلومات المستخدم
localStorage.removeItem("token"); // حذف الرمز المميز من التخزين المحلي
},
getUserInfo: async () => {
try {
set({ isLoading: true });
const token = localStorage.getItem("token"); // الحصول على التوكن من localStorage
if (!token) {
throw new Error("No token found"); // إذا لم يتم العثور على التوكن
}
const data = await getDataWithToken(`${config.baseUrl}/api/users`, token); // استخدام الدالة الجديدة مع التوكن
set({ currentUser: data, isLoading: false });
} catch (error) {
console.error("Error fetching user info", error);
set({ currentUser: null, isLoading: false });
}
},
addToCart: (product) => {
set((state) => {
const existingProduct = state.cartProduct.find(
(p) => p._id === product._id
);
return {
cartProduct: existingProduct
? state.cartProduct.map((p) =>
p._id === product._id ? { ...p, quantity: p.quantity + 1 } : p
)
: [...state.cartProduct, { ...product, quantity: 1 }],
};
});
},
decreaseQuantity: (productId) => {
set((state) => ({
// cartProduct: state.cartProduct.map((p) => p._id === productId ? { ...p, quantity: Math.max(p.quantity - 1, 1) } : p),
cartProduct: state.cartProduct.map((p) =>
String(p._id) === String(productId)
? { ...p, quantity: Math.max(p.quantity - 1, 1) }
: p
),
}));
},
removeFromCart: (productId) => {
set((state) => ({
// cartProduct: state.cartProduct.filter((item) => item._id !== productId),
cartProduct: state.cartProduct.filter(
(item) => String(item._id) !== String(productId)
),
}));
},
resetCart: () => {
set({ cartProduct: [] });
},
addToFavorite: (product) => {
set((state) => {
const isFavorite = state.favoriteProduct.some(
(item) => item._id === product._id
);
return {
favoriteProduct: isFavorite
? state.favoriteProduct.filter((item) => item._id !== product._id)
: [...state.favoriteProduct, { ...product }],
};
});
},
removeFromFavourite: (productId) => {
set((state) => ({
// favoriteProduct: state.favoriteProduct.filter((item) => item._id !== productId),
favoriteProduct: state.favoriteProduct.filter(
(item) => String(item._id) !== String(productId)
),
}));
},
resetFavorite: () => {
set({ favoriteProduct: [] });
},
}),
{
name: "supergear-storage",
storage: customStorage,
}
)
);
user.js:
const express = require("express");
const router = express.Router();
const { check, validationResult } = require("express-validator");
const User = require("../models/User");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const config = require("config");
const {auth, upload} = require("../utils/");
router.post(
"/register",
(req, res, next) => {
upload(req, res, (err) => {
if (err) {
console.error("Multer Error:", err);
return res.status(500).json({ error: "Multer error", details: err.message }); // إضافة رسالة خطأ مفصلة
}
next();
});
},
// upload, // قم بتطبيق multer كـ middleware
check("name", "name is required").notEmpty(),
check("Lname", "name is required").notEmpty(),
check("email", "please include valid email").isEmail(),
check(
"password",
"please choose a password with atleast 6 characters"
).isLength({ min: 6 }),
async (req, res) => {
console.log("req.file بعد Multer:", req.file); // تسجيل req.file بعد Multer
console.log("req.files بعد Multer:", req.files); // تسجيل req.files بعد Multer
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log("Validation Errors:", errors.array());
return res.status(400).json({ errors: errors.array() });
}
const { name, Lname, email, password } = req.body;
console.log(name, Lname, email, password );
try {
let user = await User.findOne({ email });
if (user) {
return res
.status(400)
.json({ errors: [{ msg: "User already exists" }] });
}
console.log("req.body:", req.body); // تسجيل req.body
const avatar = req.file ? `/images/${req.file.filename}` : ""; // رابط الصورة
console.log( "avatar = req.file ?",avatar );
user = new User({ name, Lname, email, password, avatar });
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
const payload = {
user: {
id: user.id,
},
};
jwt.sign(
payload,
config.get("jwtSecret"),
{ expiresIn: "5 days" },
(err, token) => {
if (err) throw err;
else {
res.json({ token });
}
}
);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
// res.send("success in sending data");
}
);
router.post(
"/login",
check("email", "please include valid email").isEmail(),
check(
"password",
"please choose a password with atleast 6 characters"
).isLength({ min: 6 }),
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email, password } = req.body;
try {
let user = await User.findOne({ email });
if (!user) {
return res
.status(400)
.json({ errors: [{ msg: "invalid condentials - email not found" }] });
}
const isMatch = await bcryptpare(password, user.password);
if (!isMatch) {
return res
.status(400)
.json({ errors: [{ msg: "invalid condentials - wrong password" }] });
}
const payload = {
user: {
id: user.id,
},
};
jwt.sign(
payload,
config.get("jwtSecret"),
{ expiresIn: "5 days" },
(err, token) => {
if (err) throw err;
else {
res.json({ token });
}
}
);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
// res.send("success in sending data");
}
);
/* takes a token and returns user info private */
router.get("/",auth, async(req, res) => {
try {
const user = await User.findById(req.user.id).select("-password");
res.json(user);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
})
module.exports = router;
regestration.tsx:
import { useState } from "react";
import { MdPhotoLibrary } from "react-icons/md";
import Login from "./Login";
import Label from "./Label";
// import upload from "../lib/upload";
import { Store } from "../lib/store";
const Registeration = () => {
const [login, setLogin] = useState(true);
const [loading, setLoading] = useState(false);
const [errMsg, setErrMsg] = useState("");
const [Avatar, setAvatar] = useState({
file: null,
url: "",
});
const handleAvatar = (e: any) => {
if (e.target.files[0]) {
setAvatar({
file: e.target.files[0],
url: URL.createObjectURL(e.target.files[0]),
});
}
};
const handleRegistration = async (e: any) => {
e.preventDefault();
setErrMsg(""); // تصفير أي خطأ سابق
const formData = new FormData(e.target);
console.log("FormData entries:", Array.from(formData.entries())); // تسجيل formData entries
if (Avatar.file) {
formData.append("avatar", Avatar.file);
console.log( "avatar", Avatar.file );
}
try {
setLoading(true);
const response = await Store.getState().registerUser(formData);
if (response.errors && response.errors.length > 0) {
setErrMsg(response.errors[0].msg); // عرض الخطأ في الواجهة
return; // منع الانتقال إلى صفحة تسجيل الدخول
}
setLogin(true);
} catch (error: any) {
console.error("Error:", error);
setErrMsg(error.message || "Something went wrong");
} finally {
setLoading(false);
}
};
return (
<div>
{login ? (
<Login setLogin={setLogin} />
) : (
<div className="bg-gray-950 rounded-lg">
<form
onSubmit={handleRegistration}
className="max-w-5xl mx-auto pt-10 px-10 lg:px-0 text-white"
>
<div className="border-b border-b-white/10 pb-5">
<h2 className="text-lg font-semibold uppercase leading-7">
Registration Form
</h2>
<p className="mt-1 text-sm leading-6 text-gray-400">
You need to provide required information to get register with
us.
</p>
</div>
<div className="border-b border-b-white/10 pb-5">
<div className="mt-5 grid grid-cols-1 gap-x-6 gap-y-5 sm:grid-cols-6">
<div className="sm:col-span-3">
<Label title="name" htmlFor="name" />
<input
type="text"
name="name"
className="block w-full rounded-md border-0 bg-white/5 py-1.5 px-4 outline-none text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-skyText sm:text-sm sm:leading-6 mt-2"
/>
</div>
<div className="sm:col-span-3">
<Label title="Last name" htmlFor="lastName" />
<input
type="text"
name="Lname"
className="block w-full rounded-md border-0 bg-white/5 py-1.5 px-4 outline-none text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-skyText sm:text-sm sm:leading-6 mt-2"
/>
</div>
<div className="sm:col-span-4">
<Label title="Email address" htmlFor="email" />
<input
type="email"
name="email"
className="block w-full rounded-md border-0 bg-white/5 py-1.5 px-4 outline-none text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-skyText sm:text-sm sm:leading-6 mt-2"
/>
</div>
<div className="sm:col-span-4">
<Label title="Password" htmlFor="password" />
<input
type="password"
name="password"
className="block w-full rounded-md border-0 bg-white/5 py-1.5 px-4 outline-none text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-skyText sm:text-sm sm:leading-6 mt-2"
/>
</div>
<div className="col-span-full">
<div className="mt-2 flex items-center gap-x-3">
<div className="flex-1">
<Label title="Cover photo" />
<div className="mt-2 flex justify-center rounded-lg border border-dashed border-white/25 px-6 py-4">
<div className="flex flex-col items-center text-center">
<div className="w-14 h-14 border border-gray-600 rounded-full p-1">
{Avatar?.url ? (
<img
src={Avatar?.url}
alt="userImage"
className="w-full h-full rounded-full object-cover"
/>
) : (
<MdPhotoLibrary className="mx-auto h-full w-full text-gray-500" />
)}
</div>
<div className="mt-4 flex items-center mb-1 text-sm leading-6 text-gray-400">
<label htmlFor="file-upload">
<span className="relative cursor-pointer rounded-md px-2 py-1 bg-gray-900 font-semibold text-gray-200 hover:bg-gray-800">
Upload a file
</span>
<input
type="file"
name="avatar"
id="file-upload"
className="sr-only"
onChange={handleAvatar}
/>
</label>
<p className="pl-1">or drag and drop</p>
</div>
<p className="text-xs leading-5 text-gray-400">
PNG, JPG, GIF up to 10MB
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{errMsg && (
<p className="bg-white/90 text-red-600 text-center py-1 rounded-md tracking-wide font-semibold">
{errMsg}
</p>
)}
<button
disabled={loading}
type="submit"
className={`mt-5 w-full py-2 uppercase text-base font-bold tracking-wide text-gray-300 rounded-md hover:text-white hover:bg-indigo-600 duration-200 ${
loading ? "bg-gray-500 hover:bg-gray-500" : "bg-indigo-700"
}`}
>
{loading ? "Loading..." : "Send"}
</button>
</form>
<p className="text-sm leading-6 text-gray-400 text-center -mt-2 py-10">
Already have an Account{" "}
<button
onClick={() => setLogin(true)}
className="text-gray-200 font-semibold underline underline-offset-2 decoration-[1px] hover:text-white duration-200"
>
Login
</button>
</p>
</div>
)}
</div>
);
};
export default Registeration;
index.ts:
// الفيتش برتجع بيانات ال ءا بي ءاي الجسون ك استرنج
import axios from "axios";
export const getData = async (endpoint: string) => {
try {
const response = await fetch(endpoint, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
if (!response.ok) {
throw new Error("data fetch failed" + response.statusText);
}
const data = await response.json();
return data;
} catch (error) {
console.log("error while fetching data", error);
throw error;
}
};
// export const postData = async (endpoint: string, formData: FormData) => {
// try {
// // const userData: {[key: string]: any} = {}; // تعريف نوع userData بشكل صحيح
// // formData.forEach((value, key) => {
// // userData[key] = value;
// // });
// const userData = Object.fromEntries(formData.entries()); // تحويل FormData إلى كائن JavaScript مباشرة
// const response = await fetch(endpoint, {
// method: "POST",
// // body: formData, // لازم تبقى بدون `JSON.stringify()`
// headers: { "Content-Type": "application/json" },
// body: JSON.stringify(userData), // تحويل الكائن إلى JSON
// });
// if (!response.ok) {
// throw new Error("Failed to upload data: " + response.statusText);
// }
// const data = await response.json();
// return data;
// } catch (error) {
// console.log("Error while uploading data", error);
// throw error;
// }
// };
export const regpostData = async (endpoint: string, formData: FormData) => {
try {
// const userData = Object.fromEntries(formData.entries()); // تحويل FormData إلى كائن JavaScript مباشرة
// const response = await axios.post(endpoint, userData, {
// headers: { 'Content-Type': 'application/json' },
// });
const response = await axios.post(endpoint, formData);
return response.data; // axios يرجع response.data مباشرة
} catch (error) {
console.error("Error while uploading data", error);
throw error;
}
};
export const loginpostData = async (endpoint: string, formData: FormData) => {
try {
const response = await axios.post(endpoint, formData, {
headers: { "Content-Type": "application/json" },
});
return response.data; // axios يرجع response.data مباشرة
} catch (error) {
console.error("Error while uploading data", error);
throw error;
}
};
export const getDataWithToken = async (endpoint: string, token: string) => {
try {
const response = await axios.get(endpoint, {
headers: { "x-auth-token": token }, // إرسال التوكن في رأس الطلب
});
return response.data;
} catch (error) {
console.error("Error while fetching data with token", error);
throw error;
}
};
const config = require("config");
const jwt = require("jsonwebtoken");
const multer = require("multer");
// بيمنع أي حد مش مسجل دخول من الوصول للـ روتس المحمية
const auth = (req, res, next) => {
// get the token from the req header
const token = req.header("x-auth-token");
if (!token) {
return res.status(401).json({ msg: "No token, authorization denied" });
}
try {
jwt.verify(token, config.get("jwtSecret"), (err, decoded) => {
if (err) {
return res.status(401).json({ msg: "Token is not valid" });
}
req.user = decoded.user;
next();
});
} catch (err) {
console.error(err.message);
res.status(500).json({ msg: err.message });
}
};
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "public/images");
},
filename: (req, file, cb) => {
cb(null, Date.now() + "-" + file.originalname);
// cb(null, `${req.user.id}`);
},
});
const upload = multer({storage: storage}).single("avatar")
module.exports = { auth, upload };
This code does not print anything
console.log("req.file after Multer:", req.file); // Log req.file after Multer
console.log("req.files after Multer:", req.files); // Log req.files after Multer
console.log("req.body:", req.body); // Log req.body
These codes are not written, even what is inside "" is not printed
+
The first time the register is executed, the image that I put in the form is not uploaded to the folder public/images
I expected field name mismatch to be the most common cause of the error.
I expected Multer's error handling to help determine the root cause of the error.
I expected req.file and req.files logging to help determine whether Multer was receiving the file.
I am having trouble registering and the problem occurs when uploading an image file using Multer in my Express.js application in the form.
I am getting an error "MulterError: Unexpected field" when trying to upload an image file from the frontend. The problem occurs only the first time, and when I submit the same image again, the registering is successful.
the error:
[server] Multer Error: MulterError: Unexpected field
[server] at wrappedFileFilter (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\multer\index.js:40:19)
[server] at Multipart.<anonymous> (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\multer\lib\make-middleware.js:107:7)
[server] at Multipart.emit (node:events:518:28)
[server] at HeaderParser.cb (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\busboy\lib\types\multipart.js:358:14)
[server] at HeaderParser.push (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\busboy\lib\types\multipart.js:162:20)
[server] at SBMH.ssCb [as _cb] (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\busboy\lib\types\multipart.js:394:37)
[server] at feed (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\streamsearch\lib\sbmh.js:248:10)
[server] at SBMH.push (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\streamsearch\lib\sbmh.js:104:16)
[server] at Multipart._write (D:\supergear-mongo\admin\node_modules\.pnpm\[email protected]\node_modules\busboy\lib\types\multipart.js:567:19)
[server] at writeOrBuffer (node:internal/streams/writable:572:12) {
[server] code: 'LIMIT_UNEXPECTED_FILE',
[server] field: 'avatar',
[server] storageErrors: []
[server] }
my files:
store.ts:
/* eslint-disable @typescript-eslint/no-explicit-any */
import { create } from "zustand";
import { persist } from "zustand/middleware";
// import axios from "axios";
import { ProductProps } from "../../type";
import { config } from "../config";
import { getDataWithToken, loginpostData, regpostData } from ".";
interface APIResponse {
token?: string;
errors?: { msg: string }[]; //user.js - 23
}
interface CartProduct extends ProductProps {
quantity: number;
}
interface UserType {
firstName: string;
lastName: string;
password: string;
email: string;
avatar: string;
id: string;
}
interface StoreType {
// user
currentUser: UserType | null;
isLoading: boolean;
// isAuthonticated: null;
// token: localStorage.getItem("token");
// registerUser: (userData: FormData) => Promise<void>;
registerUser: (userData: FormData) => Promise<APIResponse>; // ✅ تحديث التوقيع ليعيد APIResponse
loginUser: (userData: FormData) => Promise<APIResponse>; // ✅ تحديث التوقيع ليعيد APIResponse
logoutUser: () => void;
// getUserInfo: (userId: string) => Promise<void>;
getUserInfo: () => Promise<void>;
// cart
cartProduct: CartProduct[];
addToCart: (product: ProductProps) => void;
decreaseQuantity: (productId: string) => void;
removeFromCart: (productId: string) => void;
resetCart: () => void;
// favorite
favoriteProduct: CartProduct[];
addToFavorite: (product: ProductProps) => void;
removeFromFavourite: (productId: string) => void;
resetFavorite: () => void;
}
const customStorage = {
getItem: (name: string) => {
const item = localStorage.getItem(name);
return item ? JSON.parse(item) : null;
},
setItem: (name: string, value: any) => {
localStorage.setItem(name, JSON.stringify(value));
},
removeItem: (name: string) => {
localStorage.removeItem(name);
},
};
export const Store = create<StoreType>()(
persist(
(set) => ({
currentUser: null,
isLoading: true,
cartProduct: [],
favoriteProduct: [],
registerUser: async (userData: FormData): Promise<APIResponse> => {
try {
set({ isLoading: true });
const data = await regpostData(
`${config.baseUrl}/api/users/register`,
userData
);
set({ currentUser: data, isLoading: false });
return data; // ✅ إرجاع البيانات بعد التسجيل
} catch (error: any) {
console.error("Error registering user", error);
set({ currentUser: null, isLoading: false });
console.error("error.response?.data", error.response?.data);
return error.response?.data;
}
},
loginUser: async (userData: FormData): Promise<APIResponse> => {
try {
set({ isLoading: true });
const data = await loginpostData(
`${config.baseUrl}/api/users/login`,
userData
);
if (data.token) {
localStorage.setItem("token", data.token);
set({ currentUser: data, isLoading: false });
}
// set({ currentUser: data, isLoading: false });
console.log(data);
return data; // ✅ إرجاع البيانات بعد التسجيل
} catch (error: any) {
set({ currentUser: null, isLoading: false });
console.error("error.response?.data", error.response?.data);
return error.response?.data;
}
},
logoutUser: () => {
set({ currentUser: null }); // مسح معلومات المستخدم
localStorage.removeItem("token"); // حذف الرمز المميز من التخزين المحلي
},
getUserInfo: async () => {
try {
set({ isLoading: true });
const token = localStorage.getItem("token"); // الحصول على التوكن من localStorage
if (!token) {
throw new Error("No token found"); // إذا لم يتم العثور على التوكن
}
const data = await getDataWithToken(`${config.baseUrl}/api/users`, token); // استخدام الدالة الجديدة مع التوكن
set({ currentUser: data, isLoading: false });
} catch (error) {
console.error("Error fetching user info", error);
set({ currentUser: null, isLoading: false });
}
},
addToCart: (product) => {
set((state) => {
const existingProduct = state.cartProduct.find(
(p) => p._id === product._id
);
return {
cartProduct: existingProduct
? state.cartProduct.map((p) =>
p._id === product._id ? { ...p, quantity: p.quantity + 1 } : p
)
: [...state.cartProduct, { ...product, quantity: 1 }],
};
});
},
decreaseQuantity: (productId) => {
set((state) => ({
// cartProduct: state.cartProduct.map((p) => p._id === productId ? { ...p, quantity: Math.max(p.quantity - 1, 1) } : p),
cartProduct: state.cartProduct.map((p) =>
String(p._id) === String(productId)
? { ...p, quantity: Math.max(p.quantity - 1, 1) }
: p
),
}));
},
removeFromCart: (productId) => {
set((state) => ({
// cartProduct: state.cartProduct.filter((item) => item._id !== productId),
cartProduct: state.cartProduct.filter(
(item) => String(item._id) !== String(productId)
),
}));
},
resetCart: () => {
set({ cartProduct: [] });
},
addToFavorite: (product) => {
set((state) => {
const isFavorite = state.favoriteProduct.some(
(item) => item._id === product._id
);
return {
favoriteProduct: isFavorite
? state.favoriteProduct.filter((item) => item._id !== product._id)
: [...state.favoriteProduct, { ...product }],
};
});
},
removeFromFavourite: (productId) => {
set((state) => ({
// favoriteProduct: state.favoriteProduct.filter((item) => item._id !== productId),
favoriteProduct: state.favoriteProduct.filter(
(item) => String(item._id) !== String(productId)
),
}));
},
resetFavorite: () => {
set({ favoriteProduct: [] });
},
}),
{
name: "supergear-storage",
storage: customStorage,
}
)
);
user.js:
const express = require("express");
const router = express.Router();
const { check, validationResult } = require("express-validator");
const User = require("../models/User");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const config = require("config");
const {auth, upload} = require("../utils/");
router.post(
"/register",
(req, res, next) => {
upload(req, res, (err) => {
if (err) {
console.error("Multer Error:", err);
return res.status(500).json({ error: "Multer error", details: err.message }); // إضافة رسالة خطأ مفصلة
}
next();
});
},
// upload, // قم بتطبيق multer كـ middleware
check("name", "name is required").notEmpty(),
check("Lname", "name is required").notEmpty(),
check("email", "please include valid email").isEmail(),
check(
"password",
"please choose a password with atleast 6 characters"
).isLength({ min: 6 }),
async (req, res) => {
console.log("req.file بعد Multer:", req.file); // تسجيل req.file بعد Multer
console.log("req.files بعد Multer:", req.files); // تسجيل req.files بعد Multer
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log("Validation Errors:", errors.array());
return res.status(400).json({ errors: errors.array() });
}
const { name, Lname, email, password } = req.body;
console.log(name, Lname, email, password );
try {
let user = await User.findOne({ email });
if (user) {
return res
.status(400)
.json({ errors: [{ msg: "User already exists" }] });
}
console.log("req.body:", req.body); // تسجيل req.body
const avatar = req.file ? `/images/${req.file.filename}` : ""; // رابط الصورة
console.log( "avatar = req.file ?",avatar );
user = new User({ name, Lname, email, password, avatar });
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
const payload = {
user: {
id: user.id,
},
};
jwt.sign(
payload,
config.get("jwtSecret"),
{ expiresIn: "5 days" },
(err, token) => {
if (err) throw err;
else {
res.json({ token });
}
}
);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
// res.send("success in sending data");
}
);
router.post(
"/login",
check("email", "please include valid email").isEmail(),
check(
"password",
"please choose a password with atleast 6 characters"
).isLength({ min: 6 }),
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email, password } = req.body;
try {
let user = await User.findOne({ email });
if (!user) {
return res
.status(400)
.json({ errors: [{ msg: "invalid condentials - email not found" }] });
}
const isMatch = await bcryptpare(password, user.password);
if (!isMatch) {
return res
.status(400)
.json({ errors: [{ msg: "invalid condentials - wrong password" }] });
}
const payload = {
user: {
id: user.id,
},
};
jwt.sign(
payload,
config.get("jwtSecret"),
{ expiresIn: "5 days" },
(err, token) => {
if (err) throw err;
else {
res.json({ token });
}
}
);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
// res.send("success in sending data");
}
);
/* takes a token and returns user info private */
router.get("/",auth, async(req, res) => {
try {
const user = await User.findById(req.user.id).select("-password");
res.json(user);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
})
module.exports = router;
regestration.tsx:
import { useState } from "react";
import { MdPhotoLibrary } from "react-icons/md";
import Login from "./Login";
import Label from "./Label";
// import upload from "../lib/upload";
import { Store } from "../lib/store";
const Registeration = () => {
const [login, setLogin] = useState(true);
const [loading, setLoading] = useState(false);
const [errMsg, setErrMsg] = useState("");
const [Avatar, setAvatar] = useState({
file: null,
url: "",
});
const handleAvatar = (e: any) => {
if (e.target.files[0]) {
setAvatar({
file: e.target.files[0],
url: URL.createObjectURL(e.target.files[0]),
});
}
};
const handleRegistration = async (e: any) => {
e.preventDefault();
setErrMsg(""); // تصفير أي خطأ سابق
const formData = new FormData(e.target);
console.log("FormData entries:", Array.from(formData.entries())); // تسجيل formData entries
if (Avatar.file) {
formData.append("avatar", Avatar.file);
console.log( "avatar", Avatar.file );
}
try {
setLoading(true);
const response = await Store.getState().registerUser(formData);
if (response.errors && response.errors.length > 0) {
setErrMsg(response.errors[0].msg); // عرض الخطأ في الواجهة
return; // منع الانتقال إلى صفحة تسجيل الدخول
}
setLogin(true);
} catch (error: any) {
console.error("Error:", error);
setErrMsg(error.message || "Something went wrong");
} finally {
setLoading(false);
}
};
return (
<div>
{login ? (
<Login setLogin={setLogin} />
) : (
<div className="bg-gray-950 rounded-lg">
<form
onSubmit={handleRegistration}
className="max-w-5xl mx-auto pt-10 px-10 lg:px-0 text-white"
>
<div className="border-b border-b-white/10 pb-5">
<h2 className="text-lg font-semibold uppercase leading-7">
Registration Form
</h2>
<p className="mt-1 text-sm leading-6 text-gray-400">
You need to provide required information to get register with
us.
</p>
</div>
<div className="border-b border-b-white/10 pb-5">
<div className="mt-5 grid grid-cols-1 gap-x-6 gap-y-5 sm:grid-cols-6">
<div className="sm:col-span-3">
<Label title="name" htmlFor="name" />
<input
type="text"
name="name"
className="block w-full rounded-md border-0 bg-white/5 py-1.5 px-4 outline-none text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-skyText sm:text-sm sm:leading-6 mt-2"
/>
</div>
<div className="sm:col-span-3">
<Label title="Last name" htmlFor="lastName" />
<input
type="text"
name="Lname"
className="block w-full rounded-md border-0 bg-white/5 py-1.5 px-4 outline-none text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-skyText sm:text-sm sm:leading-6 mt-2"
/>
</div>
<div className="sm:col-span-4">
<Label title="Email address" htmlFor="email" />
<input
type="email"
name="email"
className="block w-full rounded-md border-0 bg-white/5 py-1.5 px-4 outline-none text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-skyText sm:text-sm sm:leading-6 mt-2"
/>
</div>
<div className="sm:col-span-4">
<Label title="Password" htmlFor="password" />
<input
type="password"
name="password"
className="block w-full rounded-md border-0 bg-white/5 py-1.5 px-4 outline-none text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-skyText sm:text-sm sm:leading-6 mt-2"
/>
</div>
<div className="col-span-full">
<div className="mt-2 flex items-center gap-x-3">
<div className="flex-1">
<Label title="Cover photo" />
<div className="mt-2 flex justify-center rounded-lg border border-dashed border-white/25 px-6 py-4">
<div className="flex flex-col items-center text-center">
<div className="w-14 h-14 border border-gray-600 rounded-full p-1">
{Avatar?.url ? (
<img
src={Avatar?.url}
alt="userImage"
className="w-full h-full rounded-full object-cover"
/>
) : (
<MdPhotoLibrary className="mx-auto h-full w-full text-gray-500" />
)}
</div>
<div className="mt-4 flex items-center mb-1 text-sm leading-6 text-gray-400">
<label htmlFor="file-upload">
<span className="relative cursor-pointer rounded-md px-2 py-1 bg-gray-900 font-semibold text-gray-200 hover:bg-gray-800">
Upload a file
</span>
<input
type="file"
name="avatar"
id="file-upload"
className="sr-only"
onChange={handleAvatar}
/>
</label>
<p className="pl-1">or drag and drop</p>
</div>
<p className="text-xs leading-5 text-gray-400">
PNG, JPG, GIF up to 10MB
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{errMsg && (
<p className="bg-white/90 text-red-600 text-center py-1 rounded-md tracking-wide font-semibold">
{errMsg}
</p>
)}
<button
disabled={loading}
type="submit"
className={`mt-5 w-full py-2 uppercase text-base font-bold tracking-wide text-gray-300 rounded-md hover:text-white hover:bg-indigo-600 duration-200 ${
loading ? "bg-gray-500 hover:bg-gray-500" : "bg-indigo-700"
}`}
>
{loading ? "Loading..." : "Send"}
</button>
</form>
<p className="text-sm leading-6 text-gray-400 text-center -mt-2 py-10">
Already have an Account{" "}
<button
onClick={() => setLogin(true)}
className="text-gray-200 font-semibold underline underline-offset-2 decoration-[1px] hover:text-white duration-200"
>
Login
</button>
</p>
</div>
)}
</div>
);
};
export default Registeration;
index.ts:
// الفيتش برتجع بيانات ال ءا بي ءاي الجسون ك استرنج
import axios from "axios";
export const getData = async (endpoint: string) => {
try {
const response = await fetch(endpoint, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
if (!response.ok) {
throw new Error("data fetch failed" + response.statusText);
}
const data = await response.json();
return data;
} catch (error) {
console.log("error while fetching data", error);
throw error;
}
};
// export const postData = async (endpoint: string, formData: FormData) => {
// try {
// // const userData: {[key: string]: any} = {}; // تعريف نوع userData بشكل صحيح
// // formData.forEach((value, key) => {
// // userData[key] = value;
// // });
// const userData = Object.fromEntries(formData.entries()); // تحويل FormData إلى كائن JavaScript مباشرة
// const response = await fetch(endpoint, {
// method: "POST",
// // body: formData, // لازم تبقى بدون `JSON.stringify()`
// headers: { "Content-Type": "application/json" },
// body: JSON.stringify(userData), // تحويل الكائن إلى JSON
// });
// if (!response.ok) {
// throw new Error("Failed to upload data: " + response.statusText);
// }
// const data = await response.json();
// return data;
// } catch (error) {
// console.log("Error while uploading data", error);
// throw error;
// }
// };
export const regpostData = async (endpoint: string, formData: FormData) => {
try {
// const userData = Object.fromEntries(formData.entries()); // تحويل FormData إلى كائن JavaScript مباشرة
// const response = await axios.post(endpoint, userData, {
// headers: { 'Content-Type': 'application/json' },
// });
const response = await axios.post(endpoint, formData);
return response.data; // axios يرجع response.data مباشرة
} catch (error) {
console.error("Error while uploading data", error);
throw error;
}
};
export const loginpostData = async (endpoint: string, formData: FormData) => {
try {
const response = await axios.post(endpoint, formData, {
headers: { "Content-Type": "application/json" },
});
return response.data; // axios يرجع response.data مباشرة
} catch (error) {
console.error("Error while uploading data", error);
throw error;
}
};
export const getDataWithToken = async (endpoint: string, token: string) => {
try {
const response = await axios.get(endpoint, {
headers: { "x-auth-token": token }, // إرسال التوكن في رأس الطلب
});
return response.data;
} catch (error) {
console.error("Error while fetching data with token", error);
throw error;
}
};
const config = require("config");
const jwt = require("jsonwebtoken");
const multer = require("multer");
// بيمنع أي حد مش مسجل دخول من الوصول للـ روتس المحمية
const auth = (req, res, next) => {
// get the token from the req header
const token = req.header("x-auth-token");
if (!token) {
return res.status(401).json({ msg: "No token, authorization denied" });
}
try {
jwt.verify(token, config.get("jwtSecret"), (err, decoded) => {
if (err) {
return res.status(401).json({ msg: "Token is not valid" });
}
req.user = decoded.user;
next();
});
} catch (err) {
console.error(err.message);
res.status(500).json({ msg: err.message });
}
};
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "public/images");
},
filename: (req, file, cb) => {
cb(null, Date.now() + "-" + file.originalname);
// cb(null, `${req.user.id}`);
},
});
const upload = multer({storage: storage}).single("avatar")
module.exports = { auth, upload };
This code does not print anything
console.log("req.file after Multer:", req.file); // Log req.file after Multer
console.log("req.files after Multer:", req.files); // Log req.files after Multer
console.log("req.body:", req.body); // Log req.body
These codes are not written, even what is inside "" is not printed
+
The first time the register is executed, the image that I put in the form is not uploaded to the folder public/images
I expected field name mismatch to be the most common cause of the error.
I expected Multer's error handling to help determine the root cause of the error.
I expected req.file and req.files logging to help determine whether Multer was receiving the file.
Share Improve this question edited Mar 8 at 8:41 eslam wael asked Mar 8 at 7:54 eslam waeleslam wael 371 silver badge5 bronze badges 2- You're posting a lot of code, but where is your Multer config/setup? – robertklep Commented Mar 8 at 8:01
- i post it @robertklep – eslam wael Commented Mar 8 at 8:42
1 Answer
Reset to default 1My guess would be that you're adding two files to formData
.
Here:
const formData = new FormData(e.target);
And here:
if (Avatar.file) {
formData.append("avatar", Avatar.file);
console.log( "avatar", Avatar.file );
}
Since Multer is set up to only expect a single file, this will cause an error.