A
Anonymous

BadgeSelect Pro Copy this Tailwind Component 0to Your Project

To implement a multi select dropdown in React with badges for already selected members, you can use a combination of state management and event handling. The selected members should be stored in the component's state, and you can display them as badges. When new members are selected, ensure that the existing selections persist. Consider using libraries like react select for the dropdown functionality, which can simplify the implementation. You can manage the selected members in the state and update it based on user interactions, ensuring that the badges reflect the current selections. Implementation of Multi Select with Badges To achieve the desired functionality where selected members are displayed as badges and persist even when new members are selected, you can modify the EditProject component as follows: Maintain State for Selected Members: Ensure that the state for selected members is updated correctly without losing previous selections. Display Badges for Selected Members: Render badges for each selected member below the multi select dropdown. Handle Member Selection: Update the state to include newly selected members while retaining previously selected ones. Updated EditProject Component javascript Run Copy code import React, { useState, useEffect } from "react"; import * as Yup from "yup"; import { updateProject, getUsers, getProjectStatuses } from "../../utils/api"; import { Form, Button, Alert, Badge } from "react bootstrap"; const getToken = () => localStorage.getItem("token"); const EditProject = ({ project, token, onSubmit }) => { const storedToken = token || getToken(); const [formData, setFormData] = useState({ name: "", description: "", startDate: "", endDate: "", createdBy: "", status: "", teamMembers: [], attachment: null, }); const [errors, setErrors] = useState({}); const [statusesList, setStatusesList] = useState([]); const [users, setUsers] = useState([]); useEffect(() => { const fetchData = async () => { try { const tokenToUse = token || getToken(); if (!tokenToUse) { console.error("Token is missing, cannot fetch users or statuses."); return; } const usersData = await getUsers(tokenToUse); const statuses = await getProjectStatuses(tokenToUse); setUsers(usersData); setStatusesList(statuses); } catch (err) { console.error("Error fetching users or statuses:", err); } }; fetchData(); }, [token]); useEffect(() => { if (project) { setFormData({ name: project.name || "", description: project.description || "", startDate: project.startDate || "", endDate: project.endDate || "", createdBy: project.createdBy ? String(project.createdBy) : "", status: project.status || "", teamMembers: project.teamMembers?.map((id) => String(id)) || [], attachment: null, }); } }, [project]); const schema = Yup.object().shape({ name: Yup.string().required("Project name is required").max(350, "Project name cannot be longer than 350 characters"), description: Yup.string().required("Description is required").max(350, "Description cannot be longer than 350 characters"), createdBy: Yup.string().required("Created By is required"), status: Yup.string().required("Status is required"), teamMembers: Yup.array().of(Yup.string()).min(1, "At least one team member is required"), }); const handleChange = async (e) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: value })); try { await Yup.reach(schema, name).validate(value); setErrors((prev) => ({ ...prev, [name]: "" })); } catch (error) { setErrors((prev) => ({ ...prev, [name]: error.message })); } }; const handleMultiSelect = (e) => { const selected = Array.from(e.target.selectedOptions, (o) => o.value); setFormData((prev) => ({ ...prev, teamMembers: Array.from(new Set([...prev.teamMembers, ...selected])), // Ensure unique selections })); }; const handleRemoveMember = (id) => { setFormData((prev) => ({ ...prev, teamMembers: prev.teamMembers.filter((m) => m !== id), })); }; const getStatusInt = (status) => { const map = { completed: 1, onhold: 2, cancelled: 3, inprogress: 4, new: 5 }; return map[status] || 0; }; const handleSubmit = async (e) => { e.preventDefault(); try { await schema.validate(formData, { abortEarly: false }); setErrors({}); const mappedData = new FormData(); mappedData.append("name", formData.name); mappedData.append("description", formData.description); mappedData.append("startDate", formData.startDate); mappedData.append("endDate", formData.endDate); mappedData.append("createdBy", parseInt(formData.createdBy)); help me complete this please my previous code: import React, { useState, useEffect } from "react"; import * as Yup from "yup"; import { updateProject, getUsers, getProjectStatuses } from "../../utils/api"; import { Form, Button, Alert, Badge } from "react bootstrap"; const getToken = () => localStorage.getItem("token"); const EditProject = ({ project, token, onSubmit }) => { const storedToken = token || getToken(); const [formData, setFormData] = useState({ name: "", description: "", startDate: "", endDate: "", createdBy: "", status: "", teamMembers: [], attachment: null, }); const [errors, setErrors] = useState({}); const [statusesList, setStatusesList] = useState([]); const [users, setUsers] = useState([]); useEffect(() => { const fetchData = async () => { try { const tokenToUse = token || getToken(); // Ensure token is present if (!tokenToUse) { console.error("Token is missing, cannot fetch users or statuses."); return; } const usersData = await getUsers(tokenToUse); const statuses = await getProjectStatuses(tokenToUse); setUsers(usersData); setStatusesList(statuses); } catch (err) { console.error("Error fetching users or statuses:", err); } }; fetchData(); }, [token]); useEffect(() => { if (project) { setFormData({ name: project.name || "", description: project.description || "", startDate: project.startDate || "", endDate: project.endDate || "", createdBy: project.createdBy ? String(project.createdBy) : "", // Ensure it's a string for comparison in the dropdown status: project.status || "", teamMembers: project.teamMembers?.map((id) => String(id)) || [], // Ensure teamMembers is an array of strings attachment: null, }); } }, [project]); const schema = Yup.object().shape({ name: Yup.string().required("Project name is required").max(350, "Project name cannot be longer than 350 characters"), description: Yup.string().required("Description is required").max(350, "Description cannot be longer than 350 characters"), createdBy: Yup.string().required("Created By is required"), status: Yup.string().required("Status is required"), teamMembers: Yup.array().of(Yup.string()).min(1, "At least one team member is required"), }); const handleChange = async (e) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: value })); try { await Yup.reach(schema, name).validate(value); setErrors((prev) => ({ ...prev, [name]: "" })); } catch (error) { setErrors((prev) => ({ ...prev, [name]: error.message })); } }; const handleMultiSelect = (e) => { const selected = Array.from(e.target.selectedOptions, (o) => o.value); setFormData((prev) => ({ ...prev, teamMembers: selected })); }; const handleRemoveMember = (id) => { setFormData((prev) => ({ ...prev, teamMembers: prev.teamMembers.filter((m) => m !== id), })); }; const getStatusInt = (status) => { const map = { completed: 1, onhold: 2, cancelled: 3, inprogress: 4, new: 5 }; return map[status] || 0; }; const handleSubmit = async (e) => { e.preventDefault(); try { await schema.validate(formData, { abortEarly: false }); setErrors({}); const mappedData = new FormData(); mappedData.append("name", formData.name); mappedData.append("description", formData.description); mappedData.append("startDate", formData.startDate); mappedData.append("endDate", formData.endDate); mappedData.append("createdBy", parseInt(formData.createdBy)); mappedData.append("status", getStatusInt(formData.status)); formData.teamMembers.forEach((id) => mappedData.append("memberId", parseInt(id)) ); if (formData.attachment) { mappedData.append("attachment", formData.attachment); } const updatedProject = await updateProject( project.id, mappedData, storedToken, true ); onSubmit && onSubmit(updatedProject); alert("Project updated successfully!"); const modalElement = document.getElementById("editModal"); if (modalElement) { const modalInstance = bootstrap.Modal.getInstance(modalElement); modalInstance?.hide(); } } catch (error) { if (error instanceof Yup.ValidationError) { const validationErrors = {}; error.inner.forEach((err) => { if (err.path) validationErrors[err.path] = err.message; }); setErrors(validationErrors); } else { console.error("Submission error:", error); } } }; return ( <Form onSubmit={handleSubmit} className="p 3"> {Object.keys(errors).length > 0 && ( <Alert variant="danger">Please fix the highlighted fields.</Alert> )} <Form.Group className="mb 3"> <Form.Label>Project Name</Form.Label> <Form.Control type="text" name="name" value={formData.name} onChange={handleChange} isInvalid={!!errors.name} /> <Form.Control.Feedback type="invalid">{errors.name}</Form.Control.Feedback> </Form.Group> <Form.Group className="mb 3"> <Form.Label>Project Description</Form.Label> <Form.Control as="textarea" name="description" value={formData.description} onChange={handleChange} isInvalid={!!errors.description} /> <Form.Control.Feedback type="invalid">{errors.description}</Form.Control.Feedback> </Form.Group> <Form.Group className="mb 3"> <Form.Label>Created By</Form.Label> <Form.Select name="createdBy" value={formData.createdBy} onChange={handleChange} isInvalid={!!errors.createdBy} > <option value="">Select Creator</option> {users.map((user) => ( <option key={user.id} value={user.id}> {user.userName} </option> ))} </Form.Select> <Form.Control.Feedback type="invalid">{errors.createdBy}</Form.Control.Feedback> </Form.Group> <Form.Group className="mb 3"> <Form.Label>Start Date</Form.Label> <Form.Control type="date" name="startDate" value={formData.startDate} onChange={handleChange} isInvalid={!!errors.startDate} /> <Form.Control.Feedback type="invalid">{errors.startDate}</Form.Control.Feedback> </Form.Group> <Form.Group className="mb 3"> <Form.Label>End Date</Form.Label> <Form.Control type="date" name="endDate" value={formData.endDate} onChange={handleChange} isInvalid={!!errors.endDate} /> <Form.Control.Feedback type="invalid">{errors.endDate}</Form.Control.Feedback> </Form.Group> <Form.Group className="mb 3"> <Form.Label>Status</Form.Label> <Form.Select name="status" value={formData.status} onChange={handleChange} isInvalid={!!errors.status} > <option value="">Select Status</option> {statusesList.map((status) => ( <option key={status.id} value={status.status}> {status.status} </option> ))} </Form.Select> <Form.Control.Feedback type="invalid">{errors.status}</Form.Control.Feedback> </Form.Group> <Form.Group className="mb 3"> <Form.Label>Attachment</Form.Label> <Form.Control type="file" name="attachment" onChange={(e) => setFormData((prev) => ({ ...prev, attachment: e.target.files[0] })) } /> {project?.attachment?.fileName && ( <div className="mt 2 text muted"> Current File: <strong>{project.attachment.fileName}</strong> </div> )} </Form.Group> <Form.Group className="mb 3"> <Form.Label>Assign Members</Form.Label> <div className="d flex flex wrap"> {users.map((user) => ( <Badge key={user.id} bg={formData.teamMembers.includes(user.id) ? "primary" : "light"} className="me 2" onClick={() => handleRemoveMember(user.id)} style={{ cursor: "pointer" }} > {user.userName} {formData.teamMembers.includes(user.id) && ( <span style={{ marginLeft: "5px" }}>×</span> )} </Badge> ))} </div> {errors.teamMembers && <div className="text danger">{errors.teamMembers}</div>} </Form.Group> <div className="text center"> <Button variant="primary" type="submit"> Update Project </Button> </div> </Form> ); }; export default EditProject;

Prompt

About

Tailwind Component- Get a simple, responsive design for your project. Perfect for fast development. Check it out and grab the code now!

Share

Last updated 1 month ago