} - A promise that resolves when the comment is posted.
- */
- const onPostComment = async (text, authorName, pluginData, geojson, label, images, pinned, mapCommentText) => {
+ const onPostComment = async (comment) => {
const { answers } = listState;
if (user) {
setListState({ ...listState, shouldAnimate: true });
}
- const commentData = { text, authorName, pluginData, geojson, label, images, answers, pinned, mapCommentText };
+ const commentData = { ...comment, answers };
- if (onPostComment) {
+ if (onPostCommentFn) {
await onPostCommentFn(section.id, commentData);
setListState({ ...listState, answers: answersInitialState });
@@ -209,7 +196,7 @@ const SortableCommentListComponent = ({
* @param {string} sectionId - The ID of the section.
* @param {object} data - The data of the comment.
*/
- const handlePostReply = (sectionId, data) => onPostComment(sectionId, data);
+ const handlePostReply = (sectionId, data) => onPostCommentFn(sectionId, data);
/**
* Handles the change of answers for a specific question.
@@ -245,7 +232,7 @@ const SortableCommentListComponent = ({
],
});
} else if (questionType === 'multiple-choice' && oldAnswer) {
- listState({
+ setListState({
answers: [
...listState.answers.filter((answer) => answer.question !== questionId),
{
diff --git a/src/components/__tests__/BaseCommentForm.jsx b/src/components/__tests__/BaseCommentForm.jsx
index 1b2121040..31cf73327 100644
--- a/src/components/__tests__/BaseCommentForm.jsx
+++ b/src/components/__tests__/BaseCommentForm.jsx
@@ -79,7 +79,17 @@ describe('', () => {
fireEvent.click(submitButton);
- expect(onPostComment).toHaveBeenCalledWith('Test comment', 'Test Nickname', undefined, {}, null, [], false, '');
+ expect(onPostComment).toHaveBeenCalledWith({
+ authorName: 'Test Nickname',
+ geojson: {},
+ images: [],
+ label: null,
+ mapCommentText: '',
+ organization: undefined,
+ pinned: false,
+ pluginData: undefined,
+ text: 'Test comment',
+ });
});
it('handles nickname change', () => {
diff --git a/src/components/admin/HearingEditor.jsx b/src/components/admin/HearingEditor.jsx
index d168ac3c1..23178c10e 100644
--- a/src/components/admin/HearingEditor.jsx
+++ b/src/components/admin/HearingEditor.jsx
@@ -1,5 +1,5 @@
/* eslint-disable react/forbid-prop-types */
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { connect, useDispatch } from 'react-redux';
import { isEmpty } from 'lodash';
@@ -72,6 +72,9 @@ const HearingEditor = (props) => {
fetchEditorContactPersons();
}, [fetchEditorContactPersons]);
+ const geoJSONRef = useRef();
+ geoJSONRef.current = hearing?.geojson;
+
const checkIfEmpty = (obj) => !Object.entries(obj).some(([, v]) => Object.entries(v).length > 0);
useEffect(() => {
@@ -124,11 +127,16 @@ const HearingEditor = (props) => {
const onSectionChange = (sectionID, field, value) => dispatch(changeSection(sectionID, field, value));
- const onCreateMapMarker = (value) => dispatch(createMapMarker(value));
-
- const onAddMapMarker = (value) => dispatch(addMapMarker(value));
-
- const onAddMapMarkersToCollection = (value) => dispatch(addMapMarkerToCollection(value));
+ const onAddMapMarker = (value) => {
+ console.log('geoJSONRef', geoJSONRef.current);
+ if (isEmpty(geoJSONRef.current) || !geoJSONRef.current) {
+ dispatch(createMapMarker(value));
+ } else if (geoJSONRef.current.type !== 'FeatureCollection') {
+ dispatch(addMapMarker(value));
+ } else {
+ dispatch(addMapMarkerToCollection(value));
+ }
+ }
/**
* Add a new attachments to a section.
@@ -239,8 +247,6 @@ const HearingEditor = (props) => {
labels={labels}
language={language}
onAddMapMarker={onAddMapMarker}
- onAddMapMarkersToCollection={onAddMapMarkersToCollection}
- onCreateMapMarker={onCreateMapMarker}
onDeleteExistingQuestion={onDeleteExistingQuestion}
onDeleteTemporaryQuestion={onDeleteTemporaryQuestion}
onHearingChange={onHearingChange}
diff --git a/src/components/admin/HearingFormStep3.jsx b/src/components/admin/HearingFormStep3.jsx
index cfd8e7b70..503d6db2f 100644
--- a/src/components/admin/HearingFormStep3.jsx
+++ b/src/components/admin/HearingFormStep3.jsx
@@ -2,10 +2,10 @@
/* eslint-disable no-underscore-dangle */
/* eslint-disable global-require */
/* eslint-disable import/no-unresolved */
-import React, { useEffect, useState } from 'react';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { injectIntl, FormattedMessage } from 'react-intl';
-import Leaflet from 'leaflet';
+import Leaflet, { featureGroup } from 'leaflet';
import { Button, Fieldset, FileInput } from 'hds-react';
import { isEmpty, includes, keys, isMatch } from 'lodash';
import { connect, useDispatch } from 'react-redux';
@@ -32,14 +32,6 @@ Leaflet.Marker.prototype.options.icon = new Leaflet.Icon({
iconAnchor: [13, 41],
});
-function getFirstGeometry(featureCollectionGeoJSON) {
- const firstFeature = featureCollectionGeoJSON.features[0];
- if (firstFeature) {
- return firstFeature.geometry;
- }
- return {};
-}
-
/**
* Returns an array of the remaining features
* @param {Object[]} currentFeatures
@@ -65,8 +57,7 @@ const HearingFormStep3 = (props) => {
let map;
let featureGroup;
const { hearing, language, isHighContrast, visible } = props; // const props
- const { onHearingChange, onCreateMapMarker, onAddMapMarker, onAddMapMarkersToCollection, onContinue } = props; // function props
- const [isEdited, setIsEdited] = useState(false);
+ const { onHearingChange, onAddMapMarker, onContinue } = props; // function props
const [initialGeoJSON, setInitialGeoJSON] = useState(props.hearing.geojson);
const dispatch = useDispatch();
@@ -75,51 +66,12 @@ const HearingFormStep3 = (props) => {
Leaflet.drawLocal = getTranslatedTooltips(language);
}, [language]);
- const onDrawEdited = (event) => {
- // TODO: Implement proper onDrawEdited functionality
- setIsEdited(true);
- onHearingChange('geojson', getFirstGeometry(event.layers.toGeoJSON()));
- };
-
- const onDrawCreated = (event) => {
- // TODO: Implement proper onDrawCreated functionality
- if (isEdited) {
- /**
- * first time an element is created and the map hasn't been edited/elements removed
- */
- setIsEdited(true);
- if (!hearing.geojson || !hearing.geojson.type) {
- /**
- * if hearing.geojson is null or doesnt have type -> add a single element
- */
- onCreateMapMarker(event.layer.toGeoJSON().geometry);
- } else if (hearing.geojson.type !== 'FeatureCollection') {
- /**
- * if hearing.geojson has a type that isn't FeatureCollection
- * -> add element and transform hearing.geojson to FeatureCollection
- */
- onAddMapMarker(event.layer.toGeoJSON());
- } else if (hearing.geojson.type === 'FeatureCollection') {
- /**
- * if hearing.geojson type is FeatureCollection - add element to geojson.features
- */
- onAddMapMarkersToCollection(event.layer.toGeoJSON());
- }
- } else if (hearing.geojson.coordinates) {
- /**
- * if geojson has coordinates -> transform hearing.geojson to FeatureCollection and add element
- */
- onAddMapMarker(event.layer.toGeoJSON());
- } else {
- /**
- * hearing.geojson is a FeatureCollection -> add element to geojson.features
- */
- onAddMapMarkersToCollection(event.layer.toGeoJSON());
- }
- };
+ const onDrawCreated = useCallback((event) => {
+ onAddMapMarker(event.layer.toGeoJSON());
+ }, [onAddMapMarker]);
// eslint-disable-next-line sonarjs/cognitive-complexity
- const onDrawDeleted = (event) => {
+ const onDrawDeleted = useCallback((event) => {
// TODO: Implement proper onDrawDeleted functionality
if (event.layers && !isEmpty(event.layers._layers) && hearing.geojson.features) {
/**
@@ -165,25 +117,20 @@ const HearingFormStep3 = (props) => {
if (remainingFeatures.length === 0) {
// hearing is a FeatureCollection and all elements have been removed
onHearingChange('geojson', {});
- setIsEdited(false);
setInitialGeoJSON({});
} else {
// hearing is a FeatureCollection that still has elements after removal
onHearingChange('geojson', { type: hearing.geojson.type, features: remainingFeatures });
if (currentStateFeatures) {
- setIsEdited(true);
setInitialGeoJSON({ type: hearing.geojson.type, features: remainingStateFeatures });
- } else {
- setIsEdited(true);
}
}
} else {
// hearing.geojson is a single element that has been removed
onHearingChange('geojson', {});
- setIsEdited(false);
setInitialGeoJSON({});
}
- };
+ }, [hearing.geojson, initialGeoJSON, onHearingChange]);
const readTextFile = (file, callback) => {
try {
@@ -217,7 +164,7 @@ const HearingFormStep3 = (props) => {
}
onHearingChange('geojson', featureCollection.features[0].geometry);
const parsedFile = parseCollection(featureCollection);
- onCreateMapMarker(parsedFile);
+ onAddMapMarker(parsedFile);
setInitialGeoJSON(parsedFile);
} else {
dispatch(addToast(createLocalizedNotificationPayload(NOTIFICATION_TYPES.error, MESSAGE_INCORRECT_FILE)));
@@ -252,9 +199,11 @@ const HearingFormStep3 = (props) => {
}
}, [visible, map]);
- const refCallBack = (el) => {
- map = el;
- };
+ function refCallback(instance) {
+ if (instance) {
+ map = instance;
+ }
+ }
if (typeof window === 'undefined') return null;
@@ -262,7 +211,7 @@ const HearingFormStep3 = (props) => {
}>
{
)}
/>
{
- featureGroup = group;
- }}
+ ref={featureGroup}
>
{
const {
answers,
@@ -51,6 +52,15 @@ const MapQuestionnaire = ({
user,
} = data;
+ /**
+ * Determines whether the logged in user is admin or not.
+ * The array in users with key adminOrganizations should be of length > 0
+ */
+ const isUserAdmin = useMemo(
+ () => loggedIn && user && Array.isArray(user.adminOrganizations) && user.adminOrganizations.length > 0,
+ [loggedIn, user],
+ );
+
const [formData, setFormData] = useState({
collapsed: true,
commentOrAnswerRequiredError: false,
@@ -71,6 +81,7 @@ const MapQuestionnaire = ({
submitting: false,
showAlert: true,
userDataChanged: false,
+ organization: isUserAdmin ? user.adminOrganizations[0] : undefined,
});
const [messageListener, setMessageListener] = useState(null);
@@ -122,7 +133,7 @@ const MapQuestionnaire = ({
const pluginComment = getPluginComment();
let pluginData = getPluginData();
- const { nickname, commentText, geojson, images, pinned, mapCommentText, imageTooBig } = formData;
+ const { nickname, commentText, geojson, images, pinned, mapCommentText, imageTooBig, organization } = formData;
const submitData = {
nickname: nickname === '' ? nicknamePlaceholder : nickname,
@@ -132,6 +143,7 @@ const MapQuestionnaire = ({
pinned,
mapCommentText,
label: null,
+ organization,
};
// plugin comment will override comment fields, if provided
@@ -171,16 +183,17 @@ const MapQuestionnaire = ({
submitData.setCommentText = config.emptyCommentString;
}
- onPostComment(
- submitData.commentText,
- submitData.nickname,
+ onPostComment({
+ text: submitData.commentText,
+ authorName: submitData.nickname,
pluginData,
- submitData.geojson,
- submitData.label,
- submitData.images,
- submitData.pinned,
- submitData.mapCommentText,
- );
+ geojson: submitData.geojson,
+ label: submitData.label,
+ images: submitData.images,
+ pinned: submitData.pinned,
+ mapCommentText: submitData.mapCommentText,
+ organization: submitData.organization ?? undefined,
+ });
setFormData((prevState) => ({
...prevState,
diff --git a/src/components/plugins/legacy/mapdon-hkr.jsx b/src/components/plugins/legacy/mapdon-hkr.jsx
index 1b184668a..5fec59676 100644
--- a/src/components/plugins/legacy/mapdon-hkr.jsx
+++ b/src/components/plugins/legacy/mapdon-hkr.jsx
@@ -125,7 +125,6 @@ class MapdonHKRPlugin extends BaseCommentForm {
}
MapdonHKRPlugin.propTypes = {
- onPostComment: PropTypes.func,
data: PropTypes.string,
};
diff --git a/src/components/plugins/legacy/mapdon-ksv.jsx b/src/components/plugins/legacy/mapdon-ksv.jsx
index 7cc3b7ed3..3bf1674b5 100644
--- a/src/components/plugins/legacy/mapdon-ksv.jsx
+++ b/src/components/plugins/legacy/mapdon-ksv.jsx
@@ -170,7 +170,6 @@ class MapdonKSVPlugin extends BaseCommentForm {
}
MapdonKSVPlugin.propTypes = {
- onPostComment: PropTypes.func,
data: PropTypes.string,
pluginPurpose: PropTypes.string,
comments: PropTypes.array,
diff --git a/src/middleware/hearingEditor.js b/src/middleware/hearingEditor.js
index 344811e34..1e691004e 100644
--- a/src/middleware/hearingEditor.js
+++ b/src/middleware/hearingEditor.js
@@ -58,7 +58,6 @@ export const normalizeReceiveEditorContactPersons =
export const normalizeSavedHearing =
({ dispatch }) => (next) => (action) => {
const NORMALIZE_ACTIONS = [EditorActions.POST_HEARING_SUCCESS, EditorActions.SAVE_HEARING_SUCCESS];
-
if (NORMALIZE_ACTIONS.includes(action.type)) {
const hearing = get(action, 'payload.hearing');
dispatch(updateHearingAfterSave(fillFrontIdsAndNormalizeHearing(hearing)));
diff --git a/src/reducers/hearingEditor/hearing.js b/src/reducers/hearingEditor/hearing.js
index 86782230e..3841542c6 100644
--- a/src/reducers/hearingEditor/hearing.js
+++ b/src/reducers/hearingEditor/hearing.js
@@ -25,7 +25,7 @@ const data = handleActions(
[EditorActions.EDIT_HEARING]: (state, { payload: { field, value } }) => ({ ...state, [field]: value }),
[EditorActions.CREATE_MAP_MARKER]: (state, { payload: { value } }) => ({
...state,
- geojson: value,
+ geojson: value.geometry,
}),
[EditorActions.ADD_MAP_MARKER]: (state, { payload: { value } }) => {
const foo = state.geojson;
diff --git a/src/utils/map.js b/src/utils/map.js
index 86413d2c3..28920b376 100644
--- a/src/utils/map.js
+++ b/src/utils/map.js
@@ -4,9 +4,9 @@ import { Polygon, GeoJSON, Marker, Polyline } from 'react-leaflet';
import 'proj4'; // import required for side effect
import 'proj4leaflet'; // import required for side effect
-import * as leafletMarkerIconUrl from '../../assets/images/leaflet/marker-icon.png';
-import * as leafletMarkerRetinaIconUrl from '../../assets/images/leaflet/marker-icon-2x.png';
-import * as leafletMarkerShadowUrl from '../../assets/images/leaflet/marker-shadow.png';
+import leafletMarkerIconUrl from '../../assets/images/leaflet/marker-icon.png';
+import leafletMarkerRetinaIconUrl from '../../assets/images/leaflet/marker-icon-2x.png';
+import leafletMarkerShadowUrl from '../../assets/images/leaflet/marker-shadow.png';
export function EPSG3067() {
const crsName = 'EPSG:3067';
diff --git a/src/utils/section.js b/src/utils/section.js
index 361591ad0..5915d51d2 100644
--- a/src/utils/section.js
+++ b/src/utils/section.js
@@ -41,7 +41,7 @@ export function isCommentRequired(hasQuestions, isReply, userAnsweredAllQuestion
* @returns {boolean} true when at least one question is answered and false if not
*/
export function hasAnyAnswers(answers) {
- return answers.some(questionAnswers => questionAnswers.answers && questionAnswers.answers.length > 0);
+ return answers && answers.some(questionAnswers => questionAnswers.answers && questionAnswers.answers.length > 0);
}
/**
diff --git a/src/views/FullscreenHearing/FullscreenHearingContainer.jsx b/src/views/FullscreenHearing/FullscreenHearingContainer.jsx
index 33987ee25..a91b924fa 100644
--- a/src/views/FullscreenHearing/FullscreenHearingContainer.jsx
+++ b/src/views/FullscreenHearing/FullscreenHearingContainer.jsx
@@ -13,7 +13,12 @@ import { getHearingWithSlug, getMainSection, getMainSectionComments } from '../.
import LoadSpinner from '../../components/LoadSpinner';
import getAttr from '../../utils/getAttr';
import { parseQuery } from '../../utils/urlQuery';
-import { fetchHearing as fetchHearingAction, postSectionComment, postVote, fetchAllSectionComments } from '../../actions';
+import {
+ fetchHearing as fetchHearingAction,
+ postSectionComment,
+ postVote,
+ fetchAllSectionComments,
+} from '../../actions';
import Link from '../../components/LinkWithLang';
import Icon from '../../utils/Icon';
import getUser from '../../selectors/user';
@@ -28,8 +33,8 @@ const FullscreenHearingContainerComponent = (ownProps) => {
const user = useSelector((state) => getUser(state));
const language = useSelector((state) => state.language);
const fetchAllComments = (hearingSlug, sectionId, ordering) => {
- dispatch(fetchAllSectionComments(hearingSlug, sectionId, ordering))
- }
+ dispatch(fetchAllSectionComments(hearingSlug, sectionId, ordering));
+ };
useEffect(() => {
if (isEmpty(hearing)) {
@@ -38,13 +43,12 @@ const FullscreenHearingContainerComponent = (ownProps) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
- const onPostComment = (text, authorName, pluginData, geojson, label, images) => {
- const sectionCommentData = { text, authorName, pluginData, geojson, label, images };
+ const onPostComment = (comment) => {
// eslint-disable-next-line no-shadow
const { mainSection } = ownProps;
const { hearingSlug } = params;
const { authCode } = parseQuery(location.search);
- const commentData = { authCode, ...sectionCommentData };
+ const commentData = { authCode, ...comment };
return dispatch(postSectionComment(hearingSlug, mainSection.id, commentData));
};
diff --git a/src/views/Hearing/__tests__/HearingContainer.test.jsx b/src/views/Hearing/__tests__/HearingContainer.test.jsx
index 5a10397e1..279e0c6dc 100644
--- a/src/views/Hearing/__tests__/HearingContainer.test.jsx
+++ b/src/views/Hearing/__tests__/HearingContainer.test.jsx
@@ -89,7 +89,9 @@ describe('', () => {
isSaving: false,
},
},
- user,
+ user: {
+ data: user,
+ },
sectionComments: [],
accessibility: {
isHighContrast: false,
diff --git a/test-utils.js b/test-utils.js
index b8e219ba6..ce87e8fd8 100644
--- a/test-utils.js
+++ b/test-utils.js
@@ -6,7 +6,7 @@ import createStore from './src/createStore';
import messages from './src/i18n';
-export const mockUser = { id: "fff", displayName: "Mock von User" };
+export const mockUser = { id: "fff", displayName: "Mock von User", adminOrganizations: [] };
export function createTestStore(state) {
commonInit();