Commit dab71996 authored by Pavel Mishakov's avatar Pavel Mishakov

lesson 85 done

parent ff9d2415
......@@ -6,6 +6,9 @@ import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Col, Container, Row } from "react-bootstrap";
import Layout from "./components/Layout/Layout";
import { Routes, Route } from "react-router-dom";
import ProductForm from "./components/ProductForm/ProductForm";
const App = () => {
......@@ -25,12 +28,12 @@ const App = () => {
}, [])
return (
<>
<h1>{messageProducts}</h1>
{JSON.stringify(products)}
<h1>Product by id: </h1>
{JSON.stringify(product)}
</>
<Layout>
<Routes>
<Route path={'/'} element={<h1>HOME PAGE</h1>} />
<Route path={'/add-product'} element={<ProductForm />} />
</Routes>
</Layout>
)
}
......
......@@ -35,7 +35,7 @@ class ProductApi {
}
}
public createProduct = async(product: IProductDto): Promise<IResponse> => {
public createProduct = async(product: FormData): Promise<IResponse> => {
try {
const response = await instance.post(`/products`, product)
return response.data
......
.Header__link {
text-decoration: none;
color: black;
}
\ No newline at end of file
import React, { FunctionComponent, ReactElement } from "react";
import { NavLink } from "react-router-dom";
import styles from './Header.module.css'
const Header: FunctionComponent = (): ReactElement => {
return (
<header className={styles.Header}>
<NavLink
className={styles.Header__link}
to={'/add-product'}
>
Add product
</NavLink>
<NavLink
className={styles.Header__link}
to={'/products'}
>
Products
</NavLink>
</header>
)
}
export default Header
\ No newline at end of file
import { ReactNode } from "react";
export default interface ILayoutProps {
children: ReactNode
}
\ No newline at end of file
import React, { FunctionComponent, ReactElement } from "react";
import Header from "../Header/Header";
import ILayoutProps from "./ILayoutProps";
import styles from './Layout.module.css'
const Layout: FunctionComponent<ILayoutProps> = (props): ReactElement => {
return (
<div className={styles.Layout}>
<Header />
<main>
{props.children}
</main>
</div>
)
}
export default Layout
\ No newline at end of file
.ProductForm__fileInput {
display: none;
}
\ No newline at end of file
import React, { ChangeEvent, FormEvent, FunctionComponent, ReactElement, useState } from "react";
import { useDispatch } from "react-redux";
import IProductDto from "../../interfaces/IProductDto";
import { createProduct } from "../../store/products/products.slice";
import { AppDispatch } from "../../store/store";
import styles from './ProductForm.module.css'
const ProductForm: FunctionComponent = (): ReactElement => {
const dispatch: AppDispatch = useDispatch()
const [product, setProduct] = useState<IProductDto>({
product: '',
price: 0,
description: '',
image: undefined
})
const [fileName, setFileName] = useState<string>('')
const inputHandler = (e: ChangeEvent<HTMLInputElement>): void => {
setProduct(prevState => {
return {...prevState, [e.target.name]: e.target.value}
})
console.log(product)
}
const inputFileHandler = (e: ChangeEvent<HTMLInputElement>): void => {
setProduct(prevState => {
return {...prevState,
image: e.target.files ? e.target.files[0] : undefined}
})
setFileName(e.target.files && e.target.files[0] ? e.target.files[0].name : '')
}
const submitHandler = (e: FormEvent) => {
e.preventDefault()
const formData = new FormData()
Object.keys(product).forEach((key: any) => {
//@ts-ignore
formData.append(key, product[key])
})
dispatch(createProduct(formData))
}
return (
<div className={styles.ProductForm}>
<form onSubmit={submitHandler}>
<input
name={'product'}
type="text"
placeholder="Title"
value={product.product}
onChange={inputHandler}
/>
<input
name={'price'}
type="number"
placeholder="Price"
value={product.price}
onChange={inputHandler}
/>
<input
name={'description'}
type="text"
placeholder="Description"
value={product.description}
onChange={inputHandler}
/>
<label>
<input
className={styles.ProductForm__fileInput}
type="file"
name={'image'}
onChange={inputFileHandler}
/>
<h2>
CHOOSE FILE
</h2>
<span>{fileName}</span>
</label>
<button>SEND</button>
</form>
</div>
)
}
export default ProductForm
\ No newline at end of file
......@@ -7,4 +7,8 @@ body {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
}
.active {
color: red !important;
}
\ No newline at end of file
......@@ -4,6 +4,9 @@ export default interface IProduct {
id: string
product: string
price: number
category_id: string
brand_id: string
description: string
suppliers?: ISupplier[]
image: string
}
\ No newline at end of file
......@@ -2,4 +2,7 @@ export default interface IProductDto {
product: string
price: number
description: string
category_id?: string | null
brand_id?: string | null
image?: File
}
\ No newline at end of file
......@@ -23,7 +23,7 @@ export const getProductById = createAppAsyncThunk(
export const createProduct = createAppAsyncThunk(
`${namespace}/createProduct`,
async (product: IProductDto) => {
async (product: FormData) => {
return productApi.createProduct(product)
}
)
......
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