SelectedItemsPane.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import React from "react";
  2. import styled from "styled-components";
  3. import { useRecoilValue } from "recoil";
  4. import { useItems } from "./Board/Items";
  5. import { selectedItemsAtom } from "../components/Board/Selector";
  6. import ItemFormFactory from "./Board/Items/Item/forms/ItemFormFactory";
  7. import { confirmAlert } from "react-confirm-alert";
  8. import "react-confirm-alert/src/react-confirm-alert.css";
  9. import { useTranslation } from "react-i18next";
  10. const SelectedPane = styled.div`
  11. position: fixed;
  12. right: 1em;
  13. bottom: 1em;
  14. background: #ffffff77;
  15. padding: 0.2em;
  16. max-height: 50vh;
  17. overflow-y: scroll;
  18. `;
  19. export const SelectedItems = () => {
  20. const {
  21. itemList,
  22. updateItem,
  23. batchUpdateItems,
  24. shuffleSelectedItems,
  25. removeItem,
  26. } = useItems();
  27. const { t } = useTranslation();
  28. const selectedItems = useRecoilValue(selectedItemsAtom);
  29. const selectedItemList = React.useMemo(() => {
  30. return itemList.filter(({ id }) => selectedItems.includes(id));
  31. }, [itemList, selectedItems]);
  32. // Align selection to center
  33. const align = React.useCallback(() => {
  34. // Compute
  35. const minMax = { min: {}, max: {} };
  36. minMax.min.x = Math.min(...selectedItemList.map(({ x }) => x));
  37. minMax.min.y = Math.min(...selectedItemList.map(({ y }) => y));
  38. minMax.max.x = Math.max(
  39. ...selectedItemList.map(({ x, actualWidth }) => x + actualWidth)
  40. );
  41. minMax.max.y = Math.max(
  42. ...selectedItemList.map(({ y, actualHeight }) => y + actualHeight)
  43. );
  44. const [newX, newY] = [
  45. (minMax.min.x + minMax.max.x) / 2,
  46. (minMax.min.y + minMax.max.y) / 2,
  47. ];
  48. let index = -1;
  49. batchUpdateItems(selectedItems, (item) => {
  50. index += 1;
  51. return {
  52. ...item,
  53. x: newX - item.actualWidth / 2 + index,
  54. y: newY - item.actualHeight / 2 - index,
  55. };
  56. });
  57. }, [selectedItemList, selectedItems, batchUpdateItems]);
  58. const flip = React.useCallback(() => {
  59. batchUpdateItems(selectedItems, (item) => ({
  60. ...item,
  61. flipped: true,
  62. }));
  63. }, [selectedItems, batchUpdateItems]);
  64. const unflip = React.useCallback(() => {
  65. batchUpdateItems(selectedItems, (item) => ({
  66. ...item,
  67. flipped: false,
  68. }));
  69. }, [selectedItems, batchUpdateItems]);
  70. if (selectedItemList.length === 0) {
  71. return null;
  72. }
  73. const onSubmitHandler = (formValues) => {
  74. updateItem(formValues.id, (item) => ({
  75. ...item,
  76. ...formValues,
  77. }));
  78. };
  79. const onRemove = () => {
  80. confirmAlert({
  81. title: t("Confirmation"),
  82. message: t("Do you really want to remove selected items ?"),
  83. buttons: [
  84. {
  85. label: t("Yes"),
  86. onClick: () =>
  87. selectedItems.forEach((id) => {
  88. removeItem(id);
  89. }),
  90. },
  91. {
  92. label: t("No"),
  93. onClick: () => {},
  94. },
  95. ],
  96. });
  97. };
  98. return (
  99. <SelectedPane>
  100. {selectedItems.length > 1 && (
  101. <div>
  102. <h2>{selectedItems.length} items selected</h2>
  103. <button onClick={shuffleSelectedItems}>{t("Shuffle")}</button>
  104. <button onClick={align}>{t("Stack")}</button>
  105. <button onClick={flip}>{t("Hide")}</button>
  106. <button onClick={unflip}>{t("SHow")}</button>
  107. <button onClick={onRemove}>{t("Remove all")}</button>
  108. </div>
  109. )}
  110. {selectedItems.length === 1 &&
  111. selectedItemList.map((item) => (
  112. <div key={item.id}>
  113. <h2>{t("Edit item")}</h2>
  114. <ItemFormFactory item={item} onSubmitHandler={onSubmitHandler} />
  115. <button onClick={onRemove}>{t("Remove")}</button>
  116. </div>
  117. ))}
  118. </SelectedPane>
  119. );
  120. };
  121. export default SelectedItems;