From 4fb0be37103bec2e728a0d9f389eaf77cd92992e Mon Sep 17 00:00:00 2001 From: olav Date: Tue, 14 Jun 2022 15:41:28 +0200 Subject: [PATCH] fix: show previous invoices page if UNLEASH_CLOUD is falsy (#1094) * fix: restore previous invoices page * fix: show previous invoices page if UNLEASH_CLOUD is falsy * fix: use correct amountFormatted invoice field name --- .../FlaggedBillingRedirect.tsx | 19 +++ .../RedirectAdminInvoices.tsx | 7 - .../admin/invoice/InvoiceAdminPage.tsx | 25 ++++ .../component/admin/invoice/InvoiceList.tsx | 122 ++++++++++++++++++ frontend/src/component/menu/Header/Header.tsx | 12 +- .../__snapshots__/routes.test.tsx.snap | 10 +- frontend/src/component/menu/routes.ts | 10 +- frontend/src/interfaces/invoice.ts | 8 ++ frontend/src/interfaces/route.ts | 2 +- 9 files changed, 191 insertions(+), 24 deletions(-) create mode 100644 frontend/src/component/admin/billing/FlaggedBillingRedirect/FlaggedBillingRedirect.tsx delete mode 100644 frontend/src/component/admin/billing/RedirectAdminInvoices/RedirectAdminInvoices.tsx create mode 100644 frontend/src/component/admin/invoice/InvoiceAdminPage.tsx create mode 100644 frontend/src/component/admin/invoice/InvoiceList.tsx create mode 100644 frontend/src/interfaces/invoice.ts diff --git a/frontend/src/component/admin/billing/FlaggedBillingRedirect/FlaggedBillingRedirect.tsx b/frontend/src/component/admin/billing/FlaggedBillingRedirect/FlaggedBillingRedirect.tsx new file mode 100644 index 0000000000..0a9d17683e --- /dev/null +++ b/frontend/src/component/admin/billing/FlaggedBillingRedirect/FlaggedBillingRedirect.tsx @@ -0,0 +1,19 @@ +import { Navigate } from 'react-router-dom'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import InvoiceAdminPage from 'component/admin/invoice/InvoiceAdminPage'; + +const FlaggedBillingRedirect = () => { + const { uiConfig, loading } = useUiConfig(); + + if (loading) { + return null; + } + + if (!uiConfig.flags.UNLEASH_CLOUD) { + return ; + } + + return ; +}; + +export default FlaggedBillingRedirect; diff --git a/frontend/src/component/admin/billing/RedirectAdminInvoices/RedirectAdminInvoices.tsx b/frontend/src/component/admin/billing/RedirectAdminInvoices/RedirectAdminInvoices.tsx deleted file mode 100644 index 07111c962e..0000000000 --- a/frontend/src/component/admin/billing/RedirectAdminInvoices/RedirectAdminInvoices.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { Navigate } from 'react-router-dom'; - -const RedirectAdminInvoices = () => { - return ; -}; - -export default RedirectAdminInvoices; diff --git a/frontend/src/component/admin/invoice/InvoiceAdminPage.tsx b/frontend/src/component/admin/invoice/InvoiceAdminPage.tsx new file mode 100644 index 0000000000..f9197c0df6 --- /dev/null +++ b/frontend/src/component/admin/invoice/InvoiceAdminPage.tsx @@ -0,0 +1,25 @@ +import { useContext } from 'react'; +import InvoiceList from './InvoiceList'; +import AccessContext from 'contexts/AccessContext'; +import { ADMIN } from 'component/providers/AccessProvider/permissions'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import { Alert } from '@mui/material'; + +const InvoiceAdminPage = () => { + const { hasAccess } = useContext(AccessContext); + return ( +
+ } + elseShow={ + + You need to be instance admin to access this section. + + } + /> +
+ ); +}; + +export default InvoiceAdminPage; diff --git a/frontend/src/component/admin/invoice/InvoiceList.tsx b/frontend/src/component/admin/invoice/InvoiceList.tsx new file mode 100644 index 0000000000..136706ca32 --- /dev/null +++ b/frontend/src/component/admin/invoice/InvoiceList.tsx @@ -0,0 +1,122 @@ +import { useEffect, useState } from 'react'; +import { + Table, + TableHead, + TableBody, + TableRow, + TableCell, + Button, +} from '@mui/material'; +import OpenInNew from '@mui/icons-material/OpenInNew'; +import { PageContent } from 'component/common/PageContent/PageContent'; +import { PageHeader } from 'component/common/PageHeader/PageHeader'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import { formatApiPath } from 'utils/formatPath'; +import useInvoices from 'hooks/api/getters/useInvoices/useInvoices'; +import { IInvoice } from 'interfaces/invoice'; +import { useLocationSettings } from 'hooks/useLocationSettings'; +import { formatDateYMD } from 'utils/formatDate'; + +const PORTAL_URL = formatApiPath('api/admin/invoices/portal'); + +const InvoiceList = () => { + const { refetchInvoices, invoices } = useInvoices(); + const [isLoaded, setLoaded] = useState(false); + const { locationSettings } = useLocationSettings(); + + useEffect(() => { + refetchInvoices(); + setLoaded(true); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + 0} + show={ + } + > + Billing portal + + } + /> + } + > +
+ + + + Amount + Status + Due date + PDF + Link + + + + {invoices.map((item: IInvoice) => ( + + + {item.amountFormatted} + + + {item.status} + + + {item.dueDate && + formatDateYMD( + item.dueDate, + locationSettings.locale + )} + + + PDF + + + + Payment link + + + + ))} + +
+
+
+ } + elseShow={
{isLoaded && 'No invoices to show.'}
} + /> + ); +}; +export default InvoiceList; diff --git a/frontend/src/component/menu/Header/Header.tsx b/frontend/src/component/menu/Header/Header.tsx index 00f6da9574..facdb236ce 100644 --- a/frontend/src/component/menu/Header/Header.tsx +++ b/frontend/src/component/menu/Header/Header.tsx @@ -23,7 +23,6 @@ import { useAuthPermissions } from 'hooks/api/getters/useAuth/useAuthPermissions import { useStyles } from './Header.styles'; import classNames from 'classnames'; import { useId } from 'hooks/useId'; -import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus'; import { IRoute } from 'interfaces/route'; const Header: VFC = () => { @@ -37,6 +36,7 @@ const Header: VFC = () => { const { permissions } = useAuthPermissions(); const { uiConfig: { links, name, flags }, + isOss, } = useUiConfig(); const smallScreen = useMediaQuery(theme.breakpoints.down('md')); const { classes: styles } = useStyles(); @@ -57,15 +57,18 @@ const Header: VFC = () => { } }, [permissions]); - const { isBilling } = useInstanceStatus(); const routes = getRoutes(); + const filterByEnterprise = (route: IRoute): boolean => { + return !route.menu.isEnterprise || !isOss(); + }; + const filteredMainRoutes = { mainNavRoutes: routes.mainNavRoutes.filter(filterByFlags(flags)), mobileRoutes: routes.mobileRoutes.filter(filterByFlags(flags)), adminRoutes: routes.adminRoutes .filter(filterByFlags(flags)) - .filter(filterByBilling(isBilling)), + .filter(filterByEnterprise), }; if (smallScreen) { @@ -196,7 +199,4 @@ const Header: VFC = () => { ); }; -export const filterByBilling = (isBilling?: boolean) => (route: IRoute) => - !route.menu.isBilling || isBilling; - export default Header; diff --git a/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap b/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap index 6c49570e44..6b5c45ae25 100644 --- a/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap +++ b/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap @@ -411,10 +411,7 @@ exports[`returns all baseRoutes 1`] = ` }, { "component": [Function], - "menu": { - "adminSettings": true, - "isBilling": true, - }, + "menu": {}, "parent": "/admin", "path": "/admin/billing", "title": "Billing", @@ -422,7 +419,10 @@ exports[`returns all baseRoutes 1`] = ` }, { "component": [Function], - "menu": {}, + "menu": { + "adminSettings": true, + "isEnterprise": true, + }, "parent": "/admin", "path": "/admin-invoices", "title": "Invoices", diff --git a/frontend/src/component/menu/routes.ts b/frontend/src/component/menu/routes.ts index 1e51189519..3189b20848 100644 --- a/frontend/src/component/menu/routes.ts +++ b/frontend/src/component/menu/routes.ts @@ -7,7 +7,6 @@ import Admin from 'component/admin'; import AdminApi from 'component/admin/api'; import AdminUsers from 'component/admin/users/UsersAdmin'; import { AuthSettings } from 'component/admin/auth/AuthSettings'; -import { Billing } from 'component/admin/billing/Billing'; import Login from 'component/user/Login/Login'; import { C, EEA, P, RE, SE } from 'component/common/flags'; import { NewUser } from 'component/user/NewUser/NewUser'; @@ -50,8 +49,9 @@ import { EditSegment } from 'component/segments/EditSegment/EditSegment'; import { IRoute } from 'interfaces/route'; import { EnvironmentTable } from 'component/environments/EnvironmentTable/EnvironmentTable'; import { SegmentTable } from 'component/segments/SegmentTable/SegmentTable'; -import RedirectAdminInvoices from 'component/admin/billing/RedirectAdminInvoices/RedirectAdminInvoices'; +import FlaggedBillingRedirect from 'component/admin/billing/FlaggedBillingRedirect/FlaggedBillingRedirect'; import { FeaturesArchiveTable } from '../archive/FeaturesArchiveTable'; +import { Billing } from 'component/admin/billing/Billing'; export const routes: IRoute[] = [ // Splash @@ -462,15 +462,15 @@ export const routes: IRoute[] = [ title: 'Billing', component: Billing, type: 'protected', - menu: { adminSettings: true, isBilling: true }, + menu: {}, }, { path: '/admin-invoices', parent: '/admin', title: 'Invoices', - component: RedirectAdminInvoices, + component: FlaggedBillingRedirect, type: 'protected', - menu: {}, + menu: { adminSettings: true, isEnterprise: true }, }, { path: '/admin', diff --git a/frontend/src/interfaces/invoice.ts b/frontend/src/interfaces/invoice.ts new file mode 100644 index 0000000000..82790c14cd --- /dev/null +++ b/frontend/src/interfaces/invoice.ts @@ -0,0 +1,8 @@ +export interface IInvoice { + amountFormatted: string; + invoicePDF: string; + invoiceURL: string; + paid: boolean; + status: string; + dueDate?: Date; +} diff --git a/frontend/src/interfaces/route.ts b/frontend/src/interfaces/route.ts index 213bec4a51..6c94cb1a80 100644 --- a/frontend/src/interfaces/route.ts +++ b/frontend/src/interfaces/route.ts @@ -17,5 +17,5 @@ interface IRouteMenu { mobile?: boolean; advanced?: boolean; adminSettings?: boolean; - isBilling?: boolean; + isEnterprise?: boolean; }