Sep 29, 2024
0
Level 2
React adding of multiple array object in the database using laravel api
I am getting this error Uncaught (in promise) ReferenceError: size is not defined when am adding my product atrributes.
ProductController.php file for my api
public function addProductAttribute(Request $request, $id)
{
$fields = $request->validate([
'size' => 'required|max:255',
'cost_price' => 'required|max:255',
'sales_price' => 'required',
'stock' => 'required',
'sku' => 'required|unique:product_attributes,sku',
]);
$product = Product::select('id','product_name','product_code','product_color','product_cost_price','product_sales_price','product_image')->with('product_attributes')->where(['id' => $id])->first();
$data = $request->all();
// echo "<pre>";
// print_r($data['sku']);
// die;
foreach($data['sku'] as $key => $value){
if(!empty($value)){
//Prevent SKU duplicate
$skuCount = ProductAttribute::where('sku',$value)->count();
if($skuCount>0){
return response()->json([
"message"=>"SKU Already exist!, Please add a new SKU"
]);
}
//Prevent Size duplicate
$sizeCount = ProductAttribute::where(['product_id'=>$id,'size'=>$data['size'][$key]])->count();
if($sizeCount>0){
return response()->json([
"message"=>"Size Already exist!, Please add a new Size"
]);
}
$productattribute = new ProductAttribute;
$productattribute->product_id = $id;
$productattribute->sku = $value;
$productattribute->size = $data['size'][$key];
$productattribute->cost_price = $data['cost_price'][$key];
$productattribute->sales_price = $data['sales_price'][$key];
$productattribute->stock = $data['stock'][$key];
$productattribute->status = 1;
$productattribute->save();
}
}
return response()->json([
"productattribute"=>$productattribute,
"product"=>$product,
"message"=>"Product Attribute Added Successfully"
]);
}
ViewProductAttributes.jsx file
import { Link, useNavigate, useParams } from "react-router-dom";
import { useContext, useEffect, useState } from "react";
import DashboardSidebar from "../DashboardSidebar";
import { AppContext } from "../../Context/AppContext";
export default function ViewProductAttributes() {
const { id } = useParams();
const navigate = useNavigate();
const { name, token } = useContext(AppContext);
const [product, setProduct] = useState([]);
const [productAttributes, setProductAttributes] = useState([]);
const [productAttributeInput, setProductAttributeInput] = useState([
{
size: "",
sku: "",
cost_price: "",
sales_price: "",
stock: "",
},
]);
const [errors, setErrors] = useState({});
async function getProductDetails() {
const res = await fetch(`/api/view_product_attribute/${id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
const data = await res.json();
if (res.ok) {
setProduct(data.product); //this product is the one comming from ProductController.php @ viewProductAttribute function
}
}
async function getProductAttributes() {
const res = await fetch(`/api/view_product_attribute/${id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
const data = await res.json();
if (res.ok) {
setProductAttributes(data.productattributes); //this productattributes is the one comming from ProductController.php @ viewProductAttribute function
}
}
const handleAddRows = () => {
setProductAttributeInput([
...productAttributeInput,
{ size: "", sku: "", cost_price: "", sales_price: "", stock: "" },
]);
};
const handleRemoveRows = (i) => {
const deleteVal = [...productAttributeInput];
deleteVal.splice(i, 1);
setProductAttributeInput(deleteVal);
};
const handleChange = (e, i) => {
const values = [...productAttributeInput];
values[i][e.target.name] = e.target.value;
setProductAttributeInput(values);
};
async function addProductAttribute(e) {
e.preventDefault();
// console.log("productAttribute", productAttributeInput);
// const Formdata = {
// size: productAttributeInput.size,
// sku: productAttributeInput.sku,
// cost_price: productAttributeInput.cost_price,
// sales_price: productAttributeInput.sales_price,
// stock: productAttributeInput.stock,
// };
const Formdata = {
size,
sku,
cost_price,
sales_price,
stock,
};
const res = await fetch(`/api/add_product_attribute/${id}`, {
method: "post",
headers: {
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(Formdata),
});
const data = await res.json();
if (data.errors) {
setErrors(data.errors);
} else {
navigate("/view_products");
alert(data.message);
}
}
//this useEffect is calling the getProductAttributes function at the top
useEffect(() => {
getProductDetails();
getProductAttributes();
}, []);
return (
<>
<div className="xsm:h-[200px] md:h-[220px] w-full bg-primary">
<div className="container">
<div className="flex justify-between">
<div className="xsm:pt-[20px] md:pt-[50px]">
<h1 className="font-roboto text-secondary xsm:text-[30px] md:text-[50px] animation-delay-300 xsm:leading-8 md:leading-[50px]">
Modern Courses
</h1>
<p className="text-white text-[17px] pb-9 xsm:pt-2 md:pt-4">
Lorem ipsum dolor sit amet consectetur
adipisicing elit. Debitis reiciendis corrupti.
</p>
</div>
</div>
</div>
</div>
<div className="pt-10">
<div className="container grid grid-cols-4 gap-6 pt-4 pb-16 items-start">
<div className="lg:col-span-3 xsm:col-span-4">
<div className="flex items-center mb-3">
<Link
to="/view_products"
className="flex items-center rounded border border-red-600 py-1 px-2 text-white bg-red-600 hover:bg-tertiary hover:border-tertiary"
>
<i className="fa-light fa-arrow-left mr-1"></i>
BACK
</Link>
</div>
<div className="space-y-4">
<div className="bg-white p-3 border border-gray-200 rounded">
<h1 className="font-roboto text-[25px] text-primary font-semibold capitalize mb-4">
ADD PRODUCT ATTRIBUTE
</h1>
<div
className="grid xsm:grid-cols-1 md:grid-cols-4 gap-4"
key={product.id}
>
<div>
<label className="text-gray-600 mb-2 block">
Product
<span className="text-red-600">
*
</span>
</label>
<input
type="text"
className="block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0"
value={product.product_name}
readOnly
/>
</div>
<div>
<label className="text-gray-600 mb-2 block">
Code
<span className="text-red-600">
*
</span>
</label>
<input
type="email"
className="block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0"
value={product.product_code}
readOnly
/>
</div>
<div>
<label className="text-gray-600 mb-2 block">
Cost Price
<span className="text-red-600">
*
</span>
</label>
<input
type="email"
className="block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0"
value={product.product_cost_price}
readOnly
/>
</div>
<div>
<label className="text-gray-600 mb-2 block">
Sales Price
<span className="text-red-600">
*
</span>
</label>
<input
type="text"
className="block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0"
value={product.product_sales_price}
readOnly
/>
</div>
</div>
<button
onClick={handleAddRows}
className="mt-10"
>
<i className="fa-light fa-plus pl-1"></i>
Add Rows
</button>
<form onSubmit={addProductAttribute}>
{productAttributeInput.map((val, i) => (
<div key={i}>
<div className="grid xsm:grid-cols-1 md:grid-cols-5 gap-4 py-1">
<div>
<input
type="text"
className="block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0"
placeholder="Size"
name="size"
value={val.size}
onChange={(e) =>
handleChange(e, i)
}
/>
{errors.size && (
<p className="text-red-600">
{errors.size[0]}
</p>
)}
</div>
<div>
<input
type="text"
className="block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0"
placeholder="SKU"
name="sku"
value={val.sku}
onChange={(e) =>
handleChange(e, i)
}
/>
{errors.sku && (
<p className="text-red-600">
{errors.sku[0]}
</p>
)}
</div>
<div>
<input
type="text"
className="block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0"
placeholder="Cost Price"
name="cost_price"
value={val.cost_price}
onChange={(e) =>
handleChange(e, i)
}
/>
{errors.cost_price && (
<p className="text-red-600">
{
errors
.cost_price[0]
}
</p>
)}
</div>
<div>
<input
type="text"
className="block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0"
placeholder="Sales Price"
name="sales_price"
value={val.sales_price}
onChange={(e) =>
handleChange(e, i)
}
/>
{errors.sales_price && (
<p className="text-red-600">
{
errors
.sales_price[0]
}
</p>
)}
</div>
<div className="flex">
<div className="block">
<input
type="number"
min="1"
className="block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0"
placeholder="Stock"
name="stock"
value={val.stock}
onChange={(e) =>
handleChange(
e,
i
)
}
/>
{errors.stock && (
<p className="text-red-600">
{
errors
.stock[0]
}
</p>
)}
</div>
<div className="flex text-primary gap-2 mt-2">
{i == 0 ? (
""
) : (
<button
onClick={
handleRemoveRows
}
>
<i className="fa-light fa-minus pl-1"></i>
</button>
)}
</div>
</div>
</div>
</div>
))}
<div class="pt-2">
<button class="bg-primary border border-primary text-white px-8 py-2 mb-3 font-medium rounded text-uppercase flex items-center gap-2 hover:bg-transparent hover:text-primary transition">
ADD
</button>
</div>
</form>
</div>
</div>
<div>
<table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
<thead className="text-xs text-gray-500 uppercase bg-gray-50 dark:text-gray-400 border-b-2 border-gray-400">
<tr className="text-nowrap">
<th className="px-3 py-2">ID</th>
<th className="px-3 py-2">
Product ID
</th>
<th className="px-3 py-2">Size</th>
<th className="px-3 py-2">SKU</th>
<th className="px-3 py-2">
Cost Price
</th>
<th className="px-3 py-2">
Sales Price
</th>
<th className="px-3 py-2">Status</th>
<th className="px-3 py-2">Action</th>
</tr>
</thead>
<tbody>
{productAttributes.length > 0 ? (
productAttributes.map(
(productAttribute) => (
<tr
key={productAttribute.id}
className="bg-white border-b dark:bg-gray-800 dark:border-gray-700"
>
<td className="px-3 py-2">
1
</td>
<td className="px-3 py-2">
{
productAttribute.product_id
}
</td>
<td className="px-3 py-2">
{productAttribute.size}
</td>
<td className="px-3 py-2">
{productAttribute.sku}
</td>
<td className="px-3 py-2">
{
productAttribute.cost_price
}
</td>
<td className="px-3 py-2">
{
productAttribute.sales_price
}
</td>
<td className="px-3 py-2 text-nowrap">
{
productAttribute.status
}
</td>
<td className="px-3 py-2">
<div className="flex text-center gap-2">
<button
// className="hover:text-tertiary"
// title="Delete"
// onClick={(e) =>
// deleteProductCategory(
// e,
// productCategory.id
// )
// }
>
<i className="fa-light fa-trash"></i>
</button>
</div>
</td>
</tr>
)
)
) : (
<p className="py-4 text-red-500 text-[20px]">
No product attributes
</p>
)}
</tbody>
</table>
{/* pagination */}
</div>
</div>
<div className="xsm:col-span-4 md:col-span-4 lg:col-span-1 px-4 pb-6 shadow rounded overflow-hidden xsm:mt-10 md:mt-[0px]">
<div className="divide-y divide-gray-200 space-y-5">
<DashboardSidebar />
</div>
</div>
</div>
</div>
</>
);
}
I know the problem is comming from this code in my ViewProductAttributes.jsx file
// console.log("productAttribute", productAttributeInput);
const Formdata = {
size,
sku,
cost_price,
sales_price,
stock,
};
Because when I console the productAttributeInput, I get the data in my console perfectly, but if someone can help me on how to insert that data into my database, that is where the problem is.
Please or to participate in this conversation.