@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
262 lines (261 loc) • 20.7 kB
JavaScript
import { __awaiter, __rest } from "tslib";
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useEffect, useState } from 'react';
import { Box, Chip, Paper, Table, TableBody, Skeleton, TableCell, TableContainer, TableHead, TableRow, Typography, Stack, CircularProgress, styled, Grid, TextField, InputAdornment, IconButton, Icon, Button, useTheme, useMediaQuery, MenuItem } from '@mui/material';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import LoadingButton from '@mui/lab/LoadingButton';
import { useInView } from 'react-intersection-observer';
import { PaymentService } from '@selfcommunity/api-services';
import { useThemeProps } from '@mui/system';
import classNames from 'classnames';
import { useSCContext, useSCPaymentsEnabled } from '@selfcommunity/react-core';
import { getConvertedAmount } from '../../utils/payment';
import Event from '../Event';
import { SCContentType } from '@selfcommunity/types';
import { CacheStrategies, Logger } from '@selfcommunity/utils';
import { SCCourseTemplateType, SCEventTemplateType } from '../../types';
import Course from '../Course';
import Group from '../Group';
import PaymentProduct from '../PaymentProduct';
import PaymentOrderPdfButton from '../PaymentOrderPdfButton';
import { SCOPE_SC_UI } from '../../constants/Errors';
import HiddenPlaceholder from '../../shared/HiddenPlaceholder';
import { LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import itLocale from 'date-fns/locale/it';
import enLocale from 'date-fns/locale/en-US';
import Category from '../Category';
const PREFIX = 'SCPaymentOrders';
const messages = defineMessages({
dateFrom: {
id: 'ui.paymentOrders.dateFrom',
defaultMessage: 'ui.paymentOrders.dateFrom'
},
dateTo: {
id: 'ui.paymentOrders.dateTo',
defaultMessage: 'ui.paymentOrders.dateTo'
},
pickerCancelAction: {
id: 'ui.paymentOrders.picker.cancel',
defaultMessage: 'ui.paymentOrders.picker.cancel'
},
pickerClearAction: {
id: 'ui.paymentOrders.picker.clear',
defaultMessage: 'ui.paymentOrders.picker.clear'
}
});
const classes = {
root: `${PREFIX}-root`,
content: `${PREFIX}-content`,
filters: `${PREFIX}-filters`,
search: `${PREFIX}-search`,
picker: `${PREFIX}-picker`
};
const options = [
{
value: SCContentType.ALL,
label: _jsx(FormattedMessage, { id: "ui.paymentOrders.contentType.all", defaultMessage: "ui.paymentOrders.contentType.all" })
},
{
value: SCContentType.COMMUNITY,
label: _jsx(FormattedMessage, { id: "ui.paymentOrders.contentType.community", defaultMessage: "ui.paymentOrders.contentType.community" })
},
{
value: SCContentType.COURSE,
label: _jsx(FormattedMessage, { id: "ui.paymentOrders.contentType.course", defaultMessage: "ui.paymentOrders.contentType.course" })
},
{
value: SCContentType.EVENT,
label: _jsx(FormattedMessage, { id: "ui.paymentOrders.contentType.event", defaultMessage: "ui.paymentOrders.contentType.event" })
},
{
value: SCContentType.GROUP,
label: _jsx(FormattedMessage, { id: "ui.paymentOrders.contentType.group", defaultMessage: "ui.paymentOrders.contentType.group" })
}
];
const Root = styled(Paper, {
slot: 'Root',
name: PREFIX
})(() => ({}));
export default function PaymentOrders(inProps) {
// PROPS
const props = useThemeProps({
props: inProps,
name: PREFIX
});
const { className, contentName = '', contentType = SCContentType.ALL } = props, rest = __rest(props, ["className", "contentName", "contentType"]);
// STATE
const [isLoading, setIsLoading] = useState(true);
const [orders, setInvoices] = useState([]);
const [hasMore, setHasMore] = useState(true);
const [isLoadingPage, setIsLoadingPage] = useState(false);
const [query, setQuery] = useState(contentName);
const [contentTypeFilter, setContentTypeFilter] = useState(contentType);
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
// HOOKS
const { isPaymentsEnabled } = useSCPaymentsEnabled();
const { ref, inView } = useInView({ triggerOnce: false });
const intl = useIntl();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
// CONTEXT
const scContext = useSCContext();
//HANDLERS
const formatDate = (date) => {
return date.toISOString().split('T')[0];
};
/**
* Handle change filter name
* @param event
*/
const handleChange = (event) => {
setQuery(event.target.value);
};
/**
* Handle content type change
* @param event
*/
const handleContentTypeChange = (event) => {
setContentTypeFilter(event.target.value);
};
/**
* Initial Invoices fetch
*/
const fetchInvoices = (searchValue = query) => __awaiter(this, void 0, void 0, function* () {
setIsLoading(true);
setHasMore(true);
setInvoices([]);
try {
const res = yield PaymentService.getPaymentsOrder(Object.assign(Object.assign(Object.assign(Object.assign({ offset: 0, ordering: '-created_at' }, (searchValue && { search: searchValue })), (contentTypeFilter && contentTypeFilter !== SCContentType.ALL && { content_type: contentTypeFilter })), (startDate && { created_at__gte: formatDate(startDate) })), (endDate && { created_at__lt: formatDate(endDate) })));
if (res) {
setInvoices(res.results);
setHasMore(res.next !== null);
}
}
catch (error) {
Logger.error(SCOPE_SC_UI, error);
}
finally {
setIsLoading(false);
}
});
/**
* Infinite load more orders
*/
const loadMore = useCallback(() => __awaiter(this, void 0, void 0, function* () {
if (!hasMore || isLoadingPage || isLoading)
return;
setIsLoadingPage(true);
try {
const res = yield PaymentService.getPaymentsOrder(Object.assign(Object.assign(Object.assign(Object.assign({ offset: orders.length, ordering: '-created_at' }, (query && { search: query })), (contentTypeFilter && contentTypeFilter !== SCContentType.ALL && { content_type: contentTypeFilter })), (startDate && { created_at__gte: formatDate(startDate) })), (endDate && { created_at__lt: formatDate(endDate) })));
if (res) {
setInvoices((prev) => prev.concat(res.results));
setHasMore(res.next !== null);
}
}
catch (error) {
Logger.error(SCOPE_SC_UI, error);
}
finally {
setIsLoadingPage(false);
}
}), [orders.length, query, hasMore, isLoadingPage, isLoading, contentTypeFilter, startDate, endDate]);
const renderContent = (order) => {
var _a;
const contentType = order.content_type;
const content = order[order.content_type];
if (contentType === SCContentType.EVENT) {
return (_jsx(Event, { event: content, cacheStrategy: CacheStrategies.NETWORK_ONLY, template: SCEventTemplateType.SNIPPET, actions: _jsx(_Fragment, {}), variant: "outlined" }));
}
else if (contentType === SCContentType.CATEGORY) {
return _jsx(Category, { category: content, cacheStrategy: CacheStrategies.NETWORK_ONLY, actions: _jsx(_Fragment, {}), variant: "outlined" });
}
else if (contentType === SCContentType.COURSE) {
return (_jsx(Course, { course: content, cacheStrategy: CacheStrategies.NETWORK_ONLY, template: SCCourseTemplateType.SNIPPET, variant: "outlined", actions: _jsx(_Fragment, {}) }));
}
else if (contentType === SCContentType.GROUP) {
return _jsx(Group, { group: content, cacheStrategy: CacheStrategies.NETWORK_ONLY, hideActions: true, variant: "outlined" });
}
else if (contentType === SCContentType.COMMUNITY) {
if ((_a = order === null || order === void 0 ? void 0 : order.payment_price) === null || _a === void 0 ? void 0 : _a.payment_product) {
return _jsx(PaymentProduct, { hidePaymentProductPrices: true, paymentProduct: order.payment_price.payment_product });
}
return null;
}
};
/**
* Load more orders
*/
useEffect(() => {
if (inView) {
loadMore();
}
}, [inView, loadMore]);
/**
* Initial load
*/
useEffect(() => {
fetchInvoices();
}, [contentTypeFilter, endDate]);
if (!isPaymentsEnabled) {
return _jsx(HiddenPlaceholder, {});
}
/**
* Render skeleton
*/
const skeleton = () => {
return (_jsxs(TableRow, Object.assign({ ref: ref }, { children: [_jsx(TableCell, Object.assign({ component: "th", scope: "row" }, { children: _jsx(Skeleton, { variant: "text", height: 40, width: 20 }) })), _jsx(TableCell, Object.assign({ component: "th", scope: "row" }, { children: _jsx(Skeleton, { variant: "text", height: 40, width: 30 }) })), _jsx(TableCell, Object.assign({ component: "th", scope: "row" }, { children: _jsx(Skeleton, { variant: "text", height: 80, width: 250 }) })), _jsx(TableCell, Object.assign({ component: "th", scope: "row" }, { children: _jsx(Skeleton, { variant: "text", height: 40, width: 65 }) })), _jsx(TableCell, Object.assign({ component: "th", scope: "row" }, { children: _jsx(Skeleton, { variant: "text", height: 40, width: 65 }) })), _jsx(TableCell, Object.assign({ component: "th", scope: "row" }, { children: _jsx(Skeleton, { variant: "text", height: 40, width: 65 }) })), _jsx(TableCell, Object.assign({ component: "th", scope: "row" }, { children: _jsx(Skeleton, { variant: "text", height: 40, width: 65 }) })), _jsx(TableCell, Object.assign({ component: "th", scope: "row" }, { children: _jsx(Skeleton, { variant: "text", height: 40, width: 65 }) }))] })));
};
return (_jsxs(Root, Object.assign({ variant: "outlined", className: classNames(classes.root, className) }, rest, { children: [_jsxs(Grid, Object.assign({ container: true, className: classes.filters, gap: 3 }, { children: [_jsx(Grid, Object.assign({ item: true, xs: 12, sm: 12, md: 3, lg: 3 }, { children: _jsx(TextField, { className: classes.search, size: 'small', fullWidth: true, value: query, label: _jsx(FormattedMessage, { id: "ui.paymentOrders.search", defaultMessage: "ui.paymentOrders.search" }), variant: "outlined", onChange: handleChange, disabled: isLoading, onKeyUp: (e) => {
e.preventDefault();
if (e.key === 'Enter') {
fetchInvoices();
}
}, InputProps: {
endAdornment: (_jsxs(InputAdornment, Object.assign({ position: "end" }, { children: [query.length > 0 && (_jsx(IconButton, Object.assign({ onClick: () => {
setQuery('');
fetchInvoices('');
}, disabled: isLoading }, { children: _jsx(Icon, { children: "close" }) }))), isMobile ? (_jsx(IconButton, { onClick: () => fetchInvoices(), disabled: isLoading })) : (_jsx(Button, { size: "small", variant: "contained", color: "secondary", onClick: () => fetchInvoices(), endIcon: _jsx(Icon, { children: "search" }), disabled: isLoading }))] })))
} }) })), _jsx(Grid, Object.assign({ item: true, xs: 12, sm: 12, md: 3, lg: 3 }, { children: _jsx(TextField, Object.assign({ select: true, fullWidth: true, disabled: isLoading, size: "small", label: _jsx(FormattedMessage, { id: "ui.paymentOrders.contentTypeFilter", defaultMessage: "ui.paymentOrders.contentTypeFilter" }), value: contentTypeFilter, onChange: handleContentTypeChange }, { children: options.map((option) => (_jsx(MenuItem, Object.assign({ value: option.value }, { children: option.label }), option.value))) })) })), _jsx(Grid, Object.assign({ item: true, xs: 12, sm: 8, md: 4 }, { children: _jsx(LocalizationProvider, Object.assign({ dateAdapter: AdapterDateFns, adapterLocale: scContext.settings.locale.default === 'it' ? itLocale : enLocale, localeText: {
cancelButtonLabel: `${intl.formatMessage(messages.pickerCancelAction)}`,
clearButtonLabel: `${intl.formatMessage(messages.pickerClearAction)}`
} }, { children: _jsxs(Grid, Object.assign({ container: true, spacing: 2 }, { children: [_jsx(Grid, Object.assign({ item: true, xs: 6 }, { children: _jsx(MobileDatePicker, { className: classes.picker, label: _jsx(FormattedMessage, { id: "ui.paymentOrders.dateFrom", defaultMessage: "ui.paymentOrders.dateFrom" }), value: startDate, slots: {
textField: (params) => (_jsx(TextField, Object.assign({}, params, { size: "small", InputProps: Object.assign(Object.assign({}, params.InputProps), { placeholder: `${intl.formatMessage(messages.dateFrom)}`, endAdornment: (_jsx(InputAdornment, Object.assign({ position: "end" }, { children: _jsx(IconButton, { children: _jsx(Icon, { children: "CalendarIcon" }) }) }))) }) })))
}, slotProps: {
actionBar: {
actions: ['cancel', 'clear', 'accept']
},
toolbar: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore,@typescript-eslint/ban-ts-comment
// @ts-ignore
toolbarTitle: _jsx(FormattedMessage, { id: "ui.paymentOrders.picker.date", defaultMessage: "ui.paymentOrders.picker.date" })
}
}, onChange: (newValue) => setStartDate(newValue) }) })), _jsx(Grid, Object.assign({ item: true, xs: 6 }, { children: _jsx(MobileDatePicker, { className: classes.picker, label: _jsx(FormattedMessage, { id: "ui.paymentOrders.dateTo", defaultMessage: "ui.paymentOrders.dateTo" }), value: endDate, slots: {
textField: (params) => (_jsx(TextField, Object.assign({}, params, { size: "small", InputProps: Object.assign(Object.assign({}, params.InputProps), { placeholder: `${intl.formatMessage(messages.dateTo)}`, endAdornment: (_jsx(InputAdornment, Object.assign({ position: "end" }, { children: _jsx(IconButton, { children: _jsx(Icon, { children: "CalendarIcon" }) }) }))) }) })))
}, slotProps: {
actionBar: {
actions: ['cancel', 'clear', 'accept']
},
toolbar: {
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore,@typescript-eslint/ban-ts-comment
// @ts-ignore
toolbarTitle: _jsx(FormattedMessage, { id: "ui.paymentOrders.picker.date", defaultMessage: "ui.paymentOrders.picker.date" })
}
}, onChange: (newValue) => setEndDate(newValue) }) }))] })) })) }))] })), _jsx(Box, Object.assign({ className: classes.content }, { children: !isLoading ? (_jsx(TableContainer, Object.assign({ style: { margin: 'auto', borderRadius: 0 } }, { children: _jsxs(Table, Object.assign({ sx: { minWidth: 650 }, "aria-label": "simple table", stickyHeader: true }, { children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, Object.assign({ width: "5%" }, { children: _jsx(FormattedMessage, { id: "ui.paymentOrders.number", defaultMessage: "ui.paymentOrders.number" }) })), _jsx(TableCell, Object.assign({ width: "7%" }, { children: _jsx(FormattedMessage, { id: "ui.paymentOrders.contentType", defaultMessage: "ui.paymentOrders.contentType" }) })), _jsx(TableCell, Object.assign({ width: "38%" }, { children: _jsx(FormattedMessage, { id: "ui.paymentOrders.content", defaultMessage: "ui.paymentOrders.content" }) })), _jsx(TableCell, Object.assign({ width: "10%" }, { children: _jsx(FormattedMessage, { id: "ui.paymentOrders.price", defaultMessage: "ui.paymentOrders.price" }) })), _jsx(TableCell, Object.assign({ width: "12%" }, { children: _jsx(FormattedMessage, { id: "ui.paymentOrders.createdAt", defaultMessage: "ui.paymentOrders.createdAt" }) })), _jsx(TableCell, Object.assign({ width: "13%" }, { children: _jsx(FormattedMessage, { id: "ui.paymentOrders.expired_at", defaultMessage: "ui.paymentOrders.expired_at" }) })), _jsx(TableCell, Object.assign({ width: "10%" }, { children: _jsx(FormattedMessage, { id: "ui.paymentOrders.status", defaultMessage: "ui.paymentOrders.status" }) })), _jsx(TableCell, { children: _jsx(FormattedMessage, { id: "ui.paymentOrders.actions", defaultMessage: "ui.paymentOrders.actions" }) })] }) }), _jsxs(TableBody, { children: [orders.map((order, index) => (_jsxs(TableRow, { children: [_jsx(TableCell, Object.assign({ scope: "row" }, { children: _jsx("b", { children: order.id }) })), _jsx(TableCell, Object.assign({ scope: "row" }, { children: _jsx(FormattedMessage, { id: `ui.paymentOrders.contentType.${order.content_type}`, defaultMessage: `ui.paymentOrders.contentType.${order.content_type}` }) })), _jsx(TableCell, Object.assign({ scope: "row" }, { children: renderContent(order) })), _jsx(TableCell, Object.assign({ scope: "row" }, { children: getConvertedAmount(order.payment_price) })), _jsx(TableCell, Object.assign({ scope: "row" }, { children: order.created_at &&
intl.formatDate(new Date(order.created_at), {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}) })), _jsx(TableCell, Object.assign({ scope: "row" }, { children: order.expired_at
? intl.formatDate(new Date(order.expired_at), {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
})
: '-' })), _jsx(TableCell, Object.assign({ scope: "row" }, { children: _jsx(Chip, { variant: 'outlined', label: _jsx(FormattedMessage, { id: "ui.paymentOrders.status.paid", defaultMessage: "ui.paymentOrders.status.paid" }), color: "success", size: "small" }) })), _jsx(TableCell, Object.assign({ scope: "row" }, { children: _jsxs(Stack, Object.assign({ direction: "row", justifyContent: "left", alignItems: "center", spacing: 2 }, { children: [order.content_type === SCContentType.EVENT && _jsx(PaymentOrderPdfButton, { paymentOrder: order }), Boolean(!order.paid && order.billing_reason === 'subscription_create') && (_jsx(LoadingButton, Object.assign({ size: "small", variant: "contained", disabled: true }, { children: _jsx(FormattedMessage, { id: "ui.paymentOrders.pay", defaultMessage: "ui.paymentOrders.pay" }) })))] })) }))] }, index))), orders.length < 1 && (_jsx(TableRow, { children: _jsx(TableCell, Object.assign({ align: "left", colSpan: 6 }, { children: _jsx(Typography, Object.assign({ variant: "body2" }, { children: _jsx(FormattedMessage, { id: "ui.paymentOrders.noOrders", defaultMessage: "ui.paymentOrders.noOrders" }) })) })) })), hasMore && _jsx(_Fragment, { children: skeleton() })] })] })) }))) : (_jsx(CircularProgress, {})) }))] })));
}