Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Story map chapter move #1175

Merged
merged 14 commits into from
Sep 18, 2023
1 change: 1 addition & 0 deletions src/assets/drag-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions src/common/components/ConfirmMenuItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright © 2021-2023 Technology Matters
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import React, { useCallback, useEffect, useState } from 'react';
import { MenuItem } from '@mui/material';

import ConfirmationDialog from 'common/components/ConfirmationDialog';

const ConfirmMenuItem = props => {
const [openConfirmation, setOpenConfirmation] = useState(false);
const { confirmTitle, confirmMessage, confirmButton, onConfirm, children } =
props;

useEffect(() => {
setOpenConfirmation(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion+nit: I don't think this needs to be set false here, I think that is the default value it will have.

}, []);

const onClick = useCallback(event => {
setOpenConfirmation(true);
event.stopPropagation();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: I'm not super familiar with the web client code, is the event.stopPropagation used commonly throughout, or is there a special reason you are using it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@david-code yes, I think that is common, there are some cases where you have the same listener on a parent component and you want to avoid the event to keep propagating

}, []);

const onCancel = useCallback(event => {
setOpenConfirmation(false);
event.stopPropagation();
}, []);

return (
<>
<ConfirmationDialog
open={openConfirmation}
title={confirmTitle}
message={confirmMessage}
confirmButtonLabel={confirmButton}
onCancel={onCancel}
onConfirm={onConfirm}
/>
<MenuItem onClick={onClick}>{children}</MenuItem>
</>
);
};

export default ConfirmMenuItem;
25 changes: 25 additions & 0 deletions src/common/components/StrictModeDroppable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { useEffect, useState } from 'react';
import { Droppable } from 'react-beautiful-dnd';

// Work around for react-beautiful-dnd issue. The issues is that the
// Droppable component is not compatible with React.StrictMode.
// StricMode is used in the development environment by default.
// See:
// - https://stackoverflow.com/a/75807063
// - https://github.com/atlassian/react-beautiful-dnd/issues/2396
const StrictModeDroppable = ({ children, ...props }) => {
const [enabled, setEnabled] = useState(false);
useEffect(() => {
const animation = requestAnimationFrame(() => setEnabled(true));
return () => {
cancelAnimationFrame(animation);
setEnabled(false);
};
}, []);
if (!enabled) {
return null;
}
return <Droppable {...props}>{children}</Droppable>;
};

export default StrictModeDroppable;
5 changes: 5 additions & 0 deletions src/localization/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,11 @@
"form_chapter_alignment_left": "Left",
"form_chapter_alignment_center": "Center",
"form_chapter_alignment_right": "Right",
"form_chapter_open_menu": "Open menu",
"form_chapter_menu_label": "{{chapterLabel}} menu",
"form_chapter_move_up": "Move Chapter Up",
"form_chapter_move_down": "Move Chapter Down",
"form_chapter_dragging_label": "Dragging {{chapterLabel}}",
"form_location_dialog_title": "Set map location for <1>{{title}}</1>",
"form_location_dialog_title_blank": "Set map location",
"location_dialog_cancel_button": "Cancel",
Expand Down
5 changes: 5 additions & 0 deletions src/localization/locales/es-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,11 @@
"form_chapter_alignment_left": "Izquierda",
"form_chapter_alignment_center": "Centro",
"form_chapter_alignment_right": "Derecha",
"form_chapter_open_menu": "Abrir menú",
"form_chapter_menu_label": "{{chapterLabel}} menú",
"form_chapter_move_up": "Mover capítulo hacia arriba",
"form_chapter_move_down": "Mover capítulo hacia abajo",
"form_chapter_dragging_label": "Arrastrando {{chapterLabel}}",
"form_location_dialog_title": "Establecer la ubicación del mapa para <1>{{title}}</1>",
"form_location_dialog_title_blank": "Establecer ubicación en el mapa",
"location_dialog_cancel_button": "Cancelar",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import React, {
useState,
} from 'react';
import _ from 'lodash/fp';
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
import { DragDropContext, Draggable } from 'react-beautiful-dnd';
import { useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import * as yup from 'yup';
Expand All @@ -38,6 +38,7 @@ import {

import List from 'common/components/List';
import StepperStep from 'common/components/StepperStep';
import StrictModeDroppable from 'common/components/StrictModeDroppable';
import Form from 'forms/components/Form';
import { FormContextProvider, useFormGetContext } from 'forms/formContext';
import { useVisualizationContext } from 'sharedData/visualization/visualizationContext';
Expand Down Expand Up @@ -82,27 +83,6 @@ const FORM_FIELDS = [
},
];

// Work around for react-beautiful-dnd issue. The issues is that the
// Droppable component is not compatible with React.StrictMode.
// StricMode is used in the development environment by default.
// See:
// - https://stackoverflow.com/a/75807063
// - https://github.com/atlassian/react-beautiful-dnd/issues/2396
const StrictModeDroppable = ({ children, ...props }) => {
const [enabled, setEnabled] = useState(false);
useEffect(() => {
const animation = requestAnimationFrame(() => setEnabled(true));
return () => {
cancelAnimationFrame(animation);
setEnabled(false);
};
}, []);
if (!enabled) {
return null;
}
return <Droppable {...props}>{children}</Droppable>;
};

const DataPoints = props => {
const { t } = useTranslation();
const { value, onChange } = props.field;
Expand Down
4 changes: 2 additions & 2 deletions src/storyMap/components/StoryMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -530,10 +530,10 @@ const StoryMap = props => {
map={map}
initialLocation={initialLocation}
>
{insetMap => (
{insetMapContext => (
<Scroller
map={map}
insetMap={insetMap}
insetMap={insetMapContext?.map}
config={config}
animation={animation}
onStepChange={onStepChange}
Expand Down
Loading
Loading