diff --git a/h/static/scripts/group-forms/components/CreateEditGroupForm.tsx b/h/static/scripts/group-forms/components/CreateEditGroupForm.tsx index 4b314475283..346e51918ba 100644 --- a/h/static/scripts/group-forms/components/CreateEditGroupForm.tsx +++ b/h/static/scripts/group-forms/components/CreateEditGroupForm.tsx @@ -6,6 +6,7 @@ import { Input, RadioGroup, Textarea, + ModalDialog, useWarnOnPageUnload, } from '@hypothesis/frontend-shared'; import { readConfig } from '../config'; @@ -17,6 +18,7 @@ import type { } from '../utils/api'; import { setLocation } from '../utils/set-location'; import SaveStateIcon from './SaveStateIcon'; +import WarningDialog from './WarningDialog'; function Star() { return *; @@ -133,6 +135,68 @@ function TextField({ ); } +/** + * Dialog that warns users about existing annotations in a group being exposed + * or hidden from public view when the group type is changed. + */ +function GroupTypeChangeWarning({ + name, + newType, + annotationCount: count, + onConfirm, + onCancel, +}: { + /** Name of the group. */ + name: string; + + /** + * The new type for the group. If this is private, the old type is inferred + * to be public and vice-versa. + */ + newType: GroupType; + + /** Number of annotations in the group. */ + annotationCount: number; + + onConfirm: () => void; + onCancel: () => void; +}) { + const newTypeIsPrivate = newType === 'private'; + + let title; + let confirmAction; + let message; + if (newTypeIsPrivate) { + title = `Make ${count} annotations private?`; + confirmAction = 'Make annotations private'; + message = `Are you sure you want to make "${name}" a private group? ${count} annotations that are publicly visible will become visible only to members of "${name}".`; + } else { + let groupDescription = 'a public group'; + switch (newType) { + case 'open': + groupDescription = 'an open group'; + break; + case 'restricted': + groupDescription = 'a restricted group'; + break; + } + + title = `Make ${count} annotations public?`; + confirmAction = 'Make annotations public'; + message = `Are you sure you want to make "${name}" ${groupDescription}? ${count} annotations that are visible only to members of "${name}" will become publicly visible.`; + } + + return ( + + ); +} + export default function CreateEditGroupForm() { const config = useMemo(() => readConfig(), []); const group = config.context.group; @@ -143,6 +207,12 @@ export default function CreateEditGroupForm() { group?.type ?? 'private', ); + // Set when the user selects a new group type if confirmation is required. + // Cleared after confirmation. + const [pendingGroupType, setPendingGroupType] = useState( + null, + ); + const [errorMessage, setErrorMessage] = useState(''); const [saveState, setSaveState] = useState< 'unmodified' | 'unsaved' | 'saving' | 'saved' @@ -249,6 +319,18 @@ export default function CreateEditGroupForm() { const groupTypeLabel = useId(); + const changeGroupType = (newType: GroupType) => { + const count = group?.num_annotations ?? 0; + const oldTypeIsPrivate = groupType === 'private'; + const newTypeIsPrivate = newType === 'private'; + + if (count === 0 || oldTypeIsPrivate === newTypeIsPrivate) { + setGroupType(newType); + } else { + setPendingGroupType(newType); + } + }; + return (

@@ -280,12 +362,12 @@ export default function CreateEditGroupForm() { {config.features.group_type && ( <>