mirror of
https://github.com/civitai/civitai.git
synced 2026-09-20 22:08:18 +08:00
904ccb83b6
* Removes imports from prisma client in frontend app * Fixes after merge conflict * Removes any traces of prisma from frontend * Removes legacyBehavior prop in next/link * Fixes after merge --------- Co-authored-by: Briant Diehl <bkdiehl@gmail.com>
206 lines
7.6 KiB
TypeScript
206 lines
7.6 KiB
TypeScript
import {
|
|
Button,
|
|
Center,
|
|
Divider,
|
|
Group,
|
|
Loader,
|
|
LoadingOverlay,
|
|
Pagination,
|
|
Paper,
|
|
Stack,
|
|
Table,
|
|
Text,
|
|
ThemeIcon,
|
|
Title,
|
|
Badge,
|
|
} from '@mantine/core';
|
|
import { useDebouncedValue } from '@mantine/hooks';
|
|
import { isEqual } from 'lodash-es';
|
|
import React, { useEffect, useState } from 'react';
|
|
import { GetPaginatedOwnedBuzzWithdrawalRequestSchema } from '../../../server/schema/buzz-withdrawal-request.schema';
|
|
import {
|
|
useMutateBuzzWithdrawalRequest,
|
|
useQueryOwnedBuzzWithdrawalRequests,
|
|
} from '../WithdrawalRequest/buzzWithdrawalRequest.util';
|
|
import { formatDate } from '../../../utils/date-helpers';
|
|
import {
|
|
formatCurrencyForDisplay,
|
|
getBuzzWithdrawalDetails,
|
|
numberWithCommas,
|
|
} from '../../../utils/number-helpers';
|
|
import { WithdrawalRequestBadgeColor, useBuzzDashboardStyles } from '../buzz.styles';
|
|
import { IconCloudOff } from '@tabler/icons-react';
|
|
import { dialogStore } from '~/components/Dialog/dialogStore';
|
|
import { CreateWithdrawalRequest } from '~/components/Buzz/WithdrawalRequest/CreateWithdrawalRequest';
|
|
import { BuzzWithdrawalRequestStatus, Currency } from '~/shared/utils/prisma/enums';
|
|
import { openConfirmModal } from '@mantine/modals';
|
|
import { showSuccessNotification } from '~/utils/notifications';
|
|
import { trpc } from '~/utils/trpc';
|
|
import { useUserPaymentConfiguration } from '~/components/UserPaymentConfiguration/util';
|
|
import { StripeConnectStatus } from '~/server/common/enums';
|
|
import BuzzWithdrawalRequestHistory from '~/components/Buzz/WithdrawalRequest/BuzzWithdrawalRequestHistory';
|
|
|
|
export function OwnedBuzzWithdrawalRequestsPaged() {
|
|
const { userPaymentConfiguration } = useUserPaymentConfiguration();
|
|
const { classes } = useBuzzDashboardStyles();
|
|
const [filters, setFilters] = useState<
|
|
Omit<GetPaginatedOwnedBuzzWithdrawalRequestSchema, 'limit'>
|
|
>({
|
|
page: 1,
|
|
});
|
|
const [debouncedFilters, cancel] = useDebouncedValue(filters, 500);
|
|
|
|
const { requests, pagination, isLoading, isRefetching } =
|
|
useQueryOwnedBuzzWithdrawalRequests(debouncedFilters);
|
|
|
|
const { cancelingBuzzWithdrawalRequest, cancelBuzzWithdrawalRequest } =
|
|
useMutateBuzzWithdrawalRequest();
|
|
|
|
//#region [useEffect] cancel debounced filters
|
|
useEffect(() => {
|
|
if (isEqual(filters, debouncedFilters)) cancel();
|
|
}, [cancel, debouncedFilters, filters]);
|
|
//#endregion
|
|
|
|
const handleCancelRequest = (id: string) => {
|
|
openConfirmModal({
|
|
title: 'Cancel withdrawal request',
|
|
children: <Text size="sm">Are you sure you want to cancel this withdrawal request?</Text>,
|
|
centered: true,
|
|
labels: { confirm: 'Cancel request', cancel: "No, don't cancel it" },
|
|
confirmProps: { color: 'red' },
|
|
closeOnConfirm: true,
|
|
onConfirm: async () => {
|
|
await cancelBuzzWithdrawalRequest({ id });
|
|
showSuccessNotification({
|
|
title: 'Withdrawal request canceled',
|
|
message: 'Withdrawal request has been canceled successfully and buzz has been refunded.',
|
|
});
|
|
},
|
|
});
|
|
};
|
|
|
|
if (!userPaymentConfiguration || !userPaymentConfiguration.tipaltiPaymentsEnabled) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<Paper withBorder p="lg" radius="md" className={classes.tileCard} id="buzz-withdrawals">
|
|
<Stack spacing="sm">
|
|
<Group position="apart">
|
|
<Title order={2}>Withdrawal Requests</Title>
|
|
<Button
|
|
onClick={() => {
|
|
dialogStore.trigger({
|
|
component: CreateWithdrawalRequest,
|
|
});
|
|
}}
|
|
>
|
|
Withdraw
|
|
</Button>
|
|
</Group>
|
|
<Divider />
|
|
{isLoading ? (
|
|
<Center p="xl">
|
|
<Loader />
|
|
</Center>
|
|
) : !!requests.length ? (
|
|
<div style={{ position: 'relative' }}>
|
|
<LoadingOverlay visible={isRefetching ?? false} zIndex={9} />
|
|
<Table>
|
|
<thead>
|
|
<tr>
|
|
<th>Requested at</th>
|
|
<th>Buzz Amount</th>
|
|
<th>Platform fee rate</th>
|
|
<th>Dollar Amount Total</th>
|
|
<th>Application Fee</th>
|
|
<th>Payout amount</th>
|
|
<th>Status</th>
|
|
<th> </th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{requests.map((request) => {
|
|
const { dollarAmount, platformFee, payoutAmount } = getBuzzWithdrawalDetails(
|
|
request.requestedBuzzAmount,
|
|
request.platformFeeRate
|
|
);
|
|
|
|
const hasReachedStripe = [
|
|
BuzzWithdrawalRequestStatus.Transferred,
|
|
BuzzWithdrawalRequestStatus.Reverted,
|
|
].some((t) => t === request.status);
|
|
|
|
return (
|
|
<tr key={request.id}>
|
|
<td>{formatDate(request.createdAt)}</td>
|
|
<td>{numberWithCommas(request.requestedBuzzAmount)}</td>
|
|
<td>{numberWithCommas(request.platformFeeRate / 100)}%</td>
|
|
<td>${formatCurrencyForDisplay(dollarAmount, Currency.USD)}</td>
|
|
<td>${formatCurrencyForDisplay(platformFee, Currency.USD)}</td>
|
|
<td>
|
|
<Stack spacing={0}>
|
|
<Text
|
|
color={
|
|
hasReachedStripe
|
|
? WithdrawalRequestBadgeColor[request.status]
|
|
: undefined
|
|
}
|
|
weight={hasReachedStripe ? 'bold' : undefined}
|
|
>
|
|
${formatCurrencyForDisplay(payoutAmount, Currency.USD)}{' '}
|
|
</Text>
|
|
</Stack>
|
|
</td>
|
|
<td>
|
|
<Badge variant="light" color={WithdrawalRequestBadgeColor[request.status]}>
|
|
{request.status}
|
|
</Badge>
|
|
</td>
|
|
<td align="right">
|
|
<Group>
|
|
{request.status === BuzzWithdrawalRequestStatus.Requested && (
|
|
<Button
|
|
color="red"
|
|
onClick={() => {
|
|
handleCancelRequest(request.id);
|
|
}}
|
|
loading={cancelingBuzzWithdrawalRequest}
|
|
size="xs"
|
|
>
|
|
<Text size="sm">Cancel</Text>
|
|
</Button>
|
|
)}
|
|
<BuzzWithdrawalRequestHistory history={request.history} />
|
|
</Group>
|
|
</td>
|
|
</tr>
|
|
);
|
|
})}
|
|
</tbody>
|
|
{pagination && pagination.totalPages > 1 && (
|
|
<Group position="apart">
|
|
<Text>Total {pagination.totalItems.toLocaleString()} items</Text>
|
|
<Pagination
|
|
page={filters.page}
|
|
onChange={(page) => setFilters((curr) => ({ ...curr, page }))}
|
|
total={pagination.totalPages}
|
|
/>
|
|
</Group>
|
|
)}
|
|
</Table>
|
|
</div>
|
|
) : (
|
|
<Stack align="center">
|
|
<ThemeIcon size={62} radius={100}>
|
|
<IconCloudOff />
|
|
</ThemeIcon>
|
|
<Text align="center">Looks like no withdrawal requests have been made. Start now!</Text>
|
|
</Stack>
|
|
)}
|
|
</Stack>
|
|
</Paper>
|
|
);
|
|
}
|