├── .gitattributes ├── src ├── axois.jsx ├── main.jsx ├── Context │ └── Context.jsx ├── App.jsx ├── index.css ├── components │ ├── Home.jsx │ ├── Navbar.jsx │ ├── Product.jsx │ ├── AddProduct.jsx │ └── UpdateProduct.jsx ├── assets │ └── react.svg └── App.css ├── vite.config.js ├── .gitignore ├── README.md ├── .eslintrc.cjs ├── index.html ├── package.json └── public └── vite.svg /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /src/axois.jsx: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const API = axios.create({ 4 | baseURL: "http://localhost:8080/api", 5 | }); 6 | 7 | export default API; 8 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.jsx' 4 | import './index.css' 5 | import { AppProvider } from './Context/Context.jsx' 6 | 7 | ReactDOM.createRoot(document.getElementById('root')).render( 8 | 9 | 10 | 11 | 12 | , 13 | ) 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react/jsx-no-target-blank': 'off', 16 | 'react-refresh/only-export-components': [ 17 | 'warn', 18 | { allowConstantExport: true }, 19 | ], 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Context/Context.jsx: -------------------------------------------------------------------------------- 1 | import axios from "../axois"; 2 | import { useState, useEffect, createContext } from "react"; 3 | 4 | const AppContext = createContext(); 5 | 6 | export const AppProvider = ({ children }) => { 7 | const [data, setData] = useState([]); 8 | const [isError, setIsError] = useState(""); 9 | 10 | const getApiData = async () => { 11 | try { 12 | const response = await axios.get("/products"); 13 | setData(response.data); 14 | } catch (error) { 15 | setIsError(error.message); 16 | } 17 | }; 18 | 19 | useEffect(() => { 20 | getApiData(); 21 | }, []); 22 | 23 | return ( 24 | 25 | {children} 26 | 27 | ); 28 | }; 29 | 30 | export default AppContext; 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "telusko-ecommerce-part-3", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "axios": "^1.6.8", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0", 16 | "react-router-dom": "^6.23.0" 17 | }, 18 | "devDependencies": { 19 | "@types/react": "^18.2.66", 20 | "@types/react-dom": "^18.2.22", 21 | "@vitejs/plugin-react": "^4.2.1", 22 | "eslint": "^8.57.0", 23 | "eslint-plugin-react": "^7.34.1", 24 | "eslint-plugin-react-hooks": "^4.6.0", 25 | "eslint-plugin-react-refresh": "^0.4.6", 26 | "vite": "^5.2.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | import React from "react"; 3 | import Home from "./components/Home"; 4 | import Navbar from "./components/Navbar"; 5 | import AddProduct from "./components/AddProduct"; 6 | import Product from "./components/Product"; 7 | import { BrowserRouter, Routes, Route } from "react-router-dom"; 8 | import { AppProvider } from "./Context/Context"; 9 | import UpdateProduct from "./components/UpdateProduct"; 10 | function App() { 11 | return ( 12 | 13 | 14 | 15 | 16 | } /> 17 | } /> 18 | } /> 19 | } /> 20 | } /> 21 | 22 | 23 | 24 | ); 25 | } 26 | 27 | export default App; 28 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | /* :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } */ 69 | -------------------------------------------------------------------------------- /src/components/Home.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Link } from "react-router-dom"; 3 | import AppContext from "../Context/Context"; 4 | 5 | const Home = () => { 6 | const { data, isError } = useContext(AppContext); 7 | console.log(data); 8 | if (isError) { 9 | return

Loading...

; 10 | } 11 | 12 | 13 | return ( 14 | <> 15 | {isError &&

{isError}

} 16 | 17 | 18 |
19 | {data&&data.map((curProduct) => { 20 | const { id, brand, name, price, productAvailable } = curProduct; 21 | const cardStyle = { 22 | width: "18rem", 23 | height: "12rem", 24 | boxShadow: "rgba(0, 0, 0, 0.24) 0px 2px 3px", 25 | backgroundColor: productAvailable ? "#fff" : "#ccc", 26 | }; 27 | return ( 28 |
37 |
38 | 42 |
43 | {curProduct.name.toUpperCase()} 44 |
45 |
53 | {"~ " + curProduct.brand} 54 |
55 | {"$" + curProduct.price} 56 |
57 |
58 |
59 | 64 | Add to Cart 65 | 66 |
67 | 68 |
69 |
70 | ); 71 | })} 72 |
73 | 74 | ); 75 | }; 76 | 77 | export default Home; 78 | -------------------------------------------------------------------------------- /src/components/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import React,{useEffect} from "react"; 2 | 3 | 4 | const Navbar = () => { 5 | 6 | 7 | return ( 8 | <> 9 |
10 | 89 |
90 | 91 | ); 92 | }; 93 | 94 | export default Navbar; 95 | -------------------------------------------------------------------------------- /src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Product.jsx: -------------------------------------------------------------------------------- 1 | import { useNavigate, useParams } from "react-router-dom"; 2 | import { useContext, useEffect } from "react"; 3 | import { useState } from "react"; 4 | import AppContext from "../Context/Context"; 5 | import axios from "../axois"; 6 | import UpdateProduct from "./UpdateProduct"; 7 | const Product = () => { 8 | const { id } = useParams(); 9 | const { data } = useContext(AppContext); 10 | const [product, setProduct] = useState(null); 11 | const [imageUrl, setImageUrl] = useState(""); 12 | const navigate = useNavigate(); 13 | 14 | useEffect(() => { 15 | const fetchProduct = async () => { 16 | try { 17 | const response = await axios.get( 18 | `http://localhost:8080/api/product/${id}` 19 | ); 20 | setProduct(response.data); 21 | if (response.data.imageName) { 22 | fetchImage(); 23 | console.log(response.data.imageName); 24 | } 25 | } catch (error) { 26 | console.error("Error fetching product:", error); 27 | } 28 | }; 29 | 30 | const fetchImage = async () => { 31 | const response = await axios.get( 32 | `http://localhost:8080/api/product/${id}/image`, 33 | { responseType: "blob" } 34 | ); 35 | setImageUrl(URL.createObjectURL(response.data)); 36 | console.log(response.data); 37 | }; 38 | 39 | fetchProduct(); 40 | }, [id]); 41 | 42 | console.log("URL Parameter ID:", id); 43 | // console.log("Product Data:", data); 44 | 45 | 46 | 47 | const deleteProduct = () => { 48 | try { 49 | axios.delete(`http://localhost:8080/api/product/${id}`); 50 | navigate("/"); // Redirect to a different route after successful deletion 51 | console.log("Product deleted successfully"); 52 | alert("Product deleted successfully"); 53 | } catch (error) { 54 | console.error("Error deleting product:", error); 55 | if (error.response) { 56 | // Error if i am getting it from backend 57 | console.error("Backend error:", error.response.data); 58 | alert("Failed to delete product. Backend error."); 59 | } else if (error.request) { 60 | // error if network errors 61 | console.error("Network error:", error.request); 62 | alert("Failed to delete product. Network error."); 63 | } else { 64 | // error if Handle other errors 65 | console.error("Other error:", error.message); 66 | alert("Failed to delete product. Please try again."); 67 | } 68 | } 69 | }; 70 | 71 | const handleEditClick = () => { 72 | navigate(`/product/update/${id}`); 73 | }; 74 | 75 | if (!product) { 76 | return ( 77 |

78 | Loading... 79 |

80 | ); 81 | } 82 | return ( 83 | <> 84 |
85 | {/*
*/} 86 | {product.imageName} 91 | 92 | {/*
*/} 93 |
94 |
95 | {product.category} 96 |

{product.name}

97 |
{product.brand}
98 |

{product.description}

99 |
100 | 101 |
102 | {"$" + product.price} 103 | 104 | Add to cart 105 | 106 |
107 | Stock Available :{" "} 108 | 109 | {product.stockQuantity} 110 | 111 |
112 |

113 |

Product listed on:
114 | {new Date(product.releaseDate).toLocaleDateString()} 115 |

116 |
117 |
118 | 121 | {/* */} 122 | 129 |
130 |
131 |
132 | 133 | ); 134 | }; 135 | 136 | export default Product; 137 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | /* #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | /* text-align: center; 6 | } 7 | /* Navbar Styles */ 8 | .navbar { 9 | position: fixed; 10 | top: 0; 11 | left: 0; 12 | width: 100%; 13 | background-color: #333; 14 | color: #fff; 15 | padding: 10px 0; 16 | z-index: 1000; 17 | } 18 | 19 | .content { 20 | padding-top: 500px; 21 | } 22 | 23 | .card{ 24 | padding-top: 500px; 25 | width: 40px; 26 | padding: 1rem; 27 | height: 13rem; 28 | border-radius: 5%; 29 | 30 | } 31 | 32 | 33 | .grid{ 34 | margin: 0 auto; 35 | max-width: 90%; 36 | display: grid; 37 | place-items: center; 38 | padding: 3rem; 39 | grid-template-columns: 0.5fr 0.5fr 0.5fr; 40 | grid-template-rows: 1fr 1fr 1fr; 41 | grid-column-gap: 2rem; 42 | grid-row-gap: 2rem; 43 | background:#fafafa; 44 | align-items: stretch; 45 | padding-top: 100px; 46 | /* box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; */ 47 | border-radius: .5rem; 48 | } 49 | .container{ 50 | max-width: 120rem; 51 | display: grid; 52 | grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); 53 | grid-template-rows: 1fr 1fr 1fr; 54 | margin: 0 auto; 55 | } 56 | /* grid-template-columns: 1fr 1fr 1fr; 57 | gap: 1.6rem; 58 | padding-top: 100px; 59 | } */ 60 | .card-brand{ 61 | font-size: 1.2rem; 62 | font-weight: 350; 63 | color: #524c4c; 64 | 65 | } 66 | .btn-primary{ 67 | border-radius: 5px; 68 | cursor: pointer; 69 | transition: all .3s ease; 70 | font-size: 1rem; 71 | } 72 | .card-button-container { 73 | position: absolute; 74 | bottom: 10px; 75 | left: 55%; 76 | /* transform: translateX(-50%); */ 77 | width: 100%; 78 | } 79 | 80 | .product-card{ 81 | padding-top: 500px; 82 | width: 40px; 83 | padding: 1rem; 84 | height: 13rem; 85 | border-radius: 5%; 86 | margin: 100px; 87 | } 88 | 89 | /* <---------------------------------------Product CSS--------------------------------------------------------------> */ 90 | 91 | 92 | .containers { 93 | max-width: 1200px; 94 | margin: 0 auto; 95 | padding: 15px; 96 | display: flex; 97 | } 98 | .left-column-img{ 99 | vertical-align: middle; 100 | width: 40rem; 101 | padding-top: 6rem; 102 | margin: 20px; 103 | } 104 | .left-column { 105 | width: 40%; 106 | position: relative; 107 | } 108 | 109 | .right-column { 110 | width: 60%; 111 | margin-top: 60px; 112 | } 113 | /* Left Column */ 114 | .left-column img { 115 | width: 100%; 116 | position: absolute; 117 | left: 0; 118 | top: 0; 119 | opacity: 0; 120 | transition: all 0.3s ease; 121 | } 122 | 123 | .left-column img.active { 124 | opacity: 1; 125 | } 126 | /* Product Description */ 127 | .product-description { 128 | border-bottom: 1px solid #E1E8EE; 129 | margin-bottom: 20px; 130 | margin-top: 60px; 131 | } 132 | .product-description span { 133 | font-size: 12px; 134 | color: #358ED7; 135 | letter-spacing: 1px; 136 | text-transform: uppercase; 137 | text-decoration: none; 138 | } 139 | .product-description h1 { 140 | font-weight: 300; 141 | font-size: 52px; 142 | color: #43484D; 143 | letter-spacing: -2px; 144 | } 145 | 146 | .product-description h5 { 147 | font-weight: 400; 148 | font-size: 24px; 149 | color: #43484D; 150 | letter-spacing: -2px; 151 | } 152 | .product-description p { 153 | font-size: 16px; 154 | font-weight: 400; 155 | color: #86939E; 156 | line-height: 24px; 157 | } 158 | .release-date{ 159 | font-weight: 300; 160 | 161 | } 162 | /* Cable Configuration */ 163 | 164 | .cable-config a { 165 | color: #358ED7; 166 | text-decoration: none; 167 | font-size: 12px; 168 | position: relative; 169 | margin: 10px 0; 170 | display: inline-block; 171 | } 172 | 173 | .cable-config a:before { 174 | content: "?"; 175 | height: 15px; 176 | width: 15px; 177 | border-radius: 50%; 178 | border: 2px solid rgba(53, 142, 215, 0.5); 179 | display: inline-block; 180 | text-align: center; 181 | line-height: 16px; 182 | opacity: 0.5; 183 | margin-right: 5px; 184 | } 185 | /* Product Price */ 186 | .product-price { 187 | /* display: flex; 188 | align-items: center; 189 | flex-direction: column; 190 | align-items: flex-start; */ 191 | display: grid; 192 | justify-items: start; 193 | /* grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); */ 194 | grid-gap: 10px 4px; 195 | 196 | } 197 | .update-button{ 198 | display: flex; 199 | width: 10rem; 200 | justify-content: space-around; 201 | } 202 | 203 | .product-price span { 204 | font-size: 26px; 205 | font-weight: 400; 206 | color: #43474D; 207 | margin-right: 20px; 208 | } 209 | 210 | .cart-btn { 211 | display: inline-block; 212 | background-color: #0d6efd; 213 | border-radius: 6px; 214 | font-size: 16px; 215 | color: #FFFFFF; 216 | text-decoration: none; 217 | padding: 12px 30px; 218 | transition: all .5s; 219 | } 220 | .cart-btn:hover { 221 | background-color: #64af3d; 222 | } 223 | /* Responsive */ 224 | @media (max-width: 940px) { 225 | .container { 226 | flex-direction: column; 227 | margin-top: 60px; 228 | } 229 | 230 | .left-column, 231 | .right-column { 232 | width: 100%; 233 | } 234 | 235 | .left-column img { 236 | width: 300px; 237 | right: 0; 238 | top: -65px; 239 | left: initial; 240 | } 241 | } 242 | 243 | @media (max-width: 535px) { 244 | .left-column img { 245 | width: 220px; 246 | top: -85px; 247 | } 248 | } 249 | /* <....................................Add Product................................................> */ 250 | 251 | .center-container { 252 | position: absolute; 253 | top: 50%; 254 | left: 50%; 255 | transform: translate(-50%, -50%); 256 | } 257 | 258 | .center-container .image-control { 259 | display: block; 260 | margin: 0 auto; 261 | padding-top: 2rem; 262 | } -------------------------------------------------------------------------------- /src/components/AddProduct.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import axios from "axios"; 3 | 4 | const AddProduct = () => { 5 | const [product, setProduct] = useState({ 6 | name: "", 7 | brand: "", 8 | description: "", 9 | price: "", 10 | category: "", 11 | stockQuantity: "", 12 | releaseDate: "", 13 | productAvailable: false, 14 | }); 15 | const [image, setImage] = useState(null); 16 | 17 | const handleInputChange = (e) => { 18 | const { name, value } = e.target; 19 | setProduct({ ...product, [name]: value }); 20 | }; 21 | 22 | const handleImageChange = (e) => { 23 | setImage(e.target.files[0]); 24 | // setProduct({...product, image: e.target.files[0]}) 25 | }; 26 | 27 | const submitHandler = (event) => { 28 | event.preventDefault(); 29 | const formData = new FormData(); 30 | formData.append("imageFile", image); 31 | formData.append( 32 | "product", 33 | new Blob([JSON.stringify(product)], { type: "application/json" }) 34 | ); 35 | 36 | axios 37 | .post("http://localhost:8080/api/product", formData, { 38 | headers: { 39 | "Content-Type": "multipart/form-data", 40 | }, 41 | }) 42 | .then((response) => { 43 | console.log("Product added successfully:", response.data); 44 | alert("Product added successfully"); 45 | }) 46 | .catch((error) => { 47 | console.error("Error adding product:", error); 48 | alert("Error adding product"); 49 | }); 50 | }; 51 | 52 | return ( 53 |
54 |
55 |
56 | 59 | 67 |
68 |
69 | 72 | 81 |
82 |
83 | 86 | 95 |
96 |
97 | 100 | 109 |
110 |
111 | 114 | 123 |
124 | 125 |
126 | 129 | 139 |
140 |
141 | 144 | 152 |
153 | {/* setProduct({...product, image: e.target.files[0]})} /> 154 | */} 155 |
156 | 159 | 164 |
165 |
166 |
167 | 174 | setProduct({ ...product, productAvailable: e.target.checked }) 175 | } 176 | /> 177 | 178 |
179 |
180 |
181 | 188 |
189 |
190 |
191 | ); 192 | }; 193 | 194 | export default AddProduct; 195 | -------------------------------------------------------------------------------- /src/components/UpdateProduct.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { useParams } from "react-router-dom"; 3 | import axios from "axios"; 4 | 5 | const UpdateProduct = () => { 6 | const { id } = useParams(); 7 | const [product, setProduct] = useState({}); 8 | const [image,setImage] = useState(null); 9 | const [updateProduct, setUpdateProduct] = useState({ 10 | name: "", 11 | brand: "", 12 | description: "", 13 | price: "", 14 | category: "", 15 | stockQuantity: "", 16 | releaseDate: "", 17 | productAvailable: false, 18 | }); 19 | 20 | useEffect(() => { 21 | const fetchProduct = async() => { 22 | try { 23 | const response = await axios.get( 24 | `http://localhost:8080/api/product/${id}` 25 | ); 26 | setProduct(response.data); 27 | // console.log(setProduct); 28 | setUpdateProduct(response.data); 29 | } catch (error) { 30 | console.error("Error fetching product:", error); 31 | } 32 | }; 33 | 34 | fetchProduct(); 35 | }, [id]); 36 | 37 | 38 | const handleSubmit = (e) => { 39 | e.preventDefault(); 40 | const updatedProduct = new FormData(); 41 | updatedProduct.append("imageFile", image); 42 | updatedProduct.append( 43 | "product", 44 | new Blob([JSON.stringify(updateProduct)], { type: "application/json" }) 45 | ); 46 | 47 | axios.put(`http://localhost:8080/api/product/${id}`,updatedProduct, { 48 | headers: { 49 | "Content-Type": "multipart/form-data", 50 | }, 51 | }) 52 | .then((response) => { 53 | console.log("Product updated successfully:", response.data); 54 | alert("Product updated successfully!"); 55 | }) 56 | .catch((error) => { 57 | console.error("Error updating product:", error); 58 | alert("Failed to update product. Please try again."); // Informative error message 59 | }); 60 | }; 61 | 62 | 63 | const formatDate = (dateString) => { 64 | const date = new Date(dateString); 65 | const year = date.getFullYear(); 66 | const month = String(date.getMonth() + 1).padStart(2, "0"); // Adding 1 to month since January is 0 67 | const day = String(date.getDate()).padStart(2, "0"); 68 | return `${year}-${month}-${day}`; 69 | }; 70 | const handleChange = (e) => { 71 | const{name,value} =e.target; 72 | setUpdateProduct({ 73 | ...updateProduct, 74 | [name]: value 75 | }); 76 | }; 77 | const handleImageChange = (e) => { 78 | setImage(e.target.files[0]); 79 | }; 80 | 81 | return ( 82 |
83 |

Update Product

84 |
85 |
86 | 89 | 99 |
100 |
101 | 104 | 115 |
116 |
117 | 120 | 131 |
132 |
133 | 136 | 147 |
148 |
149 | 152 | 163 |
164 | 165 |
166 | 169 | 180 |
181 |
182 | 185 | 190 |
191 |
192 |
193 | 200 | setProduct({ ...product, productAvailable: e.target.checked }) 201 | } 202 | /> 203 | 204 |
205 |
206 | 207 | 208 |
209 | 212 |
213 |
214 |
215 | ); 216 | }; 217 | 218 | export default UpdateProduct; 219 | --------------------------------------------------------------------------------