diff --git a/packages/files-ui/src/App.tsx b/packages/files-ui/src/App.tsx index 7446e8ebf5..f36a1873de 100644 --- a/packages/files-ui/src/App.tsx +++ b/packages/files-ui/src/App.tsx @@ -135,21 +135,21 @@ const App = () => { enableLogging={directAuthNetwork !== "mainnet"} network={directAuthNetwork} > - - - - - + + + + + - - - - - + + + + + diff --git a/packages/files-ui/src/Components/Elements/InvoiceLines.tsx b/packages/files-ui/src/Components/Elements/InvoiceLines.tsx index ba86b290d7..e4d12496a2 100644 --- a/packages/files-ui/src/Components/Elements/InvoiceLines.tsx +++ b/packages/files-ui/src/Components/Elements/InvoiceLines.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from "react" import { makeStyles, createStyles } from "@chainsafe/common-theme" import { CSFTheme } from "../../Themes/types" -import { Typography, Loading } from "@chainsafe/common-components" +import { Typography, Loading, Button } from "@chainsafe/common-components" import { Trans } from "@lingui/macro" import dayjs from "dayjs" import { useBilling } from "../../Contexts/BillingContext" @@ -60,7 +60,7 @@ interface IInvoiceProps { const InvoiceLines = ({ lineNumber }: IInvoiceProps) => { const classes = useStyles() - const { invoices } = useBilling() + const { invoices, downloadInvoice } = useBilling() const invoicesToShow = useMemo(() => { if (!invoices) return @@ -92,7 +92,7 @@ const InvoiceLines = ({ lineNumber }: IInvoiceProps) => { )} {!!invoicesToShow?.length && ( - invoicesToShow.map(({ paid_on, amount, currency, uuid }) => + invoicesToShow.map(({ amount, currency, uuid, period_start, status }) =>
{ variant="body2" className="receiptDate" > - {dayjs(paid_on).format("MMM D, YYYY")} - - - {uuid} + {dayjs.unix(period_start).format("MMM D, YYYY")} + {(status === "paid") && ( + + )} + {(status === "open") && ( + + )}
) diff --git a/packages/files-ui/src/Components/Elements/Notifications/NotificationList.tsx b/packages/files-ui/src/Components/Elements/Notifications/NotificationList.tsx index 3c03c76208..e7c78307f1 100644 --- a/packages/files-ui/src/Components/Elements/Notifications/NotificationList.tsx +++ b/packages/files-ui/src/Components/Elements/Notifications/NotificationList.tsx @@ -92,7 +92,7 @@ const NotificationList = ({ notifications }: INotificationListProps) => { className={classes.notificationTime} component="p" > - {dayjs(n.createdAt).fromNow()} + {dayjs.unix(n.createdAt).fromNow()} ))} diff --git a/packages/files-ui/src/Contexts/BillingContext.tsx b/packages/files-ui/src/Contexts/BillingContext.tsx index b16c2613a5..355a6451af 100644 --- a/packages/files-ui/src/Contexts/BillingContext.tsx +++ b/packages/files-ui/src/Contexts/BillingContext.tsx @@ -6,6 +6,10 @@ import { useCallback } from "react" import { t } from "@lingui/macro" import { PaymentMethod as StripePaymentMethod } from "@stripe/stripe-js" import { useFiles } from "./FilesContext" +import { useNotifications } from "./NotificationsContext" +import dayjs from "dayjs" +import { useHistory } from "@chainsafe/common-components" +import { ROUTE_LINKS } from "../Components/FilesRoutes" export type PaymentMethod = "crypto" | "creditCard" @@ -24,6 +28,7 @@ interface IBillingContext { updateDefaultCard: (id: StripePaymentMethod["id"]) => Promise invoices?: InvoiceResponse[] cancelCurrentSubscription: () => Promise + downloadInvoice: (invoiceId: string) => Promise } const ProductMapping: {[key: string]: { @@ -49,32 +54,86 @@ const BillingContext = React.createContext( ) const BillingProvider = ({ children }: BillingContextProps) => { - const { filesApiClient, isLoggedIn } = useFilesApi() + const { filesApiClient, isLoggedIn, accountRestricted } = useFilesApi() + const { redirect } = useHistory() + const { addNotification, removeNotification } = useNotifications() const { refreshBuckets } = useFiles() const [currentSubscription, setCurrentSubscription] = useState() const [defaultCard, setDefaultCard] = useState(undefined) const [invoices, setInvoices] = useState() + const [restrictedNotification, setRestrictedNotification] = useState() + const [unpaidInvoiceNotification, setUnpaidInvoiceNotification] = useState() + const [cardExpiringNotification, setCardExpiringNotification] = useState() useEffect(() => { if (!currentSubscription) return filesApiClient.getAllInvoices(currentSubscription.id) .then(({ invoices }) => { - setInvoices(invoices) - }) - .catch((e: any) => { + setInvoices(invoices + .filter(i => i.status !== "void") + .sort((a, b) => b.period_start - a.period_start)) + }).catch((e: any) => { console.error(e) setInvoices([]) }) }, [currentSubscription, filesApiClient]) + 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(() => { + const outstandingInvoice = invoices?.find(i => i.status === "open") + if (outstandingInvoice && !unpaidInvoiceNotification) { + const notif = addNotification({ + createdAt: outstandingInvoice.period_start, + title: t`Invoice outstanding`, + onClick: () => redirect(ROUTE_LINKS.SettingsPath("plan")) + }) + setUnpaidInvoiceNotification(notif) + } else if (!outstandingInvoice && unpaidInvoiceNotification) { + removeNotification(unpaidInvoiceNotification) + setUnpaidInvoiceNotification(undefined) + } + }, [addNotification, invoices, redirect, removeNotification, unpaidInvoiceNotification]) + + useEffect(() => { + if (defaultCard && currentSubscription) { + if (!cardExpiringNotification && currentSubscription.expiry_date > + dayjs(`${defaultCard.exp_year}-${defaultCard.exp_month}-01`, "YYYY-MM-DD").endOf("month").unix()) { + const notif = addNotification({ + createdAt: dayjs().unix(), + title: t`Credit Card is expiring soon`, + onClick: () => redirect(ROUTE_LINKS.SettingsPath("plan")) + }) + setCardExpiringNotification(notif) + } else if (cardExpiringNotification && currentSubscription?.expiry_date <= + dayjs(`${defaultCard?.exp_year}-${defaultCard?.exp_month}-01`, "YYYY-MM-DD").endOf("month").unix()) { + removeNotification(cardExpiringNotification) + setCardExpiringNotification(undefined) + } + } + }, [addNotification, cardExpiringNotification, currentSubscription, defaultCard, redirect, removeNotification]) + const refreshDefaultCard = useCallback(() => { - filesApiClient.getDefaultCard().then((card) => { - setDefaultCard(card) - }).catch((err) => { - console.error(err) - setDefaultCard(undefined) - }) + filesApiClient.getDefaultCard() + .then((card) => { + setDefaultCard(card) + }).catch((err) => { + console.error(err) + setDefaultCard(undefined) + }) }, [filesApiClient]) const deleteCard = useCallback((card: Card) => @@ -155,8 +214,19 @@ const BillingProvider = ({ children }: BillingContextProps) => { console.error(error) return Promise.reject() }) - }, [currentSubscription, fetchCurrentSubscription, filesApiClient, refreshBuckets] - ) + }, [currentSubscription, fetchCurrentSubscription, filesApiClient, refreshBuckets]) + + const downloadInvoice = useCallback(async (invoiceId: string) => { + try { + const result = await filesApiClient.downloadInvoice(invoiceId) + const link = document.createElement("a") + link.href = URL.createObjectURL(result.data) + link.download = "Chainsafe Files Invoice" + link.click() + } catch (error) { + console.error(error) + } + }, [filesApiClient]) return ( { deleteCard, updateDefaultCard, invoices, - cancelCurrentSubscription + cancelCurrentSubscription, + downloadInvoice }} > {children} diff --git a/packages/files-ui/src/locales/de/messages.po b/packages/files-ui/src/locales/de/messages.po index 360e2f358e..12b15b894d 100644 --- a/packages/files-ui/src/locales/de/messages.po +++ b/packages/files-ui/src/locales/de/messages.po @@ -49,6 +49,9 @@ msgstr "" msgid "Account" msgstr "Konto" +msgid "Account is restricted" +msgstr "" + msgid "Active links" msgstr "" @@ -250,6 +253,9 @@ msgstr "" msgid "Create your public username in <0>Settings!" msgstr "" +msgid "Credit Card is expiring soon" +msgstr "" + msgid "Credit card saved" msgstr "" @@ -472,6 +478,9 @@ msgstr "Infos" msgid "Insufficient balance" msgstr "" +msgid "Invoice outstanding" +msgstr "" + msgid "I’m done saving my backup secret phrase" msgstr "Ich bin fertig mit dem Speichern meines Sixherungsgeheimsatzes" @@ -637,6 +646,9 @@ msgstr "Passwort:" msgid "Passwords must match" msgstr "Passwörter müssen übereinstimmen" +msgid "Pay invoice" +msgstr "" + msgid "Pay with Crypto" msgstr "" diff --git a/packages/files-ui/src/locales/en/messages.po b/packages/files-ui/src/locales/en/messages.po index e19a780d30..435b2213bc 100644 --- a/packages/files-ui/src/locales/en/messages.po +++ b/packages/files-ui/src/locales/en/messages.po @@ -49,6 +49,9 @@ msgstr "Access your billing history in settings or view your" msgid "Account" msgstr "Account" +msgid "Account is restricted" +msgstr "Account is restricted" + msgid "Active links" msgstr "Active links" @@ -250,6 +253,9 @@ msgstr "Create link" msgid "Create your public username in <0>Settings!" msgstr "Create your public username in <0>Settings!" +msgid "Credit Card is expiring soon" +msgstr "Credit Card is expiring soon" + msgid "Credit card saved" msgstr "Credit card saved" @@ -475,6 +481,9 @@ msgstr "Info" msgid "Insufficient balance" msgstr "Insufficient balance" +msgid "Invoice outstanding" +msgstr "Invoice outstanding" + msgid "I’m done saving my backup secret phrase" msgstr "I’m done saving my backup secret phrase" @@ -640,6 +649,9 @@ msgstr "Password:" msgid "Passwords must match" msgstr "Passwords must match" +msgid "Pay invoice" +msgstr "Pay invoice" + msgid "Pay with Crypto" msgstr "Pay with Crypto" diff --git a/packages/files-ui/src/locales/es/messages.po b/packages/files-ui/src/locales/es/messages.po index 1a6e4e4a3c..a6e30547b2 100644 --- a/packages/files-ui/src/locales/es/messages.po +++ b/packages/files-ui/src/locales/es/messages.po @@ -50,6 +50,9 @@ msgstr "" msgid "Account" msgstr "Cuenta" +msgid "Account is restricted" +msgstr "" + msgid "Active links" msgstr "" @@ -251,6 +254,9 @@ msgstr "" msgid "Create your public username in <0>Settings!" msgstr "" +msgid "Credit Card is expiring soon" +msgstr "" + msgid "Credit card saved" msgstr "" @@ -476,6 +482,9 @@ msgstr "Info" msgid "Insufficient balance" msgstr "" +msgid "Invoice outstanding" +msgstr "" + msgid "I’m done saving my backup secret phrase" msgstr "" @@ -641,6 +650,9 @@ msgstr "Contraseña:" msgid "Passwords must match" msgstr "Las contraseñas deben coincidir" +msgid "Pay invoice" +msgstr "" + msgid "Pay with Crypto" msgstr "" diff --git a/packages/files-ui/src/locales/fr/messages.po b/packages/files-ui/src/locales/fr/messages.po index 4bd584260c..c189ffb0fc 100644 --- a/packages/files-ui/src/locales/fr/messages.po +++ b/packages/files-ui/src/locales/fr/messages.po @@ -50,6 +50,9 @@ msgstr "Accédez à l'historique de votre facturation dans les paramètres ou vi msgid "Account" msgstr "Compte" +msgid "Account is restricted" +msgstr "" + msgid "Active links" msgstr "Liens actifs" @@ -251,6 +254,9 @@ msgstr "Créer un lien" msgid "Create your public username in <0>Settings!" msgstr "Créez votre nom d'utilisateur public dans <0>Paramètres !" +msgid "Credit Card is expiring soon" +msgstr "" + msgid "Credit card saved" msgstr "Carte de crédit enregistrée" @@ -476,6 +482,9 @@ msgstr "Infos" msgid "Insufficient balance" msgstr "" +msgid "Invoice outstanding" +msgstr "" + msgid "I’m done saving my backup secret phrase" msgstr "Phrase de sauvegarde secrète enregistrée" @@ -641,6 +650,9 @@ msgstr "Mot de passe :" msgid "Passwords must match" msgstr "Les mots de passes de correspondent pas" +msgid "Pay invoice" +msgstr "" + msgid "Pay with Crypto" msgstr "" diff --git a/packages/files-ui/src/locales/no/messages.po b/packages/files-ui/src/locales/no/messages.po index 047bfde91c..1adf33c7d3 100644 --- a/packages/files-ui/src/locales/no/messages.po +++ b/packages/files-ui/src/locales/no/messages.po @@ -49,6 +49,9 @@ msgstr "" msgid "Account" msgstr "Konto" +msgid "Account is restricted" +msgstr "" + msgid "Active links" msgstr "" @@ -250,6 +253,9 @@ msgstr "" msgid "Create your public username in <0>Settings!" msgstr "" +msgid "Credit Card is expiring soon" +msgstr "" + msgid "Credit card saved" msgstr "" @@ -472,6 +478,9 @@ msgstr "Info" msgid "Insufficient balance" msgstr "" +msgid "Invoice outstanding" +msgstr "" + msgid "I’m done saving my backup secret phrase" msgstr "" @@ -637,6 +646,9 @@ msgstr "Passord:" msgid "Passwords must match" msgstr "Passordene må samsvare" +msgid "Pay invoice" +msgstr "" + msgid "Pay with Crypto" msgstr ""