Commit 9068a7f1 authored by John Lam's avatar John Lam

merge new promos

parents 82a1f9f9 cb411b58
......@@ -24,3 +24,4 @@ yarn-error.log*
.env
yarn.lock
FROM node:14.16-alpine3.13 as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY . .
RUN yarn
RUN yarn build
FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY --from=build /app/nginx/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
}
This diff is collapsed.
......@@ -6,7 +6,10 @@
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"axios": "^0.21.1",
"bootstrap": "^5.0.0",
"react": "^17.0.2",
"react-bootstrap": "^1.5.2",
"react-dom": "^17.0.2",
"react-hook-form": "^7.4.1",
"react-router": "^5.2.0",
......
import Config from '../config';
import axios from 'axios';
export const getAllProducts = async data => {
const res = await axios.get(`${Config.inventoryUrl}`);
// console.log(res.data);
return res.data;
}
\ No newline at end of file
import React from "react";
import React, { useState, useEffect } from 'react';
import { Redirect, Switch } from "react-router";
import AuthRoute from "./AuthRoute";
import ProductForm from "./ProductForm";
import PromotionNewFormComponent from './promotionforms/PromotionNewFormComponent'
import ProductGrid from "./ProductGrid";
import {getAllProducts} from "../actions/apiRequests.js"
export default function Main() {
const [productData, setproductData] = useState([]);
useEffect(() => {
loadProducts();
}, []);
const loadProducts = async (event) => {
const data = await getAllProducts();
setproductData(data);
}
return (
<div>
<Switch>
......@@ -12,7 +26,9 @@ export default function Main() {
<ProductForm />
</AuthRoute>
<AuthRoute exact path="/promos/new" component={PromotionNewFormComponent}>NEW PROMO</AuthRoute>
<AuthRoute exact path="/products">PRODUCTS</AuthRoute>
<AuthRoute exact path="/products">
<ProductGrid productData={productData} />
</AuthRoute>
<AuthRoute path="/promos">PROMOS</AuthRoute>
<AuthRoute exact path="/">
<Redirect to="/products" />
......
import React from 'react'
import './../styles/Product.css'
export default function Product({product}) {
return (
<div>
<div className="img-container">
<img src={product.productImageUrl} alt={product.productName}/>
</div>
<div className="prod-info">
<h5>{product.productName}</h5>
{product.sku}<br/>
${product.price}<br/>
In Stock: {product.stock}
</div>
</div>
)
}
import React from 'react'
import React, { useState } from "react";
import { useHistory, useLocation } from "react-router";
const emptyForm = {
sku: "",
upc: "",
productName: "",
brand: "",
category: "",
price: 0.0,
availableStock: 0,
productDescription: "",
productImageUrl: "",
productImage: ""
};
ProductForm.defaultProps = {
product: { ...emptyForm },
};
export default function ProductForm(props) {
const { product } = props;
const [form, setForm] = useState(product);
const [errors, setErrors] = useState([]);
const history = useHistory();
const validate = () => {
setErrors([]);
const errs = [];
if (form.sku.length < 3) {
errs.push("SKU must be at least 3 characters");
}
if (form.upc.length < 3) {
errs.push("UPC must be at least 3 characters");
}
if (form.productName.length === 0) {
errs.push("Please enter a product name");
}
if (form.brand.length === 0) {
errs.push("Please enter a brand");
}
if (form.category.length === 0) {
errs.push("Please specify a category");
}
if (Number(form.price) <= 0) {
errs.push("Price must be greater than 0");
}
if (Number(form.availableStock) <= 0) {
errs.push("Stock must be greater than 0");
}
setErrors([...errs]);
};
const onSubmit = (e) => {
e.preventDefault();
validate();
if (errors.length === 0) {
// console.log(form);
fetch("http://localhost:8080/api/products", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(form),
})
.then((res) => {
if (res.ok) {
res.json().then((data) => console.log(data));
history.push("/products");
} else {
setErrors([
"The provided SKU was found on an existing object, please try another",
]);
}
})
.catch((err) => {
setErrors([err.message]);
});
}
};
export default function ProductForm({ product }) {
return (
<div>
PRODUCT FORM
<div className="container mt-3">
{errors.length ? (
<ul className="list-group">
{errors.map((error, i) => (
<li key={i} className="list-group-item list-group-item-danger">
{error}
</li>
))}
</ul>
) : null}
<form onSubmit={onSubmit}>
<div className="row mt-3">
<div className="col">
<label htmlFor="productSku" className="form-label">
SKU
</label>
<input
required
name="sku"
type="text"
className="form-control"
id="productSku"
value={form.sku}
onChange={(e) => setForm({ ...form, sku: e.target.value })}
/>
</div>
<div className="col">
<label htmlFor="productUpc" className="form-label">
UPC
</label>
<input
required
name="upc"
type="text"
className="form-control"
id="productUpc"
value={form.upc}
onChange={(e) => setForm({ ...form, upc: e.target.value })}
/>
</div>
</div>
<div className="row mt-3">
<div className="col-6">
<div>
<label htmlFor="productName" className="form-label">
Name
</label>
<input
required
name="productName"
type="text"
className="form-control"
id="productName"
value={form.productName}
onChange={(e) => setForm({ ...form, productName: e.target.value })}
/>
</div>
<div>
<label htmlFor="brand" className="form-label">
Brand
</label>
<input
required
name="brand"
type="text"
className="form-control"
id="brand"
value={form.brand}
onChange={(e) => setForm({ ...form, brand: e.target.value })}
/>
</div>
<div>
<label htmlFor="category" className="form-label">
Category
</label>
<input
required
name="category"
type="text"
className="form-control"
id="category"
value={form.category}
onChange={(e) => setForm({ ...form, category: e.target.value })}
/>
</div>
</div>
<div className="col-6">
<label htmlFor="productDescription" className="form-label">
Description
</label>
<textarea
name="productDescription"
id="productDescription"
cols="40"
rows="7"
className="form-control"
value={form.productDescription}
onChange={(e) => setForm({ ...form, productDescription: e.target.value })}
></textarea>
</div>
</div>
<div className="row mt-3">
<div>
<label htmlFor="price" className="form-label">
Price
</label>
<input
required
name="price"
type="number"
className="form-control"
id="price"
value={form.price}
onChange={(e) => setForm({ ...form, price: e.target.value })}
/>
</div>
<div>
<label htmlFor="stock" className="form-label">
Stock
</label>
<input
required
name="stock"
type="number"
className="form-control"
id="stock"
value={form.availableStock}
onChange={(e) => setForm({ ...form, availableStock: e.target.value })}
/>
</div>
</div>
<div className="row mt-3">
<label htmlFor="productImage" className="form-label">
Product Image
</label>
<input
id="productImageUrl"
name="productImageUrl"
className="form-control form-control-lg"
type="url"
placeholder="Enter image URL here or upload image below..."
value={form.productImageUrl}
onChange={(e) => setForm({ ...form, productImageUrl: e.target.value, productImage:""})}
></input>
<input
id="productImage"
name="productImage"
className="form-control form-control-lg"
type="file"
value={form.productImage}
onChange={(e) => setForm({ ...form, productImage: e.target.value, productImageUrl:"" })}
></input>
</div>
<div className="row mt-3">
<div className="col-12">
<button type="submit" className="btn btn-primary mt-3">
Submit
</button>
</div>
</div>
</form>
</div>
)
);
}
import React from "react";
import Product from "./Product.jsx";
import { Col, Container, Row } from "react-bootstrap";
import "./../styles/ProductGrid.css";
export default function ProductGrid({ productData }) {
return (
<div>
<h1 id="title" className="text-center" >Inventory</h1>
<Container id="prod-grid" className="mt-3">
<Row xs={1} sm={2} md={3} lg={4}>
{productData.map((product) => {
return (
<Col key={product.sku}>
<Product product={product} />
</Col>
);
})}
</Row>
</Container>
</div>
//uses vanilla bootstrap
// <div>
// <h1 id="title">Inventory</h1>
// <div className="container" id="prod-grid" >
// <div className="row row-cols-4">
// {productData.map((product) => {
// return (
// <div className="col" key={product.sku}>
// <Product product={product}/>
// </div>
// )
// })}
// </div>
// </div>
// </div>
);
}
class Config {
static inventoryUrl = "http://localhost:8080/api/products";
static promotionsUrl = "http://localhost:8081/api/promos";
}
......
import React from "react";
import ReactDOM from "react-dom";
import 'bootstrap/dist/css/bootstrap.css';
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
......
.img-container{
position:relative;
overflow:hidden;
padding-bottom:100%;
}
img {
position: absolute;
max-width: 100%;
max-height: 100%;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}
\ No newline at end of file
#title {
margin-left: 1em;
}
#prod-grid {
margin-left: 2em;
}
\ No newline at end of file
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment