Skip to content

Commit ce8060b

Browse files
✨(frontend) add AlertModal and enhance document sharing features
- Introduced a new `AlertModal` component for confirmation dialogs. - Updated `DocToolBoxLicenceAGPL` and `DocToolBoxLicenceMIT` to include `isRootDoc` prop for better document management. - Enhanced `DocShareModal` to conditionally render content based on the root document status. - Improved `DocInheritedShareContent` to display inherited access information more effectively. - Refactored `DocRoleDropdown` to handle access removal actions and improve role management. - Updated `DocShareMemberItem` to accommodate new access management features.
1 parent 081a6e0 commit ce8060b

File tree

20 files changed

+842
-501
lines changed

20 files changed

+842
-501
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { Button, Modal, ModalSize } from '@openfun/cunningham-react';
2+
import { useTranslation } from 'react-i18next';
3+
4+
import { Box } from '../Box';
5+
import { Text } from '../Text';
6+
7+
export type AlertModalProps = {
8+
isOpen: boolean;
9+
onClose: () => void;
10+
title: string;
11+
description: string | React.ReactNode;
12+
onConfirm: () => void;
13+
confirmLabel?: string;
14+
cancelLabel?: string;
15+
};
16+
17+
export const AlertModal = ({
18+
isOpen,
19+
onClose,
20+
title,
21+
description,
22+
onConfirm,
23+
confirmLabel,
24+
cancelLabel,
25+
}: AlertModalProps) => {
26+
const { t } = useTranslation();
27+
return (
28+
<Modal
29+
isOpen={isOpen}
30+
size={ModalSize.MEDIUM}
31+
onClose={onClose}
32+
title={
33+
<Text $size="h6" $align="flex-start" $variation="1000">
34+
{title}
35+
</Text>
36+
}
37+
rightActions={
38+
<>
39+
<Button
40+
aria-label={t('Close the modal')}
41+
color="secondary"
42+
fullWidth
43+
onClick={() => onClose()}
44+
>
45+
{cancelLabel ?? t('Cancel')}
46+
</Button>
47+
<Button
48+
aria-label={confirmLabel ?? t('Confirm')}
49+
color="danger"
50+
onClick={onConfirm}
51+
>
52+
{confirmLabel ?? t('Confirm')}
53+
</Button>
54+
</>
55+
}
56+
>
57+
<Box
58+
aria-label={t('Confirmation button')}
59+
className="--docs--alert-modal"
60+
>
61+
<Box>
62+
<Text $variation="600">{description}</Text>
63+
</Box>
64+
</Box>
65+
</Modal>
66+
);
67+
};
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import { Button, useModal } from '@openfun/cunningham-react';
2+
import { useQueryClient } from '@tanstack/react-query';
3+
import { useEffect, useState } from 'react';
4+
import { useTranslation } from 'react-i18next';
5+
import { css } from 'styled-components';
6+
7+
import {
8+
DropdownMenu,
9+
DropdownMenuOption,
10+
Icon,
11+
IconOptions,
12+
} from '@/components';
13+
import { useCunninghamTheme } from '@/cunningham';
14+
import { ModalExport } from '@/docs/doc-export/';
15+
import {
16+
Doc,
17+
KEY_DOC,
18+
KEY_LIST_DOC,
19+
ModalRemoveDoc,
20+
useCopyDocLink,
21+
useCreateFavoriteDoc,
22+
useDeleteFavoriteDoc,
23+
} from '@/docs/doc-management';
24+
import {
25+
KEY_LIST_DOC_VERSIONS,
26+
ModalSelectVersion,
27+
} from '@/docs/doc-versioning';
28+
import { useAnalytics } from '@/libs';
29+
import { useResponsiveStore } from '@/stores';
30+
31+
import { DocShareModal } from '../../doc-share';
32+
import { useCopyCurrentEditorToClipboard } from '../hooks/useCopyCurrentEditorToClipboard';
33+
34+
type ModalType = ReturnType<typeof useModal>;
35+
36+
interface DocToolBoxLicenceProps {
37+
doc: Doc;
38+
modalHistory: ModalType;
39+
modalShare: ModalType;
40+
isRootDoc?: boolean;
41+
}
42+
43+
export const DocToolBoxLicenceAGPL = ({
44+
doc,
45+
modalHistory,
46+
modalShare,
47+
isRootDoc = true,
48+
}: DocToolBoxLicenceProps) => {
49+
const { t } = useTranslation();
50+
const queryClient = useQueryClient();
51+
52+
const { colorsTokens } = useCunninghamTheme();
53+
54+
const [isModalRemoveOpen, setIsModalRemoveOpen] = useState(false);
55+
const [isModalExportOpen, setIsModalExportOpen] = useState(false);
56+
57+
const { isSmallMobile, isDesktop } = useResponsiveStore();
58+
const copyDocLink = useCopyDocLink(doc.id);
59+
const { isFeatureFlagActivated } = useAnalytics();
60+
const removeFavoriteDoc = useDeleteFavoriteDoc({
61+
listInvalideQueries: [KEY_LIST_DOC, KEY_DOC],
62+
});
63+
const makeFavoriteDoc = useCreateFavoriteDoc({
64+
listInvalideQueries: [KEY_LIST_DOC, KEY_DOC],
65+
});
66+
const copyCurrentEditorToClipboard = useCopyCurrentEditorToClipboard();
67+
68+
const options: DropdownMenuOption[] = [
69+
...(isSmallMobile
70+
? [
71+
{
72+
label: t('Share'),
73+
icon: 'group',
74+
callback: modalShare.open,
75+
},
76+
{
77+
label: t('Export'),
78+
icon: 'download',
79+
callback: () => {
80+
setIsModalExportOpen(true);
81+
},
82+
},
83+
{
84+
label: t('Copy link'),
85+
icon: 'add_link',
86+
callback: copyDocLink,
87+
},
88+
]
89+
: []),
90+
{
91+
label: doc.is_favorite ? t('Unpin') : t('Pin'),
92+
icon: 'push_pin',
93+
callback: () => {
94+
if (doc.is_favorite) {
95+
removeFavoriteDoc.mutate({ id: doc.id });
96+
} else {
97+
makeFavoriteDoc.mutate({ id: doc.id });
98+
}
99+
},
100+
testId: `docs-actions-${doc.is_favorite ? 'unpin' : 'pin'}-${doc.id}`,
101+
},
102+
{
103+
label: t('Version history'),
104+
icon: 'history',
105+
disabled: !doc.abilities.versions_list,
106+
callback: () => {
107+
modalHistory.open();
108+
},
109+
show: isDesktop,
110+
},
111+
112+
{
113+
label: t('Copy as {{format}}', { format: 'Markdown' }),
114+
icon: 'content_copy',
115+
callback: () => {
116+
void copyCurrentEditorToClipboard('markdown');
117+
},
118+
},
119+
{
120+
label: t('Copy as {{format}}', { format: 'HTML' }),
121+
icon: 'content_copy',
122+
callback: () => {
123+
void copyCurrentEditorToClipboard('html');
124+
},
125+
show: isFeatureFlagActivated('CopyAsHTML'),
126+
},
127+
{
128+
label: t('Delete document'),
129+
icon: 'delete',
130+
disabled: !doc.abilities.destroy,
131+
callback: () => {
132+
setIsModalRemoveOpen(true);
133+
},
134+
},
135+
];
136+
137+
useEffect(() => {
138+
if (modalHistory.isOpen) {
139+
return;
140+
}
141+
142+
void queryClient.resetQueries({
143+
queryKey: [KEY_LIST_DOC_VERSIONS],
144+
});
145+
}, [modalHistory.isOpen, queryClient]);
146+
147+
return (
148+
<>
149+
{!isSmallMobile && (
150+
<Button
151+
color="tertiary-text"
152+
icon={<Icon iconName="download" $theme="primary" $variation="800" />}
153+
onClick={() => {
154+
setIsModalExportOpen(true);
155+
}}
156+
size={isSmallMobile ? 'small' : 'medium'}
157+
/>
158+
)}
159+
<DropdownMenu options={options}>
160+
<IconOptions
161+
isHorizontal
162+
$theme="primary"
163+
$padding={{ all: 'xs' }}
164+
$css={css`
165+
border-radius: 4px;
166+
&:hover {
167+
background-color: ${colorsTokens['greyscale-100']};
168+
}
169+
${isSmallMobile
170+
? css`
171+
padding: 10px;
172+
border: 1px solid ${colorsTokens['greyscale-300']};
173+
`
174+
: ''}
175+
`}
176+
aria-label={t('Open the document options')}
177+
/>
178+
</DropdownMenu>
179+
180+
{modalShare.isOpen && (
181+
<DocShareModal
182+
onClose={() => modalShare.close()}
183+
doc={doc}
184+
isRootDoc={isRootDoc}
185+
/>
186+
)}
187+
{isModalExportOpen && (
188+
<ModalExport onClose={() => setIsModalExportOpen(false)} doc={doc} />
189+
)}
190+
{isModalRemoveOpen && (
191+
<ModalRemoveDoc onClose={() => setIsModalRemoveOpen(false)} doc={doc} />
192+
)}
193+
{modalHistory.isOpen && (
194+
<ModalSelectVersion onClose={() => modalHistory.close()} doc={doc} />
195+
)}
196+
</>
197+
);
198+
};

0 commit comments

Comments
 (0)