Advertisement
fabiobiondi

React Pro - Real World App - Ch9. 13. Dirty State

Mar 23rd, 2023
1,008
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // pages/cms/products/components/CMSProductForm.tsx
  2. import clsx from 'clsx';
  3. import { ChangeEvent, FormEvent, useEffect, useState } from 'react';
  4. import { Product } from '@/model/product';
  5.  
  6. export interface CMSProductFormProps {
  7.   activeItem: Partial<Product> | null;
  8.   onClose: () => void;
  9.   onAdd: (product: Partial<Product>) => void;
  10.   onEdit: (product: Partial<Product>) => void;
  11. }
  12.  
  13. const initialState: Partial<Product> = {
  14.   name: '', cost: 0, description: ''
  15. }
  16.  
  17. export function CMSProductForm(props: CMSProductFormProps) {
  18.   const [formData, setFormData] = useState(initialState);
  19.   const [dirty, setDirty] = useState<boolean>(false);
  20.  
  21.   useEffect(() => {
  22.     if (props.activeItem?.id) {
  23.       setFormData({ ...props.activeItem })
  24.     } else {
  25.       setFormData(initialState)
  26.     }
  27.   }, [props.activeItem])
  28.  
  29.   function changeHandler(e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) {
  30.     const value = e.currentTarget.value;
  31.     const name = e.currentTarget.name;
  32.     setFormData(s => ({ ...s, [name]: value }));
  33.     setDirty(true);
  34.   }
  35.  
  36.   function saveHandler(e: FormEvent<HTMLFormElement>) {
  37.     e.preventDefault();
  38.     if (props.activeItem?.id) {
  39.       props.onEdit(formData);
  40.     } else {
  41.       props.onAdd(formData);
  42.     }
  43.   }
  44.  
  45.   const isNameValid = formData.name?.length;
  46.   const isCostValid = formData.cost! > 0;
  47.   const isDescValid = formData.description?.length;
  48.  
  49.   const isValid = isNameValid && isCostValid && isDescValid;
  50.  
  51.   return (
  52.     <div className={clsx(
  53.       'fixed bg-slate-200 z-10 text-black top-0 w-96  h-full transition-all',
  54.       {'-right-96': !props.activeItem, 'right-0': props.activeItem}
  55.     )}>
  56.  
  57.       <form onSubmit={saveHandler}>
  58.         <div className="flex justify-around h-16">
  59.           <button
  60.             className="text-white w-1/2 bg-green-500 hover:bg-green-600 disabled:opacity-30"
  61.             disabled={!isValid}
  62.             type="submit"
  63.           >SAVE</button>
  64.           <button
  65.             className="text-white w-1/2 bg-slate-500 hover:bg-slate-600"
  66.             onClick={props.onClose}
  67.             type="button"
  68.           >CLOSE</button>
  69.         </div>
  70.  
  71.         <div className="flex flex-col gap-3 mx-3 mt-16">
  72.           Product Name:
  73.           <input
  74.             className={clsx({ 'error': !isNameValid && dirty})}
  75.             type="text" value={formData?.name} name="name" onChange={changeHandler}
  76.           />
  77.  
  78.           Product Cost:
  79.           <input
  80.             className={clsx({ 'error': !isCostValid && dirty})}
  81.             type="number" value={formData?.cost} name="cost" onChange={changeHandler}
  82.           />
  83.  
  84.           Description
  85.           <textarea
  86.             className={clsx({ 'error': !isDescValid && dirty})}
  87.             value={formData.description} name="description" onChange={changeHandler}
  88.           ></textarea>
  89.  
  90.         </div>
  91.       </form>
  92.  
  93.  
  94.     </div>
  95.   )
  96. }
  97.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement