Rates Modal - Copy this React, Tailwind Component to your project
Import React, { useState, useEffect } from "react"; import { MdMessage, MdCall, MdVideoCall } from "react icons/md"; import { BsCash, BsClock } from "react icons/bs"; import { useDispatch } from "react redux"; import { createRates, updateRates, } from "../../../../features/rate/ratesAction"; const RatesModal = ({ modalAction, handleCloseModal, selectedItem }) => { const dispatch = useDispatch(); const [type, setType] = useState(""); const [textRate, setTextRate] = useState(""); const [durationRates, setDurationRates] = useState({ "15 min": "", "30 min": "", "45 min": "", "1 hour": "", }); const [errors, setErrors] = useState({}); const durations = ["15 min", "30 min", "45 min", "1 hour"]; const serviceTypes = [ { value: "chat", label: "Chat", icon: <MdMessage className="w 5 h 5" /> }, { value: "audio", label: "Audio", icon: <MdCall className="w 5 h 5" /> }, { value: "video", label: "Video Call", icon: <MdVideoCall className="w 5 h 5" />, }, ]; useEffect(() => { if (modalAction === "edit" && selectedItem) { console.log(`selectedItem = ${JSON.stringify(selectedItem)}`); setType(selectedItem.type || ""); if (selectedItem.type === "chat") { setTextRate(selectedItem.rates || ""); } else if ( selectedItem.type === "audio" || selectedItem.type === "video" ) { setDurationRates({ ...selectedItem.rates, }); } } }, [modalAction, selectedItem]); const validateForm = () => { const newErrors = {}; if (!type) { newErrors.type = "Please select a service type"; } if (type === "chat") { if (!textRate) { newErrors.textRate = "Please enter a rate"; } else if (isNaN(textRate) || textRate <= 0) { newErrors.textRate = "Please enter a valid rate"; } } else if (type === "audio" || type === "video") { durations.forEach((duration) => { if (!durationRates[duration]) { newErrors[duration] = "Please enter a rate"; } else if ( isNaN(durationRates[duration]) || durationRates[duration] <= 0 ) { newErrors[duration] = "Please enter a valid rate"; } }); } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSubmit = (e) => { e.preventDefault(); if (validateForm()) { const action = modalAction === "add" ? createRates : updateRates; const updateForm = { type, rates: type === "chat" ? textRate : durationRates, ...(modalAction === "edit" && { rateId: selectedItem.id }), }; console.log(`updateForm = ${JSON.stringify(updateForm)}`); // dispatch(action(updateForm)) // .unwrap() // .then(() => { // // Reset form // setType(""); // setTextRate(""); // setDurationRates({ // "15 min": "", // "30 min": "", // "45 min": "", // "1 hour": "", // }); // handleCloseModal(); // }) // .catch((error) => { // console.error("Error saving rate:", error); // }); } }; return ( <form onSubmit={handleSubmit} className="space y 6"> <div> <label className="block text sm font medium text gray 700 mb 2"> Service Type </label> <select value={type} onChange={(e) => { setType(e.target.value); setErrors({}); }} className="block w full pl 3 pr 10 py 2 text base border gray 300 focus:outline none focus:ring indigo 500 focus:border indigo 500 rounded md" > <option value="">Select a service</option> {serviceTypes.map((type) => ( <option key={type.value} value={type.value}> {type.label} </option> ))} </select> {errors.type && ( <p className="mt 1 text sm text red 600">{errors.type}</p> )} </div> {type === "chat" && ( <div> <label className="block text sm font medium text gray 700 mb 2"> Text Rate </label> <div className="relative rounded md shadow sm"> <div className="absolute inset y 0 left 0 pl 3 flex items center pointer events none"> <BsCash className="h 5 w 5 text gray 400" /> </div> <input type="number" value={textRate} onChange={(e) => setTextRate(e.target.value)} className="block w full pl 10 pr 3 py 2 border gray 300 rounded md focus:ring indigo 500 focus:border indigo 500" placeholder="Enter rate" /> </div> {errors.textRate && ( <p className="mt 1 text sm text red 600">{errors.textRate}</p> )} </div> )} {(type === "audio" || type === "video") && ( <div className="space y 4"> <label className="block text sm font medium text gray 700 mb 2"> Duration Rates </label> {Object.keys(durationRates).map((duration) => ( <div key={duration} className="flex items center space x 4"> <div className="flex 1"> <div className="relative rounded md shadow sm"> <input type="text" disabled value={duration} className="block w full pl 3 pr 3 py 2 bg gray 50 border gray 300 rounded md" /> </div> </div> <div className="flex 1"> <div className="relative rounded md shadow sm"> <input type="number" value={durationRates[duration] || ""} onChange={(e) => setDurationRates((prev) => ({ ...prev, [duration]: e.target.value, })) } className="block w full pl 3 pr 3 py 2 border gray 300 rounded md focus:ring indigo 500 focus:border indigo 500" placeholder={`Enter rate for ${duration}`} /> </div> </div> </div> ))} </div> )} <div className="flex justify center w full gap 2"> <button type="submit" className="bg blue 600 text white px 4 py 2 rounded lg hover:bg blue 700" > {modalAction === "add" ? "Add" : "Update"} Rate </button> <button type="button" onClick={handleCloseModal} className="bg red 600 text white px 4 py 2 rounded lg hover:bg red 700" > Cancel </button> </div> </form> ); }; export default RatesModal; for chat i should be able to add remove multuple question
