Files
mtdb_movie/common/resources/client/admin/plans/plans-index-page.tsx
maher 703f50a09d
Some checks failed
Build / run (push) Has been cancelled
first commit
2025-10-29 11:42:25 +01:00

165 lines
4.9 KiB
TypeScript
Executable File

import React, {Fragment} from 'react';
import {DataTablePage} from '../../datatable/page/data-table-page';
import {IconButton} from '../../ui/buttons/icon-button';
import {EditIcon} from '../../icons/material/Edit';
import {FormattedDate} from '../../i18n/formatted-date';
import {ColumnConfig} from '../../datatable/column-config';
import {Trans} from '../../i18n/trans';
import {DataTableEmptyStateMessage} from '../../datatable/page/data-table-emty-state-message';
import softwareEngineerSvg from './../tags/software-engineer.svg';
import {DataTableAddItemButton} from '../../datatable/data-table-add-item-button';
import {Product} from '../../billing/product';
import {NameWithAvatar} from '../../datatable/column-templates/name-with-avatar';
import {Link} from 'react-router-dom';
import {FormattedPrice} from '../../i18n/formatted-price';
import {SyncIcon} from '../../icons/material/Sync';
import {useSyncProducts} from './requests/use-sync-products';
import {Tooltip} from '../../ui/tooltip/tooltip';
import {useDeleteProduct} from './requests/use-delete-product';
import {DeleteIcon} from '../../icons/material/Delete';
import {DialogTrigger} from '../../ui/overlays/dialog/dialog-trigger';
import {ConfirmationDialog} from '../../ui/overlays/dialog/confirmation-dialog';
import {useNavigate} from '../../utils/hooks/use-navigate';
import {PlansIndexPageFilters} from './plans-index-page-filters';
const columnConfig: ColumnConfig<Product>[] = [
{
key: 'name',
allowsSorting: true,
visibleInMode: 'all',
header: () => <Trans message="Name" />,
body: product => {
const price = product.prices[0];
return (
<NameWithAvatar
label={product.name}
description={
product.free ? (
<Trans message="Free" />
) : (
<FormattedPrice price={price} />
)
}
/>
);
},
},
{
key: 'created_at',
allowsSorting: true,
maxWidth: 'max-w-100',
header: () => <Trans message="Created" />,
body: product => <FormattedDate date={product.created_at} />,
},
{
key: 'updated_at',
allowsSorting: true,
maxWidth: 'max-w-100',
header: () => <Trans message="Last updated" />,
body: product => <FormattedDate date={product.updated_at} />,
},
{
key: 'actions',
header: () => <Trans message="Actions" />,
visibleInMode: 'all',
hideHeader: true,
align: 'end',
maxWidth: 'max-w-84',
body: product => {
return (
<Fragment>
<IconButton
size="md"
className="text-muted"
elementType={Link}
to={`/admin/plans/${product.id}/edit`}
>
<EditIcon />
</IconButton>
<DeleteProductButton product={product} />
</Fragment>
);
},
},
];
export function PlansIndexPage() {
const navigate = useNavigate();
return (
<DataTablePage
endpoint="billing/products"
title={<Trans message="Subscription plans" />}
columns={columnConfig}
actions={<Actions />}
enableSelection={false}
filters={PlansIndexPageFilters}
onRowAction={item => {
navigate(`/admin/plans/${item.id}/edit`);
}}
emptyStateMessage={
<DataTableEmptyStateMessage
image={softwareEngineerSvg}
title={<Trans message="No plans have been created yet" />}
filteringTitle={<Trans message="No matching plans" />}
/>
}
/>
);
}
interface DeleteProductButtonProps {
product: Product;
}
function DeleteProductButton({product}: DeleteProductButtonProps) {
const deleteProduct = useDeleteProduct();
return (
<DialogTrigger
type="modal"
onClose={confirmed => {
if (confirmed) {
deleteProduct.mutate({productId: product.id});
}
}}
>
<Tooltip label={<Trans message="Delete plan" />}>
<IconButton
size="md"
className="text-muted"
disabled={deleteProduct.isPending}
>
<DeleteIcon />
</IconButton>
</Tooltip>
<ConfirmationDialog
title={<Trans message="Delete plan" />}
body={<Trans message="Are you sure you want to delete this plan?" />}
confirm={<Trans message="Delete" />}
/>
</DialogTrigger>
);
}
function Actions() {
const syncPlans = useSyncProducts();
return (
<Fragment>
<Tooltip label={<Trans message="Sync plans with Stripe & PayPal" />}>
<IconButton
color="primary"
variant="outline"
size="sm"
disabled={syncPlans.isPending}
onClick={() => {
syncPlans.mutate();
}}
>
<SyncIcon />
</IconButton>
</Tooltip>
<DataTableAddItemButton elementType={Link} to="/admin/plans/new">
<Trans message="Add new plan" />
</DataTableAddItemButton>
</Fragment>
);
}