/ src / components / Table / CargoTable.jsx
CargoTable.jsx
  1  import { useRef, useState, useEffect, useMemo } from "react";
  2  import React from "react";
  3  import styles from "../Form/form.module.scss";
  4  import { useMediaQuery } from "react-responsive";
  5  
  6  const CargoTable = ({
  7    rows,
  8    currencySymbol,
  9    onModifyTable,
 10    onAddInvoiceRow,
 11    onRemoveInvoiceRow,
 12    onTableData
 13  }) => {
 14    const isMobile = useMediaQuery({ query: `(max-width: 760px)` });
 15    const rateRef = useRef([]);
 16    const quantityRef = useRef([]);
 17  
 18    const [weight, setWeight] = useState(0);
 19  
 20    const handleWeigthChange = (e) => {
 21      const newWeight = parseFloat(e.target.value);
 22      setWeight(newWeight);
 23    };
 24  
 25    const calculateAmount = (rate, qty) => {
 26      const amount = (parseFloat(rate ? rate : 0) * parseFloat(qty ? qty : 0)).toFixed(2);
 27      return amount;
 28    };
 29  
 30    const handleClick = () => {
 31      onAddInvoiceRow();
 32    };
 33  
 34    const handleRemove = (id) => {
 35      onRemoveInvoiceRow(id);
 36    };
 37  
 38    const handleChange = (e, item, index) => {
 39      let amount;
 40  
 41      if (rateRef?.current[index] && quantityRef?.current[index]) {
 42        let rate = Number(rateRef.current[index].value);
 43        let quantity = Number(quantityRef.current[index].value);
 44        amount = calculateAmount(rate, quantity);
 45      }
 46      onModifyTable(e, item.id, amount);
 47    };
 48  
 49    const tableRows = useMemo(() =>
 50      rows.map((item, index) => (
 51        <React.Fragment key={item.id}>
 52          {!isMobile && (
 53            <tr className={styles.item__row}>
 54              <td className={styles.item__row__actions}>
 55                <div className={styles.confirm__delete__button}>
 56                  <button
 57                    type="button"
 58                    title="Remove Item"
 59                    className={styles.btn__remove}
 60                    onClick={() => handleRemove(item.id)}
 61                  >
 62                    <svg
 63                      aria-hidden="true"
 64                      focusable="false"
 65                      data-prefix="fas"
 66                      data-icon="times"
 67                      className={styles.svg__close__icon}
 68                      role="img"
 69                      xmlns="http://www.w3.org/2000/svg"
 70                      viewBox="0 0 352 512"
 71                    >
 72                      <path
 73                        fill="currentColor"
 74                        d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
 75                      ></path>
 76                    </svg>
 77                  </button>
 78                </div>
 79              </td>
 80              <td className={styles.description}>
 81                <input
 82                  className={styles.input__default}
 83                  type="text"
 84                  name="description"
 85                  id={`description__${item.id}`}
 86                  key={`des-input_${item.id}`}
 87                  placeholder="Product Name"
 88                  maxLength={30}
 89                  onChange={(e) => handleChange(e, item)}
 90                  value={item.description || ""}
 91                />
 92                <textarea
 93                  name="details"
 94                  id={`details__${item.id}`}
 95                  key={`details-input_${item.id}`}
 96                  placeholder="Product Description..."
 97                  className={`${styles.input__default} ${styles.details}`}
 98                  onChange={(e) => handleChange(e, item)}
 99                  value={item.details || ""}
100                ></textarea>
101              </td>
102              <td className={styles.rate}>
103                <input
104                  className={styles.input__default}
105                  type="number"
106                  name="rate"
107                  id={`rate__${item.id}`}
108                  ref={(el) => (rateRef.current[index] = el)}
109                  placeholder="0.00"
110                  maxLength={20}
111                  key={`rate-input_${item.id}`}
112                  onChange={(e) => handleChange(e, item, index)}
113                  value={item.rate || ""}
114                />
115              </td>
116              <td className={styles.qty}>
117                <input
118                  className={styles.input__default}
119                  type="number"
120                  name="quantity"
121                  id={`quantity__${item.id}`}
122                  ref={(el) => (quantityRef.current[index] = el)}
123                  placeholder="0"
124                  maxLength={15}
125                  key={`qty-input_${item.id}`}
126                  onChange={(e) => handleChange(e, item, index)}
127                  value={item.quantity || ""}
128                />
129              </td>
130              <td className={styles.rate}>
131                <input
132                  className={styles.input__default}
133                  type="number"
134                  name="weight"
135                  id={`weight__${item.id}`}
136                  placeholder="0.00"
137                  maxLength={20}
138                  key={`weight-input_${item.id}`}
139                  onChange={handleWeigthChange}
140                  value={weight}
141                />
142              </td>
143              <td className={styles.amount}>
144                <span>{currencySymbol} </span>
145                <span>{calculateAmount(item.rate, item.quantity, item.id)}</span>
146              </td>
147              {/* <td className={styles.tax}>Tax</td> */}
148            </tr>
149          )}
150  
151          {isMobile && (
152            <div className={styles.item__row}>
153              <div className={styles.description}>
154                <input
155                  className={styles.input__default}
156                  type="text"
157                  name="description"
158                  id={`description__${item.id}`}
159                  key={`des-input_${item.id}`}
160                  placeholder="Product Name"
161                  maxLength={20}
162                  onChange={(e) => handleChange(e, item)}
163                  value={item.description || ""}
164                />
165                <textarea
166                  name="details"
167                  id={`details__${item.id}`}
168                  key={`details-input_${item.id}`}
169                  placeholder="Product Description"
170                  className={`${styles.input__default} ${styles.mobile__details}`}
171                  onChange={(e) => handleChange(e, item)}
172                  value={item.details || ""}
173                ></textarea>
174              </div>
175              <div className={styles.input__group}>
176                <div className={styles.rate}>
177                  <input
178                    className={styles.input__default}
179                    type="number"
180                    name="rate"
181                    id={`rate__${item.id}`}
182                    ref={(el) => (rateRef.current[index] = el)}
183                    placeholder="price"
184                    maxLength={20}
185                    key={`rate-input_${item.id}`}
186                    onChange={(e) => handleChange(e, item, index)}
187                    value={item.rate || ""}
188                  />
189                </div>
190                <div className={styles.qty}>
191                  <input
192                    className={styles.input__default}
193                    type="number"
194                    name="quantity"
195                    id={`quantity__${item.id}`}
196                    ref={(el) => (quantityRef.current[index] = el)}
197                    placeholder="0"
198                    maxLength={15}
199                    key={`qty-input_${item.id}`}
200                    onChange={(e) => handleChange(e, item, index)}
201                    value={item.quantity || ""}
202                  />
203                </div>
204              </div>
205  
206              <div className={styles.item__row__actions__mobile}>
207                <div className={styles.confirm__delete__button}>
208                  <button
209                    type="button"
210                    title="Remove Item"
211                    className={styles.btn__remove}
212                    onClick={() => handleRemove(item.id)}
213                  >
214                    <svg
215                      aria-hidden="true"
216                      focusable="false"
217                      data-prefix="fas"
218                      data-icon="times"
219                      className={styles.svg__close__icon}
220                      role="img"
221                      xmlns="http://www.w3.org/2000/svg"
222                      viewBox="0 0 352 512"
223                    >
224                      <path
225                        fill="currentColor"
226                        d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
227                      ></path>
228                    </svg>
229                    <span className={styles.btn__text}>Delete</span>
230                  </button>
231                </div>
232                <div className={styles.amount}>
233                  <span>{currencySymbol} </span>
234                  <span>
235                    {calculateAmount(item.rate, item.quantity, item.id)}
236                  </span>
237                </div>
238              </div>
239            </div>
240          )}
241        </React.Fragment>
242      ))
243    , [rows, isMobile, onModifyTable]);
244  
245    useEffect(() => {
246      const updatedTableData = rows.map((item) => ({
247        productId: item ? item.id : null,
248        productName: item ? item.description : null,
249        productDescription: item ? item.details : null,
250        rate: item ? item.rate : null,
251        quantity: item ? item.quantity : null,
252        weight: weight,
253      }));
254      onTableData(updatedTableData);
255    }, [rows, weight, onTableData]);
256  
257    return (
258      <div className={styles.table__wrapper}>
259        {!isMobile && (
260          <table className={styles.table}>
261           <thead>
262              <tr className={styles.invoice__headers}>
263                <th className={styles.controls}>&nbsp;</th>
264                <th className={styles.description}>Description</th>
265                <th className={styles.rate}>Rate</th>
266                <th className={styles.qty}>Qty</th>
267                <th className={styles.rate}>Weight(Kg)</th>
268                <th className={styles.amount}>Amount</th>
269                {/* <th className={styles.tax}>Tax</th> */}
270              </tr>
271            </thead>
272            <tbody className={styles.invoice__items}>
273              <>{tableRows}</>
274              <tr className={styles.item__row}>
275                <td className={styles.item__row__actions}>
276                  <button
277                    type="button"
278                    onClick={handleClick}
279                    className={`${styles.add__invoice__item} ${styles.btn__add}`}
280                  >
281                    <svg
282                      aria-hidden="true"
283                      focusable="false"
284                      data-prefix="fas"
285                      data-icon="plus"
286                      role="img"
287                      xmlns="http://www.w3.org/2000/svg"
288                      viewBox="0 0 448 512"
289                    >
290                      <path
291                        fill="#ffffff"
292                        d="M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z"
293                      ></path>
294                    </svg>
295                  </button>
296                </td>
297              </tr>
298            </tbody>
299          </table>
300        )}
301        {isMobile && (
302          <div className={styles.mobile__section}>
303             <>{tableRows}</>
304            <button
305              type="button"
306              onClick={handleClick}
307              className={`${styles.add__invoice__item} ${styles.btn__add}`}
308            >
309              <svg
310                aria-hidden="true"
311                focusable="false"
312                data-prefix="fas"
313                data-icon="plus"
314                role="img"
315                xmlns="http://www.w3.org/2000/svg"
316                viewBox="0 0 448 512"
317              >
318                <path
319                  fill="#ffffff"
320                  d="M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z"
321                ></path>
322              </svg>
323            </button>
324          </div>
325        )}
326      </div>
327    );
328  };
329  
330  export default CargoTable;