|
|
|
|
@@ -2,7 +2,7 @@ import type { Route } from './+types/route'
|
|
|
|
|
|
|
|
|
|
import { formatCEP } from '@brazilian-utils/brazilian-utils'
|
|
|
|
|
import { zodResolver } from '@hookform/resolvers/zod'
|
|
|
|
|
import { useRequest } from 'ahooks'
|
|
|
|
|
import { useRequest, useToggle } from 'ahooks'
|
|
|
|
|
import {
|
|
|
|
|
AlertCircleIcon,
|
|
|
|
|
ArrowLeftRightIcon,
|
|
|
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
|
|
} from 'lucide-react'
|
|
|
|
|
import { useEffect } from 'react'
|
|
|
|
|
import { useForm } from 'react-hook-form'
|
|
|
|
|
import { Link } from 'react-router'
|
|
|
|
|
import { Link, useRevalidator } from 'react-router'
|
|
|
|
|
import { z } from 'zod'
|
|
|
|
|
|
|
|
|
|
import { Currency } from '@repo/ui/components/currency'
|
|
|
|
|
@@ -31,13 +31,6 @@ import {
|
|
|
|
|
CardHeader,
|
|
|
|
|
CardTitle
|
|
|
|
|
} from '@repo/ui/components/ui/card'
|
|
|
|
|
import {
|
|
|
|
|
Command,
|
|
|
|
|
CommandEmpty,
|
|
|
|
|
CommandGroup,
|
|
|
|
|
CommandItem,
|
|
|
|
|
CommandList
|
|
|
|
|
} from '@repo/ui/components/ui/command'
|
|
|
|
|
import {
|
|
|
|
|
Item,
|
|
|
|
|
ItemActions,
|
|
|
|
|
@@ -121,6 +114,13 @@ type User = {
|
|
|
|
|
type Invoice = {
|
|
|
|
|
invoice_id: string
|
|
|
|
|
secure_url: string
|
|
|
|
|
bank_slip?: {
|
|
|
|
|
bank_slip_pdf_url: string
|
|
|
|
|
}
|
|
|
|
|
pix?: {
|
|
|
|
|
qrcode: string
|
|
|
|
|
qrcode_text: string
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Attempts = {
|
|
|
|
|
@@ -180,6 +180,8 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) {
|
|
|
|
|
reset()
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
console.log(order)
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-2.5">
|
|
|
|
|
<Breadcrumb>
|
|
|
|
|
@@ -203,7 +205,8 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) {
|
|
|
|
|
|
|
|
|
|
<CardContent className="space-y-4">
|
|
|
|
|
<ItemGroup className="grid lg:grid-cols-2 gap-4">
|
|
|
|
|
<Item variant="outline">
|
|
|
|
|
<Item variant="outline" className="items-start">
|
|
|
|
|
{/* Billing address */}
|
|
|
|
|
<ItemContent>
|
|
|
|
|
<ItemTitle>Endereço de cobrança</ItemTitle>
|
|
|
|
|
<ul className="text-muted-foreground text-sm leading-normal font-normal text-balance">
|
|
|
|
|
@@ -218,14 +221,12 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) {
|
|
|
|
|
</ul>
|
|
|
|
|
</ItemContent>
|
|
|
|
|
</Item>
|
|
|
|
|
|
|
|
|
|
{/* Payment method */}
|
|
|
|
|
<Item variant="outline" className="items-start">
|
|
|
|
|
<ItemContent>
|
|
|
|
|
<ItemTitle>Forma de pagamento</ItemTitle>
|
|
|
|
|
<div className="text-muted-foreground text-sm leading-normal font-normal text-balance">
|
|
|
|
|
{Component && (
|
|
|
|
|
<Component {...order} invoice_id={invoice['invoice_id']} />
|
|
|
|
|
)}
|
|
|
|
|
{Component && <Component {...order} invoice={invoice} />}
|
|
|
|
|
</div>
|
|
|
|
|
</ItemContent>
|
|
|
|
|
|
|
|
|
|
@@ -315,8 +316,6 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) {
|
|
|
|
|
</Table>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
{/*<pre>{JSON.stringify(order, null, 2)}</pre>*/}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
@@ -337,7 +336,7 @@ type PaymentMethodProps = {
|
|
|
|
|
id: string
|
|
|
|
|
status: string
|
|
|
|
|
total: number
|
|
|
|
|
invoice_id: string
|
|
|
|
|
invoice: Invoice
|
|
|
|
|
installments: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -345,7 +344,7 @@ type BankSlipPaymentMethodProps = PaymentMethodProps & {}
|
|
|
|
|
|
|
|
|
|
function BankSlipPaymentMethod({ status }: BankSlipPaymentMethodProps) {
|
|
|
|
|
return (
|
|
|
|
|
<ul className="flex max-lg:flex-col gap-x-1.5">
|
|
|
|
|
<ul className="flex gap-x-1.5">
|
|
|
|
|
<li>Boleto bancário</li>
|
|
|
|
|
<li>
|
|
|
|
|
<Status status={status} />
|
|
|
|
|
@@ -356,8 +355,27 @@ function BankSlipPaymentMethod({ status }: BankSlipPaymentMethodProps) {
|
|
|
|
|
|
|
|
|
|
type PixPaymentMethodrops = PaymentMethodProps & {}
|
|
|
|
|
|
|
|
|
|
function PixPaymentMethod({}: PixPaymentMethodrops) {
|
|
|
|
|
return <>Pix</>
|
|
|
|
|
function PixPaymentMethod({ invoice, status }: PixPaymentMethodrops) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<ul className="flex gap-x-1.5">
|
|
|
|
|
<li>Pix</li>
|
|
|
|
|
<li>
|
|
|
|
|
<Status status={status} />
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
{invoice?.pix ? (
|
|
|
|
|
<div
|
|
|
|
|
className="font-mono text-xs break-all p-2.5 border
|
|
|
|
|
rounded-md text-red-900 dark:text-yellow-600
|
|
|
|
|
bg-gray-50 dark:bg-muted/50 select-all"
|
|
|
|
|
>
|
|
|
|
|
{invoice.pix.qrcode_text}
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function UnknownPaymentMethod() {
|
|
|
|
|
@@ -365,7 +383,7 @@ function UnknownPaymentMethod() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type CreditCardPaymentMethodProps = PaymentMethodProps & {
|
|
|
|
|
stats: { last_attempt_succeeded: boolean }
|
|
|
|
|
stats?: { last_attempt_succeeded: boolean }
|
|
|
|
|
credit_card: { last4: string; brand: string }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -375,22 +393,20 @@ function CreditCardPaymentMethod({
|
|
|
|
|
total,
|
|
|
|
|
credit_card,
|
|
|
|
|
installments,
|
|
|
|
|
invoice_id,
|
|
|
|
|
invoice,
|
|
|
|
|
stats
|
|
|
|
|
}: CreditCardPaymentMethodProps) {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<ul className="flex max-lg:flex-col gap-x-1.5">
|
|
|
|
|
<ul className="lg:flex gap-x-1">
|
|
|
|
|
<li>
|
|
|
|
|
{credit_card.brand} (Crédito) **** {credit_card.last4}
|
|
|
|
|
<Abbr maxLen={6}>{credit_card.brand}</Abbr>
|
|
|
|
|
</li>
|
|
|
|
|
<li>(Crédito) **** {credit_card.last4}</li>
|
|
|
|
|
<li>
|
|
|
|
|
{stats.last_attempt_succeeded === false ? (
|
|
|
|
|
<Badge
|
|
|
|
|
variant="outline"
|
|
|
|
|
className="text-red-400 border-red-400 px-1.5"
|
|
|
|
|
>
|
|
|
|
|
<AlertCircleIcon /> Pagamento não aprovado
|
|
|
|
|
{stats?.last_attempt_succeeded === false ? (
|
|
|
|
|
<Badge variant="outline" className="text-red-400 px-1.5">
|
|
|
|
|
<AlertCircleIcon /> Negado
|
|
|
|
|
</Badge>
|
|
|
|
|
) : (
|
|
|
|
|
<Status status={status} />
|
|
|
|
|
@@ -402,13 +418,13 @@ function CreditCardPaymentMethod({
|
|
|
|
|
{installments}x <Currency>{total / Number(installments)}</Currency>
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
{stats.last_attempt_succeeded === false ? (
|
|
|
|
|
<div className="flex justify-center mt-2">
|
|
|
|
|
{stats?.last_attempt_succeeded === false && invoice?.invoice_id ? (
|
|
|
|
|
<div className="lg:flex justify-center mt-2">
|
|
|
|
|
<CreditCardPaymentDialog
|
|
|
|
|
id={id}
|
|
|
|
|
total={total}
|
|
|
|
|
installments={installments}
|
|
|
|
|
invoice_id={invoice_id}
|
|
|
|
|
invoice_id={invoice.invoice_id}
|
|
|
|
|
>
|
|
|
|
|
<Button size="sm" variant="secondary" className="cursor-pointer">
|
|
|
|
|
<ArrowLeftRightIcon /> Pagar com outro cartão
|
|
|
|
|
@@ -433,6 +449,8 @@ function CreditCardPaymentDialog({
|
|
|
|
|
invoice_id,
|
|
|
|
|
total
|
|
|
|
|
}) {
|
|
|
|
|
const revalidator = useRevalidator()
|
|
|
|
|
const [open, { set: setOpen, toggle }] = useToggle()
|
|
|
|
|
const { runAsync } = useRequest(
|
|
|
|
|
async ({ credit_card }) => {
|
|
|
|
|
return await fetch(`/~/api/orders/${id}/payment-retries`, {
|
|
|
|
|
@@ -448,13 +466,13 @@ function CreditCardPaymentDialog({
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const onSubmit = async ({ credit_card }: Schema) => {
|
|
|
|
|
const r = await runAsync({ credit_card })
|
|
|
|
|
console.log(r.ok)
|
|
|
|
|
console.log(await r.json())
|
|
|
|
|
await runAsync({ credit_card })
|
|
|
|
|
revalidator.revalidate()
|
|
|
|
|
setOpen(false)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Dialog>
|
|
|
|
|
<Dialog open={open} onOpenChange={toggle}>
|
|
|
|
|
<DialogTrigger asChild>{children}</DialogTrigger>
|
|
|
|
|
|
|
|
|
|
<DialogContent className="sm:max-w-[425px]">
|
|
|
|
|
@@ -502,17 +520,13 @@ function PaymentAttemptsMenu({
|
|
|
|
|
return (
|
|
|
|
|
<Popover>
|
|
|
|
|
<PopoverTrigger asChild>
|
|
|
|
|
<Button variant="ghost" className="cursor-pointer">
|
|
|
|
|
<Button variant="ghost" className="cursor-pointer" size="icon-sm">
|
|
|
|
|
<EllipsisIcon />
|
|
|
|
|
</Button>
|
|
|
|
|
</PopoverTrigger>
|
|
|
|
|
<PopoverContent align="end" className="w-76">
|
|
|
|
|
{/* <div className="border-b p-2 text-xs text-muted-foreground font-medium">
|
|
|
|
|
Transações
|
|
|
|
|
</div>*/}
|
|
|
|
|
<div className="p-2 space-y-1.5">
|
|
|
|
|
{payment_attempts.map(
|
|
|
|
|
({ sk, brand, last4, status, ...props }, index) => {
|
|
|
|
|
{payment_attempts.map(({ sk, brand, last4, status }, index) => {
|
|
|
|
|
const [, , created_at] = sk.split('#')
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
@@ -536,15 +550,14 @@ function PaymentAttemptsMenu({
|
|
|
|
|
<li className="ml-auto">**** {last4}</li>
|
|
|
|
|
<li className="flex items-center">
|
|
|
|
|
{status === 'FAILED' ? (
|
|
|
|
|
<CircleXIcon className="size-4 text-red-500" />
|
|
|
|
|
<CircleXIcon className="size-4 text-red-400" />
|
|
|
|
|
) : (
|
|
|
|
|
<CircleCheckIcon className="size-4 text-green-500" />
|
|
|
|
|
<CircleCheckIcon className="size-4 text-green-400" />
|
|
|
|
|
)}
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
)}
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
</PopoverContent>
|
|
|
|
|
</Popover>
|
|
|
|
|
|