You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
3.3 KiB

  1. import {useState, useEffect, createRef} from 'react'
  2. import {useTranslation} from "react-i18next";
  3. import {
  4. Button,
  5. Card,
  6. CardBody
  7. } from "reactstrap";
  8. import {
  9. faPlus,
  10. } from "@fortawesome/free-solid-svg-icons";
  11. import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
  12. import {
  13. sortableContainer,
  14. sortableElement,
  15. sortableHandle
  16. } from "react-sortable-hoc";
  17. import arrayMove from "array-move"
  18. import CandidateField from './CandidateField'
  19. // const SortableItem = sortableElement(({className, ...childProps}) => <li className={className}><CandidateField {...childProps} /></li>);
  20. //
  21. // const SortableContainer = sortableContainer(({children}) => {
  22. // return <ul className="sortable">{children}</ul>;
  23. // });
  24. const SortableItem = ({className, ...childProps}) => <li className={className}><CandidateField {...childProps} /></li>;
  25. const SortableContainer = ({children}) => {
  26. return <ul className="sortable">{children}</ul>;
  27. };
  28. const CandidatesField = ({onChange}) => {
  29. const {t} = useTranslation();
  30. const [candidates, setCandidates] = useState([])
  31. const addCandidate = () => {
  32. if (candidates.length < 1000) {
  33. candidates.push({label: "", fieldRef: createRef()});
  34. setCandidates([...candidates]);
  35. onChange(candidates)
  36. } else {
  37. console.error("Too many candidates")
  38. }
  39. };
  40. useEffect(() => {
  41. addCandidate();
  42. addCandidate();
  43. }, [])
  44. const removeCandidate = index => {
  45. if (candidates.length === 1) {
  46. const newCandidates = []
  47. newCandidates.push({label: "", fieldRef: createRef()});
  48. newCandidates.push({label: "", fieldRef: createRef()});
  49. setCandidates(newCandidates);
  50. onChange(newCandidates)
  51. }
  52. else {
  53. const newCandidates = candidates.filter((c, i) => i != index)
  54. setCandidates(newCandidates);
  55. onChange(newCandidates);
  56. }
  57. };
  58. const editCandidate = (index, label) => {
  59. candidates[index].label = label
  60. setCandidates([...candidates]);
  61. onChange(candidates);
  62. };
  63. const handleKeyPress = (e, index) => {
  64. if (e.key === "Enter") {
  65. e.preventDefault();
  66. if (index + 1 === candidates.length) {
  67. addCandidate();
  68. }
  69. else {
  70. candidates[index + 1].fieldRef.current.focus();
  71. }
  72. }
  73. }
  74. const onSortEnd = ({oldIndex, newIndex}) => {
  75. setCandidates(arrayMove(candidates, oldIndex, newIndex));
  76. };
  77. return (
  78. <>
  79. <SortableContainer onSortEnd={onSortEnd}>
  80. {candidates.map((candidate, index) => {
  81. const className = "sortable"
  82. return (
  83. <SortableItem
  84. className={className}
  85. key={`item-${index}`}
  86. index={index}
  87. candIndex={index}
  88. label={candidate.label}
  89. onDelete={() => removeCandidate(index)}
  90. onChange={(e) => editCandidate(index, e.target.value)}
  91. onKeyPress={(e) => handleKeyPress(e, index)}
  92. innerRef={candidate.fieldRef}
  93. />
  94. )
  95. })}
  96. </SortableContainer>
  97. <Button
  98. color="secondary"
  99. className="btn-block mt-2"
  100. tabIndex={candidates.length + 2}
  101. type="button"
  102. onClick={addCandidate}
  103. >
  104. <FontAwesomeIcon icon={faPlus} className="mr-2" />
  105. {t("Add a proposal")}
  106. </Button>
  107. </>
  108. );
  109. }
  110. export default CandidatesField