mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
refactor: add useInvoices hook (#656)
* refactor: add useInvoices hook * refactor: invoiceList and InvoiceAdminPage * fix: declare path outside of the hook Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
This commit is contained in:
parent
d146c1fcf9
commit
25ca7b7216
@ -86,7 +86,7 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
|
|||||||
refetch();
|
refetch();
|
||||||
setToastData({
|
setToastData({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
show: true,
|
title: 'Deleted successfully',
|
||||||
text: 'Successfully deleted API token.',
|
text: 'Successfully deleted API token.',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import InvoiceList from './InvoiceList';
|
||||||
import InvoiceList from './invoice-container';
|
|
||||||
import AccessContext from '../../../contexts/AccessContext';
|
import AccessContext from '../../../contexts/AccessContext';
|
||||||
import { ADMIN } from '../../providers/AccessProvider/permissions';
|
import { ADMIN } from '../../providers/AccessProvider/permissions';
|
||||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||||
import { Alert } from '@material-ui/lab';
|
import { Alert } from '@material-ui/lab';
|
||||||
|
|
||||||
const InvoiceAdminPage = ({ history }) => {
|
const InvoiceAdminPage = () => {
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
@ -24,9 +22,4 @@ const InvoiceAdminPage = ({ history }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
InvoiceAdminPage.propTypes = {
|
|
||||||
match: PropTypes.object.isRequired,
|
|
||||||
history: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default InvoiceAdminPage;
|
export default InvoiceAdminPage;
|
122
frontend/src/component/admin/invoice/InvoiceList.tsx
Normal file
122
frontend/src/component/admin/invoice/InvoiceList.tsx
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableHead,
|
||||||
|
TableBody,
|
||||||
|
TableRow,
|
||||||
|
TableCell,
|
||||||
|
Button,
|
||||||
|
} from '@material-ui/core';
|
||||||
|
import OpenInNew from '@material-ui/icons/OpenInNew';
|
||||||
|
import { formatDateWithLocale } from '../../common/util';
|
||||||
|
import PageContent from '../../common/PageContent';
|
||||||
|
import HeaderTitle from '../../common/HeaderTitle';
|
||||||
|
import ConditionallyRender from '../../common/ConditionallyRender';
|
||||||
|
import { formatApiPath } from '../../../utils/format-path';
|
||||||
|
import useInvoices from '../../../hooks/api/getters/useInvoices/useInvoices';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { IInvoice } from '../../../interfaces/invoice';
|
||||||
|
|
||||||
|
const PORTAL_URL = formatApiPath('api/admin/invoices/portal');
|
||||||
|
|
||||||
|
const InvoiceList = () => {
|
||||||
|
const { refetchInvoices, invoices } = useInvoices();
|
||||||
|
const [isLoaded, setLoaded] = useState(false);
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
refetchInvoices();
|
||||||
|
setLoaded(true);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={invoices.length > 0}
|
||||||
|
show={
|
||||||
|
<PageContent
|
||||||
|
headerContent={
|
||||||
|
<HeaderTitle
|
||||||
|
title="Invoices"
|
||||||
|
actions={
|
||||||
|
<Button
|
||||||
|
href={PORTAL_URL}
|
||||||
|
rel="noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
endIcon={<OpenInNew />}
|
||||||
|
>
|
||||||
|
Billing portal
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Amount</TableCell>
|
||||||
|
<TableCell>Status</TableCell>
|
||||||
|
<TableCell>Due date</TableCell>
|
||||||
|
<TableCell>PDF</TableCell>
|
||||||
|
<TableCell>Link</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{invoices.map((item: IInvoice) => (
|
||||||
|
<TableRow
|
||||||
|
key={item.invoiceURL}
|
||||||
|
style={{
|
||||||
|
backgroundColor:
|
||||||
|
item.status === 'past-due'
|
||||||
|
? '#ff9194'
|
||||||
|
: 'inherit',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TableCell
|
||||||
|
style={{ textAlign: 'left' }}
|
||||||
|
>
|
||||||
|
{item.amountFomratted}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
style={{ textAlign: 'left' }}
|
||||||
|
>
|
||||||
|
{item.status}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
style={{ textAlign: 'left' }}
|
||||||
|
>
|
||||||
|
{item.dueDate &&
|
||||||
|
formatDateWithLocale(
|
||||||
|
item.dueDate,
|
||||||
|
location.locale
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
style={{ textAlign: 'left' }}
|
||||||
|
>
|
||||||
|
<a href={item.invoicePDF}>PDF</a>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
style={{ textAlign: 'left' }}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={item.invoiceURL}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
Payment link
|
||||||
|
</a>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</PageContent>
|
||||||
|
}
|
||||||
|
elseShow={<div>{isLoaded && 'No invoices to show.'}</div>}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default InvoiceList;
|
@ -1,11 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import Component from './invoice-list';
|
|
||||||
import { fetchInvoices } from '../../../store/e-admin-invoice/actions';
|
|
||||||
export default connect(
|
|
||||||
state => ({
|
|
||||||
location: state.settings.toJS().location || {},
|
|
||||||
invoices: state.invoiceAdmin.toJS(),
|
|
||||||
}),
|
|
||||||
{ fetchInvoices }
|
|
||||||
)(Component);
|
|
@ -1,88 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {
|
|
||||||
Table,
|
|
||||||
TableHead,
|
|
||||||
TableBody,
|
|
||||||
TableRow,
|
|
||||||
TableCell,
|
|
||||||
Button,
|
|
||||||
} from '@material-ui/core';
|
|
||||||
import OpenInNew from '@material-ui/icons/OpenInNew';
|
|
||||||
import { formatDateWithLocale } from '../../common/util';
|
|
||||||
import PageContent from '../../common/PageContent';
|
|
||||||
import HeaderTitle from '../../common/HeaderTitle';
|
|
||||||
import ConditionallyRender from '../../common/ConditionallyRender';
|
|
||||||
import { formatApiPath } from '../../../utils/format-path';
|
|
||||||
|
|
||||||
const PORTAL_URL = formatApiPath('api/admin/invoices/portal');
|
|
||||||
|
|
||||||
function InvoiceList({
|
|
||||||
location,
|
|
||||||
fetchInvoices,
|
|
||||||
invoices,
|
|
||||||
}) {
|
|
||||||
|
|
||||||
const [isLoaded, setLoaded] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchInvoices().finally(() => setLoaded(true));
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ConditionallyRender condition={invoices.length > 0}
|
|
||||||
show={
|
|
||||||
<PageContent headerContent={<HeaderTitle title="Invoices" actions={
|
|
||||||
<Button href={PORTAL_URL} rel="noreferrer" target="_blank" endIcon={<OpenInNew />}>
|
|
||||||
Billing portal
|
|
||||||
</Button>} />}>
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<Table>
|
|
||||||
<TableHead>
|
|
||||||
<TableRow>
|
|
||||||
<TableCell>Amount</TableCell>
|
|
||||||
<TableCell>Status</TableCell>
|
|
||||||
<TableCell>Due date</TableCell>
|
|
||||||
<TableCell>PDF</TableCell>
|
|
||||||
<TableCell>Link</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
<TableBody>
|
|
||||||
{invoices.map(item => (
|
|
||||||
<TableRow key={item.invoiceURL} style={{backgroundColor: item.status === 'past-due' ? '#ff9194' : 'inherit'}}>
|
|
||||||
<TableCell style={{ textAlign: 'left' }}>
|
|
||||||
{item.amountFomratted}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell style={{ textAlign: 'left' }}>
|
|
||||||
{item.status}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell style={{ textAlign: 'left' }}>
|
|
||||||
{ item.dueDate && formatDateWithLocale(
|
|
||||||
item.dueDate,
|
|
||||||
location.locale
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell style={{ textAlign: 'left' }}>
|
|
||||||
<a href={item.invoicePDF}>PDF</a>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell style={{ textAlign: 'left' }}>
|
|
||||||
<a href={item.invoiceURL} target="_blank" rel="noreferrer">Payment link</a>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
</PageContent>} elseShow={<div>{isLoaded && "No invoices to show."}</div>} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
InvoiceList.propTypes = {
|
|
||||||
location: PropTypes.object,
|
|
||||||
fetchInvoices: PropTypes.func.isRequired,
|
|
||||||
invoices: PropTypes.array.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default InvoiceList;
|
|
@ -14,8 +14,8 @@ import AddonsCreate from '../../page/addons/create';
|
|||||||
import AddonsEdit from '../../page/addons/edit';
|
import AddonsEdit from '../../page/addons/edit';
|
||||||
import Admin from '../admin';
|
import Admin from '../admin';
|
||||||
import AdminApi from '../admin/api';
|
import AdminApi from '../admin/api';
|
||||||
|
import AdminInvoice from '../admin/invoice/InvoiceAdminPage';
|
||||||
import AdminUsers from '../admin/users/UsersAdmin';
|
import AdminUsers from '../admin/users/UsersAdmin';
|
||||||
import AdminInvoice from '../admin/invoice';
|
|
||||||
import AdminAuth from '../admin/auth';
|
import AdminAuth from '../admin/auth';
|
||||||
import Login from '../user/Login/Login';
|
import Login from '../user/Login/Login';
|
||||||
import { P, C, E, EEA, RE } from '../common/flags';
|
import { P, C, E, EEA, RE } from '../common/flags';
|
||||||
|
37
frontend/src/hooks/api/getters/useInvoices/useInvoices.ts
Normal file
37
frontend/src/hooks/api/getters/useInvoices/useInvoices.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { formatApiPath } from '../../../../utils/format-path';
|
||||||
|
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||||
|
|
||||||
|
const KEY = `api/admin/invoices`;
|
||||||
|
const path = formatApiPath(KEY);
|
||||||
|
|
||||||
|
const useInvoices = (options: SWRConfiguration = {}) => {
|
||||||
|
const fetcher = () => {
|
||||||
|
return fetch(path, {
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
.then(handleErrorResponses('Invoices'))
|
||||||
|
.then(res => res.json());
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data, error } = useSWR(KEY, fetcher, options);
|
||||||
|
const [loading, setLoading] = useState(!error && !data);
|
||||||
|
|
||||||
|
const refetchInvoices = () => {
|
||||||
|
mutate(KEY);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(!error && !data);
|
||||||
|
}, [data, error]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
invoices: data?.invoices || [],
|
||||||
|
error,
|
||||||
|
loading,
|
||||||
|
refetchInvoices,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useInvoices;
|
8
frontend/src/interfaces/invoice.ts
Normal file
8
frontend/src/interfaces/invoice.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export interface IInvoice {
|
||||||
|
amountFomratted: string;
|
||||||
|
invoicePDF: string;
|
||||||
|
invoiceURL: string;
|
||||||
|
paid: boolean;
|
||||||
|
status: string;
|
||||||
|
dueDate?: Date;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user