From fde43182ac0e6bb1a0bfb21830e03b086b2a20e9 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 28 Apr 2022 17:40:30 +0530 Subject: [PATCH] add subscription details to sidebar --- .../Sidebar/SubscriptionDetails.tsx | 95 ++++ src/components/Sidebar/index.tsx | 467 +++++++----------- src/utils/storage/localStorage.ts | 1 + src/utils/strings/englishConstants.tsx | 1 + src/utils/time/index.ts | 9 + src/utils/user/index.ts | 5 + 6 files changed, 297 insertions(+), 281 deletions(-) create mode 100644 src/components/Sidebar/SubscriptionDetails.tsx diff --git a/src/components/Sidebar/SubscriptionDetails.tsx b/src/components/Sidebar/SubscriptionDetails.tsx new file mode 100644 index 000000000..94ed940ca --- /dev/null +++ b/src/components/Sidebar/SubscriptionDetails.tsx @@ -0,0 +1,95 @@ +import React from 'react'; +import { + Box, + CircularProgress, + LinearProgress, + Typography, +} from '@mui/material'; +import { FlexWrapper, SpaceBetweenFlex } from 'components/Container'; +import { UserDetails } from 'types/user'; +import constants from 'utils/strings/constants'; +import { formatDateShort } from 'utils/time'; +import { convertBytesToHumanReadable } from 'utils/billing'; + +interface Iprops { + userDetails: UserDetails; +} +export default function SubscriptionDetails({ userDetails }: Iprops) { + return ( + + {userDetails ? ( + <> + + + + Current Plan + + + {`${constants.ENDS} ${formatDateShort( + userDetails.subscription.expiryTime / 1000 + )}`} + + + + {convertBytesToHumanReadable( + userDetails.subscription.storage, + 0 + )} + + + + + + + + {`${convertBytesToHumanReadable( + userDetails.usage, + 1 + )} of ${convertBytesToHumanReadable( + userDetails.subscription.storage, + 0 + )}`} + + + {`${userDetails.fileCount} Photos`} + + + + + ) : ( + + + + )} + + ); +} diff --git a/src/components/Sidebar/index.tsx b/src/components/Sidebar/index.tsx index 3227c0fd2..005df4c2a 100644 --- a/src/components/Sidebar/index.tsx +++ b/src/components/Sidebar/index.tsx @@ -1,16 +1,9 @@ import React, { useContext, useEffect, useState } from 'react'; import constants from 'utils/strings/constants'; -import { getData, LS_KEYS, setData } from 'utils/storage/localStorage'; +import { LS_KEYS, setData } from 'utils/storage/localStorage'; import { getToken } from 'utils/common/key'; import { getEndpoint } from 'utils/common/apiUtil'; -import { - isSubscriptionActive, - getUserSubscription, - isOnFreePlan, - isSubscriptionCancelled, - isSubscribed, - convertBytesToHumanReadable, -} from 'utils/billing'; +import { convertBytesToHumanReadable } from 'utils/billing'; import isElectron from 'is-electron'; import { Collection } from 'types/collection'; @@ -19,24 +12,25 @@ import LinkButton from '../pages/gallery/LinkButton'; import { downloadApp } from 'utils/common'; import { getUserDetails, logoutUser } from 'services/userService'; import { SetDialogMessage } from '../MessageDialog'; -import EnteSpinner from '../EnteSpinner'; import RecoveryKeyModal from '../RecoveryKeyModal'; import TwoFactorModal from '../TwoFactorModal'; import ExportModal from '../ExportModal'; import { GalleryContext } from 'pages/gallery'; import InProgressIcon from '../icons/InProgressIcon'; import exportService from 'services/exportService'; -import { Subscription } from 'types/billing'; import { PAGES } from 'constants/pages'; import { ARCHIVE_SECTION, TRASH_SECTION } from 'constants/collection'; import FixLargeThumbnails from '../FixLargeThumbnail'; import { SetLoading } from 'types/gallery'; import { downloadAsFile } from 'utils/file'; import { getUploadLogs, logUploadInfo } from 'utils/upload'; -import { Box, Divider, Drawer, Typography } from '@mui/material'; +import { Divider, Drawer, Typography } from '@mui/material'; import { default as MuiStyled } from '@mui/styled-engine'; -import { Button } from 'react-bootstrap'; import ThemeToggler from './ThemeToggler'; +import SubscriptionDetails from './SubscriptionDetails'; +import { SpaceBetweenFlex } from 'components/Container'; +import { UserDetails } from 'types/user'; +import { getLocalUserDetails } from 'utils/user'; interface Props { collections: Collection[]; setDialogMessage: SetDialogMessage; @@ -50,7 +44,7 @@ export enum THEMES { const DrawerSidebar = MuiStyled(Drawer)(() => ({ '& .MuiPaper-root': { - width: '300px', + width: '320px', padding: '20px', }, })); @@ -61,12 +55,9 @@ const WidderDivider = MuiStyled(Divider)(() => ({ })); export default function Sidebar(props: Props) { - const [usage, SetUsage] = useState(null); - const [user, setUser] = useState(null); - const [subscription, setSubscription] = useState(null); + const [userDetails, setUserDetails] = useState(null); useEffect(() => { - setUser(getData(LS_KEYS.USER)); - setSubscription(getUserSubscription()); + setUserDetails(getLocalUserDetails()); }, []); const [isOpen, setIsOpen] = useState(false); const [recoverModalView, setRecoveryModalView] = useState(false); @@ -78,18 +69,9 @@ export default function Sidebar(props: Props) { useEffect(() => { const main = async () => { - if (!isOpen) { - return; - } const userDetails = await getUserDetails(); - setUser({ ...user, email: userDetails.email }); - SetUsage(convertBytesToHumanReadable(userDetails.usage)); - setSubscription(userDetails.subscription); - setData(LS_KEYS.USER, { - ...getData(LS_KEYS.USER), - email: userDetails.email, - }); - setData(LS_KEYS.SUBSCRIPTION, userDetails.subscription); + setUserDetails(userDetails); + setData(LS_KEYS.USER_DETAILS, userDetails); }; main(); }, [isOpen]); @@ -138,10 +120,6 @@ export default function Sidebar(props: Props) { }; const router = useRouter(); - function onManageClick() { - setIsOpen(false); - galleryContext.showPlanSelectorModal(); - } return ( - - {user?.email} - + + {userDetails?.email} - -
+ + + + + + { + galleryContext.setActiveCollection(ARCHIVE_SECTION); + setIsOpen(false); + }}> + {constants.ARCHIVE} + + { + galleryContext.setActiveCollection(TRASH_SECTION); + setIsOpen(false); + }}> + {constants.TRASH} + + <> + setRecoveryModalView(false)} + somethingWentWrong={() => + props.setDialogMessage({ + title: constants.ERROR, + content: + constants.RECOVER_KEY_GENERATION_FAILED, + close: { variant: 'danger' }, + }) + } + /> + setRecoveryModalView(true)}> + {constants.DOWNLOAD_RECOVERY_KEY} + + + <> + setTwoFactorModalView(false)} + setDialogMessage={props.setDialogMessage} + closeSidebar={() => setIsOpen(false)} + setLoading={props.setLoading} + /> + setTwoFactorModalView(true)}> + {constants.TWO_FACTOR} + + + { + router.push(PAGES.CHANGE_PASSWORD); + }}> + {constants.CHANGE_PASSWORD} + + { + router.push(PAGES.CHANGE_EMAIL); + }}> + {constants.UPDATE_EMAIL} + + { + router.push(PAGES.DEDUPLICATE); + }}> + {constants.DEDUPLICATE_FILES} + + + <> + setFixLargeThumbsView(false)} + show={() => setFixLargeThumbsView(true)} + /> + setFixLargeThumbsView(true)}> + {constants.FIX_LARGE_THUMBNAILS} + + + + {constants.REQUEST_FEATURE} + + initiateEmail('contact@ente.io')}> + {constants.SUPPORT} + + <> + setExportModalView(false)} + usage={convertBytesToHumanReadable( + userDetails?.usage ?? 0 + )} + /> + +
+ {constants.EXPORT} +
+ {exportService.isExportInProgress() && ( + + )} +
+ + + + + props.setDialogMessage({ + title: `${constants.CONFIRM} ${constants.LOGOUT}`, + content: constants.LOGOUT_MESSAGE, + staticBackdrop: true, + proceed: { + text: constants.LOGOUT, + action: logoutUser, + variant: 'danger', + }, + close: { text: constants.CANCEL }, + }) + }> + {constants.LOGOUT} + + + props.setDialogMessage({ + title: `${constants.DELETE_ACCOUNT}`, + content: constants.DELETE_ACCOUNT_MESSAGE(), + staticBackdrop: true, + proceed: { + text: constants.DELETE_ACCOUNT, + action: () => { + initiateEmail('account-deletion@ente.io'); + }, + variant: 'danger', + }, + close: { text: constants.CANCEL }, + }) + }> + {constants.DELETE_ACCOUNT} + +
-
-
-
- {constants.SUBSCRIPTION_PLAN} -
-
-
- {isSubscriptionActive(subscription) ? ( - isOnFreePlan(subscription) ? ( - constants.FREE_SUBSCRIPTION_INFO( - subscription?.expiryTime - ) - ) : isSubscriptionCancelled(subscription) ? ( - constants.RENEWAL_CANCELLED_SUBSCRIPTION_INFO( - subscription?.expiryTime - ) - ) : ( - constants.RENEWAL_ACTIVE_SUBSCRIPTION_INFO( - subscription?.expiryTime - ) - ) - ) : ( -

{constants.SUBSCRIPTION_EXPIRED}

- )} - -
-
-
-
-
- {constants.USAGE_DETAILS} -
-
- {usage ? ( - constants.USAGE_INFO( - usage, - convertBytesToHumanReadable( - subscription?.storage - ) - ) - ) : ( -
- -
- )} -
-
- - { - galleryContext.setActiveCollection(ARCHIVE_SECTION); - setIsOpen(false); - }}> - {constants.ARCHIVE} - - { - galleryContext.setActiveCollection(TRASH_SECTION); - setIsOpen(false); - }}> - {constants.TRASH} - - <> - setRecoveryModalView(false)} - somethingWentWrong={() => - props.setDialogMessage({ - title: constants.ERROR, - content: - constants.RECOVER_KEY_GENERATION_FAILED, - close: { variant: 'danger' }, - }) - } - /> - setRecoveryModalView(true)}> - {constants.DOWNLOAD_RECOVERY_KEY} - - - <> - setTwoFactorModalView(false)} - setDialogMessage={props.setDialogMessage} - closeSidebar={() => setIsOpen(false)} - setLoading={props.setLoading} - /> - setTwoFactorModalView(true)}> - {constants.TWO_FACTOR} - - - { - router.push(PAGES.CHANGE_PASSWORD); - }}> - {constants.CHANGE_PASSWORD} - - { - router.push(PAGES.CHANGE_EMAIL); - }}> - {constants.UPDATE_EMAIL} - - { - router.push(PAGES.DEDUPLICATE); - }}> - {constants.DEDUPLICATE_FILES} - - - <> - setFixLargeThumbsView(false)} - show={() => setFixLargeThumbsView(true)} - /> - setFixLargeThumbsView(true)}> - {constants.FIX_LARGE_THUMBNAILS} - - - - {constants.REQUEST_FEATURE} - - initiateEmail('contact@ente.io')}> - {constants.SUPPORT} - - <> - setExportModalView(false)} - usage={usage} - /> - -
- {constants.EXPORT} -
- {exportService.isExportInProgress() && ( - - )} -
- - - - - props.setDialogMessage({ - title: `${constants.CONFIRM} ${constants.LOGOUT}`, - content: constants.LOGOUT_MESSAGE, - staticBackdrop: true, - proceed: { - text: constants.LOGOUT, - action: logoutUser, - variant: 'danger', - }, - close: { text: constants.CANCEL }, - }) - }> - {constants.LOGOUT} - - - props.setDialogMessage({ - title: `${constants.DELETE_ACCOUNT}`, - content: constants.DELETE_ACCOUNT_MESSAGE(), - staticBackdrop: true, - proceed: { - text: constants.DELETE_ACCOUNT, - action: () => { - initiateEmail( - 'account-deletion@ente.io' - ); - }, - variant: 'danger', - }, - close: { text: constants.CANCEL }, - }) - }> - {constants.DELETE_ACCOUNT} - - -
-
- {constants.DOWNLOAD_UPLOAD_LOGS} -
+ marginTop: '40px', + width: '100%', + }} + /> +
+ {constants.DOWNLOAD_UPLOAD_LOGS}
diff --git a/src/utils/storage/localStorage.ts b/src/utils/storage/localStorage.ts index 63b84ba89..fb73a7ddc 100644 --- a/src/utils/storage/localStorage.ts +++ b/src/utils/storage/localStorage.ts @@ -16,6 +16,7 @@ export enum LS_KEYS { LIVE_PHOTO_INFO_SHOWN_COUNT = 'livePhotoInfoShownCount', FAILED_UPLOADS = 'failedUploads', LOGS = 'logs', + USER_DETAILS = 'userDetails', } export const setData = (key: LS_KEYS, value: object) => { diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 594081358..38123a1f1 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -718,6 +718,7 @@ const englishConstants = { ALL_ALBUMS: 'All Albums', PHOTOS: 'Photos', ENTE: 'ente', + ENDS: 'Ends', }; export default englishConstants; diff --git a/src/utils/time/index.ts b/src/utils/time/index.ts index ba85aa78d..956537ae4 100644 --- a/src/utils/time/index.ts +++ b/src/utils/time/index.ts @@ -15,6 +15,15 @@ export function dateStringWithMMH(unixTimeInMicroSeconds: number): string { }); } +export function formatDateShort(date: number | Date) { + const dateTimeFormat = new Intl.DateTimeFormat('en-IN', { + year: '2-digit', + month: 'short', + day: 'numeric', + }); + return dateTimeFormat.format(date); +} + export function getUnixTimeInMicroSecondsWithDelta(delta: TimeDelta): number { let currentDate = new Date(); if (delta?.hours) { diff --git a/src/utils/user/index.ts b/src/utils/user/index.ts index bda659fce..273160504 100644 --- a/src/utils/user/index.ts +++ b/src/utils/user/index.ts @@ -1,3 +1,4 @@ +import { UserDetails } from 'types/user'; import { getData, LS_KEYS, setData } from 'utils/storage/localStorage'; export function makeID(length) { @@ -21,3 +22,7 @@ export function getUserAnonymizedID() { } return anonymizeUserID; } + +export function getLocalUserDetails(): UserDetails { + return getData(LS_KEYS.USER_DETAILS); +}