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