1
0
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:
Youssef Khedher 2022-02-04 13:41:13 +01:00 committed by GitHub
parent d146c1fcf9
commit 25ca7b7216
8 changed files with 171 additions and 110 deletions

View File

@ -86,7 +86,7 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
refetch();
setToastData({
type: 'success',
show: true,
title: 'Deleted successfully',
text: 'Successfully deleted API token.',
});
};

View File

@ -1,14 +1,12 @@
import { useContext } from 'react';
import PropTypes from 'prop-types';
import InvoiceList from './invoice-container';
import InvoiceList from './InvoiceList';
import AccessContext from '../../../contexts/AccessContext';
import { ADMIN } from '../../providers/AccessProvider/permissions';
import ConditionallyRender from '../../common/ConditionallyRender';
import { Alert } from '@material-ui/lab';
const InvoiceAdminPage = ({ history }) => {
const InvoiceAdminPage = () => {
const { hasAccess } = useContext(AccessContext);
return (
<div>
<ConditionallyRender
@ -24,9 +22,4 @@ const InvoiceAdminPage = ({ history }) => {
);
};
InvoiceAdminPage.propTypes = {
match: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
};
export default InvoiceAdminPage;

View 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;

View File

@ -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);

View File

@ -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;

View File

@ -14,8 +14,8 @@ import AddonsCreate from '../../page/addons/create';
import AddonsEdit from '../../page/addons/edit';
import Admin from '../admin';
import AdminApi from '../admin/api';
import AdminInvoice from '../admin/invoice/InvoiceAdminPage';
import AdminUsers from '../admin/users/UsersAdmin';
import AdminInvoice from '../admin/invoice';
import AdminAuth from '../admin/auth';
import Login from '../user/Login/Login';
import { P, C, E, EEA, RE } from '../common/flags';

View 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;

View File

@ -0,0 +1,8 @@
export interface IInvoice {
amountFomratted: string;
invoicePDF: string;
invoiceURL: string;
paid: boolean;
status: string;
dueDate?: Date;
}