From f02dcae52aac95b1ccacdb576dc47d6a15d3ca2d Mon Sep 17 00:00:00 2001 From: Nathan Panchout Date: Thu, 9 Jan 2025 09:14:55 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20enhance=20DocShareModal?= =?UTF-8?q?=20and=20footer=20components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Refactored DocShareModal to improve user experience with dynamic list height and responsive design adjustments. - Introduced new styling for modal elements using createGlobalStyle for better visual consistency. - Updated footer button text from 'Ok' to 'OK' for improved clarity. - Enhanced user selection handling and search functionality within the modal for better document sharing experience. --- .../doc-share/component/DocShareModal.tsx | 220 ++++++++++-------- .../component/DocShareModalFooter.tsx | 2 +- 2 files changed, 128 insertions(+), 94 deletions(-) diff --git a/src/frontend/apps/impress/src/features/docs/doc-share/component/DocShareModal.tsx b/src/frontend/apps/impress/src/features/docs/doc-share/component/DocShareModal.tsx index 412b78d3..3438f0db 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-share/component/DocShareModal.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-share/component/DocShareModal.tsx @@ -1,7 +1,7 @@ import { Modal, ModalSize } from '@openfun/cunningham-react'; -import { useMemo, useState } from 'react'; +import { useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { css } from 'styled-components'; +import { createGlobalStyle, css } from 'styled-components'; import { useDebouncedCallback } from 'use-debounce'; import { Box } from '@/components'; @@ -29,20 +29,33 @@ import { DocShareMemberItem } from './DocShareMemberItem'; import { DocShareModalFooter } from './DocShareModalFooter'; import { DocShareModalInviteUserRow } from './DocShareModalInviteUserByEmail'; +const ShareModalStyle = createGlobalStyle` + + .c__modal__title { + padding-bottom: 0 !important; + +} + +`; + type Props = { doc: Doc; onClose: () => void; }; export const DocShareModal = ({ doc, onClose }: Props) => { const { t } = useTranslation(); + const selectedUsersRef = useRef(null); const { isDesktop } = useResponsiveStore(); const [selectedUsers, setSelectedUsers] = useState([]); const [userQuery, setUserQuery] = useState(''); const [inputValue, setInputValue] = useState(''); + + const [listHeight, setListHeight] = useState('400px'); const canShare = doc.abilities.accesses_manage; const showMemberSection = inputValue === '' && selectedUsers.length === 0; + const showFooter = selectedUsers.length === 0 && !inputValue; const onSelect = (user: User) => { setSelectedUsers((prev) => [...prev, user]); @@ -73,9 +86,12 @@ export const DocShareModal = ({ doc, onClose }: Props) => { const count = membersQuery.data?.pages[0]?.count ?? 1; return { - groupName: t('Share with {{count}} users', { - count: count, - }), + groupName: + count === 1 + ? t('Document owner') + : t('Share with {{count}} users', { + count: count, + }), elements: members, endActions: membersQuery.hasNextPage ? [ @@ -147,102 +163,120 @@ export const DocShareModal = ({ doc, onClose }: Props) => { }); }; - return ( - {t('Share the document')}} - > - - - {canShare && selectedUsers.length > 0 && ( - - { - setUserQuery(''); - setInputValue(''); - setSelectedUsers([]); - }} - /> - - )} + const handleRef = (node: HTMLDivElement) => { + const contentHeight = isDesktop ? '690px' : '100dvh - 34px'; // 690px is the height of the content in desktop ad 34px is the height of the modal title in mobile + const inputHeight = canShare ? 70 : 0; + const marginTop = 11; + const footerHeight = node?.clientHeight ?? 0; + const selectedUsersHeight = selectedUsersRef.current?.clientHeight ?? 0; - - { - setInputValue(str); - onFilter(str); - }} - inputValue={inputValue} - showInput={canShare} - loading={searchUsersQuery.isLoading} - placeholder={t('Type a name or email')} - > - {!showMemberSection && inputValue !== '' && ( - ( - - )} - /> + const height = `calc(${contentHeight} - ${footerHeight}px - ${selectedUsersHeight}px - ${inputHeight}px - ${marginTop}px)`; + + setListHeight(height); + }; + + return ( + <> + {t('Share the document')}} + > + + + +
+ {canShare && selectedUsers.length > 0 && ( + + { + setUserQuery(''); + setInputValue(''); + setSelectedUsers([]); + }} + /> + )} - {showMemberSection && ( - <> - {invitationsData.elements.length > 0 && ( - +
+ + + { + setInputValue(str); + onFilter(str); + }} + inputValue={inputValue} + showInput={canShare} + loading={searchUsersQuery.isLoading} + placeholder={t('Type a name or email')} + > + {!showMemberSection && inputValue !== '' && ( + ( + + )} + /> + )} + {showMemberSection && ( + <> + {invitationsData.elements.length > 0 && ( + + ( + + )} + /> + + )} + + ( - + group={membersData} + renderElement={(access) => ( + )} /> - )} + + )} + + +
- - ( - - )} - /> - - - )} - + + {showFooter && }
- {selectedUsers.length === 0 && !inputValue && ( - - )} -
-
+ + ); }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-share/component/DocShareModalFooter.tsx b/src/frontend/apps/impress/src/features/docs/doc-share/component/DocShareModalFooter.tsx index d4ea5dfc..c48f048f 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-share/component/DocShareModalFooter.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-share/component/DocShareModalFooter.tsx @@ -61,7 +61,7 @@ export const DocShareModalFooter = ({ doc, onClose }: Props) => { {t('Copy link')}