Merge pull request #607 from ente-io/email-share-menu

Email share menu
This commit is contained in:
Abhinav Kumar 2022-06-21 15:18:13 +05:30 committed by GitHub
commit e838421b72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 196 additions and 170 deletions

View file

@ -1,44 +1,20 @@
import React, { useState } from 'react';
import React from 'react';
import { COLLECTION_SORT_BY } from 'constants/collection';
import Menu from '@mui/material/Menu';
import { IconButton, styled } from '@mui/material';
import SortIcon from '@mui/icons-material/Sort';
import CollectionSortOptions from './options';
import OverflowMenu from 'components/OverflowMenu/menu';
export interface CollectionSortProps {
setCollectionSortBy: (sortBy: COLLECTION_SORT_BY) => void;
activeSortBy: COLLECTION_SORT_BY;
}
const StyledMenu = styled(Menu)`
& .MuiPaper-root {
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.16);
}
`;
export default function CollectionSort(props: CollectionSortProps) {
const [sortByEl, setSortByEl] = useState(null);
const handleClose = () => setSortByEl(null);
return (
<>
<IconButton
onClick={(event) => setSortByEl(event.currentTarget)}
aria-controls={sortByEl ? 'collection-sort' : undefined}
aria-haspopup="true"
aria-expanded={sortByEl ? 'true' : undefined}>
<SortIcon />
</IconButton>
<StyledMenu
id="collection-sort"
anchorEl={sortByEl}
open={Boolean(sortByEl)}
onClose={handleClose}
MenuListProps={{
disablePadding: true,
'aria-labelledby': 'collection-sort',
}}>
<CollectionSortOptions {...props} close={handleClose} />
</StyledMenu>
</>
<OverflowMenu
ariaControls="collection-sort"
triggerButtonIcon={<SortIcon />}>
<CollectionSortOptions {...props} />
</OverflowMenu>
);
}

View file

@ -1,29 +1,26 @@
import React from 'react';
import { MenuItem, ListItemIcon, ListItemText } from '@mui/material';
import React, { useContext } from 'react';
import { COLLECTION_SORT_BY } from 'constants/collection';
import TickIcon from '@mui/icons-material/Done';
import { CollectionSortProps } from '.';
export interface SortOptionProps extends CollectionSortProps {
close: () => void;
}
import { OverflowMenuContext } from 'contexts/overflowMenu';
import { OverflowMenuOption } from 'components/OverflowMenu/option';
const SortByOptionCreator =
({ setCollectionSortBy, activeSortBy, close }: SortOptionProps) =>
({ setCollectionSortBy, activeSortBy }: CollectionSortProps) =>
(props: { sortBy: COLLECTION_SORT_BY; children: any }) => {
const { close } = useContext(OverflowMenuContext);
const handleClick = () => {
setCollectionSortBy(props.sortBy);
close();
};
return (
<MenuItem onClick={handleClick} style={{ paddingLeft: '5px' }}>
<ListItemIcon style={{ minWidth: '25px' }}>
{activeSortBy === props.sortBy && (
<TickIcon sx={{ fontSize: 16 }} />
)}
</ListItemIcon>
<ListItemText>{props.children}</ListItemText>
</MenuItem>
<OverflowMenuOption
onClick={handleClick}
startIcon={activeSortBy === props.sortBy && <TickIcon />}>
{props.children}
</OverflowMenuOption>
);
};

View file

