reditect to order

This commit is contained in:
2026-01-14 21:08:23 -03:00
parent d893114e38
commit a3e4fe887d
22 changed files with 1105 additions and 1157 deletions

View File

@@ -56,6 +56,7 @@ app.include_router(orgs.billing, prefix='/orgs')
app.include_router(orgs.custom_pricing, prefix='/orgs') app.include_router(orgs.custom_pricing, prefix='/orgs')
app.include_router(orgs.scheduled, prefix='/orgs') app.include_router(orgs.scheduled, prefix='/orgs')
app.include_router(orgs.submissions, prefix='/orgs') app.include_router(orgs.submissions, prefix='/orgs')
app.include_router(orgs.seats, prefix='/orgs')
app.include_router(orgs.users, prefix='/orgs') app.include_router(orgs.users, prefix='/orgs')
app.include_router(orgs.batch_jobs, prefix='/orgs') app.include_router(orgs.batch_jobs, prefix='/orgs')

View File

@@ -24,6 +24,7 @@ def get_order(order_id: str):
TransactKey(order_id) TransactKey(order_id)
+ SortKey('0') + SortKey('0')
+ SortKey('ITEMS', rename_key='items') + SortKey('ITEMS', rename_key='items')
+ SortKey('CREATED_BY', rename_key='created_by')
+ SortKey('ADDRESS', rename_key='address') + SortKey('ADDRESS', rename_key='address')
+ SortKey('CREDIT_CARD', rename_key='credit_card') + SortKey('CREDIT_CARD', rename_key='credit_card')
+ SortKey('INVOICE', rename_key='invoice') + SortKey('INVOICE', rename_key='invoice')
@@ -38,7 +39,11 @@ def get_order(order_id: str):
attempts = dyn.collection.query(KeyPair(order_id, 'TRANSACTION#ATTEMPT#')) attempts = dyn.collection.query(KeyPair(order_id, 'TRANSACTION#ATTEMPT#'))
enrollments = dyn.collection.query(KeyPair(order_id, 'ENROLLMENT#')) enrollments = dyn.collection.query(KeyPair(order_id, 'ENROLLMENT#'))
return order | { return (
'attempts': attempts['items'], order
| {
'payment_attempts': attempts['items'],
'enrollments': enrollments['items'], 'enrollments': enrollments['items'],
} }
| ({'paid_at': order['payment_date']} if 'payment_date' in order else {})
)

View File

