add endereco e edita tabela empresas
This commit is contained in:
@@ -4,12 +4,13 @@
|
|||||||
import type { Id } from "@sgse-app/backend/convex/_generated/dataModel";
|
import type { Id } from "@sgse-app/backend/convex/_generated/dataModel";
|
||||||
import { Building2, Phone, Mail, Plus, Users, Pencil, X } from "lucide-svelte";
|
import { Building2, Phone, Mail, Plus, Users, Pencil, X } from "lucide-svelte";
|
||||||
import { resolve } from "$app/paths";
|
import { resolve } from "$app/paths";
|
||||||
import { maskCNPJ, maskPhone } from "$lib/utils/masks";
|
import { maskCNPJ, maskCEP, maskPhone, maskUF, onlyDigits } from "$lib/utils/masks";
|
||||||
|
import "$lib/svelte-compat";
|
||||||
|
|
||||||
const client = useConvexClient();
|
const client = useConvexClient();
|
||||||
const empresasQuery = useQuery(api.empresas.list, {});
|
const empresasQuery = useQuery(api.empresas.list, {});
|
||||||
|
|
||||||
let modalAberto = false;
|
let modalAberto = $state(false);
|
||||||
|
|
||||||
type ContatoForm = {
|
type ContatoForm = {
|
||||||
_id?: Id<"contatosEmpresa">;
|
_id?: Id<"contatosEmpresa">;
|
||||||
@@ -21,40 +22,137 @@
|
|||||||
_deleted?: boolean;
|
_deleted?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type EnderecoForm = {
|
||||||
|
cep: string;
|
||||||
|
logradouro: string;
|
||||||
|
numero: string;
|
||||||
|
complemento: string;
|
||||||
|
bairro: string;
|
||||||
|
cidade: string;
|
||||||
|
uf: string;
|
||||||
|
};
|
||||||
|
|
||||||
type EmpresaForm = {
|
type EmpresaForm = {
|
||||||
id?: string;
|
id?: Id<"empresas">;
|
||||||
nome: string;
|
razao_social: string;
|
||||||
|
nome_fantasia?: string;
|
||||||
cnpj: string;
|
cnpj: string;
|
||||||
telefone: string;
|
telefone: string;
|
||||||
email: string;
|
email: string;
|
||||||
descricao?: string;
|
descricao?: string;
|
||||||
|
endereco: EnderecoForm;
|
||||||
contatos: ContatoForm[];
|
contatos: ContatoForm[];
|
||||||
};
|
};
|
||||||
|
|
||||||
let empresaForm: EmpresaForm = {
|
let empresaForm = $state<EmpresaForm>({
|
||||||
nome: "",
|
razao_social: "",
|
||||||
|
nome_fantasia: "",
|
||||||
cnpj: "",
|
cnpj: "",
|
||||||
telefone: "",
|
telefone: "",
|
||||||
email: "",
|
email: "",
|
||||||
descricao: "",
|
descricao: "",
|
||||||
|
endereco: {
|
||||||
|
cep: "",
|
||||||
|
logradouro: "",
|
||||||
|
numero: "",
|
||||||
|
complemento: "",
|
||||||
|
bairro: "",
|
||||||
|
cidade: "",
|
||||||
|
uf: "",
|
||||||
|
},
|
||||||
contatos: [],
|
contatos: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
let contatoEmEdicao = $state<ContatoForm | null>(null);
|
||||||
|
let contatoIndiceEdicao = $state<number | null>(null);
|
||||||
|
let erroFormulario = $state("");
|
||||||
|
let salvando = $state(false);
|
||||||
|
|
||||||
|
let contatosModalAberto = $state(false);
|
||||||
|
let contatosDaEmpresa = $state<ContatoForm[]>([]);
|
||||||
|
let empresaContatosNome = $state("");
|
||||||
|
let carregandoCep = $state(false);
|
||||||
|
let erroCep = $state("");
|
||||||
|
let carregandoCnpj = $state(false);
|
||||||
|
let erroCnpj = $state("");
|
||||||
|
|
||||||
|
type ReceitaWsResponse = {
|
||||||
|
status?: string;
|
||||||
|
message?: string;
|
||||||
|
nome?: string;
|
||||||
|
fantasia?: string;
|
||||||
|
telefone?: string;
|
||||||
|
email?: string;
|
||||||
|
cep?: string;
|
||||||
|
logradouro?: string;
|
||||||
|
numero?: string;
|
||||||
|
complemento?: string;
|
||||||
|
bairro?: string;
|
||||||
|
municipio?: string;
|
||||||
|
uf?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
let contatoEmEdicao: ContatoForm | null = null;
|
|
||||||
let contatoIndiceEdicao: number | null = null;
|
|
||||||
let erroFormulario = "";
|
|
||||||
let salvando = false;
|
|
||||||
|
|
||||||
let contatosModalAberto = false;
|
|
||||||
let contatosDaEmpresa: ContatoForm[] = [];
|
|
||||||
let empresaContatosNome = "";
|
|
||||||
|
|
||||||
function handleEmpresaCnpjInput(event: Event) {
|
function handleEmpresaCnpjInput(event: Event) {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
empresaForm.cnpj = maskCNPJ(target.value);
|
empresaForm.cnpj = maskCNPJ(target.value);
|
||||||
target.value = empresaForm.cnpj;
|
target.value = empresaForm.cnpj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleEmpresaCnpjBlur() {
|
||||||
|
const digits = onlyDigits(empresaForm.cnpj);
|
||||||
|
if (digits.length !== 14) return;
|
||||||
|
|
||||||
|
carregandoCnpj = true;
|
||||||
|
erroCnpj = "";
|
||||||
|
try {
|
||||||
|
const response = await fetch(`https://www.receitaws.com.br/v1/cnpj/${digits}`);
|
||||||
|
const data: ReceitaWsResponse = await response.json();
|
||||||
|
|
||||||
|
if (data.status === "ERROR") {
|
||||||
|
throw new Error(data.message || "CNPJ não encontrado.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.nome && !empresaForm.razao_social) {
|
||||||
|
empresaForm.razao_social = data.nome;
|
||||||
|
}
|
||||||
|
if (data.fantasia && !empresaForm.nome_fantasia) {
|
||||||
|
empresaForm.nome_fantasia = data.fantasia;
|
||||||
|
}
|
||||||
|
if (data.telefone && !empresaForm.telefone) {
|
||||||
|
empresaForm.telefone = maskPhone(data.telefone);
|
||||||
|
}
|
||||||
|
if (data.email && !empresaForm.email) {
|
||||||
|
empresaForm.email = data.email;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
data.cep ||
|
||||||
|
data.logradouro ||
|
||||||
|
data.bairro ||
|
||||||
|
data.municipio ||
|
||||||
|
data.uf
|
||||||
|
) {
|
||||||
|
empresaForm.endereco = {
|
||||||
|
...empresaForm.endereco,
|
||||||
|
cep: data.cep ? maskCEP(data.cep) : empresaForm.endereco.cep,
|
||||||
|
logradouro: data.logradouro ?? empresaForm.endereco.logradouro,
|
||||||
|
numero: data.numero ?? empresaForm.endereco.numero,
|
||||||
|
complemento: data.complemento ?? empresaForm.endereco.complemento,
|
||||||
|
bairro: data.bairro ?? empresaForm.endereco.bairro,
|
||||||
|
cidade: data.municipio ?? empresaForm.endereco.cidade,
|
||||||
|
uf: data.uf ? maskUF(data.uf) : empresaForm.endereco.uf,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
erroCnpj =
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: "Não foi possível buscar os dados do CNPJ.";
|
||||||
|
} finally {
|
||||||
|
carregandoCnpj = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleEmpresaTelefoneInput(event: Event) {
|
function handleEmpresaTelefoneInput(event: Event) {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
empresaForm.telefone = maskPhone(target.value);
|
empresaForm.telefone = maskPhone(target.value);
|
||||||
@@ -68,13 +166,87 @@
|
|||||||
target.value = contatoEmEdicao.telefone;
|
target.value = contatoEmEdicao.telefone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCepInput(event: Event) {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
empresaForm.endereco.cep = maskCEP(target.value);
|
||||||
|
target.value = empresaForm.endereco.cep;
|
||||||
|
|
||||||
|
const digits = onlyDigits(empresaForm.endereco.cep);
|
||||||
|
if (digits.length === 8) {
|
||||||
|
void buscarCep(digits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buscarCep(cepDigits: string) {
|
||||||
|
carregandoCep = true;
|
||||||
|
erroCep = "";
|
||||||
|
try {
|
||||||
|
const response = await fetch(`https://viacep.com.br/ws/${cepDigits}/json/`);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.erro) {
|
||||||
|
throw new Error("CEP não encontrado.");
|
||||||
|
}
|
||||||
|
|
||||||
|
empresaForm.endereco = {
|
||||||
|
...empresaForm.endereco,
|
||||||
|
cep: maskCEP(cepDigits),
|
||||||
|
logradouro: data.logradouro ?? empresaForm.endereco.logradouro,
|
||||||
|
bairro: data.bairro ?? empresaForm.endereco.bairro,
|
||||||
|
cidade: data.localidade ?? empresaForm.endereco.cidade,
|
||||||
|
uf: data.uf ? maskUF(data.uf) : empresaForm.endereco.uf,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
erroCep =
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: "Não foi possível buscar o endereço pelo CEP.";
|
||||||
|
} finally {
|
||||||
|
carregandoCep = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeEnderecoForSave(endereco: EnderecoForm) {
|
||||||
|
const hasData =
|
||||||
|
endereco.cep ||
|
||||||
|
endereco.logradouro ||
|
||||||
|
endereco.numero ||
|
||||||
|
endereco.bairro ||
|
||||||
|
endereco.cidade ||
|
||||||
|
endereco.uf;
|
||||||
|
|
||||||
|
if (!hasData) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
cep: endereco.cep,
|
||||||
|
logradouro: endereco.logradouro,
|
||||||
|
numero: endereco.numero,
|
||||||
|
complemento: endereco.complemento || undefined,
|
||||||
|
bairro: endereco.bairro,
|
||||||
|
cidade: endereco.cidade,
|
||||||
|
uf: endereco.uf,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function abrirNovaEmpresa() {
|
function abrirNovaEmpresa() {
|
||||||
empresaForm = {
|
empresaForm = {
|
||||||
nome: "",
|
razao_social: "",
|
||||||
|
nome_fantasia: "",
|
||||||
cnpj: "",
|
cnpj: "",
|
||||||
telefone: "",
|
telefone: "",
|
||||||
email: "",
|
email: "",
|
||||||
descricao: "",
|
descricao: "",
|
||||||
|
endereco: {
|
||||||
|
cep: "",
|
||||||
|
logradouro: "",
|
||||||
|
numero: "",
|
||||||
|
complemento: "",
|
||||||
|
bairro: "",
|
||||||
|
cidade: "",
|
||||||
|
uf: "",
|
||||||
|
},
|
||||||
contatos: [],
|
contatos: [],
|
||||||
};
|
};
|
||||||
modalAberto = true;
|
modalAberto = true;
|
||||||
@@ -86,11 +258,21 @@
|
|||||||
|
|
||||||
empresaForm = {
|
empresaForm = {
|
||||||
id: detalhes._id,
|
id: detalhes._id,
|
||||||
nome: detalhes.nome,
|
razao_social: detalhes.razao_social,
|
||||||
|
nome_fantasia: detalhes.nome_fantasia,
|
||||||
cnpj: detalhes.cnpj,
|
cnpj: detalhes.cnpj,
|
||||||
telefone: detalhes.telefone,
|
telefone: detalhes.telefone,
|
||||||
email: detalhes.email,
|
email: detalhes.email,
|
||||||
descricao: detalhes.descricao ?? "",
|
descricao: detalhes.descricao ?? "",
|
||||||
|
endereco: {
|
||||||
|
cep: detalhes.endereco?.cep ?? "",
|
||||||
|
logradouro: detalhes.endereco?.logradouro ?? "",
|
||||||
|
numero: detalhes.endereco?.numero ?? "",
|
||||||
|
complemento: detalhes.endereco?.complemento ?? "",
|
||||||
|
bairro: detalhes.endereco?.bairro ?? "",
|
||||||
|
cidade: detalhes.endereco?.cidade ?? "",
|
||||||
|
uf: detalhes.endereco?.uf ?? "",
|
||||||
|
},
|
||||||
contatos:
|
contatos:
|
||||||
detalhes.contatos?.map((c) => ({
|
detalhes.contatos?.map((c) => ({
|
||||||
_id: c._id,
|
_id: c._id,
|
||||||
@@ -104,10 +286,10 @@
|
|||||||
modalAberto = true;
|
modalAberto = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function verContatos(empresaId: Id<"empresas">, nome: string) {
|
async function verContatos(empresaId: Id<"empresas">, razaoSocial: string) {
|
||||||
const detalhes = await client.query(api.empresas.getById, { id: empresaId });
|
const detalhes = await client.query(api.empresas.getById, { id: empresaId });
|
||||||
contatosDaEmpresa = detalhes?.contatos ?? [];
|
contatosDaEmpresa = detalhes?.contatos ?? [];
|
||||||
empresaContatosNome = nome;
|
empresaContatosNome = razaoSocial;
|
||||||
contatosModalAberto = true;
|
contatosModalAberto = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,36 +356,53 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function salvarEmpresa() {
|
async function salvarEmpresa() {
|
||||||
if (!empresaForm.nome || !empresaForm.cnpj || !empresaForm.telefone || !empresaForm.email) {
|
if (
|
||||||
|
!empresaForm.razao_social ||
|
||||||
|
!empresaForm.cnpj ||
|
||||||
|
!empresaForm.telefone ||
|
||||||
|
!empresaForm.email
|
||||||
|
) {
|
||||||
erroFormulario = "Preencha todos os campos obrigatórios da empresa.";
|
erroFormulario = "Preencha todos os campos obrigatórios da empresa.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
salvando = true;
|
salvando = true;
|
||||||
erroFormulario = "";
|
erroFormulario = "";
|
||||||
try {
|
try {
|
||||||
|
const enderecoPayload = normalizeEnderecoForSave(empresaForm.endereco);
|
||||||
|
|
||||||
if (empresaForm.id) {
|
if (empresaForm.id) {
|
||||||
await client.mutation(
|
const baseArgs = {
|
||||||
api.empresas.update as typeof api.empresas.update,
|
id: empresaForm.id,
|
||||||
{
|
razao_social: empresaForm.razao_social,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
nome_fantasia: empresaForm.nome_fantasia,
|
||||||
id: empresaForm.id as any,
|
|
||||||
nome: empresaForm.nome,
|
|
||||||
cnpj: empresaForm.cnpj,
|
cnpj: empresaForm.cnpj,
|
||||||
telefone: empresaForm.telefone,
|
telefone: empresaForm.telefone,
|
||||||
email: empresaForm.email,
|
email: empresaForm.email,
|
||||||
descricao: empresaForm.descricao || undefined,
|
descricao: empresaForm.descricao || undefined,
|
||||||
contatos: empresaForm.contatos,
|
contatos: empresaForm.contatos,
|
||||||
}
|
};
|
||||||
);
|
|
||||||
|
const args = enderecoPayload
|
||||||
|
? { ...baseArgs, endereco: enderecoPayload }
|
||||||
|
: baseArgs;
|
||||||
|
|
||||||
|
await client.mutation(api.empresas.update, args);
|
||||||
} else {
|
} else {
|
||||||
await client.mutation(api.empresas.create, {
|
const baseArgs = {
|
||||||
nome: empresaForm.nome,
|
razao_social: empresaForm.razao_social,
|
||||||
|
nome_fantasia: empresaForm.nome_fantasia,
|
||||||
cnpj: empresaForm.cnpj,
|
cnpj: empresaForm.cnpj,
|
||||||
telefone: empresaForm.telefone,
|
telefone: empresaForm.telefone,
|
||||||
email: empresaForm.email,
|
email: empresaForm.email,
|
||||||
descricao: empresaForm.descricao || undefined,
|
descricao: empresaForm.descricao || undefined,
|
||||||
contatos: empresaForm.contatos,
|
contatos: empresaForm.contatos,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
const args = enderecoPayload
|
||||||
|
? { ...baseArgs, endereco: enderecoPayload }
|
||||||
|
: baseArgs;
|
||||||
|
|
||||||
|
await client.mutation(api.empresas.create, args);
|
||||||
}
|
}
|
||||||
fecharModal();
|
fecharModal();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -264,34 +463,39 @@
|
|||||||
<table class="table table-zebra">
|
<table class="table table-zebra">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Nome</th>
|
<th>Razão social / Nome fantasia</th>
|
||||||
<th>CNPJ</th>
|
<th>CNPJ</th>
|
||||||
<th>Telefone</th>
|
<th>Telefone</th>
|
||||||
<th>E-mail</th>
|
<th>E-mail</th>
|
||||||
<th></th>
|
<th>Ações</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#each empresasQuery.data as empresa (empresa._id)}
|
{#each empresasQuery.data as empresa (empresa._id)}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{empresa.nome}</td>
|
<td>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="font-semibold">{empresa.razao_social}</span>
|
||||||
|
{#if empresa.nome_fantasia}
|
||||||
|
<span class="text-xs text-base-content/70">{empresa.nome_fantasia}</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td>{empresa.cnpj}</td>
|
<td>{empresa.cnpj}</td>
|
||||||
<td class="flex items-center gap-2">
|
<td class="flex items-center gap-2">
|
||||||
<Phone class="h-4 w-4 text-base-content/60" strokeWidth={2} />
|
<Phone class="h-4 w-4 text-base-content/60" strokeWidth={2} />
|
||||||
<span>{empresa.telefone}</span>
|
<span>{empresa.telefone}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="flex items-center gap-2">
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<Mail class="h-4 w-4 text-base-content/60" strokeWidth={2} />
|
<Mail class="h-4 w-4 text-base-content/60" strokeWidth={2} />
|
||||||
<span>{empresa.email}</span>
|
<span>{empresa.email}</span>
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<div class="flex justify-end gap-2">
|
<div class="flex justify-end gap-2">
|
||||||
<button
|
<button
|
||||||
class="btn btn-outline btn-sm gap-2"
|
class="btn btn-outline btn-sm gap-2"
|
||||||
type="button"
|
type="button"
|
||||||
onclick={() => verContatos(empresa._id, empresa.nome)}
|
onclick={() => verContatos(empresa._id, empresa.razao_social)}
|
||||||
>
|
>
|
||||||
<Users class="h-4 w-4" strokeWidth={2} />
|
<Users class="h-4 w-4" strokeWidth={2} />
|
||||||
Contatos
|
Contatos
|
||||||
@@ -339,16 +543,29 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
||||||
<div class="form-control">
|
<div class="form-control md:col-span-2">
|
||||||
<label class="label" for="nomeEmpresa"><span class="label-text">Nome da empresa *</span></label>
|
<label class="label" for="razaoSocialEmpresa">
|
||||||
|
<span class="label-text">Razão social *</span>
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
id="nomeEmpresa"
|
id="razaoSocialEmpresa"
|
||||||
class="input input-bordered w-full"
|
class="input input-bordered w-full"
|
||||||
bind:value={empresaForm.nome}
|
bind:value={empresaForm.razao_social}
|
||||||
placeholder="Nome"
|
placeholder="Razão social"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="nomeFantasiaEmpresa">
|
||||||
|
<span class="label-text">Nome fantasia</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="nomeFantasiaEmpresa"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={empresaForm.nome_fantasia}
|
||||||
|
placeholder="Nome fantasia"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<label class="label" for="cnpjEmpresa"><span class="label-text">CNPJ *</span></label>
|
<label class="label" for="cnpjEmpresa"><span class="label-text">CNPJ *</span></label>
|
||||||
<input
|
<input
|
||||||
@@ -357,9 +574,15 @@
|
|||||||
value={empresaForm.cnpj}
|
value={empresaForm.cnpj}
|
||||||
inputmode="numeric"
|
inputmode="numeric"
|
||||||
oninput={handleEmpresaCnpjInput}
|
oninput={handleEmpresaCnpjInput}
|
||||||
|
onblur={handleEmpresaCnpjBlur}
|
||||||
placeholder="00.000.000/0000-00"
|
placeholder="00.000.000/0000-00"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
{#if carregandoCnpj}
|
||||||
|
<span class="text-xs text-primary mt-1">Buscando dados do CNPJ...</span>
|
||||||
|
{:else if erroCnpj}
|
||||||
|
<span class="text-xs text-error mt-1">{erroCnpj}</span>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<label class="label" for="telefoneEmpresa"><span class="label-text">Telefone *</span></label>
|
<label class="label" for="telefoneEmpresa"><span class="label-text">Telefone *</span></label>
|
||||||
@@ -398,6 +621,87 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="divider my-4">Endereço da empresa</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="cepEmpresa"><span class="label-text">CEP</span></label>
|
||||||
|
<input
|
||||||
|
id="cepEmpresa"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
value={empresaForm.endereco.cep}
|
||||||
|
inputmode="numeric"
|
||||||
|
oninput={handleCepInput}
|
||||||
|
placeholder="00000-000"
|
||||||
|
/>
|
||||||
|
{#if carregandoCep}
|
||||||
|
<span class="text-xs text-primary mt-1">Buscando endereço pelo CEP...</span>
|
||||||
|
{:else if erroCep}
|
||||||
|
<span class="text-xs text-error mt-1">{erroCep}</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="form-control md:col-span-2">
|
||||||
|
<label class="label" for="logradouroEmpresa"><span class="label-text">Logradouro</span></label>
|
||||||
|
<input
|
||||||
|
id="logradouroEmpresa"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={empresaForm.endereco.logradouro}
|
||||||
|
placeholder="Rua, avenida, etc."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="numeroEmpresa"><span class="label-text">Número</span></label>
|
||||||
|
<input
|
||||||
|
id="numeroEmpresa"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={empresaForm.endereco.numero}
|
||||||
|
placeholder="Número"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="complementoEmpresa"><span class="label-text">Complemento</span></label>
|
||||||
|
<input
|
||||||
|
id="complementoEmpresa"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={empresaForm.endereco.complemento}
|
||||||
|
placeholder="Sala, bloco, etc."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="bairroEmpresa"><span class="label-text">Bairro</span></label>
|
||||||
|
<input
|
||||||
|
id="bairroEmpresa"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={empresaForm.endereco.bairro}
|
||||||
|
placeholder="Bairro"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="cidadeEmpresa"><span class="label-text">Cidade</span></label>
|
||||||
|
<input
|
||||||
|
id="cidadeEmpresa"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={empresaForm.endereco.cidade}
|
||||||
|
placeholder="Cidade"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="ufEmpresa"><span class="label-text">UF</span></label>
|
||||||
|
<input
|
||||||
|
id="ufEmpresa"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
maxlength="2"
|
||||||
|
bind:value={empresaForm.endereco.uf}
|
||||||
|
oninput={(event) => {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
empresaForm.endereco.uf = maskUF(target.value);
|
||||||
|
target.value = empresaForm.endereco.uf;
|
||||||
|
}}
|
||||||
|
placeholder="UF"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="divider my-4">Contatos da empresa</div>
|
<div class="divider my-4">Contatos da empresa</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-between mb-3">
|
<div class="flex items-center justify-between mb-3">
|
||||||
|
|||||||
1
bun.lock
1
bun.lock
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
|
"configVersion": 0,
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "sgse-app",
|
"name": "sgse-app",
|
||||||
|
|||||||
34
packages/backend/convex/_generated/api.d.ts
vendored
34
packages/backend/convex/_generated/api.d.ts
vendored
@@ -15,9 +15,9 @@ import type * as actions_smtp from "../actions/smtp.js";
|
|||||||
import type * as actions_utils_nodeCrypto from "../actions/utils/nodeCrypto.js";
|
import type * as actions_utils_nodeCrypto from "../actions/utils/nodeCrypto.js";
|
||||||
import type * as atestadosLicencas from "../atestadosLicencas.js";
|
import type * as atestadosLicencas from "../atestadosLicencas.js";
|
||||||
import type * as ausencias from "../ausencias.js";
|
import type * as ausencias from "../ausencias.js";
|
||||||
|
import type * as auth from "../auth.js";
|
||||||
import type * as auth_utils from "../auth/utils.js";
|
import type * as auth_utils from "../auth/utils.js";
|
||||||
import type * as chamados from "../chamados.js";
|
import type * as chamados from "../chamados.js";
|
||||||
import type * as auth from "../auth.js";
|
|
||||||
import type * as chat from "../chat.js";
|
import type * as chat from "../chat.js";
|
||||||
import type * as configuracaoEmail from "../configuracaoEmail.js";
|
import type * as configuracaoEmail from "../configuracaoEmail.js";
|
||||||
import type * as crons from "../crons.js";
|
import type * as crons from "../crons.js";
|
||||||
@@ -56,14 +56,6 @@ import type {
|
|||||||
FunctionReference,
|
FunctionReference,
|
||||||
} from "convex/server";
|
} from "convex/server";
|
||||||
|
|
||||||
/**
|
|
||||||
* A utility for referencing Convex functions in your app's API.
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* ```js
|
|
||||||
* const myFunctionReference = api.myModule.myFunction;
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
declare const fullApi: ApiFromModules<{
|
declare const fullApi: ApiFromModules<{
|
||||||
"actions/email": typeof actions_email;
|
"actions/email": typeof actions_email;
|
||||||
"actions/linkPreview": typeof actions_linkPreview;
|
"actions/linkPreview": typeof actions_linkPreview;
|
||||||
@@ -72,9 +64,9 @@ declare const fullApi: ApiFromModules<{
|
|||||||
"actions/utils/nodeCrypto": typeof actions_utils_nodeCrypto;
|
"actions/utils/nodeCrypto": typeof actions_utils_nodeCrypto;
|
||||||
atestadosLicencas: typeof atestadosLicencas;
|
atestadosLicencas: typeof atestadosLicencas;
|
||||||
ausencias: typeof ausencias;
|
ausencias: typeof ausencias;
|
||||||
|
auth: typeof auth;
|
||||||
"auth/utils": typeof auth_utils;
|
"auth/utils": typeof auth_utils;
|
||||||
chamados: typeof chamados;
|
chamados: typeof chamados;
|
||||||
auth: typeof auth;
|
|
||||||
chat: typeof chat;
|
chat: typeof chat;
|
||||||
configuracaoEmail: typeof configuracaoEmail;
|
configuracaoEmail: typeof configuracaoEmail;
|
||||||
crons: typeof crons;
|
crons: typeof crons;
|
||||||
@@ -107,14 +99,30 @@ declare const fullApi: ApiFromModules<{
|
|||||||
"utils/getClientIP": typeof utils_getClientIP;
|
"utils/getClientIP": typeof utils_getClientIP;
|
||||||
verificarMatriculas: typeof verificarMatriculas;
|
verificarMatriculas: typeof verificarMatriculas;
|
||||||
}>;
|
}>;
|
||||||
declare const fullApiWithMounts: typeof fullApi;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility for referencing Convex functions in your app's public API.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```js
|
||||||
|
* const myFunctionReference = api.myModule.myFunction;
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export declare const api: FilterApi<
|
export declare const api: FilterApi<
|
||||||
typeof fullApiWithMounts,
|
typeof fullApi,
|
||||||
FunctionReference<any, "public">
|
FunctionReference<any, "public">
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility for referencing Convex functions in your app's internal API.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```js
|
||||||
|
* const myFunctionReference = internal.myModule.myFunction;
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export declare const internal: FilterApi<
|
export declare const internal: FilterApi<
|
||||||
typeof fullApiWithMounts,
|
typeof fullApi,
|
||||||
FunctionReference<any, "internal">
|
FunctionReference<any, "internal">
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|||||||
16
packages/backend/convex/_generated/server.d.ts
vendored
16
packages/backend/convex/_generated/server.d.ts
vendored
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
ActionBuilder,
|
ActionBuilder,
|
||||||
AnyComponents,
|
|
||||||
HttpActionBuilder,
|
HttpActionBuilder,
|
||||||
MutationBuilder,
|
MutationBuilder,
|
||||||
QueryBuilder,
|
QueryBuilder,
|
||||||
@@ -19,15 +18,9 @@ import {
|
|||||||
GenericQueryCtx,
|
GenericQueryCtx,
|
||||||
GenericDatabaseReader,
|
GenericDatabaseReader,
|
||||||
GenericDatabaseWriter,
|
GenericDatabaseWriter,
|
||||||
FunctionReference,
|
|
||||||
} from "convex/server";
|
} from "convex/server";
|
||||||
import type { DataModel } from "./dataModel.js";
|
import type { DataModel } from "./dataModel.js";
|
||||||
|
|
||||||
type GenericCtx =
|
|
||||||
| GenericActionCtx<DataModel>
|
|
||||||
| GenericMutationCtx<DataModel>
|
|
||||||
| GenericQueryCtx<DataModel>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a query in this Convex app's public API.
|
* Define a query in this Convex app's public API.
|
||||||
*
|
*
|
||||||
@@ -92,11 +85,12 @@ export declare const internalAction: ActionBuilder<DataModel, "internal">;
|
|||||||
/**
|
/**
|
||||||
* Define an HTTP action.
|
* Define an HTTP action.
|
||||||
*
|
*
|
||||||
* This function will be used to respond to HTTP requests received by a Convex
|
* The wrapped function will be used to respond to HTTP requests received
|
||||||
* deployment if the requests matches the path and method where this action
|
* by a Convex deployment if the requests matches the path and method where
|
||||||
* is routed. Be sure to route your action in `convex/http.js`.
|
* this action is routed. Be sure to route your httpAction in `convex/http.js`.
|
||||||
*
|
*
|
||||||
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
||||||
|
* and a Fetch API `Request` object as its second.
|
||||||
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
||||||
*/
|
*/
|
||||||
export declare const httpAction: HttpActionBuilder;
|
export declare const httpAction: HttpActionBuilder;
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
internalActionGeneric,
|
internalActionGeneric,
|
||||||
internalMutationGeneric,
|
internalMutationGeneric,
|
||||||
internalQueryGeneric,
|
internalQueryGeneric,
|
||||||
componentsGeneric,
|
|
||||||
} from "convex/server";
|
} from "convex/server";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,10 +80,14 @@ export const action = actionGeneric;
|
|||||||
export const internalAction = internalActionGeneric;
|
export const internalAction = internalActionGeneric;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a Convex HTTP action.
|
* Define an HTTP action.
|
||||||
*
|
*
|
||||||
* @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
|
* The wrapped function will be used to respond to HTTP requests received
|
||||||
* as its second.
|
* by a Convex deployment if the requests matches the path and method where
|
||||||
* @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
|
* this action is routed. Be sure to route your httpAction in `convex/http.js`.
|
||||||
|
*
|
||||||
|
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
||||||
|
* and a Fetch API `Request` object as its second.
|
||||||
|
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
||||||
*/
|
*/
|
||||||
export const httpAction = httpActionGeneric;
|
export const httpAction = httpActionGeneric;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { v } from "convex/values";
|
|||||||
import { mutation, query } from "./_generated/server";
|
import { mutation, query } from "./_generated/server";
|
||||||
import { internal } from "./_generated/api";
|
import { internal } from "./_generated/api";
|
||||||
import { getCurrentUserFunction } from "./auth";
|
import { getCurrentUserFunction } from "./auth";
|
||||||
|
import type { Id } from "./_generated/dataModel";
|
||||||
|
|
||||||
export const list = query({
|
export const list = query({
|
||||||
args: {},
|
args: {},
|
||||||
@@ -33,8 +34,11 @@ export const getById = query({
|
|||||||
.query("contatosEmpresa")
|
.query("contatosEmpresa")
|
||||||
.withIndex("by_empresa", (q) => q.eq("empresaId", args.id))
|
.withIndex("by_empresa", (q) => q.eq("empresaId", args.id))
|
||||||
.collect();
|
.collect();
|
||||||
|
const endereco = empresa.enderecoId
|
||||||
|
? await ctx.db.get(empresa.enderecoId as Id<"enderecos">)
|
||||||
|
: null;
|
||||||
|
|
||||||
return { ...empresa, contatos };
|
return { ...empresa, endereco, contatos };
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -50,13 +54,25 @@ const contatoInput = v.object({
|
|||||||
_deleted: v.optional(v.boolean()),
|
_deleted: v.optional(v.boolean()),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const enderecoInput = v.object({
|
||||||
|
cep: v.string(),
|
||||||
|
logradouro: v.string(),
|
||||||
|
numero: v.string(),
|
||||||
|
complemento: v.optional(v.string()),
|
||||||
|
bairro: v.string(),
|
||||||
|
cidade: v.string(),
|
||||||
|
uf: v.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export const create = mutation({
|
export const create = mutation({
|
||||||
args: {
|
args: {
|
||||||
nome: v.string(),
|
razao_social: v.string(),
|
||||||
|
nome_fantasia: v.optional(v.string()),
|
||||||
cnpj: v.string(),
|
cnpj: v.string(),
|
||||||
telefone: v.string(),
|
telefone: v.string(),
|
||||||
email: v.string(),
|
email: v.string(),
|
||||||
descricao: v.optional(v.string()),
|
descricao: v.optional(v.string()),
|
||||||
|
endereco: v.optional(enderecoInput),
|
||||||
contatos: v.optional(v.array(contatoInput)),
|
contatos: v.optional(v.array(contatoInput)),
|
||||||
},
|
},
|
||||||
returns: v.id("empresas"),
|
returns: v.id("empresas"),
|
||||||
@@ -80,17 +96,49 @@ export const create = mutation({
|
|||||||
if (cnpjExistente) {
|
if (cnpjExistente) {
|
||||||
throw new Error("Já existe uma empresa cadastrada com este CNPJ.");
|
throw new Error("Já existe uma empresa cadastrada com este CNPJ.");
|
||||||
}
|
}
|
||||||
|
let enderecoId: Id<"enderecos"> | undefined;
|
||||||
|
if (args.endereco) {
|
||||||
|
enderecoId = await ctx.db.insert("enderecos", {
|
||||||
|
cep: args.endereco.cep,
|
||||||
|
logradouro: args.endereco.logradouro,
|
||||||
|
numero: args.endereco.numero,
|
||||||
|
complemento: args.endereco.complemento,
|
||||||
|
bairro: args.endereco.bairro,
|
||||||
|
cidade: args.endereco.cidade,
|
||||||
|
uf: args.endereco.uf,
|
||||||
|
criadoPor: usuarioAtual._id,
|
||||||
|
atualizadoPor: usuarioAtual._id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const empresaDoc: {
|
||||||
|
razao_social: string;
|
||||||
const empresaId = await ctx.db.insert("empresas", {
|
nome_fantasia?: string;
|
||||||
nome: args.nome,
|
cnpj: string;
|
||||||
|
telefone: string;
|
||||||
|
email: string;
|
||||||
|
descricao?: string;
|
||||||
|
enderecoId?: Id<"enderecos">;
|
||||||
|
criadoPor: Id<"usuarios">;
|
||||||
|
} = {
|
||||||
|
razao_social: args.razao_social,
|
||||||
cnpj: args.cnpj,
|
cnpj: args.cnpj,
|
||||||
telefone: args.telefone,
|
telefone: args.telefone,
|
||||||
email: args.email,
|
email: args.email,
|
||||||
descricao: args.descricao,
|
|
||||||
criadoPor: usuarioAtual._id,
|
criadoPor: usuarioAtual._id,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (args.nome_fantasia !== undefined) {
|
||||||
|
empresaDoc.nome_fantasia = args.nome_fantasia;
|
||||||
|
}
|
||||||
|
if (args.descricao !== undefined) {
|
||||||
|
empresaDoc.descricao = args.descricao;
|
||||||
|
}
|
||||||
|
if (enderecoId) {
|
||||||
|
empresaDoc.enderecoId = enderecoId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const empresaId = await ctx.db.insert("empresas", empresaDoc);
|
||||||
|
|
||||||
if (args.contatos && args.contatos.length > 0) {
|
if (args.contatos && args.contatos.length > 0) {
|
||||||
for (const contato of args.contatos) {
|
for (const contato of args.contatos) {
|
||||||
@@ -113,11 +161,13 @@ export const create = mutation({
|
|||||||
export const update = mutation({
|
export const update = mutation({
|
||||||
args: {
|
args: {
|
||||||
id: v.id("empresas"),
|
id: v.id("empresas"),
|
||||||
nome: v.string(),
|
razao_social: v.string(),
|
||||||
|
nome_fantasia: v.optional(v.string()),
|
||||||
cnpj: v.string(),
|
cnpj: v.string(),
|
||||||
telefone: v.string(),
|
telefone: v.string(),
|
||||||
email: v.string(),
|
email: v.string(),
|
||||||
descricao: v.optional(v.string()),
|
descricao: v.optional(v.string()),
|
||||||
|
endereco: v.optional(enderecoInput),
|
||||||
contatos: v.optional(v.array(contatoInput)),
|
contatos: v.optional(v.array(contatoInput)),
|
||||||
},
|
},
|
||||||
returns: v.null(),
|
returns: v.null(),
|
||||||
@@ -135,14 +185,71 @@ export const update = mutation({
|
|||||||
if (cnpjExistente && cnpjExistente._id !== args.id) {
|
if (cnpjExistente && cnpjExistente._id !== args.id) {
|
||||||
throw new Error("Já existe uma empresa cadastrada com este CNPJ.");
|
throw new Error("Já existe uma empresa cadastrada com este CNPJ.");
|
||||||
}
|
}
|
||||||
|
const empresa = await ctx.db.get(args.id);
|
||||||
|
if (!empresa) {
|
||||||
|
throw new Error("Empresa não encontrada.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.endereco) {
|
||||||
|
if (empresa.enderecoId) {
|
||||||
|
const usuarioAtual = await getCurrentUserFunction(ctx);
|
||||||
|
await ctx.db.patch(empresa.enderecoId as Id<"enderecos">, {
|
||||||
|
cep: args.endereco.cep,
|
||||||
|
logradouro: args.endereco.logradouro,
|
||||||
|
numero: args.endereco.numero,
|
||||||
|
complemento: args.endereco.complemento,
|
||||||
|
bairro: args.endereco.bairro,
|
||||||
|
cidade: args.endereco.cidade,
|
||||||
|
uf: args.endereco.uf,
|
||||||
|
atualizadoPor: usuarioAtual?._id,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const usuarioAtual = await getCurrentUserFunction(ctx);
|
||||||
|
|
||||||
|
if (!usuarioAtual) {
|
||||||
|
throw new Error("Usuário não autenticado.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const novoEnderecoId: Id<"enderecos"> = await ctx.db.insert("enderecos", {
|
||||||
|
cep: args.endereco.cep,
|
||||||
|
logradouro: args.endereco.logradouro,
|
||||||
|
numero: args.endereco.numero,
|
||||||
|
complemento: args.endereco.complemento,
|
||||||
|
bairro: args.endereco.bairro,
|
||||||
|
cidade: args.endereco.cidade,
|
||||||
|
uf: args.endereco.uf,
|
||||||
|
criadoPor: usuarioAtual._id,
|
||||||
|
atualizadoPor: usuarioAtual._id,
|
||||||
|
});
|
||||||
|
|
||||||
await ctx.db.patch(args.id, {
|
await ctx.db.patch(args.id, {
|
||||||
nome: args.nome,
|
enderecoId: novoEnderecoId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const patchDoc: {
|
||||||
|
razao_social: string;
|
||||||
|
nome_fantasia?: string;
|
||||||
|
cnpj: string;
|
||||||
|
telefone: string;
|
||||||
|
email: string;
|
||||||
|
descricao?: string;
|
||||||
|
} = {
|
||||||
|
razao_social: args.razao_social,
|
||||||
cnpj: args.cnpj,
|
cnpj: args.cnpj,
|
||||||
telefone: args.telefone,
|
telefone: args.telefone,
|
||||||
email: args.email,
|
email: args.email,
|
||||||
descricao: args.descricao,
|
};
|
||||||
});
|
|
||||||
|
if (args.nome_fantasia !== undefined) {
|
||||||
|
patchDoc.nome_fantasia = args.nome_fantasia;
|
||||||
|
}
|
||||||
|
if (args.descricao !== undefined) {
|
||||||
|
patchDoc.descricao = args.descricao;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.db.patch(args.id, patchDoc);
|
||||||
|
|
||||||
if (!args.contatos) {
|
if (!args.contatos) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -125,15 +125,28 @@ export default defineSchema({
|
|||||||
text: v.string(),
|
text: v.string(),
|
||||||
completed: v.boolean(),
|
completed: v.boolean(),
|
||||||
}),
|
}),
|
||||||
|
enderecos: defineTable({
|
||||||
|
cep: v.string(),
|
||||||
|
logradouro: v.string(),
|
||||||
|
numero: v.string(),
|
||||||
|
complemento: v.optional(v.string()),
|
||||||
|
bairro: v.string(),
|
||||||
|
cidade: v.string(),
|
||||||
|
uf: v.string(),
|
||||||
|
criadoPor: v.optional(v.id("usuarios")),
|
||||||
|
atualizadoPor: v.optional(v.id("usuarios")),
|
||||||
|
}).index("by_cep", ["cep"]),
|
||||||
empresas: defineTable({
|
empresas: defineTable({
|
||||||
nome: v.string(),
|
razao_social: v.string(),
|
||||||
|
nome_fantasia: v.optional(v.string()),
|
||||||
cnpj: v.string(),
|
cnpj: v.string(),
|
||||||
telefone: v.string(),
|
telefone: v.string(),
|
||||||
email: v.string(),
|
email: v.string(),
|
||||||
descricao: v.optional(v.string()),
|
descricao: v.optional(v.string()),
|
||||||
|
enderecoId: v.optional(v.id("enderecos")),
|
||||||
criadoPor: v.optional(v.id("usuarios")),
|
criadoPor: v.optional(v.id("usuarios")),
|
||||||
})
|
})
|
||||||
.index("by_nome", ["nome"])
|
.index("by_razao_social", ["razao_social"])
|
||||||
.index("by_cnpj", ["cnpj"]),
|
.index("by_cnpj", ["cnpj"]),
|
||||||
contatosEmpresa: defineTable({
|
contatosEmpresa: defineTable({
|
||||||
empresaId: v.id("empresas"),
|
empresaId: v.id("empresas"),
|
||||||
|
|||||||
Reference in New Issue
Block a user