1 import { useEffect, useState } from 'react';
3 import { c } from 'ttag';
5 import { Button } from '@proton/atoms';
6 import Form from '@proton/components/components/form/Form';
7 import BasicModal from '@proton/components/components/modalTwo/BasicModal';
8 import type { BasicModalProps } from '@proton/components/components/modalTwo/BasicModal';
9 import Option from '@proton/components/components/option/Option';
10 import SelectTwo from '@proton/components/components/selectTwo/SelectTwo';
11 import { useApi, useGetCalendarInfo, useNotifications } from '@proton/components/hooks';
12 import { createPublicLink } from '@proton/shared/lib/api/calendars';
13 import { MAX_CHARS_CLEARTEXT } from '@proton/shared/lib/calendar/constants';
14 import { getPrimaryCalendarKey } from '@proton/shared/lib/calendar/crypto/keys/helpers';
17 generateEncryptedPurpose,
18 getCreatePublicLinkPayload,
19 transformLinksFromAPI,
20 } from '@proton/shared/lib/calendar/sharing/shareUrl/shareUrl';
21 import type { CalendarLink, CalendarUrlResponse } from '@proton/shared/lib/interfaces/calendar';
22 import { ACCESS_LEVEL } from '@proton/shared/lib/interfaces/calendar';
23 import { splitKeys } from '@proton/shared/lib/keys';
25 import { InputFieldTwo } from '../../../components';
27 interface Props extends Omit<BasicModalProps, 'children' | 'footer'> {
36 transformedLink: CalendarLink[];
37 accessLevel: ACCESS_LEVEL;
43 const defaultAccessLevel = ACCESS_LEVEL.LIMITED;
45 const ShareLinkModal = ({ calendarID, calendarName, onSubmit, onClose, isOpen, ...rest }: Props) => {
46 const getCalendarInfo = useGetCalendarInfo();
48 const { createNotification } = useNotifications();
50 const [isLoading, setIsLoading] = useState(false);
51 const [accessLevel, setAccessLevel] = useState<ACCESS_LEVEL>(defaultAccessLevel);
52 const [purpose, setPurpose] = useState('');
54 const handleError = ({ message }: Error) => createNotification({ type: 'error', text: message });
56 const handleSubmit = async () => {
59 const { calendarKeys, passphrase, passphraseID } = await getCalendarInfo(calendarID);
60 const { publicKey } = getPrimaryCalendarKey(calendarKeys);
61 const { publicKeys } = splitKeys(calendarKeys);
63 const encryptedPurpose = purpose ? await generateEncryptedPurpose({ purpose, publicKey }) : null;
65 const { payload, passphraseKey, cacheKey } = await getCreatePublicLinkPayload({
73 const { CalendarUrl } = await api<CalendarUrlResponse>(createPublicLink(calendarID, payload));
74 const { CalendarUrlID } = CalendarUrl;
75 const link = buildLink({
81 const { privateKeys } = splitKeys(calendarKeys);
82 const transformedLink = await transformLinksFromAPI({
83 calendarUrls: [CalendarUrl],
85 calendarPassphrase: passphrase,
89 createNotification({ type: 'success', text: c('Info').t`Link created` });
92 await onSubmit({ link, transformedLink, accessLevel });
96 const error = e instanceof Error ? e : new Error('Failed to generate link');
104 setAccessLevel(defaultAccessLevel);
112 title={c('Title').t`Create public link`}
113 subline={calendarName}
116 <Button onClick={onClose}>{c('Action').t`Cancel`}</Button>
121 onClick={handleSubmit}
123 >{c('Action').t`Create`}</Button>
131 label={c('Link label (optional)').t`Access`}
134 onValue={(value: any) => setAccessLevel(value)}
136 <Option value={0} title={c('Access level').t`Limited view (see only free/busy)`} />
137 <Option value={1} title={c('Access level').t`Full view (see all event details)`} />
142 maxLength={MAX_CHARS_CLEARTEXT.PURPOSE}
143 label={c('Input label').t`Link label (optional)`}
144 assistiveText={c('Calendar link sharing label input assistive text').t`Only you can see the label`}
145 placeholder={c('Input placeholder').t`Add label`}
151 export default ShareLinkModal;