[MVPTN-2] feat(CRUD): CRUD com Mock para gerenciar a tabela t_tb_andamentoservico
This commit is contained in:
parent
02ae936c87
commit
11aff8e15a
16 changed files with 1057 additions and 66 deletions
88
package-lock.json
generated
88
package-lock.json
generated
|
|
@ -16,6 +16,8 @@
|
|||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-select": "^2.2.6",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
|
|
@ -732,6 +734,12 @@
|
|||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/number": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
|
||||
"integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
|
||||
|
|
@ -1160,6 +1168,43 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover": {
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz",
|
||||
"integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.11",
|
||||
"@radix-ui/react-focus-guards": "1.1.3",
|
||||
"@radix-ui/react-focus-scope": "1.1.7",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-popper": "1.2.8",
|
||||
"@radix-ui/react-portal": "1.1.9",
|
||||
"@radix-ui/react-presence": "1.1.5",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-slot": "1.2.3",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popper": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
|
||||
|
|
@ -1294,6 +1339,49 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz",
|
||||
"integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/number": "1.1.1",
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-collection": "1.1.7",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-direction": "1.1.1",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.11",
|
||||
"@radix-ui/react-focus-guards": "1.1.3",
|
||||
"@radix-ui/react-focus-scope": "1.1.7",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-popper": "1.2.8",
|
||||
"@radix-ui/react-portal": "1.1.9",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-slot": "1.2.3",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1",
|
||||
"@radix-ui/react-use-previous": "1.1.1",
|
||||
"@radix-ui/react-visually-hidden": "1.2.3",
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-separator": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-select": "^2.2.6",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
'use client'
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTTBAndamentoServicoReadHook } from "../../_hooks/t_tb_andamentoservico/useTTBAndamentoServicoReadHook";
|
||||
import Loading from "@/app/_components/loading/loading";
|
||||
import TTBAndamentoServicoInteface, { tipoEnum } from "../../_interfaces/TTBAndamentoServicoInterface";
|
||||
import { TTBAndamentoServicoSchema } from "../../_schemas/TTBAndamentoServico";
|
||||
import z from "zod";
|
||||
import { useTTBAndamentoServicoSaveHook } from "../../_hooks/t_tb_andamentoservico/useTTBAndamentoServicoSaveHook";
|
||||
import TTBAndamentoServicoTable from "../../_components/t_tb_andamentoservico/TTBAndamentoServicoTable";
|
||||
import TTBAndamentoServicoForm from "../../_components/t_tb_andamentoservico/TTBAndamentoServicoForm";
|
||||
import TTBAndamentoServicoAlert from "../../_components/t_tb_andamentoservico/TTBAndamentoServicoAlert";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
|
||||
type FormValues = z.infer<typeof TTBAndamentoServicoSchema>
|
||||
|
||||
export default function TTBAndamentoServico() {
|
||||
|
||||
const { tTBAndamentosServicos, fetchTTBAndamentoServico, addTTBAndamentoServico } = useTTBAndamentoServicoReadHook();
|
||||
const { tTBAndamentoServico, saveTTBAndamentoServico } = useTTBAndamentoServicoSaveHook();
|
||||
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [alertDialogOpen, setAlertDialogOpen] = useState(false);
|
||||
const [item, setItem] = useState<TTBAndamentoServicoInteface | null>(null);
|
||||
|
||||
const [formOpen, setFormOpen] = useState(false);
|
||||
const [editingItem, setEditingItem] = useState<FormValues | null>(null);
|
||||
|
||||
const [deleteOpen, setDeleteOpen] = useState(false)
|
||||
const [deleteItem, setDeleteItem] = useState<TTBAndamentoServicoInteface | null>(null)
|
||||
|
||||
const emptyForm: FormValues = {
|
||||
tb_andamentoservico_id: 0,
|
||||
descricao: "",
|
||||
situacao: "I",
|
||||
tipo: "",
|
||||
usa_email: "",
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTTBAndamentoServico();
|
||||
}, []);
|
||||
|
||||
const handleSave = async (values: FormValues) => {
|
||||
const saved = await saveTTBAndamentoServico(values);
|
||||
addTTBAndamentoServico(saved);
|
||||
setFormOpen(false);
|
||||
}
|
||||
|
||||
if (!tTBAndamentosServicos) return <Loading type={2} />;
|
||||
return (
|
||||
<div>
|
||||
<div className="flex">
|
||||
<div className="w-64 flex-1">
|
||||
<div className="text-4xl font-semibold mb-1">
|
||||
Andamentos
|
||||
</div>
|
||||
<div className="text-base text-muted-foreground">
|
||||
Gerenciamento de tipos de reconhecimentos
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-64 flex-1 text-end">
|
||||
<Button onClick={() => { setEditingItem(emptyForm); setFormOpen(true) }} className="cursor-pointer">
|
||||
<PlusIcon />Tipos
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<TTBAndamentoServicoTable
|
||||
data={tTBAndamentosServicos}
|
||||
onEdit={(item) => { setEditingItem(item); setFormOpen(true) }}
|
||||
onDelete={(item) => { setDeleteItem(item); setDeleteOpen(true) }}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<TTBAndamentoServicoForm
|
||||
isOpen={formOpen}
|
||||
onClose={() => setFormOpen(false)}
|
||||
initialData={editingItem || emptyForm}
|
||||
onSave={handleSave}
|
||||
/>
|
||||
< TTBAndamentoServicoAlert
|
||||
isOpen={deleteOpen}
|
||||
item={deleteItem}
|
||||
onClose={() => setDeleteOpen(false)}
|
||||
onConfirm={() => { setDeleteOpen(false) }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
'use client'
|
||||
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog";
|
||||
import TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface";
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean,
|
||||
item?: TTBAndamentoServicoInteface | null,
|
||||
onClose: () => void
|
||||
onConfirm: () => void
|
||||
}
|
||||
|
||||
export default function TTBAndamentoServicoAlert({ isOpen, item, onClose, onConfirm }: Props) {
|
||||
return (
|
||||
<div>
|
||||
<AlertDialog open={isOpen}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
#{item?.tb_andamentoservico_id} - {item?.descricao}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Esta ação não pode ser desfeita. Isso excluirá permanentemente o registro e seus dados dos nossos servidores.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel onClick={onClose} className="cursor-pointer">
|
||||
Cancelar
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={onConfirm} className="cursor-pointer">
|
||||
Continuar
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
'use client'
|
||||
|
||||
import z from "zod";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { TTBAndamentoServicoSchema } from "../../_schemas/TTBAndamentoServico";
|
||||
import { tipoEnum } from "../../_interfaces/TTBAndamentoServicoInterface";
|
||||
|
||||
type FormValues = z.infer<typeof TTBAndamentoServicoSchema>
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean
|
||||
onClose: () => void
|
||||
initialData?: FormValues
|
||||
onSave: (data: FormValues) => void
|
||||
}
|
||||
|
||||
export default function TTBAndamentoServicoForm({ isOpen, onClose, initialData, onSave }: Props) {
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: undefined,
|
||||
defaultValues: initialData || { tb_andamentoservico_id: 0, descricao: "", situacao: "I" }
|
||||
})
|
||||
|
||||
const tipoOptions = Object.values(tipoEnum).map((value) => ({
|
||||
value,
|
||||
// Aqui você pode personalizar o label como quiser
|
||||
label:
|
||||
value === "C" ? "Cancelado" :
|
||||
value === "E" ? "Estornado" :
|
||||
value === "PT" ? "Protocolado" :
|
||||
value === "PD" ? "Pedido" :
|
||||
value === "NC" ? "Não Consta" :
|
||||
"Outros"
|
||||
}));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Dialog open={isOpen} onOpenChange={onClose}>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSave)}
|
||||
className="space-y-1"
|
||||
>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSave)} className="space-y-8">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Andamentos</DialogTitle>
|
||||
<DialogDescription>
|
||||
Controle de andamentos de atos
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="descricao"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
Descrição
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Digite a descrição" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tipo"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
Tipo
|
||||
</FormLabel>
|
||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||
<FormControl className="w-full">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Escolha o tipo do andamento" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{tipoOptions.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Controller
|
||||
name="situacao"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<Checkbox
|
||||
checked={field.value === "A"}
|
||||
onCheckedChange={(checked) => field.onChange(checked ? "A" : "I")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Label>
|
||||
Ativo
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Controller
|
||||
name="usa_email"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<Checkbox
|
||||
checked={field.value === "A"}
|
||||
onCheckedChange={(checked) => field.onChange(checked ? "A" : "I")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Label>
|
||||
Usar email
|
||||
</Label>
|
||||
</div>
|
||||
<DialogFooter className="mb-0">
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline" type="button" className="cursor-pointer">
|
||||
Cancelar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<Button type="submit" className="cursor-pointer">
|
||||
Salvar
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
<input type="hidden" {...form.register("tb_andamentoservico_id")} />
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</form>
|
||||
</Form>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
'use client'
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
import { EllipsisIcon, PencilIcon, Trash2Icon } from "lucide-react";
|
||||
import TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface";
|
||||
|
||||
interface Props {
|
||||
data: TTBAndamentoServicoInteface[]
|
||||
onEdit: (item: TTBAndamentoServicoInteface) => void
|
||||
onDelete: (item: TTBAndamentoServicoInteface) => void
|
||||
}
|
||||
|
||||
export default function TTBAndamentoServicoTable({ data, onEdit, onDelete }: Props) {
|
||||
return (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>
|
||||
#
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
Situação
|
||||
</TableHead>
|
||||
<TableHead>
|
||||
Descrição
|
||||
</TableHead>
|
||||
<TableHead className="text-right"></TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data.map(
|
||||
(item: TTBAndamentoServicoInteface) => (
|
||||
<TableRow key={item.tb_andamentoservico_id} className="cursor-pointer">
|
||||
<TableCell className="font-medium">
|
||||
{item.tb_andamentoservico_id}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{item.situacao === 'A' ? (
|
||||
<span className="bg-blue-100 text-blue-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded-sm dark:bg-blue-900 dark:text-blue-300">
|
||||
Ativo
|
||||
</span>
|
||||
) : (
|
||||
<span className="bg-yellow-100 text-yellow-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded-sm dark:bg-yellow-900 dark:text-yellow-300">
|
||||
Inativo
|
||||
</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{item.descricao}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="cursor-pointer">
|
||||
<EllipsisIcon />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="left" align="start">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem className="cursor-pointer" onSelect={() => onEdit(item)}>
|
||||
<PencilIcon /> Editar
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem className="cursor-pointer" onSelect={() => onDelete(item)}>
|
||||
<Trash2Icon /> Remover
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
export default async function TTBAndamentoServicoIndexData() {
|
||||
return Promise.resolve({
|
||||
data: [
|
||||
{
|
||||
tb_andamentoservico_id: 1,
|
||||
descricao: "Recepção 1",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 2,
|
||||
descricao: "Aguardando assinatura da Imobiliária",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 3,
|
||||
descricao: "Esc. Impugnada (Falta Itbi, cert. ou documentos)",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 4,
|
||||
descricao: "Aguardando Certtb_andamentoservico_idão de Registro",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 5,
|
||||
descricao: "Conferencia",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 16,
|
||||
descricao: "Mapa",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 6,
|
||||
descricao: "Entregue",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 18,
|
||||
descricao: "PROTOCOLADO",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 7,
|
||||
descricao: "Protocolo",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 8,
|
||||
descricao: "Cadastro",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 9,
|
||||
descricao: "Registro/Espelho",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 10,
|
||||
descricao: "Corrigtb_andamentoservico_ido Pronto",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 11,
|
||||
descricao: "Aguardando Cliente",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 12,
|
||||
descricao: "Cancelado a pedtb_andamentoservico_ido da parte",
|
||||
status: "A",
|
||||
tipo: "C"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 13,
|
||||
descricao: "Cancelado por determinação judicial",
|
||||
status: "A",
|
||||
tipo: "C"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 14,
|
||||
descricao: "Capas e Indicador",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 15,
|
||||
descricao: "Falta assinatura",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 17,
|
||||
descricao: "Impugnado",
|
||||
status: "A",
|
||||
tipo: "G"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 19,
|
||||
descricao: "Entregre/sem registro",
|
||||
status: "A",
|
||||
tipo: "C"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 20,
|
||||
descricao: "Corrigtb_andamentoservico_ido sem Registro",
|
||||
status: "A",
|
||||
tipo: "C"
|
||||
},
|
||||
{
|
||||
tb_andamentoservico_id: 21,
|
||||
descricao: "Cancelamento de ofício",
|
||||
status: "A",
|
||||
tipo: "C"
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { faker } from "@faker-js/faker";
|
||||
|
||||
export default async function name(andamentoServico: any) {
|
||||
|
||||
return Promise.resolve({
|
||||
message: 'Dados salvos com sucesso',
|
||||
data: {
|
||||
tb_reconhecimentotipo_id: faker.number.int({ min: 1, max: 1000 }),
|
||||
descricao: andamentoServico.tb_reconhecimentotipo_id + andamentoServico.descricao,
|
||||
situacao: andamentoServico.situacao,
|
||||
tipo: andamentoServico.tipo,
|
||||
usa_email: andamentoServico.usa_email,
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
'use client'
|
||||
|
||||
import { useResponse } from "@/app/_response/ResponseContext"
|
||||
import { useState } from "react";
|
||||
import TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface";
|
||||
import TTBAndamentoServicoIndexData from "../../_data/TTBAndamentoServico/TTBAndamentoServicoIndexData";
|
||||
|
||||
export const useTTBAndamentoServicoReadHook = () => {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tTBAndamentosServicos, setTTBAndamentosServicos] = useState<TTBAndamentoServicoInteface[] | null>(null);
|
||||
|
||||
const fetchTTBAndamentoServico = async () => {
|
||||
|
||||
const response = await TTBAndamentoServicoIndexData();
|
||||
|
||||
setTTBAndamentosServicos(response.data);
|
||||
|
||||
// Define os dados do componente de resposta (toast, modal, etc)
|
||||
setResponse(response);
|
||||
|
||||
}
|
||||
|
||||
function addTTBAndamentoServico(tTTBAndamentoServico: TTBAndamentoServicoInteface) {
|
||||
|
||||
setTTBAndamentosServicos(prev => [...(prev || []), tTTBAndamentoServico]);
|
||||
|
||||
}
|
||||
|
||||
return { tTBAndamentosServicos, fetchTTBAndamentoServico, addTTBAndamentoServico }
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
'use client'
|
||||
|
||||
import { useResponse } from "@/app/_response/ResponseContext"
|
||||
import { use, useState } from "react";
|
||||
import TTBAndamentoServicoInteface from "../../_interfaces/TTBAndamentoServicoInterface";
|
||||
import TTBReconhecimentoTipoSaveData from "../../_data/TTBReconhecimentoTipo/TTBReconhecimentoTipoSaveData";
|
||||
|
||||
export const useTTBAndamentoServicoSaveHook = () => {
|
||||
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tTBAndamentoServico, setTTBAndamentoServico] = useState<TTBAndamentoServicoInteface>();
|
||||
|
||||
const saveTTBAndamentoServico = async (form: TTBAndamentoServicoInteface) => {
|
||||
|
||||
const response = await TTBReconhecimentoTipoSaveData(form);
|
||||
|
||||
setTTBAndamentoServico(response.data);
|
||||
|
||||
setResponse(response);
|
||||
|
||||
// Retorna os valores de forma imediata
|
||||
return response.data;
|
||||
|
||||
}
|
||||
|
||||
return { tTBAndamentoServico, saveTTBAndamentoServico }
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
export default interface TTBAndamentoServicoInteface {
|
||||
tb_andamentoservico_id: number,
|
||||
descricao: null | string,
|
||||
situacao: null | string,
|
||||
tipo: null | tipoEnum,
|
||||
}
|
||||
|
||||
export enum tipoEnum {
|
||||
CANCELADO = "C",
|
||||
ESTORNADO = "E",
|
||||
PROTOCOLADO = "PT",
|
||||
PEDIDO = "PD",
|
||||
NAO_CONSTA = "NC",
|
||||
OUTROS = "O",
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const TTBAndamentoServicoSchema = z.object({
|
||||
|
||||
tb_andamentoservico_id: z.number(),
|
||||
descricao: z.string(),
|
||||
situacao: z.string(),
|
||||
tipo: z.string(),
|
||||
usa_email: z.string()
|
||||
|
||||
});
|
||||
|
|
@ -6,8 +6,8 @@
|
|||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
--font-sans: Inter, sans-serif;
|
||||
--font-mono: JetBrains Mono, monospace;
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
|
|
@ -41,75 +41,142 @@
|
|||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--font-serif: Source Serif 4, serif;
|
||||
--radius: 0.375rem;
|
||||
--tracking-tighter: calc(var(--tracking-normal) - 0.05em);
|
||||
--tracking-tight: calc(var(--tracking-normal) - 0.025em);
|
||||
--tracking-wide: calc(var(--tracking-normal) + 0.025em);
|
||||
--tracking-wider: calc(var(--tracking-normal) + 0.05em);
|
||||
--tracking-widest: calc(var(--tracking-normal) + 0.1em);
|
||||
--tracking-normal: var(--tracking-normal);
|
||||
--shadow-2xl: var(--shadow-2xl);
|
||||
--shadow-xl: var(--shadow-xl);
|
||||
--shadow-lg: var(--shadow-lg);
|
||||
--shadow-md: var(--shadow-md);
|
||||
--shadow: var(--shadow);
|
||||
--shadow-sm: var(--shadow-sm);
|
||||
--shadow-xs: var(--shadow-xs);
|
||||
--shadow-2xs: var(--shadow-2xs);
|
||||
--spacing: var(--spacing);
|
||||
--letter-spacing: var(--letter-spacing);
|
||||
--shadow-offset-y: var(--shadow-offset-y);
|
||||
--shadow-offset-x: var(--shadow-offset-x);
|
||||
--shadow-spread: var(--shadow-spread);
|
||||
--shadow-blur: var(--shadow-blur);
|
||||
--shadow-opacity: var(--shadow-opacity);
|
||||
--color-shadow-color: var(--shadow-color);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
}
|
||||
|
||||
:root {
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
--radius: 0.375rem;
|
||||
--background: oklch(1.0000 0 0);
|
||||
--foreground: oklch(0.2686 0 0);
|
||||
--card: oklch(1.0000 0 0);
|
||||
--card-foreground: oklch(0.2686 0 0);
|
||||
--popover: oklch(1.0000 0 0);
|
||||
--popover-foreground: oklch(0.2686 0 0);
|
||||
--primary: oklch(0.7686 0.1647 70.0804);
|
||||
--primary-foreground: oklch(0 0 0);
|
||||
--secondary: oklch(0.9670 0.0029 264.5419);
|
||||
--secondary-foreground: oklch(0.4461 0.0263 256.8018);
|
||||
--muted: oklch(0.9846 0.0017 247.8389);
|
||||
--muted-foreground: oklch(0.5510 0.0234 264.3637);
|
||||
--accent: oklch(0.9869 0.0214 95.2774);
|
||||
--accent-foreground: oklch(0.4732 0.1247 46.2007);
|
||||
--destructive: oklch(0.6368 0.2078 25.3313);
|
||||
--border: oklch(0.9276 0.0058 264.5313);
|
||||
--input: oklch(0.9276 0.0058 264.5313);
|
||||
--ring: oklch(0.7686 0.1647 70.0804);
|
||||
--chart-1: oklch(0.7686 0.1647 70.0804);
|
||||
--chart-2: oklch(0.6658 0.1574 58.3183);
|
||||
--chart-3: oklch(0.5553 0.1455 48.9975);
|
||||
--chart-4: oklch(0.4732 0.1247 46.2007);
|
||||
--chart-5: oklch(0.4137 0.1054 45.9038);
|
||||
--sidebar: oklch(0.9846 0.0017 247.8389);
|
||||
--sidebar-foreground: oklch(0.2686 0 0);
|
||||
--sidebar-primary: oklch(0.7686 0.1647 70.0804);
|
||||
--sidebar-primary-foreground: oklch(1.0000 0 0);
|
||||
--sidebar-accent: oklch(0.9869 0.0214 95.2774);
|
||||
--sidebar-accent-foreground: oklch(0.4732 0.1247 46.2007);
|
||||
--sidebar-border: oklch(0.9276 0.0058 264.5313);
|
||||
--sidebar-ring: oklch(0.7686 0.1647 70.0804);
|
||||
--destructive-foreground: oklch(1.0000 0 0);
|
||||
--font-sans: Inter, sans-serif;
|
||||
--font-serif: Source Serif 4, serif;
|
||||
--font-mono: JetBrains Mono, monospace;
|
||||
--shadow-color: hsl(0 0% 0%);
|
||||
--shadow-opacity: 0.1;
|
||||
--shadow-blur: 8px;
|
||||
--shadow-spread: -1px;
|
||||
--shadow-offset-x: 0px;
|
||||
--shadow-offset-y: 4px;
|
||||
--letter-spacing: 0em;
|
||||
--spacing: 0.25rem;
|
||||
--shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 2px 4px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 4px 6px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 8px 10px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
|
||||
--tracking-normal: 0em;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.145 0 0);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.205 0 0);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.205 0 0);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.922 0 0);
|
||||
--primary-foreground: oklch(0.205 0 0);
|
||||
--secondary: oklch(0.269 0 0);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.269 0 0);
|
||||
--muted-foreground: oklch(0.708 0 0);
|
||||
--accent: oklch(0.269 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.556 0 0);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.205 0 0);
|
||||
--sidebar-foreground: oklch(0.985 0 0);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.269 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.556 0 0);
|
||||
--background: oklch(0.2046 0 0);
|
||||
--foreground: oklch(0.9219 0 0);
|
||||
--card: oklch(0.2686 0 0);
|
||||
--card-foreground: oklch(0.9219 0 0);
|
||||
--popover: oklch(0.2686 0 0);
|
||||
--popover-foreground: oklch(0.9219 0 0);
|
||||
--primary: oklch(0.7686 0.1647 70.0804);
|
||||
--primary-foreground: oklch(0 0 0);
|
||||
--secondary: oklch(0.2686 0 0);
|
||||
--secondary-foreground: oklch(0.9219 0 0);
|
||||
--muted: oklch(0.2686 0 0);
|
||||
--muted-foreground: oklch(0.7155 0 0);
|
||||
--accent: oklch(0.4732 0.1247 46.2007);
|
||||
--accent-foreground: oklch(0.9243 0.1151 95.7459);
|
||||
--destructive: oklch(0.6368 0.2078 25.3313);
|
||||
--border: oklch(0.3715 0 0);
|
||||
--input: oklch(0.3715 0 0);
|
||||
--ring: oklch(0.7686 0.1647 70.0804);
|
||||
--chart-1: oklch(0.8369 0.1644 84.4286);
|
||||
--chart-2: oklch(0.6658 0.1574 58.3183);
|
||||
--chart-3: oklch(0.4732 0.1247 46.2007);
|
||||
--chart-4: oklch(0.5553 0.1455 48.9975);
|
||||
--chart-5: oklch(0.4732 0.1247 46.2007);
|
||||
--sidebar: oklch(0.1684 0 0);
|
||||
--sidebar-foreground: oklch(0.9219 0 0);
|
||||
--sidebar-primary: oklch(0.7686 0.1647 70.0804);
|
||||
--sidebar-primary-foreground: oklch(1.0000 0 0);
|
||||
--sidebar-accent: oklch(0.4732 0.1247 46.2007);
|
||||
--sidebar-accent-foreground: oklch(0.9243 0.1151 95.7459);
|
||||
--sidebar-border: oklch(0.3715 0 0);
|
||||
--sidebar-ring: oklch(0.7686 0.1647 70.0804);
|
||||
--destructive-foreground: oklch(1.0000 0 0);
|
||||
--radius: 0.375rem;
|
||||
--font-sans: Inter, sans-serif;
|
||||
--font-serif: Source Serif 4, serif;
|
||||
--font-mono: JetBrains Mono, monospace;
|
||||
--shadow-color: hsl(0 0% 0%);
|
||||
--shadow-opacity: 0.1;
|
||||
--shadow-blur: 8px;
|
||||
--shadow-spread: -1px;
|
||||
--shadow-offset-x: 0px;
|
||||
--shadow-offset-y: 4px;
|
||||
--letter-spacing: 0em;
|
||||
--spacing: 0.25rem;
|
||||
--shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 2px 4px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 4px 6px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 8px 10px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
|
@ -118,8 +185,9 @@
|
|||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
letter-spacing: var(--tracking-normal);
|
||||
}
|
||||
.bg-brand{
|
||||
background-color: #1A292F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,6 +72,10 @@ const data = {
|
|||
title: "Reconhecimentos",
|
||||
url: "/cadastros/reconhecimentos/",
|
||||
},
|
||||
{
|
||||
title: "Andamentos",
|
||||
url: "/cadastros/andamentos/",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
48
src/components/ui/popover.tsx
Normal file
48
src/components/ui/popover.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Popover({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
||||
return <PopoverPrimitive.Root data-slot="popover" {...props} />
|
||||
}
|
||||
|
||||
function PopoverTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
||||
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
||||
}
|
||||
|
||||
function PopoverContent({
|
||||
className,
|
||||
align = "center",
|
||||
sideOffset = 4,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
||||
return (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
data-slot="popover-content"
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverAnchor({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
||||
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
|
||||
}
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
||||
185
src/components/ui/select.tsx
Normal file
185
src/components/ui/select.tsx
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Select({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
||||
return <SelectPrimitive.Root data-slot="select" {...props} />
|
||||
}
|
||||
|
||||
function SelectGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
||||
return <SelectPrimitive.Group data-slot="select-group" {...props} />
|
||||
}
|
||||
|
||||
function SelectValue({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
||||
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
||||
}
|
||||
|
||||
function SelectTrigger({
|
||||
className,
|
||||
size = "default",
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
||||
size?: "sm" | "default"
|
||||
}) {
|
||||
return (
|
||||
<SelectPrimitive.Trigger
|
||||
data-slot="select-trigger"
|
||||
data-size={size}
|
||||
className={cn(
|
||||
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDownIcon className="size-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectContent({
|
||||
className,
|
||||
children,
|
||||
position = "popper",
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
||||
return (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
data-slot="select-content"
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectLabel({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
||||
return (
|
||||
<SelectPrimitive.Label
|
||||
data-slot="select-label"
|
||||
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectItem({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
||||
return (
|
||||
<SelectPrimitive.Item
|
||||
data-slot="select-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute right-2 flex size-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
||||
return (
|
||||
<SelectPrimitive.Separator
|
||||
data-slot="select-separator"
|
||||
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollUpButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
data-slot="select-scroll-up-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUpIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollDownButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
data-slot="select-scroll-down-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDownIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectScrollDownButton,
|
||||
SelectScrollUpButton,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue