react-beautiful-dnd#Draggable JavaScript Examples

The following examples show how to use react-beautiful-dnd#Draggable. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.js    From react-material-ui-table-row-drag-and-drop with Creative Commons Zero v1.0 Universal 6 votes vote down vote up
DraggableComponent = (id, index) => (props) => {
    return (
        <Draggable draggableId={id} index={index}>
            {(provided, snapshot) => (
                <TableRow
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                    style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)}

                    {...props}
                >
                    {props.children}
                </TableRow>
            )}
        </Draggable>
    )
}
Example #2
Source File: SortableList.jsx    From notence with MIT License 6 votes vote down vote up
export default function SortableList({ items, onSort, children }) {
  const handleDragEnd = (result) => {
    if (!result.destination) {
      return;
    }

    const [startIndex, endIndex] = [result.source.index, result.destination.index];
    onSort({ startIndex, endIndex });
  };

  const renderListItem = (item) => (draggableProvided) => {
    const restProps = {
      innerRef: draggableProvided.innerRef,
      ...draggableProvided.draggableProps,
      ...draggableProvided.dragHandleProps,
    };

    return children(item, restProps);
  };

  return (
    <DragDropContext onDragEnd={handleDragEnd}>
      <Droppable droppableId="sortableList">
        {(provided) => (
          // eslint-disable-next-line react/jsx-props-no-spreading
          <div {...provided.droppableProps} ref={provided.innerRef}>
            {items.map((item, index) => (
              <Draggable key={item.id} draggableId={item.id} index={index}>
                {renderListItem(item)}
              </Draggable>
            ))}
            {provided.placeholder}
          </div>
        )}
      </Droppable>
    </DragDropContext>
  );
}
Example #3
Source File: components.js    From idena-web with MIT License 6 votes vote down vote up
function DraggableItem({draggableId, index, ...props}) {
  return (
    <Draggable draggableId={draggableId} index={index}>
      {provided => (
        <div
          ref={provided.innerRef}
          {...provided.draggableProps}
          {...provided.dragHandleProps}
          {...props}
        />
      )}
    </Draggable>
  )
}
Example #4
Source File: DraggableFileItem.js    From sailplane-web with GNU General Public License v3.0 6 votes vote down vote up
export function DraggableFileItem({
  data,
  sharedFs,
  setCurrentDirectory,
  ipfs,
  fileIndex,
  isParent,
  onIconClicked,
}) {
  return (
    <Draggable draggableId={data.path} index={fileIndex}>
      {({innerRef, draggableProps, dragHandleProps}, snapshot) => {
        return (
          <div
            ref={innerRef}
            {...draggableProps}
            {...dragHandleProps}
            style={getDraggableStyleHack(draggableProps.style, snapshot)}>
            <FileItem
              sharedFs={sharedFs}
              setCurrentDirectory={setCurrentDirectory}
              isParent={isParent}
              fileIndex={fileIndex}
              ipfs={ipfs}
              data={data}
              snapshot={snapshot}
              onIconClicked={onIconClicked}
            />
          </div>
        );
      }}
    </Draggable>
  );
}
Example #5
Source File: Tile.jsx    From react_53 with MIT License 6 votes vote down vote up
function Tile(props) {
  const { title, description, id, index, columnId } = props;

  return (
    <Draggable draggableId={id} index={index}>
      {(provided) => (
        <div
          className={styles.tile}
          {...provided.draggableProps}
          {...provided.dragHandleProps}
          ref={provided.innerRef}
        >
          <TileHeader title={title} id={id} columnId={columnId} />
          <TileBody description={description} />
        </div>
      )}
    </Draggable>
  );
}
Example #6
Source File: DraggableCard.js    From trello-clone with MIT License 6 votes vote down vote up
DraggableCard = ({ card, list, index }) => {
    return (
        <Draggable draggableId={card.id.toString()} index={index}>
            {(provided, snapshot) => {
                if (
                    typeof provided.draggableProps.onTransitionEnd ===
                    "function"
                ) {
                    const anim = window?.requestAnimationFrame(() =>
                        provided.draggableProps.onTransitionEnd({
                            propertyName: "transform",
                        })
                    );
                }
                return (
                    <Card
                        card={card}
                        list={list}
                        provided={provided}
                        isDragging={snapshot.isDragging}
                    />
                );
            }}
        </Draggable>
    );
}
Example #7
Source File: index.js    From Edlib with GNU General Public License v3.0 6 votes vote down vote up
function draggable(props){
    const {
        children,
        dragKey,
        index,
    } = props;
    return (
        <Draggable
            key={dragKey}
            draggableId={dragKey}
            index={index}
        >
        {(provided, snapshot) => (
            <div ref={provided.innerRef}
                 {...provided.draggableProps}
                 {...provided.dragHandleProps}>
                {children}
            </div>
        )}
        </Draggable>
    );
}
Example #8
Source File: PackAppsList.js    From winstall with GNU General Public License v3.0 6 votes vote down vote up
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>
  );
}
Example #9
Source File: item.js    From rainbow-modules with MIT License 6 votes vote down vote up
Item = (props) => {
    const { row, field, component, id, index, ...rest } = props;
    const value = row[field];

    return (
        <Draggable draggableId={id} index={index}>
            {(provided, snapshot) => (
                <ItemContainer
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                    ref={provided.innerRef}
                    isDragging={snapshot.isDragging}
                >
                    <StyledIcon />
                    <Content {...rest} component={component} value={value} row={row} />
                </ItemContainer>
            )}
        </Draggable>
    );
}
Example #10
Source File: index.jsx    From react-antd-admin-template with MIT License 5 votes vote down vote up
render() {
    const path = this.props.location.pathname;
    const openKey = this.state.openKey;
    return (
      <div className="sidebar-menu-container">
        <Scrollbars autoHide autoHideTimeout={1000} autoHideDuration={200}>
          <DragDropContext onDragEnd={this.onDragEnd}>
            <Droppable droppableId="droppable">
              {(provided, snapshot) => (
                <div {...provided.droppableProps} ref={provided.innerRef}>
                  {this.state.menuTreeNode.map((item, index) => (
                    <Draggable
                      key={item.key}
                      draggableId={item.key}
                      index={index}
                    >
                      {(provided, snapshot) => (
                        <div
                          ref={provided.innerRef}
                          {...provided.draggableProps}
                          {...provided.dragHandleProps}
                        >
                          <Menu
                            mode="inline"
                            theme="dark"
                            onSelect={this.handleMenuSelect}
                            selectedKeys={[path]}
                            defaultOpenKeys={openKey}
                          >
                            {item}
                          </Menu>
                        </div>
                      )}
                    </Draggable>
                  ))}
                </div>
              )}
            </Droppable>
          </DragDropContext>
        </Scrollbars>
      </div>
    );
  }
