Page MenuHomePhabricator

D8530.diff
No OneTemporary

D8530.diff

diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js
--- a/lib/shared/thread-utils.js
+++ b/lib/shared/thread-utils.js
@@ -1605,6 +1605,22 @@
}, [threadInfo]);
}
+function communityOrThreadNoun(threadInfo: RawThreadInfo | ThreadInfo): string {
+ return threadTypeIsCommunityRoot(threadInfo.type)
+ ? 'community'
+ : threadNoun(threadInfo.type, threadInfo.parentThreadID);
+}
+
+function getThreadsToDeleteText(
+ threadInfo: RawThreadInfo | ThreadInfo,
+): string {
+ return `${
+ threadTypeIsCommunityRoot(threadInfo.type)
+ ? 'Subchannels and threads'
+ : 'Threads'
+ } within this ${communityOrThreadNoun(threadInfo)}`;
+}
+
export {
threadHasPermission,
viewerIsMember,
@@ -1672,4 +1688,5 @@
threadInfoInsideCommunity,
useRoleMemberCountsForCommunity,
useRoleUserSurfacedPermissions,
+ getThreadsToDeleteText,
};
diff --git a/web/modals/threads/settings/thread-settings-delete-confirmation-modal.css b/web/modals/threads/settings/thread-settings-delete-confirmation-modal.css
new file mode 100644
--- /dev/null
+++ b/web/modals/threads/settings/thread-settings-delete-confirmation-modal.css
@@ -0,0 +1,14 @@
+.container {
+ padding: 0 40px 32px;
+ border-radius: 8px;
+ color: var(--modal-fg);
+}
+.text {
+ font-size: var(--xl-font-20);
+ padding: 5px 0px 20px;
+}
+.buttonContainer {
+ display: flex;
+ justify-content: flex-end;
+ gap: 24px;
+}
diff --git a/web/modals/threads/settings/thread-settings-delete-confirmation-modal.react.js b/web/modals/threads/settings/thread-settings-delete-confirmation-modal.react.js
new file mode 100644
--- /dev/null
+++ b/web/modals/threads/settings/thread-settings-delete-confirmation-modal.react.js
@@ -0,0 +1,54 @@
+// @flow
+
+import * as React from 'react';
+
+import { useModalContext } from 'lib/components/modal-provider.react.js';
+import { getThreadsToDeleteText } from 'lib/shared/thread-utils.js';
+import type { ThreadInfo } from 'lib/types/thread-types';
+
+import css from './thread-settings-delete-confirmation-modal.css';
+import Button from '../../../components/button.react.js';
+import Modal from '../../modal.react.js';
+
+type BaseProps = {
+ +threadInfo: ThreadInfo,
+ +onConfirmation: () => mixed,
+};
+
+function ThreadDeleteConfirmationModal({
+ threadInfo,
+ onConfirmation,
+}: BaseProps): React.Node {
+ const { popModal } = useModalContext();
+ const threadsToDeleteText = React.useMemo(
+ () => getThreadsToDeleteText(threadInfo),
+ [threadInfo],
+ );
+
+ return (
+ <Modal
+ size="large"
+ name="Warning"
+ icon="warning-circle"
+ withCloseButton={false}
+ onClose={popModal}
+ >
+ <div className={css.container}>
+ <p className={css.text}>
+ {threadsToDeleteText} will also be permanently deleted. Are you sure
+ you want to continue?
+ </p>
+ <div className={css.buttonContainer}>
+ <Button variant="outline" onClick={popModal}>
+ No
+ </Button>
+ <Button variant="filled" onClick={onConfirmation} type="submit">
+ Yes
+ </Button>
+ </div>
+ </div>
+ </Modal>
+ );
+}
+
+export default ThreadDeleteConfirmationModal;
diff --git a/web/modals/threads/settings/thread-settings-delete-tab.react.js b/web/modals/threads/settings/thread-settings-delete-tab.react.js
--- a/web/modals/threads/settings/thread-settings-delete-tab.react.js
+++ b/web/modals/threads/settings/thread-settings-delete-tab.react.js
@@ -8,6 +8,7 @@
} from 'lib/actions/thread-actions.js';
import { useModalContext } from 'lib/components/modal-provider.react.js';
import SWMansionIcon from 'lib/components/SWMansionIcon.react.js';
+import { containedThreadInfos } from 'lib/selectors/thread-selectors.js';
import { type SetState } from 'lib/types/hook-types.js';
import { type ThreadInfo } from 'lib/types/thread-types.js';
import {
@@ -16,8 +17,10 @@
} from 'lib/utils/action-utils.js';
import SubmitSection from './submit-section.react.js';
+import ThreadDeleteConfirmationModal from './thread-settings-delete-confirmation-modal.react.js';
import css from './thread-settings-delete-tab.css';
import { buttonThemes } from '../../../components/button.react.js';
+import { useSelector } from '../../../redux/redux-utils.js';
type ThreadSettingsDeleteTabProps = {
+threadSettingsOperationInProgress: boolean,
@@ -39,14 +42,28 @@
const modalContext = useModalContext();
const dispatchActionPromise = useDispatchActionPromise();
const callDeleteThread = useServerCall(deleteThread);
+ const containedThreads = useSelector(
+ state => containedThreadInfos(state)[threadInfo.id],
+ );
+ const shouldUseDeleteConfirmationModal = React.useMemo(
+ () => containedThreads?.length > 0,
+ [containedThreads?.length],
+ );
+ const popThreadDeleteConfirmationModal = React.useCallback(() => {
+ if (shouldUseDeleteConfirmationModal) {
+ modalContext.popModal();
+ }
+ }, [modalContext, shouldUseDeleteConfirmationModal]);
const deleteThreadAction = React.useCallback(async () => {
try {
setErrorMessage('');
const response = await callDeleteThread(threadInfo.id);
+ popThreadDeleteConfirmationModal();
modalContext.popModal();
return response;
} catch (e) {
+ popThreadDeleteConfirmationModal();
setErrorMessage(
e.message === 'invalid_credentials'
? 'permission not granted'
@@ -54,14 +71,36 @@
);
throw e;
}
- }, [callDeleteThread, modalContext, setErrorMessage, threadInfo.id]);
-
+ }, [
+ callDeleteThread,
+ modalContext,
+ popThreadDeleteConfirmationModal,
+ setErrorMessage,
+ threadInfo.id,
+ ]);
+ const dispatchDeleteThreadAction = React.useCallback(() => {
+ dispatchActionPromise(deleteThreadActionTypes, deleteThreadAction());
+ }, [dispatchActionPromise, deleteThreadAction]);
const onDelete = React.useCallback(
(event: SyntheticEvent<HTMLElement>) => {
event.preventDefault();
- dispatchActionPromise(deleteThreadActionTypes, deleteThreadAction());
+ if (shouldUseDeleteConfirmationModal) {
+ modalContext.pushModal(
+ <ThreadDeleteConfirmationModal
+ threadInfo={threadInfo}
+ onConfirmation={dispatchDeleteThreadAction}
+ />,
+ );
+ } else {
+ dispatchDeleteThreadAction();
+ }
},
- [deleteThreadAction, dispatchActionPromise],
+ [
+ dispatchDeleteThreadAction,
+ modalContext,
+ shouldUseDeleteConfirmationModal,
+ threadInfo,
+ ],
);
return (

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 30, 1:39 AM (21 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2598963
Default Alt Text
D8530.diff (6 KB)

Event Timeline