add subscription to org

This commit is contained in:
2026-01-17 23:45:25 -03:00
parent d0a9998bf4
commit 3f0f7ec1e1
14 changed files with 550 additions and 367 deletions

View File

@@ -1,6 +1,5 @@
import type { Route } from './+types/route'
import type { MouseEvent, ReactNode } from 'react'
import { useRequest, useToggle } from 'ahooks'
import {
AlertTriangleIcon,
@@ -15,44 +14,15 @@ import {
RocketIcon,
UserIcon
} from 'lucide-react'
import { toast } from 'sonner'
import { DateTime as LuxonDateTime } from 'luxon'
import type { MouseEvent, ReactNode } from 'react'
import { Fragment, Suspense } from 'react'
import { Await } from 'react-router'
import { toast } from 'sonner'
import { request as req } from '@repo/util/request'
import { Button } from '@repo/ui/components/ui/button'
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle
} from '@repo/ui/components/ui/empty'
import { Skeleton } from '@repo/ui/components/skeleton'
import { Card, CardContent } from '@repo/ui/components/ui/card'
import {
Item,
ItemActions,
ItemContent,
ItemDescription,
ItemGroup,
ItemMedia,
ItemSeparator,
ItemTitle
} from '@repo/ui/components/ui/item'
import { Link } from 'react-router'
import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar'
import { initials } from '@repo/ui/lib/utils'
import { Abbr } from '@repo/ui/components/abbr'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger
} from '@repo/ui/components/ui/dropdown-menu'
import { DateTime } from '@repo/ui/components/datetime'
import { Skeleton } from '@repo/ui/components/skeleton'
import {
AlertDialog,
AlertDialogAction,
@@ -64,17 +34,44 @@ import {
AlertDialogTitle,
AlertDialogTrigger
} from '@repo/ui/components/ui/alert-dialog'
import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar'
import { Button } from '@repo/ui/components/ui/button'
import { Card, CardContent } from '@repo/ui/components/ui/card'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger
} from '@repo/ui/components/ui/dropdown-menu'
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle
} from '@repo/ui/components/ui/empty'
import {
Item,
ItemActions,
ItemContent,
ItemDescription,
ItemGroup,
ItemMedia,
ItemSeparator,
ItemTitle
} from '@repo/ui/components/ui/item'
import { Spinner } from '@repo/ui/components/ui/spinner'
import { useParams } from 'react-router'
import { useRevalidator } from 'react-router'
import { DateTime } from '@repo/ui/components/datetime'
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger
} from '@repo/ui/components/ui/tabs'
import { useSearchParams } from 'react-router'
import { initials } from '@repo/ui/lib/utils'
import { request as req } from '@repo/util/request'
import { Link, useParams, useRevalidator, useSearchParams } from 'react-router'
export function meta({}: Route.MetaArgs) {
return [{ title: 'Matrículas agendadas' }]
@@ -442,8 +439,8 @@ function ActionMenu({ sk }: { sk: string }) {
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="*:cursor-pointer w-42">
<Proceedtem sk={sk} onSuccess={onSuccess} />
<DropdownMenuSeparator />
{/* <Proceedtem sk={sk} onSuccess={onSuccess} />
<DropdownMenuSeparator />*/}
<CancelItem sk={sk} onSuccess={onSuccess} />
</DropdownMenuContent>
</DropdownMenu>

View File

@@ -89,108 +89,104 @@ export default function Route({}: Route.ComponentProps) {
return (
<Form {...form}>
<form onSubmit={handleSubmit(onSubmit)}>
<fieldset disabled={!!user?.rate_limit_exceeded} className="space-y-4">
{user?.rate_limit_exceeded && (
<Alert variant="destructive">
<AlertCircleIcon />
<AlertTitle>Limite diário de atualizações atingido.</AlertTitle>
<AlertDescription>
Tente novamente a partir de{' '}
{getDaysRemaining(user.rate_limit_exceeded.ttl)}
</AlertDescription>
</Alert>
)}
<form onSubmit={handleSubmit(onSubmit)} className="space-y-3">
{user?.rate_limit_exceeded && (
<Alert variant="destructive">
<AlertCircleIcon />
<AlertTitle>Limite diário de atualizações atingido.</AlertTitle>
<AlertDescription>
Tente novamente a partir de{' '}
{getDaysRemaining(user.rate_limit_exceeded.ttl)}
</AlertDescription>
</Alert>
)}
<Card>
<CardHeader>
<CardTitle className="text-2xl">Editar colaborador</CardTitle>
<CardDescription>
Configurar as informações gerais para este colaborador.
</CardDescription>
</CardHeader>
<Card>
<CardHeader>
<CardTitle className="text-2xl">Editar colaborador</CardTitle>
<CardDescription>
Configurar as informações gerais para este colaborador.
</CardDescription>
</CardHeader>
<CardContent>
<FieldSet>
<FormField
control={control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Nome</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<CardContent className="space-y-6">
<FieldSet disabled={!!user?.rate_limit_exceeded}>
<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>
)}
/>
</FieldSet>
<div className="flex justify-end">
<Button
type="submit"
className="cursor-pointer"
disabled={formState.isSubmitting}
>
{formState.isSubmitting && <Spinner />}
Editar
</Button>
</div>
</FieldSet>
</CardContent>
</Card>
</fieldset>
<Button
type="submit"
className="cursor-pointer"
disabled={formState.isSubmitting || !!user?.rate_limit_exceeded}
>
{formState.isSubmitting && <Spinner />}
Editar colaborador
</Button>
</CardContent>
</Card>
</form>
</Form>
)

View File

@@ -83,7 +83,7 @@ export default function Route({ loaderData: { data } }: Route.ComponentProps) {
)
})}
</NativeSelect>
<Button>Mudar</Button>
<Button>Alterar email</Button>
</form>
</CardContent>
</Card>

View File

@@ -1,7 +1,7 @@
import type { Route } from './+types/route'
import { useEffect } from 'react'
import { zodResolver } from '@hookform/resolvers/zod'
import { useEffect } from 'react'
import { useForm } from 'react-hook-form'
import { PatternFormat } from 'react-number-format'
import { Link, useFetcher } from 'react-router'
@@ -37,6 +37,7 @@ import { Spinner } from '@repo/ui/components/ui/spinner'
import { HttpMethod, request as req } from '@repo/util/request'
import { useWorksapce } from '@/components/workspace-switcher'
import { FieldSet } from '@repo/ui/components/ui/field'
import { formSchema, type Schema } from './data'
export function meta({}: Route.MetaArgs) {
@@ -115,7 +116,7 @@ export default function Route({}: Route.ComponentProps) {
<div className="lg:max-w-2xl mx-auto">
<Form {...form}>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<form onSubmit={handleSubmit(onSubmit)}>
<Card>
<CardHeader>
<CardTitle className="text-2xl">
@@ -126,99 +127,99 @@ export default function Route({}: Route.ComponentProps) {
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<FormField
control={control}
name="name"
defaultValue=""
render={({ field }) => (
<FormItem>
<FormLabel>Nome</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="space-y-2.5">
<CardContent className="space-y-6">
<FieldSet>
<FormField
control={control}
name="email"
name="name"
defaultValue=""
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormLabel>Nome</FormLabel>
<FormControl>
<Input
{...field}
readOnly={givenEmail}
className="read-only:pointer-events-none read-only:opacity-50"
/>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="space-y-2.5">
<FormField
control={control}
name="email"
defaultValue=""
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input
{...field}
readOnly={givenEmail}
className="read-only:pointer-events-none read-only:opacity-50"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={control}
name="given_email"
defaultValue={false}
render={({ field: { value, onChange, ...field } }) => (
<FormItem className="flex items-center gap-2">
<FormControl>
<Checkbox
checked={Boolean(value)}
onCheckedChange={onChange}
tabIndex={-1}
{...field}
/>
</FormControl>
<FormLabel className="cursor-pointer">
Usar email gerado pela plataforma
</FormLabel>
</FormItem>
)}
/>
</div>
<FormField
control={control}
name="given_email"
defaultValue={false}
render={({ field: { value, onChange, ...field } }) => (
<FormItem className="flex items-center gap-2">
name="cpf"
defaultValue=""
render={({ field: { onChange, ref, ...props } }) => (
<FormItem>
<FormLabel>CPF</FormLabel>
<FormControl>
<Checkbox
checked={Boolean(value)}
onCheckedChange={onChange}
tabIndex={-1}
{...field}
<PatternFormat
format="###.###.###-##"
mask="_"
placeholder="___.___.___-__"
customInput={Input}
getInputRef={ref}
onValueChange={({ value }) => {
onChange(value)
}}
{...props}
/>
</FormControl>
<FormLabel className="cursor-pointer">
Usar email gerado pela plataforma
</FormLabel>
<FormMessage />
</FormItem>
)}
/>
</div>
</FieldSet>
<FormField
control={control}
name="cpf"
defaultValue=""
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>
)}
/>
<div className="flex justify-end">
<Button
type="submit"
className="cursor-pointer"
disabled={formState.isSubmitting}
>
{formState.isSubmitting && <Spinner />}
Adicionar
</Button>
</div>
<Button
type="submit"
className="cursor-pointer"
disabled={formState.isSubmitting}
>
{formState.isSubmitting && <Spinner />}
Adicionar usuário
</Button>
</CardContent>
</Card>
</form>