@@ -7,6 +7,7 @@ from http import HTTPStatus
from typing import Any, Literal from typing import Any, Literal
from uuid import uuid4 from uuid import uuid4
from aws_lambda_powertools import Logger
from aws_lambda_powertools.event_handler.api_gateway import Router from aws_lambda_powertools.event_handler.api_gateway import Router
from aws_lambda_powertools.event_handler.exceptions import ( from aws_lambda_powertools.event_handler.exceptions import (
NotFoundError, NotFoundError,
@@ -30,6 +31,7 @@ from config import DUE_DAYS, ORDER_TABLE
from routes.enrollments.enroll import Enrollment from routes.enrollments.enroll import Enrollment
router = Router() router = Router()
logger = Logger(__name__)
dyn = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client) dyn = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client)
@@ -138,6 +140,7 @@ def checkout(payload: Checkout):
org_id = payload.org_id org_id = payload.org_id
address = payload.address address = payload.address
credit_card = payload.credit_card credit_card = payload.credit_card
created_by = payload.created_by
items = payload.items items = payload.items
enrollments = payload.enrollments enrollments = payload.enrollments
coupon = payload.coupon coupon = payload.coupon
@@ -201,6 +204,17 @@ def checkout(payload: Checkout):
| address.model_dump() | address.model_dump()
) )
if created_by:
transact.put(
item={
'id': order_id,
'sk': 'CREATED_BY',
'user_id': created_by.id,
'name': created_by.name,
'created_at': now_,
}
)
if credit_card: if credit_card:
transact.put( transact.put(
item={ item={

View File

@@ -5,6 +5,7 @@ from .billing import router as billing
from .custom_pricing import router as custom_pricing from .custom_pricing import router as custom_pricing
from .enrollments.scheduled import router as scheduled from .enrollments.scheduled import router as scheduled
from .enrollments.submissions import router as submissions from .enrollments.submissions import router as submissions
from .seats import router as seats
from .users.add import router as users from .users.add import router as users
from .users.batch_jobs import router as batch_jobs from .users.batch_jobs import router as batch_jobs
@@ -16,6 +17,7 @@ __all__ = [
'custom_pricing', 'custom_pricing',
'scheduled', 'scheduled',
'submissions', 'submissions',
'seats',
'users', 'users',
'batch_jobs', 'batch_jobs',
] ]

View File

@@ -102,7 +102,6 @@ def test_checkout_coupon(
lambda_context, lambda_context,
) )
body = json.loads(r['body']) body = json.loads(r['body'])
print(body)
assert r['statusCode'] == HTTPStatus.CREATED assert r['statusCode'] == HTTPStatus.CREATED
r = dynamodb_persistence_layer.collection.query(PartitionKey(body['id'])) r = dynamodb_persistence_layer.collection.query(PartitionKey(body['id']))
@@ -125,7 +124,7 @@ def test_checkout_from_user(
'cpf': '07879819908', 'cpf': '07879819908',
'name': 'Sérgio R Siqueira', 'name': 'Sérgio R Siqueira',
'email': 'sergio@somosbeta.com.br', 'email': 'sergio@somosbeta.com.br',
'payment_method': 'MANUAL', 'payment_method': 'BANK_SLIP',
'address': { 'address': {
'sk': 'METADATA#ADDRESS', 'sk': 'METADATA#ADDRESS',
'address1': 'Rua Monsenhor Ivo Zanlorenzi', 'address1': 'Rua Monsenhor Ivo Zanlorenzi',

View File

@@ -1,11 +1,11 @@
import { BellIcon } from 'lucide-react' import { BellIcon } from 'lucide-react'
import { Button } from '@repo/ui/components/ui/button'
import { import {
Popover, Popover,
PopoverContent, PopoverContent,
PopoverTrigger PopoverTrigger
} from '@repo/ui/components/ui/popover' } from '@repo/ui/components/ui/popover'
import { Button } from '@repo/ui/components/ui/button'
export function Notification() { export function Notification() {
return ( return (

View File

@@ -1,5 +1,5 @@
import { type ReactNode, createContext, useContext } from 'react'
import { type LucideIcon } from 'lucide-react' import { type LucideIcon } from 'lucide-react'
import { createContext, useContext, type ReactNode } from 'react'
import { cn } from '@repo/ui/lib/utils' import { cn } from '@repo/ui/lib/utils'

View File

@@ -4,8 +4,8 @@ import React, {
useContext, useContext,
useMemo, useMemo,
useState, useState,
type ReactNode, type ReactElement,
type ReactElement type ReactNode
} from 'react' } from 'react'
type WizardContextProps = (name: string) => void type WizardContextProps = (name: string) => void

View File

@@ -1,13 +1,13 @@
'use client' 'use client'
import { formatCNPJ } from '@brazilian-utils/brazilian-utils' import { formatCNPJ } from '@brazilian-utils/brazilian-utils'
import { IconRosetteDiscountCheckFilled } from '@tabler/icons-react'
import { import {
CheckIcon,
BadgeCheckIcon, BadgeCheckIcon,
CheckIcon,
ChevronsUpDownIcon, ChevronsUpDownIcon,
PlusIcon PlusIcon
} from 'lucide-react' } from 'lucide-react'
import { IconRosetteDiscountCheckFilled } from '@tabler/icons-react'
import { createContext, use } from 'react' import { createContext, use } from 'react'
import { useLocation } from 'react-router' import { useLocation } from 'react-router'

View File

@@ -1,4 +1,4 @@
import { type LoaderFunctionArgs, createContext } from 'react-router' import { createContext, type LoaderFunctionArgs } from 'react-router'
import { userContext } from '@repo/auth/context' import { userContext } from '@repo/auth/context'
import { request as req } from '@repo/util/request' import { request as req } from '@repo/util/request'

View File

@@ -1,15 +1,15 @@
import { useSearchParams } from 'react-router' import { addMonths, subMonths } from 'date-fns'
import { ChevronRightIcon, ChevronLeftIcon } from 'lucide-react' import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
import { subMonths, addMonths } from 'date-fns'
import { DateTime as LuxonDateTime } from 'luxon' import { DateTime as LuxonDateTime } from 'luxon'
import { useSearchParams } from 'react-router'
import { TZ } from '@/conf' import { TZ } from '@/conf'
import { DateTime } from '@repo/ui/components/datetime'
import { Badge } from '@repo/ui/components/ui/badge'
import { Button } from '@repo/ui/components/ui/button' import { Button } from '@repo/ui/components/ui/button'
import { ButtonGroup } from '@repo/ui/components/ui/button-group' import { ButtonGroup } from '@repo/ui/components/ui/button-group'
import { Badge } from '@repo/ui/components/ui/badge'
import { DateTime } from '@repo/ui/components/datetime'
import { formatDate, billingPeriod } from './util' import { billingPeriod, formatDate } from './util'
type RangePeriodProps = { type RangePeriodProps = {
startDate: Date startDate: Date

View File

@@ -1,15 +1,26 @@
import type { Route } from './+types/route' import type { Route } from './+types/route'
import Fuse from 'fuse.js' import Fuse from 'fuse.js'
import { BanIcon } from 'lucide-react'
import { DateTime as LuxonDateTime } from 'luxon' import { DateTime as LuxonDateTime } from 'luxon'
import { Suspense, useMemo } from 'react' import { Suspense, useMemo } from 'react'
import { BanIcon } from 'lucide-react'
import { Await, useSearchParams } from 'react-router' import { Await, useSearchParams } from 'react-router'
import { cn } from '@repo/ui/lib/utils' import { Abbr } from '@repo/ui/components/abbr'
import { request as req } from '@repo/util/request' import { Currency } from '@repo/ui/components/currency'
import { DateTime } from '@repo/ui/components/datetime'
import { SearchForm } from '@repo/ui/components/search-form'
import { Skeleton } from '@repo/ui/components/skeleton' import { Skeleton } from '@repo/ui/components/skeleton'
import { Button } from '@repo/ui/components/ui/button'
import { Card, CardContent } from '@repo/ui/components/ui/card' import { Card, CardContent } from '@repo/ui/components/ui/card'
import {
Empty,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle
} from '@repo/ui/components/ui/empty'
import { Kbd } from '@repo/ui/components/ui/kbd'
import { import {
Table, Table,
TableBody, TableBody,
@@ -19,24 +30,13 @@ import {
TableHeader, TableHeader,
TableRow TableRow
} from '@repo/ui/components/ui/table' } from '@repo/ui/components/ui/table'
import { Abbr } from '@repo/ui/components/abbr' import { cn } from '@repo/ui/lib/utils'
import { Button } from '@repo/ui/components/ui/button' import { request as req } from '@repo/util/request'
import { SearchForm } from '@repo/ui/components/search-form'
import {
Empty,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle
} from '@repo/ui/components/ui/empty'
import { Kbd } from '@repo/ui/components/ui/kbd'
import { Currency } from '@repo/ui/components/currency'
import { DateTime } from '@repo/ui/components/datetime'
import { TZ } from '@/conf' import { TZ } from '@/conf'
import { billingPeriod, formatDate } from './util'
import { RangePeriod } from './range-period'
import { statuses } from './data' import { statuses } from './data'
import { RangePeriod } from './range-period'
import { billingPeriod, formatDate } from './util'
export function meta({}) { export function meta({}) {
return [{ title: 'Resumo de cobranças' }] return [{ title: 'Resumo de cobranças' }]

View File

@@ -2,27 +2,36 @@ import type { Route } from './+types/route'
import { import {
AlertCircleIcon, AlertCircleIcon,
BanIcon,
CalendarIcon,
CheckCircle2Icon, CheckCircle2Icon,
ClockIcon, ClockIcon,
CalendarIcon,
UserIcon,
BanIcon,
PlusIcon,
EllipsisIcon, EllipsisIcon,
RotateCcw PlusIcon,
RotateCcw,
UserIcon
} from 'lucide-react' } from 'lucide-react'
import { Link, useParams } from 'react-router'
import { Suspense } from 'react'
import { DateTime as LuxonDateTime } from 'luxon' import { DateTime as LuxonDateTime } from 'luxon'
import { Suspense } from 'react'
import { Link, useParams } from 'react-router'
import { Abbr } from '@repo/ui/components/abbr'
import { DateTime } from '@repo/ui/components/datetime'
import { Skeleton } from '@repo/ui/components/skeleton'
import { import {
Empty, Alert,
EmptyContent, AlertDescription,
EmptyDescription, AlertTitle
EmptyHeader, } from '@repo/ui/components/ui/alert'
EmptyMedia, import {
EmptyTitle Breadcrumb,
} from '@repo/ui/components/ui/empty' BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator
} from '@repo/ui/components/ui/breadcrumb'
import { Button } from '@repo/ui/components/ui/button'
import { import {
Card, Card,
CardContent, CardContent,
@@ -31,31 +40,22 @@ import {
CardHeader, CardHeader,
CardTitle CardTitle
} from '@repo/ui/components/ui/card' } from '@repo/ui/components/ui/card'
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator
} from '@repo/ui/components/ui/breadcrumb'
import {
Alert,
AlertDescription,
AlertTitle
} from '@repo/ui/components/ui/alert'
import { request as req } from '@repo/util/request'
import { Skeleton } from '@repo/ui/components/skeleton'
import { Await } from 'react-router'
import { Abbr } from '@repo/ui/components/abbr'
import { Button } from '@repo/ui/components/ui/button'
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger DropdownMenuTrigger
} from '@repo/ui/components/ui/dropdown-menu' } from '@repo/ui/components/ui/dropdown-menu'
import { DateTime } from '@repo/ui/components/datetime' import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle
} from '@repo/ui/components/ui/empty'
import { request as req } from '@repo/util/request'
import { Await } from 'react-router'
export function meta({}: Route.MetaArgs) { export function meta({}: Route.MetaArgs) {
return [{ title: 'Relatório de matrículas' }] return [{ title: 'Relatório de matrículas' }]
@@ -69,9 +69,7 @@ export async function loader({ context, request, params }: Route.LoaderArgs) {
request request
}).then((r) => r.json()) }).then((r) => r.json())
return { return { submission }
submission
}
} }
export default function Route({ export default function Route({

View File

@@ -1,17 +1,12 @@
import type { Route } from './+types/route' import type { Route } from './+types/route'
import { useEffect, useState } from 'react'
import { useFetcher, Link } from 'react-router'
import { useMount } from 'ahooks' import { useMount } from 'ahooks'
import { BookSearchIcon, CircleCheckBigIcon, WalletIcon } from 'lucide-react' import { BookSearchIcon, CircleCheckBigIcon, WalletIcon } from 'lucide-react'
import { use, useEffect, useState } from 'react'
import { Link, redirect, useFetcher } from 'react-router'
import { import { cloudflareContext, userContext } from '@repo/auth/context'
Card, import { Skeleton } from '@repo/ui/components/skeleton'
CardContent,
CardHeader,
CardDescription,
CardTitle
} from '@repo/ui/components/ui/card'
import { import {
Breadcrumb, Breadcrumb,
BreadcrumbItem, BreadcrumbItem,
@@ -20,22 +15,27 @@ import {
BreadcrumbPage, BreadcrumbPage,
BreadcrumbSeparator BreadcrumbSeparator
} from '@repo/ui/components/ui/breadcrumb' } from '@repo/ui/components/ui/breadcrumb'
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle
} from '@repo/ui/components/ui/card'
import { Label } from '@repo/ui/components/ui/label'
import { Switch } from '@repo/ui/components/ui/switch' import { Switch } from '@repo/ui/components/ui/switch'
import { createSearch } from '@repo/util/meili' import { createSearch } from '@repo/util/meili'
import { cloudflareContext, userContext } from '@repo/auth/context' import { HttpMethod, request as req } from '@repo/util/request'
import { Label } from '@repo/ui/components/ui/label'
import { Skeleton } from '@repo/ui/components/skeleton'
import { request as req, HttpMethod } from '@repo/util/request'
import { INTERNAL_EMAIL_DOMAIN } from '@/conf'
import { workspaceContext } from '@/middleware/workspace'
import { useWorksapce } from '@/components/workspace-switcher'
import { Step, StepItem, StepSeparator } from '@/components/step' import { Step, StepItem, StepSeparator } from '@/components/step'
import { Wizard, WizardStep } from '@/components/wizard' import { Wizard, WizardStep } from '@/components/wizard'
import { useWorksapce } from '@/components/workspace-switcher'
import { INTERNAL_EMAIL_DOMAIN } from '@/conf'
import { workspaceContext } from '@/middleware/workspace'
import type { Course } from '../_.$orgid.enrollments.add/data' import type { Course } from '../_.$orgid.enrollments.add/data'
import { Assigned } from './assigned'
import { Bulk } from './bulk' import { Bulk } from './bulk'
import { Payment } from './payment' import { Payment } from './payment'
import { Assigned } from './assigned'
import { Review } from './review' import { Review } from './review'
import { useWizardStore } from './store' import { useWizardStore } from './store'
@@ -43,7 +43,7 @@ export function meta({}: Route.MetaArgs) {
return [{ title: 'Comprar matrículas' }] return [{ title: 'Comprar matrículas' }]
} }
export async function loader({ context }: Route.LoaderArgs) { export async function loader({ context, params, request }: Route.LoaderArgs) {
const cloudflare = context.get(cloudflareContext) const cloudflare = context.get(cloudflareContext)
const courses = createSearch<Course>({ const courses = createSearch<Course>({
index: 'saladeaula_courses', index: 'saladeaula_courses',
@@ -53,10 +53,16 @@ export async function loader({ context }: Route.LoaderArgs) {
env: cloudflare.env env: cloudflare.env
}) })
return { courses } const seats = req({
url: `/orgs/${params.orgid}/seats`,
request,
context
}).then((r) => r.json() as any)
return { courses, seats }
} }
export async function action({ params, request, context }: Route.ActionArgs) { export async function action({ request, context }: Route.ActionArgs) {
const body = (await request.json()) as object const body = (await request.json()) as object
const user = context.get(userContext)! const user = context.get(userContext)!
const { activeWorkspace } = context.get(workspaceContext) const { activeWorkspace } = context.get(workspaceContext)
@@ -83,13 +89,12 @@ export async function action({ params, request, context }: Route.ActionArgs) {
return { ok: false, error } return { ok: false, error }
} }
console.log(await r.json()) const { id } = (await r.json()) as { id: string }
throw redirect(`../payments/${id}`)
return { ok: true }
} }
export default function Route({ export default function Route({
loaderData: { courses } loaderData: { courses, seats: seats_ }
}: Route.ComponentProps) { }: Route.ComponentProps) {
const fetcher = useFetcher() const fetcher = useFetcher()
const [mounted, setMounted] = useState(false) const [mounted, setMounted] = useState(false)
@@ -97,6 +102,9 @@ export default function Route({
const { index, kind, setIndex, setKind, reset, update, ...state } = const { index, kind, setIndex, setKind, reset, update, ...state } =
useWizardStore() useWizardStore()
// @TODO
const seats = use(seats_)
const onSubmit = async () => { const onSubmit = async () => {
const items = state.items.map(({ course, quantity }) => ({ const items = state.items.map(({ course, quantity }) => ({
...course, ...course,
@@ -119,14 +127,12 @@ export default function Route({
} }
}, [address]) }, [address])
useEffect(() => {
console.log(fetcher.data)
}, [fetcher.data])
if (!mounted) { if (!mounted) {
return <Skeleton /> return <Skeleton />
} }
console.log(seats)
return ( return (
<div className="space-y-2.5"> <div className="space-y-2.5">
<Breadcrumb> <Breadcrumb>

View File

@@ -1,8 +1,11 @@
import type { Route } from './+types/route' import type { Route } from './+types/route'
import { Link } from 'react-router' import { formatCEP } from '@brazilian-utils/brazilian-utils'
import { Suspense, useEffect } from 'react'
import { Await, Link } from 'react-router'
import { request as req } from '@repo/util/request' import { Currency } from '@repo/ui/components/currency'
import { Skeleton } from '@repo/ui/components/skeleton'
import { import {
Breadcrumb, Breadcrumb,
BreadcrumbItem, BreadcrumbItem,
@@ -11,6 +14,22 @@ import {
BreadcrumbPage, BreadcrumbPage,
BreadcrumbSeparator BreadcrumbSeparator
} from '@repo/ui/components/ui/breadcrumb' } from '@repo/ui/components/ui/breadcrumb'
import {
Card,
CardContent,
CardHeader,
CardTitle
} from '@repo/ui/components/ui/card'
import {
Item,
ItemContent,
ItemDescription,
ItemGroup,
ItemTitle
} from '@repo/ui/components/ui/item'
import { paymentMethods } from '@repo/ui/routes/orders/data'
import { request as req } from '@repo/util/request'
import { useWizardStore } from '../_.$orgid.enrollments.buy/store'
export function meta() { export function meta() {
return [ return [
@@ -20,28 +39,32 @@ export function meta() {
] ]
} }
export async function loader({ params, request, context }: Route.LoaderArgs) { export async function loader({ context, request, params }: Route.LoaderArgs) {
const r = await req({ const order = await req({
url: `/orders/${params.id}`, url: `/orders/${params.id}`,
request, context,
context request
}) }).then((r) => r.json())
if (!r.ok) { return { order }
throw new Response(null, { status: r.status })
}
return { order: await r.json() }
} }
export default function Route({ loaderData: { order } }: Route.ComponentProps) { export default function Route({ loaderData: { order } }: Route.ComponentProps) {
const { reset } = useWizardStore()
const { address, total, credit_card, payment_method, invoice, installments } =
order
useEffect(() => {
reset()
}, [])
return ( return (
<div className="space-y-2.5"> <div className="space-y-2.5">
<Breadcrumb> <Breadcrumb>
<BreadcrumbList> <BreadcrumbList>
<BreadcrumbItem> <BreadcrumbItem>
<BreadcrumbLink asChild> <BreadcrumbLink asChild>
<Link to="../payments">Histórico de pagamentos</Link> <Link to="../payments">Pagamentos</Link>
</BreadcrumbLink> </BreadcrumbLink>
</BreadcrumbItem> </BreadcrumbItem>
<BreadcrumbSeparator /> <BreadcrumbSeparator />
@@ -50,7 +73,55 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) {
</BreadcrumbItem> </BreadcrumbItem>
</BreadcrumbList> </BreadcrumbList>
</Breadcrumb> </Breadcrumb>
<pre>{JSON.stringify(order, null, 2)}</pre>
<Card className="lg:max-w-4xl mx-auto space-y-2.5">
<CardHeader>
<CardTitle className="text-2xl">Detalhes do pagamento</CardTitle>
</CardHeader>
<CardContent>
<ItemGroup className="grid lg:grid-cols-2 gap-4">
<Item variant="outline">
<ItemContent>
<ItemTitle>Endereço de cobrança</ItemTitle>
<ul className="text-muted-foreground text-sm leading-normal font-normal text-balance">
{address?.address1}
{address?.address2 ? <>, {address?.address2}</> : null}
<br />
{address?.neighborhood}
<br />
{address?.city}, {address?.state}
<br />
{formatCEP(address?.postcode)}
</ul>
</ItemContent>
</Item>
<Item variant="outline" className="items-start">
<ItemContent>
<ItemTitle>Forma de pagamento</ItemTitle>
<ItemDescription>
{credit_card ? (
<>
{credit_card.brand} (Crédito) **** {credit_card.last4}
<br />
{installments}x{' '}
<Currency>{total / Number(installments)}</Currency>
</>
) : (
<>
{payment_method
? paymentMethods[payment_method]
: payment_method}
</>
)}
</ItemDescription>
</ItemContent>
</Item>
</ItemGroup>
{/*<pre>{JSON.stringify(order, null, 2)}</pre>*/}
</CardContent>
</Card>
</div> </div>
) )
} }

View File

@@ -12,7 +12,7 @@
"typecheck": "npm run cf-typegen && react-router typegen && tsc -b" "typecheck": "npm run cf-typegen && react-router typegen && tsc -b"
}, },
"dependencies": { "dependencies": {
"@react-router/fs-routes": "^7.10.1", "@react-router/fs-routes": "^7.12.0",
"@repo/auth": "*", "@repo/auth": "*",
"@repo/ui": "*", "@repo/ui": "*",
"@repo/util": "^0.0.0", "@repo/util": "^0.0.0",
@@ -24,31 +24,31 @@
"fuse.js": "^7.1.0", "fuse.js": "^7.1.0",
"isbot": "^5.1.32", "isbot": "^5.1.32",
"luxon": "^3.7.2", "luxon": "^3.7.2",
"meilisearch": "^0.54.0", "meilisearch": "^0.55.0",
"meilisearch-helper": "github:sergiors/meilisearch-helper", "meilisearch-helper": "github:sergiors/meilisearch-helper",
"ramda": "^0.32.0", "ramda": "^0.32.0",
"react": "^19.2.1", "react": "^19.2.3",
"react-dom": "^19.2.1", "react-dom": "^19.2.3",
"react-router": "^7.10.1", "react-router": "^7.12.0",
"unique-names-generator": "^4.7.1", "unique-names-generator": "^4.7.1",
"zod": "^4.1.13", "zod": "^4.3.5",
"zustand": "^5.0.9" "zustand": "^5.0.10"
}, },
"devDependencies": { "devDependencies": {
"@cloudflare/vite-plugin": "^1.17.0", "@cloudflare/vite-plugin": "^1.20.3",
"@tailwindcss/vite": "^4.1.17", "@tailwindcss/vite": "^4.1.18",
"@types/file-saver": "^2.0.7", "@types/file-saver": "^2.0.7",
"@types/luxon": "^3.7.1", "@types/luxon": "^3.7.1",
"@types/node": "^24.10.1", "@types/node": "^25.0.8",
"@types/react": "^19.2.7", "@types/react": "^19.2.8",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"prettier": "^3.7.4", "prettier": "^3.7.4",
"remix-flat-routes": "^0.8.5", "remix-flat-routes": "^0.8.5",
"tailwindcss": "^4.1.17", "tailwindcss": "^4.1.18",
"tw-animate-css": "^1.4.0", "tw-animate-css": "^1.4.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vite": "^7.2.6", "vite": "^7.3.1",
"vite-tsconfig-paths": "^5.1.4", "vite-tsconfig-paths": "^6.0.4",
"wrangler": "^4.53.0" "wrangler": "^4.59.1"
} }
} }

View File

@@ -4,6 +4,7 @@ export default {
ssr: true, ssr: true,
future: { future: {
v8_viteEnvironmentApi: true, v8_viteEnvironmentApi: true,
v8_splitRouteModules: true,
v8_middleware: true v8_middleware: true
} }
} satisfies Config } satisfies Config

View File

@@ -1,6 +1,6 @@
/* eslint-disable */ /* eslint-disable */
// Generated by Wrangler by running `wrangler types` (hash: 58c6149f238624e8945df7f87e575516) // Generated by Wrangler by running `wrangler types` (hash: 58c6149f238624e8945df7f87e575516)
// Runtime types generated with workerd@1.20251202.0 2025-04-04 // Runtime types generated with workerd@1.20260111.0 2025-04-04
declare namespace Cloudflare { declare namespace Cloudflare {
interface GlobalProps { interface GlobalProps {
mainModule: typeof import("./workers/app"); mainModule: typeof import("./workers/app");
@@ -500,8 +500,10 @@ interface DurableObjectNamespaceNewUniqueIdOptions {
jurisdiction?: DurableObjectJurisdiction; jurisdiction?: DurableObjectJurisdiction;
} }
type DurableObjectLocationHint = "wnam" | "enam" | "sam" | "weur" | "eeur" | "apac" | "oc" | "afr" | "me"; type DurableObjectLocationHint = "wnam" | "enam" | "sam" | "weur" | "eeur" | "apac" | "oc" | "afr" | "me";
type DurableObjectRoutingMode = "primary-only";
interface DurableObjectNamespaceGetDurableObjectOptions { interface DurableObjectNamespaceGetDurableObjectOptions {
locationHint?: DurableObjectLocationHint; locationHint?: DurableObjectLocationHint;
routingMode?: DurableObjectRoutingMode;
} }
interface DurableObjectClass<_T extends Rpc.DurableObjectBranded | undefined = undefined> { interface DurableObjectClass<_T extends Rpc.DurableObjectBranded | undefined = undefined> {
} }
@@ -2085,6 +2087,8 @@ interface Transformer<I = any, O = any> {
expectedLength?: number; expectedLength?: number;
} }
interface StreamPipeOptions { interface StreamPipeOptions {
preventAbort?: boolean;
preventCancel?: boolean;
/** /**
* Pipes this readable stream to a given writable stream destination. The way in which the piping process behaves under various error conditions can be customized with a number of passed options. It returns a promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered. * Pipes this readable stream to a given writable stream destination. The way in which the piping process behaves under various error conditions can be customized with a number of passed options. It returns a promise that fulfills when the piping process completes successfully, or rejects if any errors were encountered.
* *
@@ -2103,8 +2107,6 @@ interface StreamPipeOptions {
* The signal option can be set to an AbortSignal to allow aborting an ongoing pipe operation via the corresponding AbortController. In this case, this source readable stream will be canceled, and destination aborted, unless the respective options preventCancel or preventAbort are set. * The signal option can be set to an AbortSignal to allow aborting an ongoing pipe operation via the corresponding AbortController. In this case, this source readable stream will be canceled, and destination aborted, unless the respective options preventCancel or preventAbort are set.
*/ */
preventClose?: boolean; preventClose?: boolean;
preventAbort?: boolean;
preventCancel?: boolean;
signal?: AbortSignal; signal?: AbortSignal;
} }
type ReadableStreamReadResult<R = any> = { type ReadableStreamReadResult<R = any> = {
@@ -2379,13 +2381,13 @@ declare abstract class TransformStreamDefaultController<O = any> {
terminate(): void; terminate(): void;
} }
interface ReadableWritablePair<R = any, W = any> { interface ReadableWritablePair<R = any, W = any> {
readable: ReadableStream<R>;
/** /**
* Provides a convenient, chainable way of piping this readable stream through a transform stream (or any other { writable, readable } pair). It simply pipes the stream into the writable side of the supplied pair, and returns the readable side for further use. * Provides a convenient, chainable way of piping this readable stream through a transform stream (or any other { writable, readable } pair). It simply pipes the stream into the writable side of the supplied pair, and returns the readable side for further use.
* *
* Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader. * Piping a stream will lock it for the duration of the pipe, preventing any other consumer from acquiring a reader.
*/ */
writable: WritableStream<W>; writable: WritableStream<W>;
readable: ReadableStream<R>;
} }
/** /**
* The **`WritableStream`** interface of the Streams API provides a standard abstraction for writing streaming data to a destination, known as a sink. * The **`WritableStream`** interface of the Streams API provides a standard abstraction for writing streaming data to a destination, known as a sink.
@@ -3261,7 +3263,7 @@ interface WorkerStubEntrypointOptions {
props?: any; props?: any;
} }
interface WorkerLoader { interface WorkerLoader {
get(name: string, getCode: () => WorkerLoaderWorkerCode | Promise<WorkerLoaderWorkerCode>): WorkerStub; get(name: string | null, getCode: () => WorkerLoaderWorkerCode | Promise<WorkerLoaderWorkerCode>): WorkerStub;
} }
interface WorkerLoaderModule { interface WorkerLoaderModule {
js?: string; js?: string;
@@ -8443,7 +8445,7 @@ type AiOptions = {
* Maximum 5 tags are allowed each request. * Maximum 5 tags are allowed each request.
* Duplicate tags will removed. * Duplicate tags will removed.
*/ */
tags: string[]; tags?: string[];
gateway?: GatewayOptions; gateway?: GatewayOptions;
returnRawResponse?: boolean; returnRawResponse?: boolean;
prefix?: string; prefix?: string;

View File

@@ -50,6 +50,7 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) {
</BreadcrumbItem> </BreadcrumbItem>
</BreadcrumbList> </BreadcrumbList>
</Breadcrumb> </Breadcrumb>
<pre>{JSON.stringify(order, null, 2)}</pre> <pre>{JSON.stringify(order, null, 2)}</pre>
</div> </div>
) )

1876
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,18 +9,18 @@
}, },
"devDependencies": { "devDependencies": {
"prettier": "^3.7.4", "prettier": "^3.7.4",
"turbo": "^2.6.3", "turbo": "^2.7.4",
"typescript": "5.9.3" "typescript": "5.9.3"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "^4.53.3", "@rollup/rollup-linux-x64-gnu": "^4.55.1",
"@tailwindcss/oxide-linux-x64-gnu": "^4.1.17", "@tailwindcss/oxide-linux-x64-gnu": "^4.1.18",
"lightningcss-linux-x64-gnu": "^1.30.2" "lightningcss-linux-x64-gnu": "^1.30.2"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
}, },
"packageManager": "npm@11.6.4", "packageManager": "npm@11.7.0",
"workspaces": [ "workspaces": [
"apps/*", "apps/*",
"packages/*" "packages/*"

View File

@@ -55,7 +55,7 @@ export const columns: ColumnDef<Order>[] = [
{ {
accessorKey: 'due_date', accessorKey: 'due_date',
enableSorting: true, enableSorting: true,
meta: { title: 'Vence em' }, meta: { title: 'Vencimento em' },
header: DataTableColumnHeaderSort, header: DataTableColumnHeaderSort,
cell: DataTableColumnDatetime cell: DataTableColumnDatetime
}, },