import React, { useState, useEffect, useCallback } from "react"; import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; import styles from "../styles/packsAppList.module.scss"; import SingleApp from "./SingleApp"; import { FiPlus, FiPlusCircle, FiXCircle } from "react-icons/fi"; import Search from "./Search"; import Modal from "react-modal"; Modal.setAppElement("#__next"); const AppsList = ({ apps, onListUpdate }) => { return apps.map((app, index) => ( <App app={app} index={index} key={app._id} onListUpdate={onListUpdate}/> )); }; const reorder = (list, startIndex, endIndex) => { const result = Array.from(list); const [removed] = result.splice(startIndex, 1); result.splice(endIndex, 0, removed); return result; }; function App({ app, index, onListUpdate }) { return ( <Draggable draggableId={app._id} index={index}> {(provided) => ( <div className={styles.appCard} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} > <SingleApp app={app} pack={true} displaySelect={false}/> <button className={styles.unselectApp} onClick={() => onListUpdate(app._id)} aria-label={"Remove app from pack"} > <FiPlus /> </button> </div> )} </Draggable> ); } function PackAppsList({ notLoggedIn = false, providedApps, reorderEnabled, onListUpdate, allApps}){ const [apps, setApps] = useState([]); const [, updateState] = useState(); const forceUpdate = useCallback(() => updateState({}), []); const [showAdd, setShowAdd] = useState(false); useEffect(() => { setApps(providedApps) }, []) if(!reorderEnabled){ return ( <ul className={`${styles.appsList} ${styles.noDragList}`}> {apps.map((app) => ( <div className={styles.appCard} key={app._id}> <SingleApp app={app} pack={true} displaySelect={true}/> </div> ))} </ul> ); } const onDragEnd = (result) => { if (!result.destination) { return; } if (result.destination.index === result.source.index) { return; } const updatedApps = reorder( apps, result.source.index, result.destination.index ); onListUpdate(updatedApps) setApps(updatedApps); } const manageUpdates = (id) => { const updatedApps = apps.filter(i => i._id !== id); setApps(updatedApps); onListUpdate(updatedApps); } const handleSelect = (app, isSelected) => { let existingApps = apps; if (isSelected) { existingApps.push(app); } else { existingApps = existingApps.filter(a => a._id !== app._id); } setApps(existingApps); onListUpdate(existingApps); forceUpdate(); } const closeModal = () => { setShowAdd(false); } return ( <> <h2>Apps in this pack</h2> {!notLoggedIn && <p>Tip! Drag and drop any app to re-order how they appear in your pack.</p>} <button className={`button center ${apps.length === 0 ? '' : 'subtle'}`} onClick={() => setShowAdd(!showAdd)}><FiPlusCircle/> {`Add ${apps.length != 0 ? "More" : ""} Apps`}</button><br/> <Modal isOpen={showAdd} onRequestClose={closeModal} className={styles.addModal} overlayClassName={styles.modalOverlay} contentLabel="Example Modal" > <div className={styles.modalHeader}> <h2>Add Apps</h2> <FiXCircle onClick={closeModal}/> </div> <Search apps={allApps} preventGlobalSelect={handleSelect} isPackView={true} alreadySelected={apps} limit={4}/> </Modal> {notLoggedIn ? <p>You need to login first before you can view the apps in this pack.</p> : ( <DragDropContext onDragEnd={onDragEnd}> <Droppable droppableId="list"> {(provided) => ( <ul ref={provided.innerRef} {...provided.droppableProps} className={styles.appsList} > <AppsList apps={apps} onListUpdate={manageUpdates} /> {provided.placeholder} </ul> )} </Droppable> </DragDropContext> ) } </> ); } export default PackAppsList;