Example #11
Source File: step.js    From pathways with GNU General Public License v3.0 5 votes vote down vote up
step = (props) => {

    let tagColor
    switch (props.stepType) {
        case 'Content': tagColor = '#0077b6'; break;
        case 'Pathway': tagColor = '#2ec4b6'; break;
        case 'Shared Step': tagColor = '#9b5de5'; break;
    }

    const content = props.heading.length < 40 ? props.heading
                                              : `${props.heading.slice(0, 40)}...`

    const selected = props.selected

    return (
        <Draggable
            key={props.id}
            draggableId={props.id.toString()}
            index={props.index}
        >
            {(provided, snapshot) => (
                <div
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                    style={getItemStyle(
                        snapshot.isDragging,
                        provided.draggableProps.style,
                        selected,
                        tagColor
                    )}
                >
                    <div className={classes.TopRow}>
                        <div className={classes.StepTitle}>
                            <p>{content}</p>
                        </div>

                        <div 
                            className={classes.EditBtn}
                            onClick={() => props.onSelectStep(props.id)}
                        >
                            <EditIcon fontSize="45px" color="#555"/>
                        </div>
                    </div>
                    
                    <div className={classes.Details}>
                        {/* <Rating value={props.rating}/> */}
                        
                        
                    </div>

                    
                    
                    <div className={classes.BottomRow}>
                        <StepTag stepType={props.stepType} />

                        {selected ? <div className={classes.Unsaved} style={{backgroundColor: `${tagColor}`}}/> 
                                  : null}

                        <div 
                            className={classes.DeleteBtn}
                            onClick={() => props.onDeleteStep(props.id)}
                        >
                            <DeleteIcon color="#aaa" fontSize="30px"/>
                        </div>
                    </div>
                </div>
            )}
        </Draggable>
    );
}
Example #12
Source File: slide.js    From horondi_admin with MIT License 5 votes vote down vote up
Slide = ({ slide, index }) => {
  const styles = useStyles();
  const { discoverMoreTitle, discoverMoreSymbol } =
    config.titles.homePageSliderTitle;
  const { IMG_URL } = config;
  return (
    <Draggable
      style={(_isDragging, draggableStyle) => ({
        ...draggableStyle,
        position: 'static'
      })}
      draggableId={slide._id}
      index={index}
    >
      {(provided, snapshot) => (
        <Container
          className={styles.dndDivison}
          {...provided.draggableProps}
          {...provided.dragHandleProps}
          innerRef={provided.innerRef}
          isDragging={snapshot.isDragging}
        >
          <Paper elevation={20} className={styles.dndItem} key={slide._id}>
            <Avatar
              variant='square'
              className={styles.square}
              src={`${IMG_URL}${slide.images.small}`}
              color='primary'
            >
              <ImageIcon />
            </Avatar>
            <div className={styles.slideContent}>
              <div>
                <h3>{slide.title[0].value}</h3>
                <p>{slide.description[0].value}</p>
              </div>
              <p className={styles.discoverMore}>
                {' '}
                {discoverMoreTitle}
                <span>{discoverMoreSymbol}</span>
              </p>
            </div>
          </Paper>
        </Container>
      )}
    </Draggable>
  );
}
Example #13
Source File: DragDrop.js    From google-forms with MIT License 5 votes vote down vote up
export default function DragAndDrop(){
  // constructor(props) {
  //   super(props);
  //   this.state = {
  //     items: [ {id: "item-0", content: "item 0"},
  //     {id: "item-1", content: "item 1"}
  //     ,{id: "item-2", content: "item 2"}
  //     ,{id: "item-3", content: "item 3"}
  //     ,{id: "item-4", content: "item 4"}]
  //   };

  //   this.onDragEnd = this.onDragEnd.bind(this);
  // }

  const [items, setItems] = React.useState([ {id: "item-0", content: "item 0"},
  {id: "item-1", content: "item 1"}
  ,{id: "item-2", content: "item 2"}
  ,{id: "item-3", content: "item 3"}
  ,{id: "item-4", content: "item 4"}])


 function onDragEnd(result) {
    if (!result.destination) {
      return;
    }
    var itemgg = [...items]
    const itemF = reorder(
      itemgg,
      result.source.index,
      result.destination.index
    );
    setItems(itemF)
  }
  
  const reorder = (list, startIndex, endIndex) => {
    const result = Array.from(list);
    const [removed] = result.splice(startIndex, 1);
    result.splice(endIndex, 0, removed);
    return result;
  };

    return (
      <DragDropContext onDragEnd={onDragEnd}>
        <Droppable droppableId="droppable">
          {(provided, snapshot) => (
            <div
              {...provided.droppableProps}
              ref={provided.innerRef}
            >
              {items.map((item, index) => (
                <Draggable key={item.id} draggableId={item.id} index={index}>
                  {(provided, snapshot) => (
                    <div
                      ref={provided.innerRef}
                      {...provided.draggableProps}
                      {...provided.dragHandleProps}

                    >
                      {item.content}
                    </div>
                  )}
                </Draggable>
              ))}
              {provided.placeholder}
            </div>
          )}
        </Droppable>
      </DragDropContext>
    );
}
Example #14
Source File: List.js    From social-media-strategy-fe with MIT License 5 votes vote down vote up
List = ({ list, user }) => {
	const { listContainer, postsContainer } = useStyles();

	return (
		<Draggable key={list.id} draggableId={list.id} index={list.index}>
			{(provided, snapshot) => (
				<div
					className={listContainer}
					ref={provided.innerRef}
					{...provided.draggableProps}
				>
					<ListHeader
						list={list}
						dragHandleProps={provided.dragHandleProps}
						user={user}
					/>
					<Droppable
						direction="vertical"
						droppableId={String(list.id)}
						type="post"
					>
						{(provided, snapshot) => (
							<div
								{...provided.droppableProps}
								ref={provided.innerRef}
								className={postsContainer}
								style={{
									background: snapshot.isDraggingOver
										? "aliceblue"
										: "transparent",
								}}
							>
								<Scrollbars autoHide>
									{list.posts?.map((post, index) => (
										<Post key={post.id} post={post} />
									))}
									<CreatePostButton listId={list.id} />
								</Scrollbars>
								{provided.placeholder}
							</div>
						)}
					</Droppable>
				</div>
			)}
		</Draggable>
	);
}
Example #15
Source File: List.js    From TrelloClone with MIT License 5 votes vote down vote up
List = ({ listId, index }) => {
  const [addingCard, setAddingCard] = useState(false);
  const list = useSelector((state) =>
    state.board.board.listObjects.find((object) => object._id === listId)
  );
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getList(listId));
  }, [dispatch, listId]);

  const createCardFormRef = useRef(null);
  useEffect(() => {
    addingCard && createCardFormRef.current.scrollIntoView();
  }, [addingCard]);

  return !list || (list && list.archived) ? (
    ''
  ) : (
    <Draggable draggableId={listId} index={index}>
      {(provided) => (
        <div
          className='list-wrapper'
          {...provided.draggableProps}
          {...provided.dragHandleProps}
          ref={provided.innerRef}
        >
          <div className='list-top'>
            <ListTitle list={list} />
            <ListMenu listId={listId} />
          </div>
          <Droppable droppableId={listId} type='card'>
            {(provided) => (
              <div
                className={`list ${addingCard ? 'adding-card' : 'not-adding-card'}`}
                {...provided.droppableProps}
                ref={provided.innerRef}
              >
                <div className='cards'>
                  {list.cards.map((cardId, index) => (
                    <Card key={cardId} cardId={cardId} list={list} index={index} />
                  ))}
                </div>
                {provided.placeholder}
                {addingCard && (
                  <div ref={createCardFormRef}>
                    <CreateCardForm listId={listId} setAdding={setAddingCard} />
                  </div>
                )}
              </div>
            )}
          </Droppable>
          {!addingCard && (
            <div className='create-card-button'>
              <Button variant='contained' onClick={() => setAddingCard(true)}>
                + Add a card
              </Button>
            </div>
          )}
        </div>
      )}
    </Draggable>
  );
}
Example #16
Source File: SortableBoard.jsx    From notence with MIT License 5 votes vote down vote up
export default function SortableBoard({ groups, onChange, onItemCreate, children }) {
  const handleDragEnd = (result) => {
    if (!result.destination) {
      return;
    }

    onChange(result);
  };

  const renderItem = (item) => (draggableProvided) => {
    const restProps = {
      innerRef: draggableProvided.innerRef,
      ...draggableProvided.draggableProps,
      ...draggableProvided.dragHandleProps,
    };

    return children(item, restProps);
  };

  return (
    <DragDropContext onDragEnd={handleDragEnd}>
      <BoardWrapper>
        {Object.entries(groups).map(([groupId, group]) => (
          <Board key={groupId}>
            <BoardTitle>{group.name}</BoardTitle>

            <Droppable droppableId={groupId}>
              {(provided) => (
                // eslint-disable-next-line react/jsx-props-no-spreading
                <BoardContent {...provided.droppableProps} ref={provided.innerRef}>
                  {group.items.map((item, index) => (
                    <Draggable key={item.id} draggableId={item.id} index={index}>
                      {renderItem(item)}
                    </Draggable>
                  ))}
                  {provided.placeholder}

                  <AddBtn onClick={() => onItemCreate(groupId)} icon={<PlusOutlined />}>
                    New
                  </AddBtn>
                </BoardContent>
              )}
            </Droppable>
          </Board>
        ))}
      </BoardWrapper>
    </DragDropContext>
  );
}
Example #17
Source File: TaskBoard.js    From fokus with GNU General Public License v3.0 4 votes vote down vote up
export function TaskBoard() {
    const tasks = useSelector((state) => state.tasks.taskArray);
    const meta = useSelector((state) => state.tasks.meta);
    let focussedTask = meta.focussedTaskIndex !== -1 ? tasks[meta.focussedTaskIndex] : null;
    const dispatch = useDispatch();

    function handleOnDragEnd(result) {
        if (!result.destination) return;

        let items = [...tasks.map((i) => ({ ...i }))];
        const [reorderedItem] = items.splice(result.source.index, 1);
        items.splice(result.destination.index, 0, reorderedItem);

        let i = result.source.index;
        let direction = result.destination.index > result.source.index; // direction true means moving right & swapping
        // below is logic to reset globalKeys to maintain correct sort order.
        while (i != result.destination.index) {
            if (direction) {
                items[i].globalKey = tasks[i].globalKey;
                i++;
            } else {
                items[i].globalKey = tasks[i].globalKey;
                i--;
            }
            if (i == result.destination.index) {
                items[i].globalKey = tasks[i].globalKey;
            }
        }

        if (meta.focussedTaskIndex !== -1) {
            let greaterIndex = Math.max(result.destination.index, result.source.index);
            let smallerIndex = Math.min(result.destination.index, result.source.index);

            if (result.source.index === meta.focussedTaskIndex) {
                dispatch(focusOnTask(result.destination.index));
            } else if (meta.focussedTaskIndex >= smallerIndex && meta.focussedTaskIndex <= greaterIndex) {
                if (result.destination.index > result.source.index) {
                    dispatch(focusOnTask(meta.focussedTaskIndex - 1)); // -1
                } else {
                    dispatch(focusOnTask(meta.focussedTaskIndex + 1)); // +1
                }
            }
        }

        dispatch(updateOrder(items)); // order is imp. focus then updateOrder
    }

    function getFlipKey() {
        let flipKey = "";
        tasks.forEach((i) => {
            flipKey += `${i.globalKey}`;
        });
        flipKey += `${meta.completedTaskStartIndex}`;
        return flipKey;
    }

    function isFocussed(id) {
        if (focussedTask !== null && focussedTask.id === id) return true;
        return false;
    }

    // input has both onChange and onKeyDown - can be optimised by using one and combining

    return (
        <TaskBoardContainer>
            <TaskInput focussedTaskIndex={meta.focussedTaskIndex} />
            {tasks.length === 0 ? <NoTasks /> : tasks.length === meta.completedTasksCount && <NoTasks allCompleted={true} />}
            <Flipper flipKey={getFlipKey()}>
                <DragDropContext onDragEnd={handleOnDragEnd}>
                    <Droppable droppableId="dropArea">
                        {(provided) => (
                            <div {...provided.droppableProps} ref={provided.innerRef}>
                                {tasks.map((i, index) =>
                                    !i.isCompleted ? (
                                        <Draggable isDragDisabled={i.isCompleted} key={i.id} draggableId={`${i.id}`} index={index}>
                                            {(provided2) => (
                                                <TaskCard
                                                    focussedTaskIndex={meta.focussedTaskIndex}
                                                    focussedTaskGlobalKey={meta.focussedTaskIndex !== -1 ? tasks[meta.focussedTaskIndex].globalKey : -1}
                                                    taskIndex={index}
                                                    forwardRBDProvided={provided2}
                                                    task={i}
                                                    isFocussed={isFocussed(i.id)}
                                                />
                                            )}
                                        </Draggable>
                                    ) : (
                                        ""
                                    )
                                )}
                                {provided.placeholder}
                            </div>
                        )}
                    </Droppable>
                </DragDropContext>

                {meta.completedTaskStartIndex !== -1 && <Divider />}

                {meta.showCompletedTasks &&
                    tasks.map((i, index) =>
                        i.isCompleted ? (
                            <TaskCard
                                focussedTaskIndex={meta.focussedTaskIndex}
                                focussedTaskGlobalKey={meta.focussedTaskIndex !== -1 ? tasks[meta.focussedTaskIndex].globalKey : -1}
                                taskIndex={index}
                                key={i.id}
                                forwardRBDProvided={{ innerRef: null }}
                                task={i}
                                isFocussed={isFocussed(i.id)}
                            />
                        ) : (
                            ""
                        )
                    )}
            </Flipper>
            <EmptySpace />
        </TaskBoardContainer>
    );
}
Example #18
Source File: TodoList.jsx    From 4IZ268-2021-2022-ZS with MIT License 4 votes vote down vote up
function TodoList() {
  const [todos, setTodos] = useState([])
  const [isOpen, setIsOpen] = useState(false)
  const [input, setInput] = useState('')

  // restore Todos from localStorage
  useEffect(() => {
    const restored = localStorage.getItem('todos')

    restored && setTodos(JSON.parse(restored))
  }, [])

  // save Todos to localStorage
  useEffect(() => {
    localStorage.setItem('todos', JSON.stringify(todos))
  }, [todos])

  function handleOpenList() {
    setIsOpen(!isOpen)
  }

  function handleInput(e) {
    const input = e.target.value
    if (input.length < 30) {
      setInput(input)
    }
  }

  function handleSubmit(e) {
    const input = e.target.value

    if (e.code === 'Enter' && input) {
      setTodos([
        ...todos,
        {
          task: input,
          completed: false,
        },
      ])

      setInput('')
    }
  }

  function toggleCompletion(idx) {
    const newTodos = [...todos]
    newTodos[idx].completed = !newTodos[idx].completed
    setTodos(newTodos)
  }

  function removeTodo(idx) {
    const newTodos = [...todos]
    newTodos.splice(idx, 1)
    setTodos(newTodos)
  }

  const onDragEnd = useCallback(
    (result) => {
      // dropped outside the list
      if (!result.destination) {
        return
      }

      const newState = reorder(
        todos,
        result.source.index,
        result.destination.index
      )

      setTodos(newState)
    },
    [todos]
  )

  function reorder(list, startIndex, endIndex) {
    const result = Array.from(list)
    const [removed] = result.splice(startIndex, 1)
    result.splice(endIndex, 0, removed)

    return result
  }

  return (
    <div className='relative'>
      <div
        className={`absolute ${
          isOpen ? 'bottom-14 opacity-100' : 'bottom-12 opacity-0'
        } right-4 px-7 pt-5 pb-8 bg-black/60 backdrop-blur-sm rounded-lg transition-all`}>
        <DragDropContext onDragEnd={onDragEnd}>
          <Droppable droppableId='droppable'>
            {(provided, snapshot) => (
              <div {...provided.droppableProps} ref={provided.innerRef}>
                {todos.map((item, idx) => (
                  <Draggable
                    key={item.task}
                    draggableId={item.task}
                    index={idx}>
                    {(provided, snapshot) => (
                      <div
                        ref={provided.innerRef}
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}>
                        <Todo
                          todo={item}
                          handleCompletion={(idx) => toggleCompletion(idx)}
                          handleRemoval={(idx) => removeTodo(idx)}
                        />
                      </div>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </div>
            )}
          </Droppable>
        </DragDropContext>
        <input
          className='w-56 bg-transparent border-b border-solid border-white
              opacity-60 hover:opacity-80 focus:opacity-100 focus:outline-none
              transition-colors mt-4 mx-4'
          type='text'
          value={input}
          placeholder='New Todo'
          onChange={handleInput}
          onKeyPress={handleSubmit}
        />
      </div>

      <button
        onClick={handleOpenList}
        className='text-xl font-medium px-4 py-3 opacity-70 hover:opacity-90 transition-opacity'>
        Todos
      </button>
    </div>
  )
}
Example #19
Source File: projects.js    From community-forum-frontend with GNU General Public License v3.0 4 votes vote down vote up
render() {
    return (
      <div>
        <Modal show={this.state.showModal} onHide={this.handleClose} centered>
          <div className="modalbody">
            <Modal.Body>
              <TopicForm
                projectID={this.state.projectID}
                handleTopicSubmission={this.handleTopicSubmission}
              />
            </Modal.Body>
          </div>
        </Modal>
        <DragDropContext onDragEnd={this.onDragEnd}>
          <div className="projectCards">
            {this.state.categoriesArray.map((categoryID) => {
              const category = this.state.categories[categoryID._id];
              return (
                <Card
                  className="projectCard"
                  bg="light"
                  style={{ width: "21rem" }}
                  key={category._id}
                >
                  <Card.Header color="#366FF0" className="projectcardheader">
                    {category.categoryName}
                  </Card.Header>
                  <Droppable droppableId={category._id}>
                    {(provided) => (
                      <div
                        className="cardcontent"
                        ref={provided.innerRef}
                        {...provided.droppableProps}
                      >
                        {category.topicIds.map((topicid, index) => {
                          const topic = this.state.Topics[topicid];
                          if (topic) {
                            return (
                              <Draggable draggableId={topic._id} index={index}>
                                {(provided) => (
                                  <Card
                                    onClick={() =>
                                      this.props.handleDiscussionTrue(topic)
                                    }
                                    key={topic._id}
                                    className="topicscard"
                                    {...provided.draggableProps}
                                    {...provided.dragHandleProps}
                                    ref={provided.innerRef}
                                  >
                                    <Card.Title className="topicsheading">
                                      {topic.topicName}
                                    </Card.Title>
                                    <Card.Text className="topicdescription">
                                      {topic.topicDescription}
                                    </Card.Text>
                                    <div>
                                      {topic.topicTags ? (
                                        topic.topicTags.map((k) => {
                                          return (
                                            <Badge
                                              variant="primary"
                                              className="tags"
                                            >
                                              {k}
                                            </Badge>
                                          );
                                        })
                                      ) : (
                                        <Badge variant="primary"></Badge>
                                      )}
                                    </div>
                                  </Card>
                                )}
                              </Draggable>
                            );
                          }
                        })}
                        {provided.placeholder}
                      </div>
                    )}
                  </Droppable>
                  <div
                    className="addnewcard"
                    onClick={() => this.handleShow(category._id)}
                  >
                    <IconContext.Provider
                      value={{
                        style: { verticalAlign: "middle" },
                        className: "reacticon",
                      }}
                    >
                      <FiPlus />
                    </IconContext.Provider>{" "}
                    Add another discussion
                  </div>
                </Card>
              );
            })}
          </div>
        </DragDropContext>
      </div>
    );
  }
Example #20
Source File: QuestionsTab.js    From google-forms with MIT License 4 votes vote down vote up
function QuestionsTab(props) {

  const [questions, setQuestions]= React.useState([]);
  const [openUploadImagePop, setOpenUploadImagePop] = React.useState(false);
  const [imageContextData, setImageContextData] = React.useState({question: null, option: null});
  const [formData, setFormData] = React.useState({});
  const [loadingFormData, setLoadingFormData] = React.useState(true);
  

  React.useEffect(()=>{
    
    if(props.formData.questions !== undefined){
      //console.log(props.formData.questions.length);
      if(props.formData.questions.length === 0){
        setQuestions([{questionText: "Question", options : [{optionText: "Option 1"}], open: false}]);
      } else{
        setQuestions(props.formData.questions)
      }
      setLoadingFormData(false)
    } 
    setFormData(props.formData)
  }, [props.formData])
  

  function saveQuestions(){
    console.log("auto saving questions initiated");
    var data = {
      formId: formData._id,
      name: formData.name,
      description: formData.description,
      questions: questions
    }

    formService.autoSave(data)
    .then((result) => {     
         console.log(result);
         setQuestions(result.questions)
        },
        error => {
        const resMessage =
            (error.response &&
            error.response.data &&
            error.response.data.message) ||
            error.message ||
            error.toString();
            console.log(resMessage);
        }
    );
    
  }

  function checkImageHereOrNotForQuestion(gg){
   // console.log(gg);
    if ((gg === undefined)||(gg==="")){
      return false;
    } else{
      return true;
    }
  }

  function checkImageHereOrNotForOption(gg){
   // console.log(gg);
    if ((gg === undefined)||(gg==="")){
      return false;
    } else{
      return true;
    }
  }

  function addMoreQuestionField(){
      expandCloseAll(); //I AM GOD

      setQuestions(questions=> [...questions, {questionText: "Question", options : [{optionText: "Option 1"}], open: true}]);
  }

  function copyQuestion(i){
    let qs = [...questions]; 
    expandCloseAll();
    const myNewOptions = [];
    qs[i].options.forEach(opn => {
      if ((opn.optionImage !== undefined)||(opn.optionImage !=="")) {
        var opn1new = {
          optionText : opn.optionText,
          optionImage: opn.optionImage
        }
      } else{
        var opn1new = {
          optionText : opn.optionText
        }
      }
      myNewOptions.push(opn1new)
    });
    const qImage = qs[i].questionImage || "";
    var newQuestion = {questionText: qs[i].questionText, questionImage : qImage ,options:myNewOptions, open: true}
     setQuestions(questions=> [...questions, newQuestion]); 
  }

  const handleImagePopupOpen = () => {
    setOpenUploadImagePop(true);
  };


  function uploadImage(i, j){
    
    setImageContextData({
      question: i,
      option: j
    });
    handleImagePopupOpen();
    
  }

  function updateImageLink(link, context){
    
    var optionsOfQuestion = [...questions];
    var i = context.question

    if (context.option == null) {
      optionsOfQuestion[i].questionImage= link;
    } else {
      var j = context.option
      optionsOfQuestion[i].options[j].optionImage = link;
    }
    setQuestions(optionsOfQuestion);
  }

  function deleteQuestion(i){
    let qs = [...questions]; 
    if(questions.length > 1){
      qs.splice(i, 1);
    }
    setQuestions(qs)
  }

  function handleOptionValue(text,i, j){
    var optionsOfQuestion = [...questions];
    optionsOfQuestion[i].options[j].optionText = text;
    //newMembersEmail[i]= email;
      setQuestions(optionsOfQuestion);
  }

  function handleQuestionValue(text, i){
    var optionsOfQuestion = [...questions];
    optionsOfQuestion[i].questionText = text;
      setQuestions(optionsOfQuestion);
  }

 function onDragEnd(result) {
  if (!result.destination) {
    return;
  }
  var itemgg = [...questions];

  const itemF = reorder(
    itemgg,
    result.source.index,
    result.destination.index
  );

  setQuestions(itemF);
  }

  const reorder = (list, startIndex, endIndex) => {
    const result = Array.from(list);
    const [removed] = result.splice(startIndex, 1);
    result.splice(endIndex, 0, removed);
    return result;
  };

  function showAsQuestion(i){
    let qs = [...questions];  
     qs[i].open = false;
     setQuestions(qs);
  }

  function addOption(i){
    var optionsOfQuestion = [...questions];
    if(optionsOfQuestion[i].options.length < 5){
      optionsOfQuestion[i].options.push({optionText: "Option " + (optionsOfQuestion[i].options.length + 1)})
    } else{
      console.log("Max  5 options ");  
    }
    //console.log(optionsOfQuestion);
    setQuestions(optionsOfQuestion)
  }

  function removeOption(i, j){
    var optionsOfQuestion = [...questions];
    if(optionsOfQuestion[i].options.length > 1){
      optionsOfQuestion[i].options.splice(j, 1);
      setQuestions(optionsOfQuestion)
      console.log(i + "__" + j);
    }   
  }

  function expandCloseAll(){
    let qs = [...questions]; 
     for (let j = 0; j < qs.length; j++) {  
      qs[j].open = false;
     }
     setQuestions(qs);
  }

  function handleExpand(i){
    let qs = [...questions]; 
    for (let j = 0; j < qs.length; j++) {
      if(i ===j ){
        qs[i].open = true;
 
      } else{
        qs[j].open = false;
       }
    }
     setQuestions(qs);
  }

  function questionsUI(){
    return  questions.map((ques, i)=> (
      <Draggable key={i} draggableId={i + 'id'} index={i}>
                  {(provided, snapshot) => (
                    <div
                      ref={provided.innerRef}
                      {...provided.draggableProps}
                      {...provided.dragHandleProps}
                    >
                      <div>
          <div style={{marginBottom: "15px"}}>
            <div style={{width:'100%', marginBottom: '-7px' }}>
              <DragIndicatorIcon style={{transform: "rotate(-90deg)", color:'#DAE0E2'}} fontSize="small"/>
            </div>
          
            <Accordion onChange={()=>{handleExpand(i)}} expanded={questions[i].open}>
              <AccordionSummary            
                aria-controls="panel1a-content"
                id="panel1a-header"
                elevation={1} style={{width:'100%'}}
              >
                { !questions[i].open ? (
              <div style={{display: 'flex',flexDirection:'column', alignItems:'flex-start', marginLeft: '3px', paddingTop: '15px', paddingBottom: '15px'}}>
                {/* <TextField id="standard-basic" label=" " value="Question" InputProps={{ disableUnderline: true }} />  */}
                
                <Typography variant="subtitle1" style={{marginLeft: '0px'}}>{i+1}.  {ques.questionText}</Typography>


                {ques.questionImage !==""?(
                  <div>
                    <img src={ques.questionImage} width="400px" height="auto" /><br></br><br></br>
                  </div>
                ): "" }
                
                {ques.options.map((op, j)=>(
                 
                 <div key={j}>
                   <div style={{display: 'flex'}}>
                    <FormControlLabel disabled control={<Radio style={{marginRight: '3px', }} />} label={
                        <Typography style={{color: '#555555'}}>
                          {ques.options[j].optionText}
                        </Typography>
                      } />
                   </div>

                  <div>
                    {op.optionImage !==""?(
                      <img src={op.optionImage} width="160px" height="auto" />
                    ): "" }
                  </div>
                 </div>
                ))}  
              </div>            
              ): ""}   
              </AccordionSummary>

              <AccordionDetails>
              <div style={{display: 'flex',flexDirection:'column', alignItems:'flex-start', marginLeft: '15px', marginTop:'-15px'}}>
                <div style={{display:'flex', width: '100%', justifyContent: 'space-between'}}>
                  <Typography style={{marginTop:'20px'}}>{i+1}.</Typography>
                  <TextField 
                        fullWidth={true} 
                        placeholder="Question Text" 
                        style={{marginBottom: '18px'}}  
                        rows={2}
                        rowsMax={20}
                        multiline={true}

                        value={ques.questionText}
                        variant="filled"
                      onChange={(e)=>{handleQuestionValue(e.target.value, i)}}
                  />
                  <IconButton aria-label="upload image" onClick={()=>{uploadImage(i, null)}}>
                        <CropOriginalIcon />
                  </IconButton>
                </div>

                <div>
                     {
                       checkImageHereOrNotForQuestion(ques.questionImage) ? (
                        <div>
                            <div style={{width:'150px', display: 'flex', alignItems:'flex-start', paddingLeft:'20px'}}>
                            <img src={ques.questionImage} width="150px" height="auto"/>
                            <IconButton style={{marginLeft: '-15px', marginTop: '-15px',zIndex:999, backgroundColor: 'lightgrey', color:'grey'}} 
                                        size="small"
                                        onClick={()=>{
                                          updateImageLink("", {question: i, option: null})
                                        }}>
                              <CloseIcon />
                            </IconButton>
                            </div>
                        </div>
                       ): ""
                     }
                </div>
                
                <div style={{width: '100%'}}>
                {ques.options.map((op, j)=>(
                 
                 <div key={j}>
                      <div  style={{display:'flex', flexDirection:'row', marginLeft:'-12.5px', justifyContent: 'space-between', paddingTop: '5px', paddingBottom: '5px'}}>

                          <Radio disabled /> 
                          <TextField 
                            fullWidth={true} 
                            placeholder="Option text" 
                            style={{marginTop: '5px'}} 
                            value={ques.options[j].optionText}
                            onChange={(e)=>{handleOptionValue(e.target.value, i, j)}}
                          />

                          <IconButton aria-label="upload image" onClick={()=>{uploadImage(i, j)}}>
                            <CropOriginalIcon />
                          </IconButton>

                          <IconButton aria-label="delete" onClick={()=>{removeOption(i, j)}}>
                            <CloseIcon />
                          </IconButton>
                          </div>

                          <div>
                          {
                            checkImageHereOrNotForOption(op.optionImage) ? (
                            <div>
                              <div style={{width:'150px', display: 'flex', alignItems:'flex-start', paddingLeft:'20px'}}>
                                <img src={op.optionImage} width="90px" height="auto"/>
                                
                                <IconButton style={{marginLeft: '-15px', marginTop: '-15px',zIndex:999, backgroundColor: 'lightgrey', color:'grey'}}
                                            size="small"
                                            onClick={()=>{
                                              updateImageLink("", {question: i, option: j})
                                            }}
                                            >
                                  <CloseIcon />
                                </IconButton>
                              </div>
                              <br></br>
                              <br></br>  
                            </div>
                            ): ""
                          }
                          </div>
                 </div>
                ))}  
                </div>  
                
                
                {ques.options.length < 5 ? (
                  <div>
                  <FormControlLabel disabled control={<Radio />} label={
                    <Button size="small" onClick={()=>{addOption(i)}} style={{textTransform: 'none', marginLeft:"-5px"}}>
                      Add Option
                    </Button>
                  } /> 
                  </div>
                ): ""}

                <br></br>
                <br></br>

                <Typography variant="body2" style={{color: 'grey'}}>You can add maximum 5 options. If you want to add more then change in settings. Multiple choice single option is availible</Typography>
              </div>
              </AccordionDetails>

              <Divider />
              
              <AccordionActions>               
                    <IconButton aria-label="View" onClick={()=>{showAsQuestion(i)}}>
                      <VisibilityIcon />
                    </IconButton>

                    <IconButton aria-label="Copy" onClick={()=>{copyQuestion(i)}}>
                      <FilterNoneIcon />
                    </IconButton>
                    <Divider orientation="vertical" flexItem/>

                    <IconButton aria-label="delete" onClick={()=>{deleteQuestion(i)}}>
                      <DeleteOutlineIcon />
                    </IconButton>

                    <IconButton aria-label="Image">
                      <MoreVertIcon />
                    </IconButton>
              </AccordionActions>
            </Accordion>
          </div>
      </div>
                    </div>
                  )}
      </Draggable>
      
     )
    )
  }




  return (
       <div style={{marginTop:'15px', marginBottom: '7px', paddingBottom:"30px"}}>
           <Grid
            container
            direction="column"
            justify="center"
            alignItems="center"
            >
              {loadingFormData ? (<CircularProgress />):""}
              
             <Grid item xs={12} sm={5} style={{width: '100%'}}>
                 
                  <Grid style={{borderTop: '10px solid teal', borderRadius: 10}}>
                      <div>
                          <div>
                            <Paper elevation={2} style={{width:'100%'}}>
                              <div style={{display: 'flex',flexDirection:'column', alignItems:'flex-start', marginLeft: '15px', paddingTop: '20px', paddingBottom: '20px'}}>
                                <Typography variant="h4" style={{fontFamily:'sans-serif Roboto', marginBottom:"15px"}}>
                                  {formData.name}
                                </Typography>
                                <Typography variant="subtitle1">{formData.description}</Typography>
                              </div>
                            </Paper>
                          </div> 
                      </div>       
                  </Grid>  

                  <Grid style={{paddingTop: '10px'}}>
                    <div>
                    <ImageUplaodModel handleImagePopOpen={openUploadImagePop} handleImagePopClose={()=>{setOpenUploadImagePop(false)}} updateImageLink={updateImageLink} contextData={imageContextData}/>

                    <DragDropContext onDragEnd={onDragEnd}>
                      <Droppable droppableId="droppable">
                        {(provided, snapshot) => (
                          <div
                            {...provided.droppableProps}
                            ref={provided.innerRef}
                          >
                            {questionsUI()}

                            {provided.placeholder}
                          </div>
                        )}
                      </Droppable>
                    </DragDropContext>
                    <div>                       
                        <Button
                          variant="contained"
                          
                          onClick={addMoreQuestionField}
                          endIcon={<AddCircleIcon />}
                          style={{margin: '5px'}}
                        >Add Question </Button>

                        <Button
                          variant="contained"
                          color="primary"
                          onClick={saveQuestions}
                          style={{margin: '15px'}}
                          endIcon={<SaveIcon />}
                        >Save Questions </Button>
                      </div>
                    </div>
                  </Grid>        
              </Grid>           
           </Grid>
       </div>
  );
}
Example #21
Source File: List.js    From trello-clone with MIT License 4 votes vote down vote up
List = ({ list, index }) => {
    const { board, setBoard } = useContext(globalContext);
    const [addingCard, setAddingCard] = useState(false);
    const [cardTitle, setCardTitle] = useState("");
    const [editingTitle, setEditingTitle] = useState(false);

    useBlurSetState(".list__add-card-form", addingCard, setAddingCard);
    useBlurSetState(".list__title-edit", editingTitle, setEditingTitle);

    const onAddCard = async (e) => {
        e.preventDefault();
        if (cardTitle.trim() === "") return;
        const { data } = await authAxios.post(`${backendUrl}/boards/items/`, {
            list: list.id,
            title: cardTitle,
        });
        setAddingCard(false);
        addCard(board, setBoard)(list.id, data);
    };

    const listCards = useRef(null);
    useEffect(() => {
        if (addingCard)
            listCards.current.scrollTop = listCards.current.scrollHeight;
    }, [addingCard]);

    useEffect(() => {
        if (editingTitle) {
            const editListTitle = document.querySelector(".list__title-edit");
            editListTitle.focus();
            editListTitle.select();
        }
    }, [editingTitle]);

    return (
        <Draggable draggableId={"list" + list.id.toString()} index={index}>
            {(provided, snapshot) => {
                if (
                    typeof provided.draggableProps.onTransitionEnd ===
                    "function"
                ) {
                    const anim = window?.requestAnimationFrame(() =>
                        provided.draggableProps.onTransitionEnd({
                            propertyName: "transform",
                        })
                    );
                }
                return (
                    <div
                        className="list"
                        ref={provided.innerRef}
                        {...provided.draggableProps}
                        style={getListStyle(
                            snapshot.isDragging,
                            provided.draggableProps.style
                        )}
                    >
                        <div
                            className="list__title"
                            {...provided.dragHandleProps}
                            style={getListTitleStyle(
                                snapshot.isDragging,
                                provided.dragHandleProps.style
                            )}
                        >
                            {!editingTitle ? (
                                <p onClick={() => setEditingTitle(true)}>
                                    {list.title}
                                </p>
                            ) : (
                                <EditList
                                    list={list}
                                    setEditingTitle={setEditingTitle}
                                />
                            )}
                            <i className="far fa-ellipsis-h"></i>
                        </div>
                        <Droppable droppableId={list.id.toString()} type="item">
                            {(provided) => (
                                <div
                                    className="list__cards"
                                    ref={mergeRefs(
                                        provided.innerRef,
                                        listCards
                                    )}
                                    {...provided.droppableProps}
                                >
                                    {list.items.map((card, index) => (
                                        <DraggableCard
                                            card={card}
                                            list={list}
                                            index={index}
                                            key={uuidv4()}
                                        />
                                    ))}
                                    {provided.placeholder}
                                    {addingCard && (
                                        <AddCard
                                            onAddCard={onAddCard}
                                            cardTitle={cardTitle}
                                            setCardTitle={setCardTitle}
                                        />
                                    )}
                                </div>
                            )}
                        </Droppable>
                        {!addingCard ? (
                            <button
                                className="list__add-card"
                                onClick={() => setAddingCard(true)}
                            >
                                Add card
                            </button>
                        ) : cardTitle.trim() !== "" ? (
                            <button
                                className="list__add-card list__add-card--active btn"
                                onClick={onAddCard}
                            >
                                Add
                            </button>
                        ) : (
                            <button
                                className="list__add-card list__add-card--active btn btn--disabled"
                                disabled
                            >
                                Add
                            </button>
                        )}
                    </div>
                );
            }}
        </Draggable>
    );
}
Example #22
Source File: Board.js    From ytx-card-game with MIT License 4 votes vote down vote up
Board = (props) => {
	const { state, dispatch } = useContext(store)
	const isGamePaused = () => state.game && state.game.gamePaused
	const [allyCards, setAllyCards] = useState({
		[ALLY_TYPES.hand]: [],
		[ALLY_TYPES.field]: [],
	})

	useLayoutEffect(() => {
		if (state.game) {
			if (state.playerNumber === 1) {
				setAllyCards({
					[ALLY_TYPES.hand]: [...state.game.player1.hand],
					[ALLY_TYPES.field]: [...state.game.player1.field],
				})
			} else {
				setAllyCards({
					[ALLY_TYPES.hand]: [...state.game.player2.hand],
					[ALLY_TYPES.field]: [...state.game.player2.field],
				})
			}
		}
	}, [state.game])

	const getAllyStateType = (droppableId) => {
		return allyCards[droppableId]
	}

	const invokeCard = (card) => {
		console.log('invoke card', card)
		if (!card.isInvoked) {
			let me
			if (state.playerNumber === 1) {
				me = state.game.player1
			} else {
				me = state.game.player2
			}
			// Invokes a card into the field and updates ally hand with a new deep copy
			if (me.field.length >= FIELD_SIZE) {
				return dispatch({
					type: 'SET_ERROR',
					payload: {
						error: 'The field is full',
					},
				})
			}
			if (card.cost > me.energy) {
				return dispatch({
					type: 'SET_ERROR',
					payload: {
						error:
							"You don't have enough energy to invoke this card",
					},
				})
			}
			card.isInvoked = true
			state.socket.emit('invoke-card', {
				game: state.game,
				card,
			})
		}
	}

	const onDragEnd = useCallback(
		(result) => {
			const { source, destination } = result
			if (!destination) {
				return
			}
			let allyState = getAllyStateType(source.droppableId)
			const isEnoughEnergyToInvoke =
				state.playerNumber === 1
					? state.game.player1.energy
					: state.game.player2.energy
			console.log(
				isEnoughEnergyToInvoke,
				allyState.cost,
				'energy',
				state.playerNumber,
				state.game.player1.energy,
				state.game.player2.energy,
			)
			if (isEnoughEnergyToInvoke < allyState[source.index].cost) {
				return
			}
			if (source.droppableId === destination.droppableId) {
				const items = reorder(
					allyState,
					source.index,
					destination.index,
				)
				setAllyCards({ ...allyCards, [source.droppableId]: items })
			} else {
				//invoke card
				invokeCard(allyCards[ALLY_TYPES.hand][source.index])
				const result = move(
					getAllyStateType(source.droppableId),
					getAllyStateType(destination.droppableId),
					source,
					destination,
				)
				setAllyCards({
					[ALLY_TYPES.hand]: result[ALLY_TYPES.hand],
					[ALLY_TYPES.field]: result[ALLY_TYPES.field],
				})
			}
		},
		[state.game, allyCards],
	)

	return (
		<Page>
			<ResultMsg
				winner={state.gameOver && state.areYouTheWinner}
				loser={state.gameOver && !state.areYouTheWinner}
			>
				{state.gameOver && state.areYouTheWinner
					? 'Congratulations! You are the winner!'
					: state.gameOver && !state.areYouTheWinner
						? 'You lost! Better luck next time!'
						: null}
			</ResultMsg>
			{/* <p>Turn: {state.game ? state.game.currentTurnNumber : 0}</p>
			<p>Timer: {props.turnCountdownTimer}</p> */}
			<ExitLink hidden={!state.gameOver} to="/">
				Exit
			</ExitLink>
			{state.game ? (
				<Game className="game">
					<EnemyDeck>Enemy's <br /> Deck</EnemyDeck>
					<YourDeck>Your <br /> Deck</YourDeck>
					<EnemyStatsBox
						className={
							state.isAttackMode
								? 'enemy-stats attack-mode'
								: 'enemy-stats'
						}
						onClick={() => {
							if (state.isAttackMode) props.attackDirectly()
						}}
					>
						<p>Enemy</p>
						<p>
							{state.playerNumber === 1
								? state.game.player2.life
								: state.game.player1.life}
							<FaHeart />
						</p>
						<p>
							{state.playerNumber === 1
								? state.game.player2.energy
								: state.game.player1.energy}
							<FaBolt />
						</p>
					</EnemyStatsBox>
					<AllyStatsBox className="my-stats">
						<p>You</p>
						<p>
							{state.playerNumber === 1
								? state.game.player1.life
								: state.game.player2.life}
							<FaHeart />
						</p>
						<p>
							{state.playerNumber === 1
								? state.game.player1.energy
								: state.game.player2.energy}
							<FaBolt />
						</p>
					</AllyStatsBox>
					<CardContainer className="cards-container enemy-cards-container">
						{state.visualEnemyHand}
					</CardContainer>
					<Field className="field">
						<DragDropContext onDragEnd={onDragEnd}>
							<EnemyField
								className={
									state.isAttackMode
										? 'enemy-field attack-mode'
										: 'enemy-field'
								}
							>
								{state.enemyFieldHtml}
							</EnemyField>
							<FieldContainer top >
								<Droppable
									droppableId={`${ALLY_TYPES.field}`}
									direction="horizontal"
								>
									{(provided, snapshot) => (
										<CardPanel
											ref={provided.innerRef}
											isDraggingOver={snapshot.isDraggingOver}
										>
											{allyCards[ALLY_TYPES.field].map(
												(allyFieldCard, index) => (
													<Draggable
														key={index}
														draggableId={`allyFieldCard${index}`}
														index={index}
														isDragDisabled={true}
													>
														{(
															provided,
															snapshot,
														) => (
															<div
																ref={
																	provided.innerRef
																}
																{...provided.draggableProps}
																{...provided.dragHandleProps}
															>
																<BoardCard
																	{...allyFieldCard}
																/>
															</div>
														)}
													</Draggable>
												),
											)}
											{provided.placeholder}
										</CardPanel>
									)}
								</Droppable>
							</FieldContainer>
							<FieldContainer bottom>
								<Droppable
									droppableId={`${ALLY_TYPES.hand}`}
									direction="horizontal"
								>
									{(provided, snapshot) => (
										<CardPanel
											ref={provided.innerRef}
											// isDraggingOver={snapshot.isDraggingOver}
											outter
										>
											{allyCards[ALLY_TYPES.hand].map(
												(allyHandCard, index) => (
													<Draggable
														key={index}
														draggableId={`allyHand${index}`}
														index={index}
														isDragDisabled={
															state.playerNumber !==
															state.game
																.currentPlayerTurn
														}
													>
														{(
															provided,
															snapshot,
														) => (
															<div
																ref={
																	provided.innerRef
																}
																{...provided.draggableProps}
																{...provided.dragHandleProps}
															>
																<BoardCard
																	{...allyHandCard}
																/>
															</div>
														)}
													</Draggable>
												),
											)}
											{provided.placeholder}
										</CardPanel>
									)}
								</Droppable>
							</FieldContainer>
						</DragDropContext>
					</Field>
					<Button
						className="end-turn"
						disabled={state.isOtherPlayerTurn || isGamePaused()}
						onClick={() => {
							props.endTurn()
						}}
					>
						End Turn
					</Button>
					<Button
						className="surrender"
						style={{
							backgroundColor: 'red',
						}}
						disabled={isGamePaused()}
						onClick={() => {
							props.surrender()
						}}
					>
						Surrender
					</Button>
				</Game>
			) : (
					<p>Game loading...</p>
				)}
		</Page>
	)
}
Example #23
Source File: tableDrag.js    From camel-store-admin with Apache License 2.0 4 votes vote down vote up
render() {
    const { columns, dataSource, restProps, total } = this.conversionObject()
    const { scroll, pagination } = restProps;
    const { pageSize, offsetWidthBody } = this.state
    const widthtable = scroll && scroll.x ? ( offsetWidthBody > scroll.x ? offsetWidthBody : scroll.x) : 'auto'

    return (
      <div className={styles.dragTable}>
      {/*<Table*/}
        {/*columns={columns}*/}
        {/*dataSource={dataSource}*/}
        {/*components={this.components}*/}
        {/*pagination={false}*/}
        {/*size='small'*/}
        {/*onRow={(record, index) => ({*/}
          {/*index,*/}
          {/*moveRow: this.moveRow,*/}
        {/*})}*/}
        {/*{...restProps}*/}
      {/*/>*/}
        <DragDropContext onDragEnd={this.onDragEnd}>
        <div className="ant-table-wrapper">
          <div className="ant-spin-nested-loading">
            <div className="ant-spin-container">
              <div className="ant-table ant-table-small ant-table-scroll-position-left">
                <div className="ant-table-content">
                  <div className="ant-table-body" id="tableDragbody" style={ scroll && scroll.x ? {overflowX: 'scroll'} : {}}>
                    <table style={isNaN(widthtable) ? {} : {width:widthtable + 'px'}} id="tableDrag">
                      <thead className="ant-table-thead">
                      <tr>
                        { columns.map(item => {
                          return (<th style={item.width ? { width: `${item.width}px`,userSelect:'none'} : {userSelect:'none'}}><div>{item.title}</div></th>)
                        })}
                      </tr></thead>
                      <Droppable droppableId="droppable">
                        {(provided, snapshot) => (
                          <tbody className="ant-table-tbody" ref={provided.innerRef}>
                            {dataSource.length > 0 && dataSource.map((item, index) => (
                              <Draggable key={item.key} draggableId={item.key} index={index}>
                                {(provided, snapshot) => (
                                  <tr className="ant-table-row ant-table-row-level-0" data-row-key={index}
                                    ref={provided.innerRef}
                                    {...provided.draggableProps}
                                    {...provided.dragHandleProps}
                                    style={getItemStyle(
                                      snapshot.isDragging,
                                      provided.draggableProps.style
                                    )}
                                  >
                                    {columns.map(item_in => {
                                      return (
                                        <td style={item_in.width ? { width: `${item_in.width}px`,userSelect:'none'} : {userSelect:'none'}}>
                                          {item_in.render && item_in.render(item[item_in.dataIndex],item) || item[item_in.dataIndex]}
                                        </td>
                                      )
                                    })}
                                  </tr>
                                )}
                              </Draggable>
                            ))}
                            {provided.placeholder}
                          </tbody>
                        )}
                      </Droppable>
                    </table>
                  </div>
                  {dataSource.length === 0 && <div className="ant-table-placeholder"><Empty /></div>}
                </div>
              </div>
            </div>
          </div>
        </div>
        </DragDropContext>
        { pagination &&
          <Row><Col style={{textAlign:'right', marginTop: 10, marginBottom: 10 }}>
            <Pagination pageSize={pageSize} size="small" total={total} showSizeChanger
                        onChange={this.pageChange} onShowSizeChange={this.pageSizeChange}/>
          </Col></Row> }
      </div>
    );
  }
Example #24
Source File: index.js    From ActiveLearningStudio-react-client with GNU Affero General Public License v3.0 4 votes vote down vote up
ResourceCard = (props) => {
  const {
    resource,
    playlist,
    match,
    index,
    teamPermission,
    handleShow,
    setProjectId,
    setProjectPlaylistId,
    setProjectPlaylistActivityId,
    // wizard,
  } = props;
  const organization = useSelector((state) => state.organization);
  const dispatch = useDispatch();
  const parser = new DOMParser()
  let resourceTitle = parser.parseFromString(resource.metadata && resource.metadata.title !== undefined ? resource.metadata.title : resource.title, 'text/html').body.textContent;
  return (
    <Draggable key={resource.id} draggableId={`${resource.id}`} index={index}>
      {(provided) => (
        <div className="playlist-resource playlist-resource-bg" ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
          <div className="resource-card-wrapper d-flex align-items-center">
            {!!resource.thumb_url && (
              <div className="activity-thumb-wrapper">
                {/* <Link to={`/org/${organization.currentOrganization?.domain}/project/${match.params.projectId}/playlist/${playlist.id}/activity/${resource.id}/edit`}> */}
                <div
                  className="activity-thumb"
                  style={{
                    backgroundImage: resource.thumb_url?.includes('pexels.com') ? `url(${resource.thumb_url})` : `url(${global.config.resourceUrl}${resource.thumb_url})`,
                  }}
                />
                {/* </Link> */}
              </div>
            )}

            <div className="title" style={{ flex: 1 }}>
              <Link
                className="playlist-resource-title"
                onClick={async () => {
                  toast.dismiss();
                  toast.info('Loading Activity ...', {
                    className: 'project-loading',
                    closeOnClick: false,
                    closeButton: false,
                    position: toast.POSITION.BOTTOM_RIGHT,
                    autoClose: 10000,
                    icon: '',
                  });
                  const result = await resourceService.activityH5p(resource.id);
                  toast.dismiss();

                  dispatch({
                    type: actionTypes.SET_ACTIVE_ACTIVITY_SCREEN,
                    payload: result.activity?.source_type ? 'addvideo' : 'addactivity',
                    playlist: playlist,
                    project: match.params.projectId,
                    activity: result.activity,
                  });
                  if (result.activity?.source_type) {
                    dispatch({
                      type: 'SET_ACTIVE_VIDEO_SCREEN',
                      payload: result.activity,
                    });
                  }
                }}
                title={resourceTitle}
              >
                {resourceTitle}
              </Link>
            </div>
            {/* {resource.shared && (
              <Badge pill variant="success" className="p-1">
                Shared
              </Badge>
            )} */}
            <div className="activity-options-wrapper check">
              <ResourceCardDropdown
                resource={resource}
                playlist={playlist}
                teamPermission={teamPermission || {}}
                previewPage="buildPreview"
                handleShow={handleShow}
                setProjectId={setProjectId}
                setProjectPlaylistId={setProjectPlaylistId}
                setProjectPlaylistActivityId={setProjectPlaylistActivityId}
                // wizard
              />
            </div>
          </div>
        </div>
      )}
    </Draggable>
  );
}
Example #25
Source File: List.js    From Trellis with GNU General Public License v3.0 4 votes vote down vote up
export default function Column({ column, tasks, index }) {
  const classes = useStyles()
  const [cardTitle, setCardTitle] = useState('')
  const [listTitle, setListTitle] = useState(column.name)
  const [addCardFlag, setAddCardFlag] = useState(false)
  const [editable, setEditable] = useState(false)
  const [list, setList] = useState(true)
  const [showDelete, setShowDelete] = useState(false)
  const { token, user } = useSelector((state) => state.user)
  const dispatch = useDispatch()

  const handleChange = (e) => {
    e.preventDefault()
    setCardTitle(e.target.value)
  }

  const submitHandler = () => {
    if (cardTitle === '') return
    const text = cardTitle.trim().replace(/\s+/g, ' ')
    setCardTitle(text)
    const totalTasks = tasks.length
    const postCardReq = {
      name: text,
      boardId: column.boardId,
      listId: column._id,
      order:
        totalTasks === 0 ? 'n' : midString(tasks[totalTasks - 1].order, ''),
    }
    dispatch(createNewCard(postCardReq, token))
    dispatch(
      createNewActivity(
        {
          text: `${user.username} added ${text} to ${column.name}`,
          boardId: column.boardId,
        },
        token,
      ),
    )
    setCardTitle('')
  }
  const handleAddition = () => {
    setAddCardFlag(true)
  }
  const closeButtonHandler = () => {
    setAddCardFlag(false)
    setCardTitle('')
  }
  const changedHandler = (e) => {
    e.preventDefault()
    setListTitle(e.target.value)
  }
  const handleKeyDown = (e) => {
    if (e.key === 'Enter') {
      e.preventDefault()
      submitHandler()
    }
  }
  const updateListTitle = () => {
    const text = listTitle.trim().replace(/\s+/g, ' ')
    if (text === '') {
      setListTitle(column.name)
      setEditable(false)
      return
    }
    setListTitle(text)
    dispatch(updateListById(column._id, { name: listTitle }))
    // eslint-disable-next-line no-param-reassign
    column.name = text
    setEditable(false)
  }

  return (
    <div className={classes.wrapper}>
      {list && (
        <Draggable draggableId={column._id} index={index}>
          {(provided) => (
            <div {...provided.draggableProps} ref={provided.innerRef}>
              <Paper
                elevation={0}
                onMouseEnter={() => setShowDelete(true)}
                onMouseLeave={() => setShowDelete(false)}
                className={classes.root}
                {...provided.dragHandleProps}
              >
                <div
                  className={classes.title}
                  onClick={() => setEditable(true)}
                >
                  {!editable && (
                    <div style={{ position: 'relative' }}>
                      <div>{column.name}</div>
                      {showDelete && (
                        <IconButton
                          size="small"
                          style={{
                            right: 0,
                            top: 0,
                            position: 'absolute',
                            backgroundColor: '#EBECF0',
                            zIndex: 100,
                          }}
                          onClick={() => {
                            setList(false)
                            dispatch(deleteListById(column._id))
                            const text = `${user.username} deleted list ${column.name}`
                            dispatch(
                              createNewActivity(
                                { text, boardId: column.boardId },
                                token,
                              ),
                            )
                          }}
                        >
                          <DeleteIcon
                            fontSize="small"
                            style={{ backgroundColor: '#EBECF0' }}
                          />
                        </IconButton>
                      )}
                    </div>
                  )}
                  {editable && (
                    <div className={classes.editable}>
                      <InputBase
                        onChange={changedHandler}
                        multiline
                        fullWidth
                        value={listTitle}
                        style={{ fontWeight: 'bold' }}
                        autoFocus
                        onFocus={(e) => {
                          const val = e.target.value
                          e.target.value = ''
                          e.target.value = val
                        }}
                        onBlur={updateListTitle}
                      />
                    </div>
                  )}
                </div>
                <Droppable droppableId={column._id} type="card">
                  {
                    // eslint-disable-next-line no-shadow
                    (provided) => (
                      <div ref={provided.innerRef} {...provided.droppableProps}>
                        <div className={classes.scroll}>
                          {/* eslint-disable-next-line no-shadow */}
                          {tasks.map((task, index) => (
                            <Card key={task._id} task={task} index={index} />
                          ))}
                          {addCardFlag && (
                            <InputCard
                              value={cardTitle}
                              changedHandler={handleChange}
                              itemAdded={submitHandler}
                              closeHandler={closeButtonHandler}
                              keyDownHandler={handleKeyDown}
                              type="card"
                              btnText="Add Card"
                              placeholder="Enter a title for this card..."
                              width="230px"
                            />
                          )}
                          {provided.placeholder}
                        </div>
                        {!addCardFlag && (
                          <AddItem
                            handleClick={handleAddition}
                            icon={<AddIcon />}
                            btnText="Add another card"
                            type="card"
                            width="256px"
                          />
                        )}
                      </div>
                    )
                  }
                </Droppable>
              </Paper>
            </div>
          )}
        </Draggable>
      )}
    </div>
  )
}
Example #26
Source File: Card.js    From Trellis with GNU General Public License v3.0 4 votes vote down vote up
export default function Card({ task, index }) {
  const [editable, setEditable] = useState(false)
  const [title, setTitle] = useState(task.name)
  const [card, setCard] = useState(true)
  const [showDelete, setShowDelete] = useState(false)
  const classes = useStyles()
  const { token, user } = useSelector((state) => state.user)
  const dispatch = useDispatch()
  return (
    <Draggable draggableId={task._id} index={index}>
      {(provided) => (
        <div
          {...provided.draggableProps}
          {...provided.dragHandleProps}
          ref={provided.innerRef}
        >
          {card && (
            <Paper
              className={classes.card}
              onMouseEnter={() => setShowDelete(true)}
              onMouseLeave={() => setShowDelete(false)}
              onClick={() => {
                setEditable(true)
              }}
            >
              {editable ? (
                <InputBase
                  onChange={(e) => {
                    e.preventDefault()
                    setTitle(e.target.value)
                  }}
                  multiline
                  fullWidth
                  value={title}
                  style={{ minHeight: '7px' }}
                  autoFocus
                  onFocus={(e) => {
                    const val = e.target.value
                    e.target.value = ''
                    e.target.value = val
                  }}
                  onBlur={() => {
                    setEditable(false)
                    const text = title.trim().replace(/\s+/g, ' ')
                    if (text === '') {
                      setTitle(task.name)
                      return
                    }
                    setTitle(text)
                    dispatch(updateCardById(task._id, { name: text }))
                    // eslint-disable-next-line no-param-reassign
                    task.name = text
                  }}
                />
              ) : (
                <div style={{ position: 'relative' }}>
                  <div>{task.name}</div>
                  {showDelete && (
                    <IconButton
                      className={classes.delete}
                      size="small"
                      onClick={() => {
                        setCard(false)
                        dispatch(deleteCardById(task._id))
                        const text = `${user.username} deleted card ${task.name}`
                        dispatch(
                          createNewActivity(
                            { text, boardId: task.boardId },
                            token,
                          ),
                        )
                      }}
                    >
                      <DeleteForeverIcon
                        fontSize="small"
                        style={{ backgroundColor: '#EBECF0' }}
                      />
                    </IconButton>
                  )}
                </div>
              )}
            </Paper>
          )}
        </div>
      )}
    </Draggable>
  )
}
Example #27
Source File: socialcard.js    From linkin with MIT License 4 votes vote down vote up
export default function LinkCard({
  item,
  updateLink,
  deleteLink,
  loading,
  index,
  isDragDisabled,
}) {
  const refSubmitButtom = useRef(null);
  const [cardInfo, setCardInfo] = useState(item);

  const {
    register,
    handleSubmit,
    formState: { errors },
    reset,
    watch,
  } = useForm({ defaultValues: item });

  useEffect(() => {
    // reset when the linkdata is change to the form update with new values
    if (cardInfo.id === undefined && item.id) {
      // console.log("reset with item");
      reset(item);
      setCardInfo(item);
    }
    // reset when the link is deleted to the card will show differert value
    if (cardInfo.id !== item.id) {
      // console.log("reset after delete");
      reset(item);
      setCardInfo(item);
    }
  }, [item]);

  watch((data, { type }) => {
    // console.log(type);
    //console.log(data);
    // event fired when reset the form with updated data
    if (type == undefined) {
      return;
    }
    debouncedSaveLinkData();
  });

  // debounced function to save the data after 1.5 seconds
  const debouncedSaveLinkData = useCallback(
    debounce(() => {
      refSubmitButtom?.current?.click();
    }, 1500),
    []
  );

  const submitAction = (data) => {
    // when the form is submited by enter , the debounced action is canceled to avoid uplicate debounce
    debouncedSaveLinkData.cancel();
    // console.log(data);
    updateLink(data);
  };

  return (
    <>
      <Draggable
        isDragDisabled={isDragDisabled}
        key={item.id}
        draggableId={String(item.id)}
        index={index}
      >
        {(provided) => (
          <div
            className="card mt-3"
            ref={provided.innerRef}
            {...provided.draggableProps}
          >
            <div className="d-flex flex-row">
              <div className="card-body py-2 px-4">
                <form onSubmit={handleSubmit(submitAction)}>
                  <div className="d-flex flex-row justify-content-between">
                    <div
                      {...provided.dragHandleProps}
                      className={`${styles.boxshadowmenu} ms-1 `}
                    ></div>{" "}
                    <div className="form-check form-switch d-grid gap-2 d-md-flex justify-content-md-end">
                      <input
                        className="form-check-input"
                        type="checkbox"
                        {...register(`active`)}
                      />
                    </div>
                  </div>
                  <div className="mb-1 small">
                    <input
                      type="text"
                      className={
                        errors.linkUrl
                          ? "form-control form-control-sm mb-2  is-invalid"
                          : "form-control form-control-sm mb-2 "
                      }
                      placeholder="Enter Link Url"
                      {...register(`linkUrl`, {
                        pattern: {
                          message: "Should be a valid URL",
                          value:
                            /((https?:\/\/(?:www\.|(?!www))[a-z0-9][a-z0-9-]+[a-z0-9]\.[^\s]{2,}|www\.[a-z0-9][a-z0-9-]+[a-z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-z0-9]+\.[^\s]{2,}|www\.[a-z0-9]+\.[^\s]{2,})|(((^mailto:)(([a-z])([a-z0-9_\.-]+)?)[@](([a-z])([a-z0-9_\.-]+)?)(\.([a-z]){2,}))))/i,
                        },
                      })}
                    />
                    {errors.linkUrl && (
                      <div className="invalid-feedback">
                        {errors.linkUrl.message}
                      </div>
                    )}
                  </div>
                  <div className="mb-1 small">
                    <div className="form-text">
                      Use{" "}
                      <a
                        className="text-decoration-none"
                        href="https://fontawesome.com/v5.15/icons?d=gallery&p=2"
                        target="_blank"
                      >
                        fontawesome
                      </a>{" "}
                      for icon classes
                    </div>
                  </div>
                  <input
                    type="text"
                    className={
                      errors.iconClass
                        ? "form-control form-control-sm mb-2  is-invalid"
                        : "form-control form-control-sm mb-2 "
                    }
                    placeholder="Enter Icon Class"
                    {...register(`iconClass`)}
                  />
                  <div className="mb-3 ">
                    <div className="input-group mb-3">
                      <input
                        type="number"
                        className={
                          errors.borderRadius
                            ? "form-control is-invalid"
                            : "form-control"
                        }
                        placeholder="Enter Border Radius"
                        {...register("borderRadius", {
                          min: {
                            message: "Font Size must be above 0px",
                            value: 0,
                          },
                        })}
                      />
                      <span className="input-group-text">px</span>
                      {errors.borderRadius && (
                        <div className="invalid-feedback">
                          {errors.borderRadius.message}
                        </div>
                      )}
                    </div>
                  </div>
                  <div className="row">
                    <div className="col">
                      <div className="mb-1 small ">
                        <label className="form-label small">
                          Link background color
                        </label>
                        <input
                          type="color"
                          className="form-control form-control-sm mb-2 form-control-color"
                          title="Choose Link background color"
                          placeholder="Choose Link background color"
                          {...register("bgColor")}
                        />
                      </div>
                    </div>
                  </div>
                  {/* <div className="mb-1 small ">
                  <label className="form-label small">Link accent color </label>
                  <input
                    type="color"
                    className="form-control form-control-sm mb-2 form-control-color"
                    title="Choose Link accent color"
                    placeholder="Choose Link accent color"
                    {...register("accentColor")}
                  />
                </div> */}
                  <div className="d-grid gap-2 d-md-flex justify-content-md-end">
                    <button
                      className="btn btn-outline-danger btn-sm"
                      type="button"
                      disabled={loading}
                      hidden={!item.id}
                      onClick={() => {
                        deleteLink(item.id);
                      }}
                    >
                      Delete
                    </button>
                  </div>
                  <button hidden={true} ref={refSubmitButtom} type={"submit"} />
                </form>
              </div>
            </div>
          </div>
        )}
      </Draggable>
    </>
  );
}
Example #28
Source File: linkcard.js    From linkin with MIT License 4 votes vote down vote up
export default function LinkCard({
  item,
  updateLink,
  deleteLink,
  loading,
  index,
  isDragDisabled,
}) {
  const refSubmitButtom = useRef(null);
  const [cardInfo, setCardInfo] = useState(item);

  const {
    register,
    handleSubmit,
    formState: { errors },
    reset,
    watch,
  } = useForm({ defaultValues: item });

  useEffect(() => {
    // reset when the linkdata is change to the form update with new values
    if (cardInfo.id === undefined && item.id) {
      // console.log("reset with item");
      reset(item);
      setCardInfo(item);
    }
    // reset when the link is deleted to the card will show differert value
    if (cardInfo.id !== item.id) {
      // console.log("reset after delete");
      reset(item);
      setCardInfo(item);
    }
    // logic to test comment settings data and reset
    // reset(item);
    if (
      cardInfo.borderRadius !== item.borderRadius ||
      cardInfo.textColor !== item.textColor ||
      cardInfo.bgColor !== item.bgColor
    ) {
      // console.log("reset after common settings change");
      reset(item);
      setCardInfo(item);
    }
  }, [item]);

  watch((data, { type }) => {
    // console.log(type);
    //console.log(data);
    // event fired when reset the form with updated data
    if (type == undefined) {
      return;
    }
    debouncedSaveLinkData();
  });

  // debounced function to save the data after 1.5 seconds
  const debouncedSaveLinkData = useCallback(
    debounce(() => {
      refSubmitButtom?.current?.click();
    }, 1500),
    []
  );

  const submitAction = (data) => {
    // when the form is submited by enter , the debounced action is canceled to avoid uplicate debounce
    debouncedSaveLinkData.cancel();
    // console.log(data);
    updateLink(data);
  };

  return (
    <>
      <Draggable
        isDragDisabled={isDragDisabled}
        key={item.id}
        draggableId={String(item.id)}
        index={index}
      >
        {(provided) => (
          <div
            className="card mt-3"
            ref={provided.innerRef}
            {...provided.draggableProps}
          >
            <div className="d-flex flex-row">
              <div className="card-body py-2 px-4">
                <form onSubmit={handleSubmit(submitAction)}>
                  <div className="d-flex flex-row justify-content-between">
                    <div
                      {...provided.dragHandleProps}
                      className={`${styles.boxshadowmenu} ms-1 `}
                    ></div>{" "}
                    <div className="form-check form-switch d-grid gap-2 d-md-flex justify-content-md-end">
                      <input
                        className="form-check-input"
                        type="checkbox"
                        {...register(`active`)}
                      />
                    </div>
                  </div>
                  <div className="mb-1 small">
                    <input
                      type="text"
                      className={
                        errors.displayText
                          ? "form-control form-control-sm mb-2 is-invalid"
                          : "form-control form-control-sm mb-2"
                      }
                      placeholder="Enter Link Display Text"
                      {...register(`displayText`, {
                        required: true,
                      })}
                    />
                    {errors.displayText && (
                      <div className="invalid-feedback">
                        Link Display Text is required
                      </div>
                    )}
                  </div>
                  <div className="mb-1 small">
                    <input
                      type="text"
                      className={
                        errors.linkUrl
                          ? "form-control form-control-sm mb-2  is-invalid"
                          : "form-control form-control-sm mb-2 "
                      }
                      placeholder="Enter Link Url"
                      {...register(`linkUrl`, {
                        pattern: {
                          message: "Should be a valid URL",
                          // see https://regexr.com/67tue
                          value:
                            /((https?:\/\/(?:www\.|(?!www))[a-z0-9][a-z0-9-]+[a-z0-9]\.[^\s]{2,}|www\.[a-z0-9][a-z0-9-]+[a-z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-z0-9]+\.[^\s]{2,}|www\.[a-z0-9]+\.[^\s]{2,})|(((^mailto:)(([a-z])([a-z0-9_\.-]+)?)[@](([a-z])([a-z0-9_\.-]+)?)(\.([a-z]){2,}))))/i,
                        },
                      })}
                    />
                    {errors.linkUrl && (
                      <div className="invalid-feedback">
                        {errors.linkUrl.message}
                      </div>
                    )}
                  </div>
                  <div className="mb-1 small">
                    <div className="form-text">
                      Use{" "}
                      <a
                        className="text-decoration-none"
                        href="https://fontawesome.com/v5.15/icons?d=gallery&p=2"
                        target="_blank"
                      >
                        fontawesome
                      </a>{" "}
                      for icon classes
                    </div>
                  </div>
                  <input
                    type="text"
                    className={
                      errors.iconClass
                        ? "form-control form-control-sm mb-2  is-invalid"
                        : "form-control form-control-sm mb-2 "
                    }
                    placeholder="Enter Icon Class"
                    {...register(`iconClass`)}
                  />
                  <div className="mb-3 ">
                    <div className="input-group mb-3">
                      <input
                        type="number"
                        className={
                          errors.borderRadius
                            ? "form-control is-invalid"
                            : "form-control"
                        }
                        placeholder="Enter Border Radius"
                        {...register("borderRadius", {
                          min: {
                            message: "Font Size must be above 0px",
                            value: 0,
                          },
                        })}
                      />
                      <span className="input-group-text">px</span>
                      {errors.borderRadius && (
                        <div className="invalid-feedback">
                          {errors.borderRadius.message}
                        </div>
                      )}
                    </div>
                  </div>
                  <div className="row">
                    <div className="col">
                      <div className="mb-1 small ">
                        <label className="form-label small ">
                          Link Display Text Font color
                        </label>
                        <input
                          type="color"
                          className="form-control form-control-sm mb-2 form-control-color"
                          title="Choose Link text color"
                          placeholder="Choose Link text color"
                          {...register("textColor")}
                        />
                      </div>
                    </div>
                    <div className="col">
                      <div className="mb-1 small ">
                        <label className="form-label small">
                          Link background color
                        </label>
                        <input
                          type="color"
                          className="form-control form-control-sm mb-2 form-control-color"
                          title="Choose Link background color"
                          placeholder="Choose Link background color"
                          {...register("bgColor")}
                        />
                      </div>
                    </div>
                  </div>
                  {/* <div className="mb-1 small ">
                  <label className="form-label small">Link accent color </label>
                  <input
                    type="color"
                    className="form-control form-control-sm mb-2 form-control-color"
                    title="Choose Link accent color"
                    placeholder="Choose Link accent color"
                    {...register("accentColor")}
                  />
                </div> */}
                  <div className="d-grid gap-2 d-md-flex justify-content-md-end">
                    <button
                      className="btn btn-outline-danger btn-sm"
                      type="button"
                      disabled={loading}
                      hidden={!item.id}
                      onClick={() => {
                        deleteLink(item.id);
                      }}
                    >
                      Delete
                    </button>
                  </div>
                  <button hidden={true} ref={refSubmitButtom} type={"submit"} />
                </form>
              </div>
            </div>
          </div>
        )}
      </Draggable>
    </>
  );
}
Example #29
Source File: index.js    From website with MIT License 4 votes vote down vote up
DragNDropInputField = ({ onChange, error, initialImages = null }) => {
  const [selectedImages, setSelectedImages] = useState([]);
  const [alertMessage, setAlertMessage] = useState('');
  const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
    onDrop: (files) => onUpload(files, selectedImages),
    accept: '.jpeg, .png, .jpg',
  });

  const onCloseAlert = () => setAlertMessage('');

  const displayUploadFileAlert = (message) => {
    setAlertMessage(message);
    setTimeout(() => {
      onCloseAlert(); // hide alert message after 5 seconds
    }, 5000);
  };

  const onUpload = useCallback((acceptedFiles, selectedImages) => {
    if (acceptedFiles.some((file) => file.size > MAXIMUM_FILE_SIZE_LIMIT)) {
      displayUploadFileAlert('Unable to upload images that are more than 25mb');
      acceptedFiles = acceptedFiles.filter((file) => file.size <= MAXIMUM_FILE_SIZE_LIMIT);
    }

    const allowedRemainingImages = MAXIMUM_ALLOWED_PHOTOS - selectedImages.length;
    if (allowedRemainingImages < acceptedFiles.length) {
      displayUploadFileAlert('Unable to upload more than 4 images');
    }

    // Only take maximum 4 images.
    if (acceptedFiles.length > 0 && selectedImages.length <= MAXIMUM_ALLOWED_PHOTOS - 1) {
      const acceptedImages = acceptedFiles.map((file) => {
        return Object.assign(file, {
          preview: URL.createObjectURL(file),
          id: uuidv4(),
        });
      });

      if (allowedRemainingImages > 0) {
        const allowedImages = acceptedImages.splice(0, allowedRemainingImages);
        setSelectedImages((prevSelectedImages) => [...prevSelectedImages, ...allowedImages]);
      }
    }
  }, []);

  useEffect(() => {
    onChange(selectedImages);
  }, [selectedImages]);

  useEffect(() => {
    if (initialImages) {
      let initial = initialImages.map((imageUrl) => ({
        preview: imageUrl,
        id: uuidv4(),
      }));
      setSelectedImages(initial);
    }
  }, [initialImages]);

  const onDragEnd = (result) => {
    if (!result.destination) {
      // dropped outside the list
      return;
    }
    const items = reorder(selectedImages, result.source.index, result.destination.index);
    setSelectedImages(items);
  };

  // a little function to help us with reordering the result
  const reorder = (list, startIndex, endIndex) => {
    const result = Array.from(list);
    const [removed] = result.splice(startIndex, 1);
    result.splice(endIndex, 0, removed);
    return result;
  };

  const onDeleteClick = (index) => {
    let cloneSelectedImages = [...selectedImages];
    cloneSelectedImages.splice(index, 1);
    setSelectedImages(cloneSelectedImages);
  };

  return (
    <Container>
      <DragNDropContainer {...getRootProps({ isDragActive, isDragAccept, isDragReject })}>
        <input {...getInputProps()} />
        <p>Drag 'n' drop up to {MAXIMUM_ALLOWED_PHOTOS} photos, or click to select photos</p>
      </DragNDropContainer>
      {error && <Error>{error}</Error>}

      <DragDropContext onDragEnd={onDragEnd}>
        <Droppable droppableId="droppable" direction="horizontal">
          {(provided, snapshot) => (
            <HorizontalImagesContainer ref={provided.innerRef} {...provided.droppableProps}>
              {selectedImages.map((item, index) => (
                <Draggable key={item.id} draggableId={item.id} index={index}>
                  {(provided, snapshot) => (
                    <DraggableImageContainer
                      ref={provided.innerRef}
                      {...provided.draggableProps}
                      {...provided.dragHandleProps}
                      isDragging={snapshot.isDragging}
                      draggableStyle={provided.draggableProps.style}
                    >
                      <Image src={item.preview} onDeleteClick={() => onDeleteClick(index)} />
                    </DraggableImageContainer>
                  )}
                </Draggable>
              ))}
              {provided.placeholder}
            </HorizontalImagesContainer>
          )}
        </Droppable>
      </DragDropContext>

      {selectedImages.length > 0 ? (
        <CoverTextWrapper>
          <Text type="white" align="center">
            Cover
          </Text>
        </CoverTextWrapper>
      ) : null}
      {alertMessage.length > 0 && (
        <AlertContainer>
          <Alert icon type="critical" title="Something has gone wrong" closable onClose={onCloseAlert}>
            {alertMessage}
          </Alert>
        </AlertContainer>
      )}
    </Container>
  );
}