Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions frontend/src/components/comments/commentInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { formatUserNamesToLink, markdownFromHtml } from '../../utils/htmlFromMar
import { iconConfig } from './editorIconConfig';
import messages from './messages';
import { CurrentUserAvatar } from '../user/avatar';
import * as safeStorage from '../../utils/safe_storage';

const maxFileSize = 1 * 1024 * 1024; // 1MB

Expand All @@ -40,6 +41,7 @@ function CommentInputField({
const isBundle = useRef(false);
const lastConvertedRef = useRef(null);
const [isShowPreview, setIsShowPreview] = useState(false);
const hasMounted = useRef(false);

const appendImgToComment = (url) => setComment(`${comment}\n![image](${url})\n`);
const [uploadError, uploading, onDrop] = useOnDrop(appendImgToComment);
Expand Down Expand Up @@ -139,18 +141,29 @@ function CommentInputField({

useEffect(() => {
if (!sessionkey) return;
const commenEvent = sessionStorage.getItem(sessionkey);
if (commenEvent) {
setComment(commenEvent);
const saved = safeStorage.getItem(sessionkey);
if (saved) {
setComment(saved);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sessionkey]);

useEffect(() => {
if (!sessionkey) return;
sessionStorage.setItem(sessionkey, comment);
if (comment) {
safeStorage.setItem(sessionkey, comment);
} else if (hasMounted.current) {
// Only purge after mount β€” avoids deleting the saved draft before
// the restore effect above has had a chance to apply it.
safeStorage.removeItem(sessionkey);
}
}, [comment, sessionkey]);

// Mark component as mounted after all initial effects run
useEffect(() => {
hasMounted.current = true;
}, []);

useEffect(() => {
if (
comment &&
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/components/taskSelection/action.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { FormattedMessage, useIntl } from 'react-intl';

import messages from './messages';
import * as safeStorage from '../../utils/safe_storage';
import { ProjectInstructions } from './instructions';
import { TasksMap } from './map';
import { HeaderLine } from '../projectDetail/header';
Expand Down Expand Up @@ -85,7 +86,14 @@
const [disabled, setDisable] = useState(false);
const [taskComment, setTaskComment] = useState('');
const [selectedStatus, setSelectedStatus] = useState();
const [validationComments, setValidationComments] = useState({});
const [validationComments, setValidationComments] = useState(() => {
const restored = {};
tasksIds.forEach((id) => {
const saved = safeStorage.getItem(`tm-comment-validation-${project.projectId}-${id}`);

Check warning on line 92 in frontend/src/components/taskSelection/action.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'project.projectId' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=hotosm_tasking-manager&issues=AZ5jOhZNxRHZv9iNtCeW&open=AZ5jOhZNxRHZv9iNtCeW&pullRequest=7257
if (saved) restored[id] = saved;
});
return restored;
});
const [validationStatus, setValidationStatus] = useState({});
const [historyTabChecked, setHistoryTabChecked] = useState(false);
const [showMapChangesModal, setShowMapChangesModal] = useState(false);
Expand Down
20 changes: 17 additions & 3 deletions frontend/src/components/taskSelection/actionSidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
submitValidationTask,
} from '../../api/projects';
import ReactPlaceholder from 'react-placeholder';
import * as safeStorage from '../../utils/safe_storage';

const CommentInputField = lazy(() =>
import('../comments/commentInput' /* webpackChunkName: "commentInput" */),
Expand Down Expand Up @@ -69,7 +70,7 @@ export function CompletionTabForMapping({
const clearLockedTasks = useClearLockedTasks();
const directedFrom = localStorage.getItem('lastProjectPathname');
const { projectId } = project;
const SESSION_KEY = 'task-comment';
const SESSION_KEY = `tm-comment-mapping-${projectId}-${tasksIds?.[0]}`;

const splitTaskMutation = useMutation({
mutationFn: () => splitTask(projectId, tasksIds[0], token, locale),
Expand Down Expand Up @@ -148,7 +149,7 @@ export function CompletionTabForMapping({
payload.status = selectedStatus;
}
submitTaskMutation.mutate({ url, payload });
sessionStorage.removeItem(SESSION_KEY);
safeStorage.removeItem(SESSION_KEY);
};

const invalidateProjectData = () => {
Expand Down Expand Up @@ -390,8 +391,15 @@ export function CompletionTabForValidation({
const updateStatus = (id, newStatus) =>
setValidationStatus({ ...validationStatus, [id]: newStatus });

const updateComment = (id, newComment) =>
const updateComment = (id, newComment) => {
setValidationComments({ ...validationComments, [id]: newComment });
const key = `tm-comment-validation-${projectId}-${id}`;
if (newComment) {
safeStorage.setItem(key, newComment);
} else {
safeStorage.removeItem(key);
}
};

const copyCommentToTasks = (id, statusFilter) => {
const comment = validationComments[id];
Expand Down Expand Up @@ -420,6 +428,9 @@ export function CompletionTabForValidation({
})),
};
stopValidationMutation.mutate(payload);
tasksIds?.forEach((taskId) => {
safeStorage.removeItem(`tm-comment-validation-${projectId}-${taskId}`);
});
};

const onSubmitTask = () => {
Expand All @@ -431,6 +442,9 @@ export function CompletionTabForValidation({
})),
};
submitTaskMutation.mutate(payload);
tasksIds?.forEach((taskId) => {
safeStorage.removeItem(`tm-comment-validation-${projectId}-${taskId}`);
});
};

const navigateToTasksPage = (applyFilter = false) => {
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/taskSelection/taskActivity.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { useTaskDetail } from '../../api/projects';
import { Alert } from '../alert';
import { MessageStatus } from '../comments/status';
import { postTaskComment } from '../../api/questionsAndComments';
import * as safeStorage from '../../utils/safe_storage';

import './styles.scss';

Expand All @@ -36,7 +37,7 @@ const PostComment = ({ projectId, taskId, contributors, setCommentPayload }) =>
const token = useSelector((state) => state.auth.token);
const locale = useSelector((state) => state.preferences['locale']);
const [comment, setComment] = useState('');
const SESSION_KEY = `task-comment-${taskId}`;
const SESSION_KEY = `tm-comment-history-${projectId}-${taskId}`;

const saveComment = () => {
if (comment) {
Expand All @@ -49,7 +50,7 @@ const PostComment = ({ projectId, taskId, contributors, setCommentPayload }) =>
onSuccess: (res) => {
setCommentPayload(res.data);
setComment('');
sessionStorage.removeItem(SESSION_KEY);
safeStorage.removeItem(SESSION_KEY);
},
});

Expand Down
Loading