reditect to order
This commit is contained in:
@@ -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')
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
'enrollments': enrollments['items'],
|
| {
|
||||||
}
|
'payment_attempts': attempts['items'],
|
||||||
|
'enrollments': enrollments['items'],
|
||||||
|
}
|
||||||
|
| ({'paid_at': order['payment_date']} if 'payment_date' in order else {})
|
||||||
|
)
|
||||||
|
|||||||
@@ -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={
|
||||||
|
|||||||
@@ -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',
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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' }]
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
1880
package-lock.json
generated
1880
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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/*"
|
||||||
|
|||||||
@@ -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
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user