View difference between Paste ID: 7RJeRbj4 and 14SXNcCv
SHOW: | | - or go back to the newest paste.
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
        {
72
          formData.img &&
73
            <img src={formData.img} alt={formData.name} className="w-full" />
74
        }
75
76
        <div className="flex flex-col gap-3 mx-3 mt-16">
77
          Product Name:
78
          <input
79
            className={clsx({ 'error': !isNameValid && dirty})}
80
            type="text" value={formData?.name} name="name" onChange={changeHandler}
81
          />
82
83
          Product Cost:
84
          <input
85
            className={clsx({ 'error': !isCostValid && dirty})}
86
            type="number" value={formData?.cost} name="cost" onChange={changeHandler}
87
          />
88
89
          Description
90
          <textarea
91
            className={clsx({ 'error': !isDescValid && dirty})}
92
            value={formData.description} name="description" onChange={changeHandler}
93
          ></textarea>
94
95
        </div>
96
      </form>
97
98
99
    </div>
100
  )
101
}
102