remove subscription endpoint

This commit is contained in:
2026-01-17 16:39:48 -03:00
parent d26abc02c9
commit d0a9998bf4
19 changed files with 450 additions and 192 deletions

View File

@@ -75,9 +75,9 @@ export function WorkspaceSwitcher() {
className="aria-expanded:border flex aspect-square size-8 items-center justify-center rounded-lg relative"
aria-expanded={state === 'expanded'}
>
{subscription && (
{subscription ? (
<BadgeCheckIcon className="fill-blue-500 stroke-white absolute size-4 dark:size-3.5 -top-1.5 -right-1.5" />
)}
) : null}
{initials(activeWorkspace.name)}
</div>

View File

@@ -53,33 +53,18 @@ export const workspaceMiddleware = async (
({ id }) => id === org_id
) as Workspace
const [subscription, address] = await Promise.all([
req({
url: `/orgs/${activeWorkspace.id}/subscription`,
request,
context
})
.then((r) => r.json())
.then(emptyObjectToNull),
req({
url: `/orgs/${activeWorkspace.id}/address`,
request,
context
})
.then((r) => r.json())
.then(emptyObjectToNull)
])
const org = (await req({
url: `/orgs/${activeWorkspace.id}`,
request,
context
}).then((r) => r.json())) as any
context.set(workspaceContext, {
activeWorkspace,
workspaces,
subscription,
address
subscription: org?.['subscription'] || null,
address: org?.['address'] || null
})
return await next()
}
const emptyObjectToNull = (data: any) =>
data && Object.keys(data).length === 0 ? null : data

View File

@@ -34,6 +34,7 @@ import { cn } from '@repo/ui/lib/utils'
import { request as req } from '@repo/util/request'
import { TZ } from '@/conf'
import { workspaceContext } from '@/middleware/workspace'
import { statuses } from './data'
import { RangePeriod } from './range-period'
import { billingPeriod, formatDate } from './util'
@@ -43,16 +44,9 @@ export function meta({}) {
}
export async function loader({ context, request, params }: Route.LoaderArgs) {
const workspace = context.get(workspaceContext)
const { searchParams } = new URL(request.url)
const subscription = await req({
url: `/orgs/${params.orgid}/subscription`,
context,
request
})
const { billing_day = 1 } = (await subscription.json()) as {
billing_day: number
}
const { billing_day = 1 } = workspace?.subscription || {}
const [startDate, endDate] = billingPeriod(
billing_day,

View File

@@ -9,6 +9,7 @@ import {
CircleCheckIcon,
CircleXIcon,
EllipsisIcon,
ExternalLinkIcon,
HelpCircleIcon
} from 'lucide-react'
import { useEffect } from 'react'
@@ -355,9 +356,14 @@ function BankSlipPaymentMethod({
{invoice?.bank_slip ? (
<>
<Button variant="link" asChild>
<Button
size="sm"
variant="secondary"
className="cursor-pointer"
asChild
>
<a href={invoice.bank_slip.bank_slip_pdf_url} target="_blank">
Abrir o boleto bancário
<ExternalLinkIcon /> Abrir o boleto bancário
</a>
</Button>
</>

View File

@@ -1,13 +1,18 @@
import type { Route } from './+types/route'
import { useEffect } from 'react'
import { zodResolver } from '@hookform/resolvers/zod'
import { PatternFormat } from 'react-number-format'
import { useFetcher, Link, useOutletContext } from 'react-router'
import { AlertCircleIcon } from 'lucide-react'
import { useEffect } from 'react'
import { useForm } from 'react-hook-form'
import { PatternFormat } from 'react-number-format'
import { Link, useFetcher, useOutletContext } from 'react-router'
import { toast } from 'sonner'
import {
Alert,
AlertDescription,
AlertTitle
} from '@repo/ui/components/ui/alert'
import { Button } from '@repo/ui/components/ui/button'
import {
Card,
@@ -27,13 +32,9 @@ import {
import { Input } from '@repo/ui/components/ui/input'
import { Spinner } from '@repo/ui/components/ui/spinner'
import { type User } from '@repo/ui/routes/users/data'
import {
Alert,
AlertDescription,
AlertTitle
} from '@repo/ui/components/ui/alert'
import { request as req, HttpMethod } from '@repo/util/request'
import { HttpMethod, request as req } from '@repo/util/request'
import { FieldSet } from '@repo/ui/components/ui/field'
import { formSchema, type Schema } from '../_.$orgid.users.add/data'
export async function action({ params, request, context }: Route.ActionArgs) {
@@ -109,80 +110,84 @@ export default function Route({}: Route.ComponentProps) {
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<FormField
control={control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Nome</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<CardContent>
<FieldSet>
<FormField
control={control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Nome</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={control}
name="email"
disabled={true}
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormLabel className="text-sm font-normal text-muted-foreground">
<span>
Para gerenciar os emails ou trocar o email principal,
use as{' '}
<Link
to="emails"
className="text-blue-400 underline hover:no-underline"
>
configurações de emails
</Link>
</span>
</FormLabel>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={control}
name="email"
disabled={true}
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormLabel className="text-sm font-normal text-muted-foreground">
<span>
Para gerenciar os emails ou trocar o email principal,
use as{' '}
<Link
to="emails"
className="text-blue-400 underline hover:no-underline"
>
configurações de emails
</Link>
</span>
</FormLabel>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={control}
name="cpf"
render={({ field: { onChange, ref, ...props } }) => (
<FormItem>
<FormLabel>CPF</FormLabel>
<FormControl>
<PatternFormat
format="###.###.###-##"
mask="_"
placeholder="___.___.___-__"
customInput={Input}
getInputRef={ref}
onValueChange={({ value }) => {
onChange(value)
}}
{...props}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={control}
name="cpf"
render={({ field: { onChange, ref, ...props } }) => (
<FormItem>
<FormLabel>CPF</FormLabel>
<FormControl>
<PatternFormat
format="###.###.###-##"
mask="_"
placeholder="___.___.___-__"
customInput={Input}
getInputRef={ref}
onValueChange={({ value }) => {
onChange(value)
}}
{...props}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button
type="submit"
className="cursor-pointer"
disabled={formState.isSubmitting}
>
{formState.isSubmitting && <Spinner />}
Editar
</Button>
<div className="flex justify-end">
<Button
type="submit"
className="cursor-pointer"
disabled={formState.isSubmitting}
>
{formState.isSubmitting && <Spinner />}
Editar
</Button>
</div>
</FieldSet>
</CardContent>
</Card>
</fieldset>

View File

@@ -1,23 +1,23 @@
import type { Route } from './+types/route'
import * as cookie from 'cookie'
import { Outlet, type ShouldRevalidateFunctionArgs } from 'react-router'
import { useEffect } from 'react'
import { Outlet, type ShouldRevalidateFunctionArgs } from 'react-router'
import { userContext } from '@repo/auth/context'
import { authMiddleware } from '@repo/auth/middleware/auth'
import { ModeToggle, ThemedImage } from '@repo/ui/components/dark-mode'
import { NavUser } from '@repo/ui/components/nav-user'
import {
SidebarInset,
SidebarProvider,
SidebarTrigger
} from '@repo/ui/components/ui/sidebar'
import { userContext } from '@repo/auth/context'
import { authMiddleware } from '@repo/auth/middleware/auth'
import { Toaster } from '@repo/ui/components/ui/sonner'
import { ModeToggle, ThemedImage } from '@repo/ui/components/dark-mode'
import { NavUser } from '@repo/ui/components/nav-user'
import { WorkspaceProvider } from '@/components/workspace-switcher'
import { AppSidebar } from '@/components/app-sidebar'
import { workspaceMiddleware, workspaceContext } from '@/middleware/workspace'
import { WorkspaceProvider } from '@/components/workspace-switcher'
import { workspaceContext, workspaceMiddleware } from '@/middleware/workspace'
// import { Notification } from '@/components/notification'

View File

@@ -5,18 +5,19 @@ import { useToggle } from 'ahooks'
import { EllipsisIcon, FileBadgeIcon } from 'lucide-react'
import type { ComponentProps } from 'react'
import {
DataTableColumnHeaderSelect,
DataTableColumnSelect
} from '@repo/ui/components/data-table/column-select'
import { Button } from '@repo/ui/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger
} from '@repo/ui/components/ui/dropdown-menu'
import { Spinner } from '@repo/ui/components/ui/spinner'
import {
DataTableColumnHeaderSelect,
DataTableColumnSelect
} from '@repo/ui/components/data-table/column-select'
import {
columns as columns_,
type Enrollment
@@ -65,12 +66,13 @@ function ActionMenu({ row }: { row: any }) {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-46 *:cursor-pointer">
<CopyToClipboardItem text={row.id} />
<DownloadItem
id={row.id}
disabled={!cert}
onSuccess={() => setOpen(false)}
/>
<DropdownMenuSeparator />
<CopyToClipboardItem text={row.id} />
</DropdownMenuContent>
</DropdownMenu>
</div>

View File

@@ -0,0 +1,168 @@
import type { Route } from './+types/route'
import { useForm } from 'react-hook-form'
import { Link } from 'react-router'
import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar'
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator
} from '@repo/ui/components/ui/breadcrumb'
import { Button } from '@repo/ui/components/ui/button'
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle
} from '@repo/ui/components/ui/card'
import { FieldSet } from '@repo/ui/components/ui/field'
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage
} from '@repo/ui/components/ui/form'
import { Input } from '@repo/ui/components/ui/input'
import { initials } from '@repo/ui/lib/utils'
import { request as req } from '@repo/util/request'
import { BadgeCheckIcon } from 'lucide-react'
export function meta() {
return [
{
title: 'Editar empresa'
}
]
}
export async function loader({ params, request, context }: Route.LoaderArgs) {
const r = await req({
url: `/orgs/${params.id}`,
request,
context
})
if (!r.ok) {
throw new Response(null, { status: r.status })
}
return { org: await r.json() } as { org: any }
}
export default function Route({ loaderData: { org } }: Route.ComponentProps) {
const form = useForm({ defaultValues: org })
const { handleSubmit } = form
const onSubmit = async () => {}
return (
<div className="space-y-2.5">
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link to="../orgs">Empresas</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Editar empresa</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
<div className="lg:max-w-2xl mx-auto space-y-2.5">
<div className="flex gap-2.5 items-center mb-5">
<div className="relative">
{org?.subscription ? (
<BadgeCheckIcon className="fill-blue-500 stroke-white absolute size-4 dark:size-3.5 -top-0 -right-0 z-2" />
) : null}
<Avatar className="size-12">
<AvatarFallback>{initials(org.name)}</AvatarFallback>
</Avatar>
</div>
<ul>
<li className="font-bold text-lg">{org.name}</li>
<li className="text-muted-foreground text-sm truncate max-lg:max-w-62">
{org.email}
</li>
</ul>
</div>
<Form {...form}>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-8">
<Card>
<CardHeader>
<CardTitle className="font-semibold text-2xl">
Editar empresa
</CardTitle>
<CardDescription>
Configurar as informações gerais para esta empresa.
</CardDescription>
</CardHeader>
<CardContent>
<FieldSet disabled={true}>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Nome</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="cnpj"
render={({ field }) => (
<FormItem>
<FormLabel>CNPJ</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-end">
<Button type="submit">Editar</Button>
</div>
</FieldSet>
</CardContent>
</Card>
</form>
</Form>
</div>
</div>
)
}

View File

@@ -1,23 +1,27 @@
'use client'
import { type ColumnDef } from '@tanstack/react-table'
import { EllipsisIcon } from 'lucide-react'
import { EllipsisIcon, PencilIcon } from 'lucide-react'
import { NavLink } from 'react-router'
import { Button } from '@repo/ui/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger
} from '@repo/ui/components/ui/dropdown-menu'
import { Abbr } from '@repo/ui/components/abbr'
import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar'
import { initials } from '@repo/ui/lib/utils'
import {
DataTableColumnCpfCnpj,
DataTableColumnDatetime,
DataTableColumnHeaderSelect,
DataTableColumnSelect
} from '@repo/ui/components/data-table'
import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar'
import { Button } from '@repo/ui/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger
} from '@repo/ui/components/ui/dropdown-menu'
import { Spinner } from '@repo/ui/components/ui/spinner'
import { initials } from '@repo/ui/lib/utils'
import type { Org } from '@repo/ui/routes/orgs/data'
import { CopyToClipboardItem } from '../_app.users._index/columns'
@@ -86,6 +90,17 @@ function ActionMenu({ row }: { row: any }) {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-36 *:cursor-pointer">
<DropdownMenuItem asChild onSelect={(e) => e.preventDefault()}>
<NavLink to={`${row.id}`}>
{({ isPending }) => (
<>
{isPending ? <Spinner /> : <PencilIcon />}
Editar
</>
)}
</NavLink>
</DropdownMenuItem>
<DropdownMenuSeparator />
<CopyToClipboardItem text={row.id} />
</DropdownMenuContent>
</DropdownMenu>