From 297a732676acf2c71c9c516413013a258124e429 Mon Sep 17 00:00:00 2001 From: Damillora Date: Mon, 29 Mar 2021 14:40:58 +0700 Subject: [PATCH] Refactor with React hooks --- Next/{interfaces => lib}/product.ts | 11 ++ Next/pages/product/create.tsx | 131 +++++++++------------ Next/pages/product/edit/[id].tsx | 171 +++++++++++----------------- Next/pages/product/index.tsx | 2 +- Next/pages/shared/Layout.tsx | 6 +- TestAppRuna/Shop.sqlite.db | Bin 36864 -> 36864 bytes 6 files changed, 138 insertions(+), 183 deletions(-) rename Next/{interfaces => lib}/product.ts (68%) diff --git a/Next/interfaces/product.ts b/Next/lib/product.ts similarity index 68% rename from Next/interfaces/product.ts rename to Next/lib/product.ts index 2c1cdd6..934a5ff 100644 --- a/Next/interfaces/product.ts +++ b/Next/lib/product.ts @@ -20,4 +20,15 @@ export interface ProductFormState { }, errors: string[], busy: boolean, +} + +export function validateForm(form): string[] { + let errors: string[] = []; + if (!form.name) { + errors.push("Name required"); + } + if (!form.price) { + errors.push("Price required"); + } + return errors; } \ No newline at end of file diff --git a/Next/pages/product/create.tsx b/Next/pages/product/create.tsx index df586cd..c09f22c 100644 --- a/Next/pages/product/create.tsx +++ b/Next/pages/product/create.tsx @@ -1,66 +1,48 @@ -import React, { ChangeEvent } from 'react'; +import React, { useEffect, useState } from 'react'; +import { useRouter } from 'next/router'; import { Layout } from '../shared/Layout'; import { ProductClient } from '../../APIClient'; import Swal from 'sweetalert2'; import ProductForm from '../../components/ProductForm'; -import Errors from '../../components/Errors'; import Link from 'next/link'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faArrowLeft } from '@fortawesome/free-solid-svg-icons'; -import { ProductFormState } from '../../interfaces/product'; +import { validateForm } from '../../lib/product'; -class CreateProduct extends React.Component<{}, ProductFormState> { - constructor(props) { - super(props) - this.state = { - form: { - name: "", - price: 0, - }, - errors: [], - busy: false, - } - } - onNameChanged(newName) { - this.setState({ - form: { +function Errors({ errors }) { + return errors.map(x => ( +
  • {x}
  • + )); +} + +function CreateProduct() { + let [form, setForm] = useState({ name: "", price: 0 }); + let [busy, setBusy] = useState(false); + let [errors,setErrors] = useState([""]); + + const onNameChanged = (newName: string) => { + setForm( + { name: newName, - price: this.state.form.price, + price: form.price, } + ); + } + const onPriceChanged = (newPrice: number) => { + setForm({ + name: form.name, + price: newPrice, }); } - onPriceChanged(newPrice) { - this.setState({ - form: { - name: this.state.form.name, - price: newPrice - } - }); - } - async validate() { - let errors: string[] = []; - if (!this.state.form.name) { - errors.push("Name required"); - } - if (!this.state.form.price) { - errors.push("Price required"); - } - await new Promise((resolve) => { - this.setState({ - errors - }, () => resolve(undefined)); - }) + const validate = () => { + let errors: string[] = validateForm(form); + setErrors(errors); return errors.length == 0; } - async onSubmit() { - if (await this.validate()) { - await new Promise((resolve) => { - this.setState({ - busy: true, - }, () => resolve(undefined)); - }) + const onSubmit = async () => { + if (validate()) { + setBusy(true); try { - const form = this.state.form; const client = new ProductClient(); await client.post({ name: form.name, @@ -68,44 +50,37 @@ class CreateProduct extends React.Component<{}, ProductFormState> { }) Swal.fire({ title: "Submitted!", - text: "Product is now in database", + text: "Product is added in database", }) } catch (error) { } finally { - await new Promise((resolve) => { - this.setState({ - busy: false, - }, () => resolve(undefined)); - }) - + setBusy(false); } } } - render() { - return ( -
    -

    Create Product

    - - - Return to index - - - -
      - -
    -
    - ) - } -} + return ( +
    +

    Create Product

    + + + Return to index + + + +
      + +
    +
    + ); +} export default function CreateProductPage() { return ( diff --git a/Next/pages/product/edit/[id].tsx b/Next/pages/product/edit/[id].tsx index 6dac913..3c21ebe 100644 --- a/Next/pages/product/edit/[id].tsx +++ b/Next/pages/product/edit/[id].tsx @@ -1,5 +1,5 @@ -import React, { ChangeEvent } from 'react'; -import { withRouter, NextRouter, useRouter } from 'next/router'; +import React, { useEffect, useState } from 'react'; +import { useRouter } from 'next/router'; import { Layout } from '../../shared/Layout'; import { ProductClient } from '../../../APIClient'; import Swal from 'sweetalert2'; @@ -7,90 +7,69 @@ import ProductForm from '../../../components/ProductForm'; import Link from 'next/link'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faArrowLeft } from '@fortawesome/free-solid-svg-icons'; -import { ProductDataProps, ProductFormState } from '../../../interfaces/product'; +import { validateForm } from '../../../lib/product'; function Errors({ errors }) { return errors.map(x => (
  • {x}
  • )); } -class EditProduct extends React.Component { - constructor(props) { - super(props) - const id = props.productID; - this.state = { - form: { - name: "", - price: 0, - }, - errors: [], - busy: false, - } + +function EditProduct({ productID }) { + if (typeof productID != "string") { + return ( +
    +
    + ) } - async componentDidMount() { + let [form, setForm] = useState({ name: "", price: 0 }); + let [busy, setBusy] = useState(false); + let [errors,setErrors] = useState([""]); + + const getInitialData = async() => { const client = new ProductClient(); - await new Promise((resolve) => { - this.setState({ - busy: true, - }, () => resolve(undefined)); - }) - if (this.props.productID) { - let data = await client.get(this.props.productID); - await new Promise((resolve) => { - this.setState({ - busy: false, - }, () => resolve(undefined)); - }) - this.setState({ - form: { - name: data.name, - price: data.price, - } - }); - } + let data = await client.get(productID); + setBusy(false); + setForm( + { + name: data.name, + price: data.price, + } + ); } - onNameChanged(newName: string) { - this.setState({ - form: { + // Startup + useEffect(() => { + setBusy(true); + if (productID) { + getInitialData(); + } + }, [productID]); + + const onNameChanged = (newName: string) => { + setForm( + { name: newName, - price: this.state.form.price, + price: form.price, } + ); + } + const onPriceChanged = (newPrice: number) => { + setForm({ + name: form.name, + price: newPrice, }); } - onPriceChanged(newPrice: number) { - this.setState({ - form: { - name: this.state.form.name, - price: newPrice, - } - }); - } - async validate() { - let errors: string[] = []; - if (!this.state.form.name) { - errors.push("Name required"); - } - if (!this.state.form.price) { - errors.push("Email required"); - } - await new Promise((resolve) => { - this.setState({ - errors - }, () => resolve(undefined)); - }) + const validate = () => { + let errors: string[] = validateForm(form); + setErrors(errors); return errors.length == 0; } - async onSubmit() { - if (await this.validate()) { - await new Promise((resolve) => { - this.setState({ - busy: true, - }, () => resolve(undefined)); - }) + const onSubmit = async () => { + if (validate()) { + setBusy(true); try { - const form = this.state.form; const client = new ProductClient(); - await client.put(this.props.productID, { + await client.put(productID, { name: form.name, price: form.price, }) @@ -101,43 +80,31 @@ class EditProduct extends React.Component { } catch (error) { } finally { - await new Promise((resolve) => { - this.setState({ - busy: false, - }, () => resolve(undefined)); - }) - + setBusy(false); } } } - render() { - if (typeof this.props.productID != "string") { - return ( -
    -
    - ) - } - return ( -
    -

    Edit Product

    - - - Return to index + + return ( +
    +

    Edit Product

    + +
    + Return to index - - -
      - -
    -
    - ) - } + + +
      + +
    +
    + ); } export default function EditProductPage() { diff --git a/Next/pages/product/index.tsx b/Next/pages/product/index.tsx index 1cbbdaa..6d7f239 100644 --- a/Next/pages/product/index.tsx +++ b/Next/pages/product/index.tsx @@ -7,7 +7,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faEdit, faTrash } from '@fortawesome/free-solid-svg-icons'; import { useRouter } from 'next/router'; import Link from 'next/link'; -import { DeleteProductProps, ProductDataProps, ProductListRowsProps, ProductState } from '../../interfaces/product'; +import { DeleteProductProps, ProductDataProps, ProductListRowsProps, ProductState } from '../../lib/product'; const DeleteProductButton: React.FunctionComponent = ({ productID, onDelete }) => { const onClickDelete = async () => { diff --git a/Next/pages/shared/Layout.tsx b/Next/pages/shared/Layout.tsx index 6d1a3d5..ca24974 100644 --- a/Next/pages/shared/Layout.tsx +++ b/Next/pages/shared/Layout.tsx @@ -18,7 +18,7 @@ const NavLink: React.FunctionComponent<{href: string}> = ({href, children}) => { if(active) { return "page"; } else { - return null; + return undefined; } } const active = router.pathname == href; @@ -26,7 +26,7 @@ const NavLink: React.FunctionComponent<{href: string}> = ({href, children}) => { return (
  • - {children} + {children}
  • ); @@ -53,6 +53,8 @@ const NavBar: React.FunctionComponent<{}> = () => {
      Home Todo + Customer + Product
    diff --git a/TestAppRuna/Shop.sqlite.db b/TestAppRuna/Shop.sqlite.db index 77747a9bb6cf8db75063663ace7839a6ac4ad412..cccb0388dd5afc97bdefecf69a0a1af5af537333 100644 GIT binary patch delta 135 zcmZozz|^pSX#<-9M>_-mG5&Ubhs}Ztru>tg?Hz3x7#M7sSwfW+&5fLmU7U@LbuA4n z9Cb}h4J~yoj4h0GjV#R!-ApVD4O~o(LlScn74l0<(lSd7jSLJnAFw~guR@H*&FlPw F902qSA~OI0 delta 135 zcmZozz|^pSX#<-9M+*c0G5!{Qhs}Ztru>tg?Hz3#m{~$~Wlb$z42(>T9Cck>Tr6}= z3|(Axo!m@JbzLmYT}=&5EnJ