@ -1,14 +1,14 @@
import React from 'react';
import { MenuList } from '@mui/material';
import { COLLECTION_SORT_BY } from 'constants/collection';
import constants from 'utils/strings/constants';
import SortByOptionCreator, { SortOptionProps } from './optionCreator';
import SortByOptionCreator from './optionCreator';
import { CollectionSortProps } from '.';
export default function CollectionSortOptions(props: SortOptionProps) {
export default function CollectionSortOptions(props: CollectionSortProps) {
const SortByOption = SortByOptionCreator(props);
return (
<MenuList>
<>
<SortByOption sortBy={COLLECTION_SORT_BY.NAME}>
{constants.SORT_BY_NAME}
</SortByOption>
@ -21,6 +21,6 @@ export default function CollectionSortOptions(props: SortOptionProps) {
<SortByOption sortBy={COLLECTION_SORT_BY.UPDATION_TIME_DESCENDING}>
{constants.SORT_BY_UPDATION_TIME_DESCENDING}
</SortByOption>
</MenuList>
</>
);
}

View file

@ -1,4 +1,4 @@
import React, { useContext, useState } from 'react';
import React, { useContext } from 'react';
import * as CollectionAPI from 'services/collectionService';
import {
changeCollectionVisibility,
@ -8,15 +8,13 @@ import constants from 'utils/strings/constants';
import { SetCollectionNamerAttributes } from './CollectionNamer';
import { Collection } from 'types/collection';
import { IsArchived } from 'utils/magicMetadata';
import { InvertedIconButton } from 'components/Container';
import OptionIcon from 'components/icons/OptionIcon-2';
import Paper from '@mui/material/Paper';
import MenuList from '@mui/material/MenuList';
import { ListItem, Menu, MenuItem } from '@mui/material';
import { GalleryContext } from 'pages/gallery';
import { logError } from 'utils/sentry';
import { VISIBILITY_STATE } from 'types/magicMetadata';
import { AppContext } from 'pages/_app';
import OverflowMenu from 'components/OverflowMenu/menu';
import { OverflowMenuOption } from 'components/OverflowMenu/option';
import MoreVertIcon from '@mui/icons-material/MoreVert';
interface CollectionOptionsProps {
setCollectionNamerAttributes: SetCollectionNamerAttributes;
@ -44,9 +42,6 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
useContext(AppContext);
const { syncWithRemote } = useContext(GalleryContext);
const [optionEl, setOptionEl] = useState(null);
const handleClose = () => setOptionEl(null);
const handleCollectionAction = (action: CollectionActions) => {
let callback;
switch (action) {
@ -78,7 +73,6 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
startLoading();
try {
await callback(...args);
handleClose();
} catch (e) {
setDialogMessage({
title: constants.ERROR,
@ -155,71 +149,42 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
};
return (
<>
<InvertedIconButton
style={{
transform: 'rotate(90deg)',
}}
onClick={(event) => setOptionEl(event.currentTarget)}
aria-controls={optionEl ? 'collection-options' : undefined}
aria-haspopup="true"
aria-expanded={optionEl ? 'true' : undefined}>
<OptionIcon />
</InvertedIconButton>
<Menu
id="collection-options"
anchorEl={optionEl}
open={Boolean(optionEl)}
onClose={handleClose}
MenuListProps={{
disablePadding: true,
'aria-labelledby': 'collection-options',
}}>
<Paper>
<MenuList>
<MenuItem>
<ListItem onClick={showRenameCollectionModal}>
{constants.RENAME}
</ListItem>
</MenuItem>
<MenuItem>
<ListItem onClick={showCollectionShareModal}>
{constants.SHARE}
</ListItem>
</MenuItem>
<MenuItem>
<ListItem onClick={confirmDownloadCollection}>
{constants.DOWNLOAD}
</ListItem>
</MenuItem>
<MenuItem>
{IsArchived(activeCollection) ? (
<ListItem
onClick={handleCollectionAction(
CollectionActions.UNARCHIVE
)}>
{constants.UNARCHIVE}
</ListItem>
) : (
<ListItem
onClick={handleCollectionAction(
CollectionActions.ARCHIVE
)}>
{constants.ARCHIVE}
</ListItem>
)}
</MenuItem>
<MenuItem>
<ListItem
color="danger"
onClick={confirmDeleteCollection}>
{constants.DELETE}
</ListItem>
</MenuItem>
</MenuList>
</Paper>
</Menu>
</>
<OverflowMenu
ariaControls={`collection-options-${props.activeCollection.id}`}
triggerButtonIcon={<MoreVertIcon />}
triggerButtonProps={{
sx: {
background: (theme) => theme.palette.background.paper,
},
}}>
<OverflowMenuOption onClick={showRenameCollectionModal}>
{constants.RENAME}
</OverflowMenuOption>
<OverflowMenuOption onClick={showCollectionShareModal}>
{constants.SHARE}
</OverflowMenuOption>
<OverflowMenuOption onClick={confirmDownloadCollection}>
{constants.DOWNLOAD}
</OverflowMenuOption>
{IsArchived(activeCollection) ? (
<OverflowMenuOption
onClick={handleCollectionAction(
CollectionActions.UNARCHIVE
)}>
{constants.UNARCHIVE}
</OverflowMenuOption>
) : (
<OverflowMenuOption
onClick={handleCollectionAction(CollectionActions.ARCHIVE)}>
{constants.ARCHIVE}
</OverflowMenuOption>
)}
<OverflowMenuOption
color="danger"
onClick={confirmDeleteCollection}>
{constants.DELETE}
</OverflowMenuOption>
</OverflowMenu>
);
};

View file

@ -1,22 +1,34 @@
import React from 'react';
import { IconButton } from '@mui/material';
import { SpaceBetweenFlex } from 'components/Container';
import { User } from 'types/user';
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
import OverflowMenu from 'components/OverflowMenu/menu';
import NotInterestedIcon from '@mui/icons-material/NotInterested';
import constants from 'utils/strings/constants';
import { OverflowMenuOption } from 'components/OverflowMenu/option';
interface IProps {
sharee: User;
collectionUnshare: (sharee: User) => void;
}
const ShareeRow = ({ sharee, collectionUnshare }: IProps) => (
<SpaceBetweenFlex>
{sharee.email}
<IconButton
sx={{ ml: 2, color: 'text.secondary' }}
onClick={() => collectionUnshare(sharee)}>
<MoreHorizIcon />
</IconButton>
</SpaceBetweenFlex>
);
const ShareeRow = ({ sharee, collectionUnshare }: IProps) => {
const handleClick = () => collectionUnshare(sharee);
return (
<SpaceBetweenFlex>
{sharee.email}
<OverflowMenu
ariaControls={`email-share-${sharee.email}`}
triggerButtonIcon={<MoreHorizIcon />}>
<OverflowMenuOption
color="danger"
onClick={handleClick}
startIcon={<NotInterestedIcon />}>
{constants.REMOVE}
</OverflowMenuOption>
</OverflowMenu>
</SpaceBetweenFlex>
);
};
export default ShareeRow;

View file

@ -0,0 +1,63 @@
import React, { useState } from 'react';
import Menu from '@mui/material/Menu';
import { IconButton, styled } from '@mui/material';
import { OverflowMenuContext } from 'contexts/overflowMenu';
export interface Iprops {
triggerButtonIcon: React.ReactNode;
triggerButtonProps?: any;
children?: React.ReactNode;
ariaControls: string;
}
const StyledMenu = styled(Menu)`
& .MuiPaper-root {
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.16),
0px 3px 6px rgba(0, 0, 0, 0.12);
}
& .MuiList-root {
padding: 0;
border: none;
}
`;
export default function OverflowMenu({
children,
ariaControls,
triggerButtonIcon,
triggerButtonProps,
}: Iprops) {
const [sortByEl, setSortByEl] = useState(null);
const handleClose = () => setSortByEl(null);
return (
<OverflowMenuContext.Provider value={{ close: handleClose }}>
<IconButton
onClick={(event) => setSortByEl(event.currentTarget)}
aria-controls={sortByEl ? ariaControls : undefined}
aria-haspopup="true"
aria-expanded={sortByEl ? 'true' : undefined}
{...triggerButtonProps}>
{triggerButtonIcon}
</IconButton>
<StyledMenu
id={ariaControls}
anchorEl={sortByEl}
open={Boolean(sortByEl)}
onClose={handleClose}
MenuListProps={{
disablePadding: true,
'aria-labelledby': ariaControls,
}}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'center',
horizontal: 'right',
}}>
{children}
</StyledMenu>
</OverflowMenuContext.Provider>
);
}

View file

@ -0,0 +1,37 @@
import { MenuItem, ListItemIcon, ButtonProps, Typography } from '@mui/material';
import React from 'react';
interface Iprops {
onClick: () => void;
color?: ButtonProps['color'];
startIcon?: React.ReactNode;
children?: any;
}
export function OverflowMenuOption({
onClick,
color = 'primary',
startIcon,
children,
}: Iprops) {
return (
<MenuItem
onClick={onClick}
sx={{
color: (theme) => theme.palette[color].main,
padding: '12px',
}}>
{startIcon && (
<ListItemIcon
sx={{
color: 'inherit',
padding: '0',
paddingRight: '12px',
fontSize: '20px',
}}>
{startIcon}
</ListItemIcon>
)}
<Typography variant="button">{children}</Typography>
</MenuItem>
);
}

View file

@ -1,21 +0,0 @@
import React from 'react';
export default function OptionIcon(props) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
height={props.height}
viewBox={props.viewBox}
width={props.width}
fill="currentColor">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />{' '}
</svg>
);
}
OptionIcon.defaultProps = {
height: 20,
width: 20,
viewBox: '0 0 24 24',
};

View file

@ -0,0 +1,5 @@
import { createContext } from 'react';
export const OverflowMenuContext = createContext({
close: () => null,
});

View file

@ -77,15 +77,6 @@ const darkThemeOptions = createTheme({
},
},
},
MuiMenu: {
styleOverrides: {
paper: { margin: '10px' },
list: {
padding: 0,
border: 'none',
},
},
},
MuiButton: {
defaultProps: {
@ -155,16 +146,17 @@ const darkThemeOptions = createTheme({
typography: {
body1: {
fontSize: '16px',
lineHeight: '24px',
lineHeight: '20px',
},
body2: {
fontSize: '14px',
lineHeight: '20px',
lineHeight: '17px',
},
button: {
fontSize: '16px',
lineHeight: '19.36px',
lineHeight: '20px',
fontWeight: 'bold',
textTransform: 'none',
},
title: {
fontSize: '32px',