update notification ui
This commit is contained in:
parent
abb2270745
commit
b9b4a9b617
94
src/components/Notification.tsx
Normal file
94
src/components/Notification.tsx
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
IconButton,
|
||||||
|
Paper,
|
||||||
|
Snackbar,
|
||||||
|
SnackbarProps,
|
||||||
|
Stack,
|
||||||
|
Typography,
|
||||||
|
} from '@mui/material';
|
||||||
|
import React from 'react';
|
||||||
|
import { NotificationAttributes } from 'types/gallery';
|
||||||
|
|
||||||
|
import DiscFullIcon from '@mui/icons-material/DiscFull';
|
||||||
|
|
||||||
|
interface Iprops {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
attributes: NotificationAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Notification({ open, onClose, attributes }: Iprops) {
|
||||||
|
if (!attributes) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose: SnackbarProps['onClose'] = (_, reason) => {
|
||||||
|
if (!reason) {
|
||||||
|
onClose;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
attributes.action?.callback();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Snackbar
|
||||||
|
onClose={handleClose}
|
||||||
|
open={open}
|
||||||
|
anchorOrigin={{
|
||||||
|
horizontal: 'right',
|
||||||
|
vertical: 'bottom',
|
||||||
|
}}>
|
||||||
|
<Paper
|
||||||
|
component={Button}
|
||||||
|
color={attributes.variant}
|
||||||
|
onClick={handleClick}
|
||||||
|
css={`
|
||||||
|
width: 320px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
`}
|
||||||
|
sx={{ textAlign: 'left' }}>
|
||||||
|
<Stack
|
||||||
|
flex={'1'}
|
||||||
|
spacing={2}
|
||||||
|
direction="row"
|
||||||
|
alignItems={'center'}>
|
||||||
|
<Box>
|
||||||
|
<DiscFullIcon fontSize="large" />
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ flex: 1 }}>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="rgba(255, 255, 255, 0.7)"
|
||||||
|
mb={0.5}>
|
||||||
|
{attributes.message}{' '}
|
||||||
|
</Typography>
|
||||||
|
{attributes?.action && (
|
||||||
|
<Typography
|
||||||
|
mb={0.5}
|
||||||
|
css={`
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 19px;
|
||||||
|
`}>
|
||||||
|
{attributes?.action.text}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<IconButton
|
||||||
|
onClick={onClose}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||||
|
}}>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Snackbar>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,59 +0,0 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import { Toast } from 'react-bootstrap';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { NotificationAttributes } from 'types/gallery';
|
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
|
||||||
position: absolute;
|
|
||||||
top: 60px;
|
|
||||||
right: 10px;
|
|
||||||
z-index: 1501;
|
|
||||||
min-height: 100px;
|
|
||||||
`;
|
|
||||||
const AUTO_HIDE_TIME_IN_MILLISECONDS = 3000;
|
|
||||||
|
|
||||||
interface Iprops {
|
|
||||||
attributes: NotificationAttributes;
|
|
||||||
clearAttributes: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ToastNotification({
|
|
||||||
attributes,
|
|
||||||
clearAttributes,
|
|
||||||
}: Iprops) {
|
|
||||||
const [show, setShow] = useState(false);
|
|
||||||
const closeToast = () => {
|
|
||||||
setShow(false);
|
|
||||||
clearAttributes();
|
|
||||||
};
|
|
||||||
useEffect(() => {
|
|
||||||
if (!attributes) {
|
|
||||||
setShow(false);
|
|
||||||
} else {
|
|
||||||
setShow(true);
|
|
||||||
}
|
|
||||||
}, [attributes]);
|
|
||||||
return (
|
|
||||||
<Wrapper>
|
|
||||||
<Toast
|
|
||||||
onClose={closeToast}
|
|
||||||
show={show}
|
|
||||||
delay={AUTO_HIDE_TIME_IN_MILLISECONDS}
|
|
||||||
autohide>
|
|
||||||
{attributes?.title && (
|
|
||||||
<Toast.Header
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
}}>
|
|
||||||
<h6 style={{ marginBottom: 0 }}>{attributes.title} </h6>
|
|
||||||
</Toast.Header>
|
|
||||||
)}
|
|
||||||
{attributes?.message && (
|
|
||||||
<Toast.Body>{attributes.message}</Toast.Body>
|
|
||||||
)}
|
|
||||||
</Toast>
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -102,7 +102,7 @@ import {
|
||||||
NotificationAttributes,
|
NotificationAttributes,
|
||||||
} from 'types/gallery';
|
} from 'types/gallery';
|
||||||
import { VISIBILITY_STATE } from 'types/magicMetadata';
|
import { VISIBILITY_STATE } from 'types/magicMetadata';
|
||||||
import ToastNotification from 'components/ToastNotification';
|
import Notification from 'components/Notification';
|
||||||
import { ElectronFile } from 'types/upload';
|
import { ElectronFile } from 'types/upload';
|
||||||
import importService from 'services/importService';
|
import importService from 'services/importService';
|
||||||
import Collections from 'components/Collections';
|
import Collections from 'components/Collections';
|
||||||
|
@ -147,9 +147,7 @@ export default function Gallery() {
|
||||||
|
|
||||||
const [files, setFiles] = useState<EnteFile[]>(null);
|
const [files, setFiles] = useState<EnteFile[]>(null);
|
||||||
const [favItemIds, setFavItemIds] = useState<Set<number>>();
|
const [favItemIds, setFavItemIds] = useState<Set<number>>();
|
||||||
const [bannerMessage, setBannerMessage] = useState<JSX.Element | string>(
|
const [bannerMessage, setBannerMessage] = useState<JSX.Element | string>();
|
||||||
null
|
|
||||||
);
|
|
||||||
const [isFirstLoad, setIsFirstLoad] = useState(false);
|
const [isFirstLoad, setIsFirstLoad] = useState(false);
|
||||||
const [isFirstFetch, setIsFirstFetch] = useState(false);
|
const [isFirstFetch, setIsFirstFetch] = useState(false);
|
||||||
const [selected, setSelected] = useState<SelectedState>({
|
const [selected, setSelected] = useState<SelectedState>({
|
||||||
|
@ -194,6 +192,10 @@ export default function Gallery() {
|
||||||
const [fixCreationTimeAttributes, setFixCreationTimeAttributes] =
|
const [fixCreationTimeAttributes, setFixCreationTimeAttributes] =
|
||||||
useState<FixCreationTimeAttributes>(null);
|
useState<FixCreationTimeAttributes>(null);
|
||||||
|
|
||||||
|
const [notificationView, setNotificationView] = useState(false);
|
||||||
|
|
||||||
|
const closeNotification = () => setNotificationView(false);
|
||||||
|
|
||||||
const [notificationAttributes, setNotificationAttributes] =
|
const [notificationAttributes, setNotificationAttributes] =
|
||||||
useState<NotificationAttributes>(null);
|
useState<NotificationAttributes>(null);
|
||||||
|
|
||||||
|
@ -202,8 +204,6 @@ export default function Gallery() {
|
||||||
|
|
||||||
const showPlanSelectorModal = () => setPlanModalView(true);
|
const showPlanSelectorModal = () => setPlanModalView(true);
|
||||||
|
|
||||||
const clearNotificationAttributes = () => setNotificationAttributes(null);
|
|
||||||
|
|
||||||
const [electronFiles, setElectronFiles] = useState<ElectronFile[]>(null);
|
const [electronFiles, setElectronFiles] = useState<ElectronFile[]>(null);
|
||||||
const [uploadTypeSelectorView, setUploadTypeSelectorView] = useState(false);
|
const [uploadTypeSelectorView, setUploadTypeSelectorView] = useState(false);
|
||||||
|
|
||||||
|
@ -259,6 +259,11 @@ export default function Gallery() {
|
||||||
[fixCreationTimeAttributes]
|
[fixCreationTimeAttributes]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() => notificationAttributes && setNotificationView(true),
|
||||||
|
[notificationAttributes]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => setDroppedFiles(acceptedFiles), [acceptedFiles]);
|
useEffect(() => setDroppedFiles(acceptedFiles), [acceptedFiles]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -602,9 +607,10 @@ export default function Gallery() {
|
||||||
setLoading={setBlockingLoad}
|
setLoading={setBlockingLoad}
|
||||||
/>
|
/>
|
||||||
<AlertBanner bannerMessage={bannerMessage} />
|
<AlertBanner bannerMessage={bannerMessage} />
|
||||||
<ToastNotification
|
<Notification
|
||||||
|
open={notificationView}
|
||||||
|
onClose={closeNotification}
|
||||||
attributes={notificationAttributes}
|
attributes={notificationAttributes}
|
||||||
clearAttributes={clearNotificationAttributes}
|
|
||||||
/>
|
/>
|
||||||
<CollectionNamer
|
<CollectionNamer
|
||||||
show={collectionNamerView}
|
show={collectionNamerView}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ButtonProps } from '@mui/material';
|
||||||
import { Collection } from 'types/collection';
|
import { Collection } from 'types/collection';
|
||||||
import { EnteFile } from 'types/file';
|
import { EnteFile } from 'types/file';
|
||||||
import { Search, SearchResultSummary } from 'types/search';
|
import { Search, SearchResultSummary } from 'types/search';
|
||||||
|
@ -28,6 +29,10 @@ export type GalleryContextType = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface NotificationAttributes {
|
export interface NotificationAttributes {
|
||||||
message: string;
|
variant: ButtonProps['color'];
|
||||||
title: string;
|
message: JSX.Element | string;
|
||||||
|
action?: {
|
||||||
|
text: string;
|
||||||
|
callback: () => void;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue