From 0986609d55057b962d9006e57165843d49d720a5 Mon Sep 17 00:00:00 2001 From: Maxime Princelle <maxime@princelle.org> Date: Fri, 17 Dec 2021 14:12:16 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20add=20add=20product=20with=20back?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 + src/apis/back.ts | 54 +++++++++++ src/components/core/navbar.tsx | 4 +- src/pages/add_product.tsx | 163 +++++++++++++++++++++++++++++++++ 4 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 src/pages/add_product.tsx diff --git a/src/App.tsx b/src/App.tsx index 4cb233a..228d676 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,6 +12,7 @@ import Sell from './pages/sell'; import Login from './pages/login'; import Stock from './pages/stock'; import Users from './pages/users'; +import AddProduct from './pages/add_product'; import Main from './components/layout/main'; export default function App() { @@ -27,6 +28,7 @@ export default function App() { <Route index element={<Sell />} /> <Route path="stock" element={<Stock />} /> <Route path="users" element={<Users />} /> + <Route path="add-product" element={<AddProduct />} /> </Route> <Route path="*" element={<h1>No match !</h1>} /> </Routes> diff --git a/src/apis/back.ts b/src/apis/back.ts index 0932f46..d53e6a9 100644 --- a/src/apis/back.ts +++ b/src/apis/back.ts @@ -30,3 +30,57 @@ export async function getItems(): Promise<Product[]> { return products; }; + +export async function getCategories(): Promise<any[]> { + const categories = await axios.get(`${BASE_URL}/category`, { + headers: { + 'Content-Type': 'application/json', + 'apikey': APIKEY, + } + }).then(({ data }) => data) + .catch(error => { + console.error(error); + return []; + }); + + return categories; +} + +export async function addItem(name: string, price: number, priceAdherant: number, stock: number, category_id: any): Promise<any> { + // Create the item without stock + let item = await axios.post(`${BASE_URL}/item`, { + name: name, + price: price, + subscriber_price: priceAdherant, + category: category_id, + }, { + headers: { + 'Content-Type': 'application/json', + 'apikey': APIKEY, + }}).then(({ data }) => { + console.log(data) + return data; + }) + .catch(error => { + console.error(error); + return null; + }); + + // Create the stock + if (item) { + await axios.put(`${BASE_URL}/stock`, { + item_id: item.id, + quantity: stock, + }, { + headers: { + 'Content-Type': 'application/json', + 'apikey': APIKEY, + }}).then(({ data }) => data) + .catch(error => { + console.error(error); + return []; + }); + } else { + console.error("Error while creating item"); + } +} \ No newline at end of file diff --git a/src/components/core/navbar.tsx b/src/components/core/navbar.tsx index 617daca..2a859e7 100644 --- a/src/components/core/navbar.tsx +++ b/src/components/core/navbar.tsx @@ -5,7 +5,8 @@ import { CurrencyEuroIcon, //HomeIcon, ShoppingCartIcon, - XIcon + XIcon, + PlusCircleIcon } from '@heroicons/react/outline'; import { Link } from 'react-router-dom'; @@ -15,6 +16,7 @@ const navigation = [ { name: 'Vendre', href: '/dashboard', icon: CurrencyEuroIcon }, { name: 'Gestion des stocks', href: '/dashboard/stock', icon: ShoppingCartIcon }, { name: 'Utilisateurs', href: '/dashboard/users', icon: UsersIcon }, + { name: 'Ajouter un product', href: '/dashboard/add-product', icon: PlusCircleIcon }, ]; function classNames(...classes: unknown[]) { diff --git a/src/pages/add_product.tsx b/src/pages/add_product.tsx new file mode 100644 index 0000000..c0d9d3d --- /dev/null +++ b/src/pages/add_product.tsx @@ -0,0 +1,163 @@ +import { useState, useEffect } from 'react'; + +import { getCategories, addItem } from '../apis/back'; + +const AddProduct = () => { + const [categories, setCategories] = useState<any[]>([]); + + const [name, setName] = useState(""); + const [price, setPrice] = useState(0); + const [priceAdherant, setPriceAdherant] = useState(0); + const [stock, setStock] = useState(0); + const [category_id, setCategory] = useState("n/a"); + + useEffect(() => { + getCategories().then((data) => { + setCategories(data); + }).catch((_) => { + setCategories([]); + }); + }, []); + + function createItem() { + if (category_id !== "n/a") { + console.log("Creating item: " + name + " " + price + " " + priceAdherant + " " + stock + " " + category_id); + addItem(name, price, priceAdherant, stock, category_id).then((data) => { + console.log(data); + + // Reset form data + setName(""); + setPrice(0); + setPriceAdherant(0); + setStock(0); + setCategory("n/a"); + }).catch((_) => { + console.log("Error"); + }); + } else { + console.log("Please select a category"); + } + } + + return ( + <div className="max-w-7xl mx-auto px-4 sm:px-6 md:px-8"> + <div className="pt-8"> + <div className="mb-12"> + <h3 className="text-3xl leading-6 font-medium text-gray-900">Ajouter un produit</h3> + </div> + <div className=""> + <div className="mt-5"> + <label htmlFor="name" className="block text-sm font-medium text-gray-700"> + Nom + </label> + <div className="mt-1"> + <input + type="text" + name="name" + id="name" + onChange={(e) => setName(e.target.value)} + value={name} + className="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md" + /> + </div> + </div> + + <div> + <p className="mt-10 text-xl">Prix</p> + <div className="flex flex-row w-full mt-3"> + <div className="w-1/2 mr-2"> + <label htmlFor="price" className="block text-sm font-medium text-gray-700"> + Prix (normal) + </label> + <div className="mt-1"> + <input + type="number" + name="price" + id="price" + onChange={(e) => setPrice(parseFloat(e.target.value))} + value={price} + min="0.5" + placeholder="1.5" + step="0.5" + className="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md" + /> + </div> + </div> + + <div className="w-1/2 ml-2"> + <label htmlFor="price-adherant" className="block text-sm font-medium text-gray-700"> + Prix (adhérent) + </label> + <div className="mt-1"> + <input + type="number" + name="price-adherant" + id="price-adherant" + onChange={(e) => setPriceAdherant(parseFloat(e.target.value))} + value={priceAdherant} + min="0.5" + placeholder="1.5" + step="0.5" + className="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md" + /> + </div> + </div> + </div> + </div> + + <div> + <p className="mt-10 text-xl">Catégorie</p> + <div className="flex flex-row w-full mt-3"> + <div className="w-1/2"> + <div className="mt-1"> + <select + id="category" + name="category" + onChange={(e) => setCategory(e.target.value.toString())} + value={category_id} + className="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md" + > + <option value="0">Choisir une catégorie</option> + {categories.map((category) => ( + <option key={category.id} value={category.id}> + {category.name} + </option> + ))} + </select> + </div> + </div> + </div> + </div> + + <div> + <p className="mt-10 text-xl">Quantité</p> + <div className="flex flex-row w-full mt-3"> + <div className="w-1/2"> + <div className="mt-1"> + <input + type="number" + name="quantity" + id="quantity" + onChange={(e) => setStock(parseInt(e.target.value))} + value={stock} + min="0" + placeholder="1" + step="1" + className="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md" + /> + </div> + </div> + </div> + </div> + + <button type="button" className="mt-10 w-full sm:w-auto bg-indigo-500 text-white py-2 px-4 rounded-md hover:bg-indigo-600" onClick={() => {createItem()}}> + Ajouter + </button> + + </div> + </div> + </div> + ) +} + +export default AddProduct; \ No newline at end of file -- GitLab