UNPKG

@selfcommunity/react-ui

Version:

React UI Components to integrate a Community created with SelfCommunity Platform.

262 lines (261 loc) • 20.7 kB
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, {})) }))] }))); }