diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx index 6d0847287a..6394a8b577 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx @@ -164,7 +164,7 @@ const CSFFileBrowser: React.FC = () => { addToast({ type:"error", title: t`Uploads disabled`, - subtitle: t`Oops! You need to pay for this month to upload more content.` + subtitle: t`Your account is restricted. Until you've settled up, you can't upload any new content.` }) return } diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFileBrowser.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFileBrowser.tsx index 6ad90d9000..6a8f00515a 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFileBrowser.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFileBrowser.tsx @@ -205,7 +205,7 @@ const SharedFileBrowser = () => { addToast({ type:"error", title: t`Uploads disabled`, - subtitle: t`Oops! You need to pay for this month to upload more content.` + subtitle: t`Your account is restricted. Until you've settled up, you can't upload any new content.` }) return } diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesList.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesList.tsx index 657bdf5f28..c62c400a65 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesList.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesList.tsx @@ -895,6 +895,7 @@ const FilesList = ({ isShared = false }: Props) => { onClick={() => setCreateFolderModalOpen(true)} variant="outline" size="large" + disabled={accountRestricted} > @@ -906,6 +907,7 @@ const FilesList = ({ isShared = false }: Props) => { onClick={() => setIsUploadModalOpen(true)} variant="outline" size="large" + disabled={accountRestricted} > diff --git a/packages/files-ui/src/locales/de/messages.po b/packages/files-ui/src/locales/de/messages.po index 39df0ebec4..754dc78899 100644 --- a/packages/files-ui/src/locales/de/messages.po +++ b/packages/files-ui/src/locales/de/messages.po @@ -619,9 +619,6 @@ msgstr "" msgid "Only send the exact amount of {0} to this address" msgstr "" -msgid "Oops! You need to pay for this month to upload more content." -msgstr "" - msgid "Operating system:" msgstr "Betriebssystem:" @@ -1141,6 +1138,9 @@ msgstr "" msgid "You've got a payment due. Until you've settled up, we've placed your account in restricted mode" msgstr "" +msgid "Your account is restricted. Until you've settled up, you can't upload any new content." +msgstr "" + msgid "Your content exceeds the {planStorageCapacity} storage capacity for this plan." msgstr "" diff --git a/packages/files-ui/src/locales/en/messages.po b/packages/files-ui/src/locales/en/messages.po index 10c39e1325..a864ddcb27 100644 --- a/packages/files-ui/src/locales/en/messages.po +++ b/packages/files-ui/src/locales/en/messages.po @@ -622,9 +622,6 @@ msgstr "One sec, getting files ready…" msgid "Only send the exact amount of {0} to this address" msgstr "Only send the exact amount of {0} to this address" -msgid "Oops! You need to pay for this month to upload more content." -msgstr "Oops! You need to pay for this month to upload more content." - msgid "Operating system:" msgstr "Operating system:" @@ -1144,6 +1141,9 @@ msgstr "You will need to sign a message in your wallet to complete sign in." msgid "You've got a payment due. Until you've settled up, we've placed your account in restricted mode" msgstr "You've got a payment due. Until you've settled up, we've placed your account in restricted mode" +msgid "Your account is restricted. Until you've settled up, you can't upload any new content." +msgstr "Your account is restricted. Until you've settled up, you can't upload any new content." + msgid "Your content exceeds the {planStorageCapacity} storage capacity for this plan." msgstr "Your content exceeds the {planStorageCapacity} storage capacity for this plan." diff --git a/packages/files-ui/src/locales/es/messages.po b/packages/files-ui/src/locales/es/messages.po index 50b9c306ca..cf4764df37 100644 --- a/packages/files-ui/src/locales/es/messages.po +++ b/packages/files-ui/src/locales/es/messages.po @@ -623,9 +623,6 @@ msgstr "" msgid "Only send the exact amount of {0} to this address" msgstr "" -msgid "Oops! You need to pay for this month to upload more content." -msgstr "" - msgid "Operating system:" msgstr "Sistema operativo:" @@ -1145,6 +1142,9 @@ msgstr "Deberá firmar un mensaje en su billetera para completar el inicio de se msgid "You've got a payment due. Until you've settled up, we've placed your account in restricted mode" msgstr "" +msgid "Your account is restricted. Until you've settled up, you can't upload any new content." +msgstr "" + msgid "Your content exceeds the {planStorageCapacity} storage capacity for this plan." msgstr "" diff --git a/packages/files-ui/src/locales/fr/messages.po b/packages/files-ui/src/locales/fr/messages.po index 96692e72bc..423b090876 100644 --- a/packages/files-ui/src/locales/fr/messages.po +++ b/packages/files-ui/src/locales/fr/messages.po @@ -623,9 +623,6 @@ msgstr "Les fichiers sont presque prêts…" msgid "Only send the exact amount of {0} to this address" msgstr "N'envoyez que la somme exacte de {0} à cette adresse" -msgid "Oops! You need to pay for this month to upload more content." -msgstr "Oups ! Vous devez payer pour ce mois-ci pour ajouter plus de contenu." - msgid "Operating system:" msgstr "Système d’exploitation :" @@ -1145,6 +1142,9 @@ msgstr "Vous devrez signer un message avec votre wallet pour terminer la procéd msgid "You've got a payment due. Until you've settled up, we've placed your account in restricted mode" msgstr "Vous avez un paiement en retard. Tant qu'il n'a pas été réglé, l'accès à votre compte a été restreint" +msgid "Your account is restricted. Until you've settled up, you can't upload any new content." +msgstr "" + msgid "Your content exceeds the {planStorageCapacity} storage capacity for this plan." msgstr "Votre contenu dépasse la capacité de stockage de {planStorageCapacity} de cette formule." diff --git a/packages/files-ui/src/locales/no/messages.po b/packages/files-ui/src/locales/no/messages.po index 5f20f111a9..1dfe8ebfca 100644 --- a/packages/files-ui/src/locales/no/messages.po +++ b/packages/files-ui/src/locales/no/messages.po @@ -619,9 +619,6 @@ msgstr "" msgid "Only send the exact amount of {0} to this address" msgstr "" -msgid "Oops! You need to pay for this month to upload more content." -msgstr "" - msgid "Operating system:" msgstr "Operativsystem:" @@ -1141,6 +1138,9 @@ msgstr "" msgid "You've got a payment due. Until you've settled up, we've placed your account in restricted mode" msgstr "" +msgid "Your account is restricted. Until you've settled up, you can't upload any new content." +msgstr "" + msgid "Your content exceeds the {planStorageCapacity} storage capacity for this plan." msgstr "" diff --git a/packages/storage-ui/src/Components/Elements/RestrictedModeBanner.tsx b/packages/storage-ui/src/Components/Elements/RestrictedModeBanner.tsx new file mode 100644 index 0000000000..560e74976d --- /dev/null +++ b/packages/storage-ui/src/Components/Elements/RestrictedModeBanner.tsx @@ -0,0 +1,49 @@ +import { Typography, Button, useHistory } from "@chainsafe/common-components" +import { createStyles, makeStyles, useThemeSwitcher } from "@chainsafe/common-theme" +import { Trans } from "@lingui/macro" +import React from "react" +import { CSSTheme } from "../../Themes/types" +import { ROUTE_LINKS } from "../StorageRoutes" + +const useStyles = makeStyles( + ({ breakpoints, constants, palette }: CSSTheme) => { + return createStyles({ + accountRestrictedNotification: { + position: "fixed", + bottom: 0, + backgroundColor: palette.additional["gray"][10], + color: palette.additional["gray"][1], + padding: `${constants.generalUnit * 2}px ${constants.generalUnit * 3}px`, + left: 0, + width: "100vw", + [breakpoints.up("md")]: { + left: `${constants.navWidth}px`, + width:`calc(100vw - ${constants.navWidth}px)`, + display: "flex", + justifyContent: "space-between", + alignItems: "center" + } + } + }) + } +) + +const RestrictedModeBanner = () => { + const classes = useStyles() + const { desktop } = useThemeSwitcher() + const { redirect } = useHistory() + + return ( +
+ + You've got a payment due. Until you've settled up, we've placed your account in restricted mode + + +
) +} + +export default RestrictedModeBanner \ No newline at end of file diff --git a/packages/storage-ui/src/Components/Modules/FilesList/FilesList.tsx b/packages/storage-ui/src/Components/Modules/FilesList/FilesList.tsx index 5e0d46027d..3222004bb6 100644 --- a/packages/storage-ui/src/Components/Modules/FilesList/FilesList.tsx +++ b/packages/storage-ui/src/Components/Modules/FilesList/FilesList.tsx @@ -44,6 +44,8 @@ import MimeMatcher from "../../../Utils/MimeMatcher" import { useLanguageContext } from "../../../Contexts/LanguageContext" import { ISelectedFile, useFileBrowser } from "../../../Contexts/FileBrowserContext" import SurveyBanner from "../SurveyBanner" +import { useStorageApi } from "../../../Contexts/StorageApiContext" +import RestrictedModeBanner from "../../Elements/RestrictedModeBanner" interface IStyleProps { themeKey: string @@ -69,6 +71,10 @@ const useStyles = makeStyles( minHeight: `calc(100vh - ${Number(constants.contentTopPadding)}px)`, "&.droppable": { borderColor: palette.primary.main + }, + "&.bottomBanner": { + minHeight: `calc(100vh - ${Number(constants.contentTopPadding) + Number(constants.bottomBannerHeight)}px)`, + paddingBottom: constants.bottomBannerHeight } } }, @@ -287,7 +293,7 @@ const sortFoldersFirst = (a: FileSystemItemType, b: FileSystemItemType) => const FilesList = () => { const { themeKey, desktop } = useThemeSwitcher() - + const { accountRestricted } = useStorageApi() const { heading, controls = true, @@ -566,6 +572,8 @@ const FilesList = () => {
@@ -605,6 +613,7 @@ const FilesList = () => { onClick={() => setCreateFolderModalOpen(true)} variant="outline" size="large" + disabled={accountRestricted} > @@ -616,6 +625,7 @@ const FilesList = () => { onClick={() => setIsUploadModalOpen(true)} variant="outline" size="large" + disabled={accountRestricted} > @@ -654,6 +664,7 @@ const FilesList = () => { size="large" className={classes.mobileButton} fullsize + disabled={accountRestricted} > @@ -669,6 +680,7 @@ const FilesList = () => { variant="primary" fullsize className={classes.mobileButton} + disabled={accountRestricted} > @@ -1018,11 +1030,9 @@ const FilesList = () => { ) } - {/* - setFileInfoPath(undefined)} - /> */} + {accountRestricted && + + }
) } diff --git a/packages/storage-ui/src/Components/Pages/BucketPage.tsx b/packages/storage-ui/src/Components/Pages/BucketPage.tsx index 9d32b8bc75..312afa5fc2 100644 --- a/packages/storage-ui/src/Components/Pages/BucketPage.tsx +++ b/packages/storage-ui/src/Components/Pages/BucketPage.tsx @@ -23,7 +23,7 @@ import { usePageTrack } from "../../Contexts/PosthogContext" const BucketPage: React.FC = () => { const { storageBuckets, uploadFiles, uploadsInProgress, getStorageSummary, downloadFile } = useStorage() - const { storageApiClient } = useStorageApi() + const { storageApiClient, accountRestricted } = useStorageApi() const { addToast } = useToasts() const [loadingCurrentPath, setLoadingCurrentPath] = useState(false) const [pathContents, setPathContents] = useState([]) @@ -162,9 +162,19 @@ const BucketPage: React.FC = () => { const handleUploadOnDrop = useCallback(async (files: File[], fileItems: DataTransferItemList, path: string) => { if (!bucket) return + + if (accountRestricted) { + addToast({ + type:"error", + title: t`Uploads disabled`, + subtitle: t`Your account is restricted. Until you've settled up, you can't upload any new content.` + }) + return + } + let hasFolder = false for (let i = 0; i < files.length; i++) { - if (fileItems[i].webkitGetAsEntry().isDirectory) { + if (fileItems[i].webkitGetAsEntry()?.isDirectory) { hasFolder = true } } @@ -178,7 +188,7 @@ const BucketPage: React.FC = () => { .then(() => refreshContents()) .catch(console.error) } - }, [addToast, uploadFiles, bucket, refreshContents]) + }, [bucket, accountRestricted, addToast, uploadFiles, refreshContents]) const viewFolder = useCallback((toView: ISelectedFile) => { const fileSystemItem = pathContents.find(f => f.cid === toView.cid && f.name === toView.name) diff --git a/packages/storage-ui/src/Components/Pages/BucketsPage.tsx b/packages/storage-ui/src/Components/Pages/BucketsPage.tsx index d2c44105be..a1925658e2 100644 --- a/packages/storage-ui/src/Components/Pages/BucketsPage.tsx +++ b/packages/storage-ui/src/Components/Pages/BucketsPage.tsx @@ -20,6 +20,8 @@ import CustomModal from "../Elements/CustomModal" import { Form, FormikProvider, useFormik } from "formik" import { bucketNameValidator } from "../../Utils/validationSchema" import { useCallback } from "react" +import RestrictedModeBanner from "../Elements/RestrictedModeBanner" +import { useStorageApi } from "../../Contexts/StorageApiContext" import { usePageTrack } from "../../Contexts/PosthogContext" export const desktopGridSettings = "3fr 190px 70px !important" @@ -116,6 +118,7 @@ const useStyles = makeStyles(({ breakpoints, animation, constants, typography }: const BucketsPage = () => { const classes = useStyles() const { storageBuckets, createBucket, refreshBuckets } = useStorage() + const { accountRestricted } = useStorageApi() const [isCreateBucketModalOpen, setIsCreateBucketModalOpen] = useState(false) const bucketsToShow = useMemo(() => storageBuckets.filter(b => b.status === "created"), [storageBuckets]) const bucketNameValidationSchema = useMemo( @@ -171,6 +174,7 @@ const BucketsPage = () => { data-cy="button-create-bucket" onClick={() => setIsCreateBucketModalOpen(true)} variant="outline" + disabled={accountRestricted} > Create Bucket @@ -214,6 +218,9 @@ const BucketsPage = () => { )} + {accountRestricted && + + } { const classes = useStyles() const { pins } = useStorage() + const { accountRestricted } = useStorageApi() const [addCIDOpen, setAddCIDOpen] = useState(false) const [sortColumn, setSortColumn] = useState("date_uploaded") const [sortDirection, setSortDirection] = useState("descend") @@ -114,6 +117,7 @@ const CidsPage = () => { onClick={() => setAddCIDOpen(true)} variant="outline" size="large" + disabled={accountRestricted} > @@ -186,6 +190,9 @@ const CidsPage = () => { close={() => setAddCIDOpen(false)} modalOpen={addCIDOpen} /> + {accountRestricted && + + } ) } diff --git a/packages/storage-ui/src/Contexts/BillingContext.tsx b/packages/storage-ui/src/Contexts/BillingContext.tsx index 8db4af62f8..072a162a95 100644 --- a/packages/storage-ui/src/Contexts/BillingContext.tsx +++ b/packages/storage-ui/src/Contexts/BillingContext.tsx @@ -58,9 +58,7 @@ const BillingContext = React.createContext( ) const BillingProvider = ({ children }: BillingContextProps) => { - const { storageApiClient, isLoggedIn - // accountRestricted - } = useStorageApi() + const { storageApiClient, isLoggedIn, accountRestricted } = useStorageApi() const { redirect } = useHistory() const { addNotification, removeNotification } = useNotifications() const { refreshBuckets } = useStorage() @@ -69,7 +67,7 @@ const BillingProvider = ({ children }: BillingContextProps) => { const [invoices, setInvoices] = useState() const isPendingInvoice = useMemo(() => currentSubscription?.status === "pending_update", [currentSubscription]) const openInvoice = useMemo(() => invoices?.find((i) => i.status === "open"), [invoices]) - // const [restrictedNotification, setRestrictedNotification] = useState() + const [restrictedNotification, setRestrictedNotification] = useState() const [unpaidInvoiceNotification, setUnpaidInvoiceNotification] = useState() const [cardExpiringNotification, setCardExpiringNotification] = useState() const [isBillingEnabled, setIsBillingEnabled] = useState(false) @@ -99,19 +97,19 @@ const BillingProvider = ({ children }: BillingContextProps) => { .catch(console.error) }, [storageApiClient, isLoggedIn]) - // useEffect(() => { - // if (accountRestricted && !restrictedNotification) { - // const notif = addNotification({ - // createdAt: dayjs().unix(), - // title: t`Account is restricted`, - // onClick: () => redirect(ROUTE_LINKS.SettingsPath("plan")) - // }) - // setRestrictedNotification(notif) - // } else if (accountRestricted === false && restrictedNotification) { - // removeNotification(restrictedNotification) - // setRestrictedNotification(undefined) - // } - // }, [accountRestricted, addNotification, redirect, removeNotification, restrictedNotification]) + useEffect(() => { + if (accountRestricted && !restrictedNotification) { + const notif = addNotification({ + createdAt: dayjs().unix(), + title: t`Account is restricted`, + onClick: () => redirect(ROUTE_LINKS.SettingsPath("plan")) + }) + setRestrictedNotification(notif) + } else if (accountRestricted === false && restrictedNotification) { + removeNotification(restrictedNotification) + setRestrictedNotification(undefined) + } + }, [accountRestricted, addNotification, redirect, removeNotification, restrictedNotification]) useEffect(() => { if (!!openInvoice && !unpaidInvoiceNotification) { diff --git a/packages/storage-ui/src/Contexts/StorageApiContext.tsx b/packages/storage-ui/src/Contexts/StorageApiContext.tsx index deee4c4cc6..e94dc1b1a1 100644 --- a/packages/storage-ui/src/Contexts/StorageApiContext.tsx +++ b/packages/storage-ui/src/Contexts/StorageApiContext.tsx @@ -69,6 +69,7 @@ type StorageApiContext = { logout: () => void status: DirectAuthContextStatus resetStatus(): void + accountRestricted?: boolean } const StorageApiContext = React.createContext(undefined) @@ -103,6 +104,7 @@ const StorageApiProvider = ({ apiUrl, withLocalStorage = true, children }: Stora const [decodedRefreshToken, setDecodedRefreshToken] = useState< { exp: number; enckey?: string; mps?: string; uuid: string } | undefined >(undefined) + const [accountRestricted, setAccountRestricted] = useState(false) // returning user const isReturningUserLocal = localStorageGet(isReturningUserStorageKey) @@ -228,6 +230,22 @@ const StorageApiProvider = ({ apiUrl, withLocalStorage = true, children }: Stora // eslint-disable-next-line react-hooks/exhaustive-deps }, [canUseLocalStorage]) + + useEffect(() => { + if (accessToken && accessToken.token && storageApiClient) { + storageApiClient?.setToken(accessToken.token) + const decodedAccessToken = jwtDecode<{ perm: { secured?: string; files?: string } }>( + accessToken.token + ) + + if (decodedAccessToken.perm.files === "restricted") { + setAccountRestricted(true) + } else { + setAccountRestricted(false) + } + } + }, [accessToken, storageApiClient]) + const selectWallet = async () => { if (onboard && !isReady) { let walletSelected = !!wallet @@ -259,12 +277,6 @@ const StorageApiProvider = ({ apiUrl, withLocalStorage = true, children }: Stora } }, [refreshToken]) - useEffect(() => { - if (accessToken && accessToken.token && storageApiClient) { - storageApiClient?.setToken(accessToken.token) - } - }, [accessToken, storageApiClient]) - const isLoggedIn = () => { if (isLoadingUser) { return undefined @@ -409,7 +421,8 @@ const StorageApiProvider = ({ apiUrl, withLocalStorage = true, children }: Stora userInfo, selectWallet, resetAndSelectWallet, - logout + logout, + accountRestricted }} > {children} diff --git a/packages/storage-ui/src/locales/en/messages.po b/packages/storage-ui/src/locales/en/messages.po index db885bdd99..eaa56c1881 100644 --- a/packages/storage-ui/src/locales/en/messages.po +++ b/packages/storage-ui/src/locales/en/messages.po @@ -46,6 +46,9 @@ msgstr "Accepted currencies" msgid "Access your billing history in settings or view your" msgstr "Access your billing history in settings or view your" +msgid "Account is restricted" +msgstr "Account is restricted" + msgid "Add API Key" msgstr "Add API Key" @@ -337,6 +340,9 @@ msgstr "Go back" msgid "Go back" msgstr "Go back" +msgid "Go to Payments" +msgstr "Go to Payments" + msgid "Have a question?" msgstr "Have a question?" @@ -679,6 +685,9 @@ msgstr "Upload complete" msgid "Uploading {0} files" msgstr "Uploading {0} files" +msgid "Uploads disabled" +msgstr "Uploads disabled" + msgid "Use a different login method" msgstr "Use a different login method" @@ -727,6 +736,12 @@ msgstr "You now have:" msgid "You will need to sign a message in your wallet to complete sign in." msgstr "You will need to sign a message in your wallet to complete sign in." +msgid "You've got a payment due. Until you've settled up, we've placed your account in restricted mode" +msgstr "You've got a payment due. Until you've settled up, we've placed your account in restricted mode" + +msgid "Your account is restricted. Until you've settled up, you can't upload any new content." +msgstr "Your account is restricted. Until you've settled up, you can't upload any new content." + msgid "Your content exceeds the {planStorageCapacity} storage capacity for this plan." msgstr "Your content exceeds the {planStorageCapacity} storage capacity for this plan."