mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 11:01:45 +00:00
refactor(ui): renomear "Pagador/Pagadores" para "Pessoa/Pessoas" na interface
Todas as strings visíveis ao usuário (labels, títulos, toasts, mensagens de erro, cabeçalhos de tabela, exportações) foram atualizadas. Acordos de gênero em português corrigidos. Código, rotas (/payers) e schema do banco (pagadores) permanecem inalterados — divergência intencional documentada em CLAUDE.md e CHANGELOG. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR
|
|||||||
|
|
||||||
## [2.4.2] - 2026-04-20
|
## [2.4.2] - 2026-04-20
|
||||||
|
|
||||||
Esta versão é quase toda sobre organização e polimento. O código interno do Dashboard foi reestruturado — módulos espalhados pela raiz da feature foram agrupados em subdiretórios coesos e a arquitetura de widgets foi renovada com um novo `widget-registry`. A sidebar lateral foi aposentada em favor de uma navegação concentrada na navbar. A interface passou por um refinamento visual amplo: cards redesenhados, dark mode mais consistente e efeitos decorativos removidos para uma composição mais limpa. As imagens de preview da landing page foram atualizadas. Por fim, a integração com Logo.dev ganhou uma arquitetura mais segura — o token agora é lido apenas no servidor e nunca chega ao cliente.
|
Esta versão é quase toda sobre organização e polimento. O código interno do Dashboard foi reestruturado — módulos espalhados pela raiz da feature foram agrupados em subdiretórios coesos e a arquitetura de widgets foi renovada com um novo `widget-registry`. A sidebar lateral foi aposentada em favor de uma navegação concentrada na navbar. A interface passou por um refinamento visual amplo: cards redesenhados, dark mode mais consistente e efeitos decorativos removidos para uma composição mais limpa. As imagens de preview da landing page foram atualizadas. Por fim, a integração com Logo.dev ganhou uma arquitetura mais segura — o token agora é lido apenas no servidor e nunca chega ao cliente. O conceito de "Pagador" foi renomeado para "Pessoa" em toda a interface.
|
||||||
|
|
||||||
### Adicionado
|
### Adicionado
|
||||||
|
|
||||||
@@ -29,6 +29,7 @@ Esta versão é quase toda sobre organização e polimento. O código interno do
|
|||||||
- Landing: imagens de preview atualizadas; `mainFeatures` + `extraFeatures` unificados em grid único; dark mode nos botões de CTA
|
- Landing: imagens de preview atualizadas; `mainFeatures` + `extraFeatures` unificados em grid único; dark mode nos botões de CTA
|
||||||
- Navbar: dark mode corrigido no navbar-shell (`dark:bg-card`, `dark:border-b-border/60`)
|
- Navbar: dark mode corrigido no navbar-shell (`dark:bg-card`, `dark:border-b-border/60`)
|
||||||
- Logo.dev: `NEXT_PUBLIC_LOGO_DEV_TOKEN` renomeado para `LOGO_DEV_TOKEN` (agora lido em runtime server-side apenas)
|
- Logo.dev: `NEXT_PUBLIC_LOGO_DEV_TOKEN` renomeado para `LOGO_DEV_TOKEN` (agora lido em runtime server-side apenas)
|
||||||
|
- UI: conceito "Pagador/Pagadores" renomeado para **"Pessoa/Pessoas"** em toda a interface — labels, títulos, toasts, mensagens de erro, cabeçalhos de tabela e exportações. Código, rotas (`/payers`) e schema do banco (`pagadores`) permanecem inalterados; a divergência entre UI e código é intencional
|
||||||
- Deps: next 16.2.3 → 16.2.4, better-auth 1.6.2 → 1.6.5, ai 6.0.159 → 6.0.168 e outros patches menores
|
- Deps: next 16.2.3 → 16.2.4, better-auth 1.6.2 → 1.6.5, ai 6.0.159 → 6.0.168 e outros patches menores
|
||||||
|
|
||||||
### Removido
|
### Removido
|
||||||
|
|||||||
@@ -217,7 +217,9 @@ Layouts, `loading.tsx` e metadata continuam em `src/app/`.
|
|||||||
| `contas` | `accounts` |
|
| `contas` | `accounts` |
|
||||||
| `categorias` | `categories` |
|
| `categorias` | `categories` |
|
||||||
| `orcamentos` | `budgets` |
|
| `orcamentos` | `budgets` |
|
||||||
| `pagadores` | `payers` |
|
| `pessoas` | `payers` |
|
||||||
|
|
||||||
|
> **Nota:** o conceito de "pagador" foi renomeado para **"pessoa"** na UI (labels, toasts, textos visíveis ao usuário). O código, rotas e schema continuam usando o termo original em inglês (`payer`, `payerId`, `adminPayerId`) e em português interno (`pagador` como variável). Não renomear esses identificadores — a divergência entre UI e código é intencional e documentada.
|
||||||
| `anotacoes` | `notes` |
|
| `anotacoes` | `notes` |
|
||||||
| `calendario` | `calendar` |
|
| `calendario` | `calendar` |
|
||||||
| `ajustes` | `settings` |
|
| `ajustes` | `settings` |
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { RiGroupLine } from "@remixicon/react";
|
|||||||
import PageDescription from "@/shared/components/page-description";
|
import PageDescription from "@/shared/components/page-description";
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: "Pagadores",
|
title: "Pessoas",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
@@ -14,7 +14,7 @@ export default function RootLayout({
|
|||||||
<section className="space-y-6">
|
<section className="space-y-6">
|
||||||
<PageDescription
|
<PageDescription
|
||||||
icon={<RiGroupLine />}
|
icon={<RiGroupLine />}
|
||||||
title="Pagadores"
|
title="Pessoas"
|
||||||
subtitle="Gerencie as pessoas ou entidades responsáveis pelos pagamentos."
|
subtitle="Gerencie as pessoas ou entidades responsáveis pelos pagamentos."
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Skeleton } from "@/shared/components/ui/skeleton";
|
import { Skeleton } from "@/shared/components/ui/skeleton";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loading state para a página de pagadores
|
* Loading state para a página de pessoas
|
||||||
* Layout: Header + Input de compartilhamento + Grid de cards
|
* Layout: Header + Input de compartilhamento + Grid de cards
|
||||||
*/
|
*/
|
||||||
export default function PagadoresLoading() {
|
export default function PagadoresLoading() {
|
||||||
@@ -17,7 +17,7 @@ export default function PagadoresLoading() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Grid de cards de pagadores */}
|
{/* Grid de cards de pessoas */}
|
||||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||||
{Array.from({ length: 6 }).map((_, i) => (
|
{Array.from({ length: 6 }).map((_, i) => (
|
||||||
<div key={i} className="rounded-md border p-6 space-y-4">
|
<div key={i} className="rounded-md border p-6 space-y-4">
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export async function createAccountAction(
|
|||||||
|
|
||||||
if (hasInitialBalance && !adminPayerId) {
|
if (hasInitialBalance && !adminPayerId) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Pagador com papel administrador não encontrado. Crie um pagador admin antes de definir um saldo inicial.",
|
"Pessoa com papel administrador não encontrado. Crie um pessoa admin antes de definir um saldo inicial.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ export async function transferBetweenAccountsAction(
|
|||||||
|
|
||||||
if (!adminPayerId) {
|
if (!adminPayerId) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Pagador administrador não encontrado. Por favor, crie um pagador admin.",
|
"Pessoa administrador não encontrado. Por favor, crie um pessoa admin.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export function AccountStatementCard({
|
|||||||
|
|
||||||
<MetaItem
|
<MetaItem
|
||||||
label="Saídas"
|
label="Saídas"
|
||||||
tooltip="Total de despesas pagas neste mês (considerando divisão entre pagadores)."
|
tooltip="Total de despesas pagas neste mês (considerando divisão entre pessoas)."
|
||||||
>
|
>
|
||||||
<span className="text-sm font-medium text-destructive">
|
<span className="text-sm font-medium text-destructive">
|
||||||
{formatCurrency(totalExpenses)}
|
{formatCurrency(totalExpenses)}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const CARDS = [
|
|||||||
helpTitle: "Como calculamos receitas",
|
helpTitle: "Como calculamos receitas",
|
||||||
helpLines: [
|
helpLines: [
|
||||||
"Somamos os lançamentos do tipo Receita no período selecionado.",
|
"Somamos os lançamentos do tipo Receita no período selecionado.",
|
||||||
"Consideramos lançamentos efetivados e não efetivados do pagador principal (admin).",
|
"Consideramos lançamentos efetivados e não efetivados da pessoa principal (admin).",
|
||||||
"Movimentações de contas marcadas como não consideradas no saldo total ficam fora deste card.",
|
"Movimentações de contas marcadas como não consideradas no saldo total ficam fora deste card.",
|
||||||
"Não entram transferências internas nem lançamentos automáticos de fatura.",
|
"Não entram transferências internas nem lançamentos automáticos de fatura.",
|
||||||
"Saldo inicial também fica fora quando a conta está marcada para desconsiderá-lo das receitas.",
|
"Saldo inicial também fica fora quando a conta está marcada para desconsiderá-lo das receitas.",
|
||||||
@@ -54,7 +54,7 @@ const CARDS = [
|
|||||||
helpTitle: "Como calculamos despesas",
|
helpTitle: "Como calculamos despesas",
|
||||||
helpLines: [
|
helpLines: [
|
||||||
"Somamos os lançamentos do tipo Despesa no período selecionado.",
|
"Somamos os lançamentos do tipo Despesa no período selecionado.",
|
||||||
"Consideramos lançamentos efetivados e não efetivados do pagador principal (admin).",
|
"Consideramos lançamentos efetivados e não efetivados da pessoa principal (admin).",
|
||||||
"Movimentações de contas marcadas como não consideradas no saldo total ficam fora deste card.",
|
"Movimentações de contas marcadas como não consideradas no saldo total ficam fora deste card.",
|
||||||
"Não entram transferências internas nem lançamentos automáticos de fatura.",
|
"Não entram transferências internas nem lançamentos automáticos de fatura.",
|
||||||
"O valor mostrado é a saída efetiva do período, sempre em número positivo no card.",
|
"O valor mostrado é a saída efetiva do período, sempre em número positivo no card.",
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export function InvoiceListItem({ invoice, onPay }: InvoiceListItemProps) {
|
|||||||
<HoverCardTrigger asChild>{linkNode}</HoverCardTrigger>
|
<HoverCardTrigger asChild>{linkNode}</HoverCardTrigger>
|
||||||
<HoverCardContent align="start" className="w-80 space-y-3">
|
<HoverCardContent align="start" className="w-80 space-y-3">
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
Distribuição por pagador
|
Distribuição por pessoa
|
||||||
</p>
|
</p>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{breakdown.map((share, index) => (
|
{breakdown.map((share, index) => (
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ export function PayersWidget({ payers }: PayersWidgetProps) {
|
|||||||
{payers.length === 0 ? (
|
{payers.length === 0 ? (
|
||||||
<WidgetEmptyState
|
<WidgetEmptyState
|
||||||
icon={<RiGroupLine className="size-6 text-muted-foreground" />}
|
icon={<RiGroupLine className="size-6 text-muted-foreground" />}
|
||||||
title="Nenhum pagador para o período"
|
title="Nenhuma pessoa para o período"
|
||||||
description="Quando houver despesas associadas a pagadores, eles aparecerão aqui."
|
description="Quando houver despesas associadas a pessoas, elas aparecerão aqui."
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export async function fetchInstallmentAnalysis(
|
|||||||
return { installmentGroups: [], totalPendingInstallments: 0 };
|
return { installmentGroups: [], totalPendingInstallments: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Buscar todos os lançamentos parcelados não antecipados do pagador admin
|
// 1. Buscar todos os lançamentos parcelados não antecipados da pessoa admin
|
||||||
const installmentRows = await db
|
const installmentRows = await db
|
||||||
.select({
|
.select({
|
||||||
id: transactions.id,
|
id: transactions.id,
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ export async function fetchDashboardInvoices(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const payerId = row.payerId ?? null;
|
const payerId = row.payerId ?? null;
|
||||||
const pagadorName = row.pagadorName?.trim() || "Sem pagador";
|
const pagadorName = row.pagadorName?.trim() || "Sem pessoa";
|
||||||
const pagadorAvatar = row.pagadorAvatar ?? null;
|
const pagadorAvatar = row.pagadorAvatar ?? null;
|
||||||
const payerKey = payerId ?? "__without-payer__";
|
const payerKey = payerId ?? "__without-payer__";
|
||||||
const key = `${row.cardId}:${payerKey}`;
|
const key = `${row.cardId}:${payerKey}`;
|
||||||
|
|||||||
@@ -251,8 +251,8 @@ export const widgetsConfig: WidgetConfig[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "pagadores",
|
id: "pagadores",
|
||||||
title: "Pagadores",
|
title: "Pessoas",
|
||||||
subtitle: "Despesas por pagador no período",
|
subtitle: "Despesas por pessoa no período",
|
||||||
icon: <RiGroupLine className="size-4" />,
|
icon: <RiGroupLine className="size-4" />,
|
||||||
component: ({ data }) => (
|
component: ({ data }) => (
|
||||||
<PayersWidget payers={data.pagadoresSnapshot.payers} />
|
<PayersWidget payers={data.pagadoresSnapshot.payers} />
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ const statusEnum = z
|
|||||||
|
|
||||||
const baseSchema = z.object({
|
const baseSchema = z.object({
|
||||||
name: z
|
name: z
|
||||||
.string({ message: "Informe o nome do pagador." })
|
.string({ message: "Informe o nome da pessoa." })
|
||||||
.trim()
|
.trim()
|
||||||
.min(1, "Informe o nome do pagador."),
|
.min(1, "Informe o nome da pessoa."),
|
||||||
email: z
|
email: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
@@ -110,7 +110,7 @@ export async function createPayerAction(
|
|||||||
|
|
||||||
revalidate(user.id);
|
revalidate(user.id);
|
||||||
|
|
||||||
return { success: true, message: "Payer criado com sucesso." };
|
return { success: true, message: "Pessoa criada com sucesso." };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return handleActionError(error);
|
return handleActionError(error);
|
||||||
}
|
}
|
||||||
@@ -130,7 +130,7 @@ export async function updatePayerAction(
|
|||||||
if (!existing) {
|
if (!existing) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: "Pagador não encontrado.",
|
error: "Pessoa não encontrada.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ export async function updatePayerAction(
|
|||||||
|
|
||||||
revalidate(currentUser.id);
|
revalidate(currentUser.id);
|
||||||
|
|
||||||
return { success: true, message: "Payer atualizado com sucesso." };
|
return { success: true, message: "Pessoa atualizada com sucesso." };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return handleActionError(error);
|
return handleActionError(error);
|
||||||
}
|
}
|
||||||
@@ -180,14 +180,14 @@ export async function deletePayerAction(
|
|||||||
if (!existing) {
|
if (!existing) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: "Pagador não encontrado.",
|
error: "Pessoa não encontrada.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existing.role === PAYER_ROLE_ADMIN) {
|
if (existing.role === PAYER_ROLE_ADMIN) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: "Pagadores administradores não podem ser removidos.",
|
error: "Pessoas administradoras não podem ser removidas.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ export async function deletePayerAction(
|
|||||||
|
|
||||||
revalidate(user.id);
|
revalidate(user.id);
|
||||||
|
|
||||||
return { success: true, message: "Payer removido com sucesso." };
|
return { success: true, message: "Pessoa removida com sucesso." };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return handleActionError(error);
|
return handleActionError(error);
|
||||||
}
|
}
|
||||||
@@ -221,7 +221,7 @@ export async function joinPayerByShareCodeAction(
|
|||||||
if (pagadorRow.userId === user.id) {
|
if (pagadorRow.userId === user.id) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: "Você já é o proprietário deste pagador.",
|
error: "Você já é o proprietário desta entidade pagadora.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ export async function joinPayerByShareCodeAction(
|
|||||||
if (existingShare) {
|
if (existingShare) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: "Você já possui acesso a este pagador.",
|
error: "Você já possui acesso a esta pessoa.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +248,7 @@ export async function joinPayerByShareCodeAction(
|
|||||||
|
|
||||||
revalidate(user.id);
|
revalidate(user.id);
|
||||||
|
|
||||||
return { success: true, message: "Payer adicionado à sua lista." };
|
return { success: true, message: "Pessoa adicionada à sua lista." };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return handleActionError(error);
|
return handleActionError(error);
|
||||||
}
|
}
|
||||||
@@ -313,7 +313,7 @@ export async function regeneratePayerShareCodeAction(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
return { success: false, error: "Payer não encontrado." };
|
return { success: false, error: "Pessoa não encontrada." };
|
||||||
}
|
}
|
||||||
|
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export function PayerHeaderCard({
|
|||||||
|
|
||||||
const openConfirmDialog = () => {
|
const openConfirmDialog = () => {
|
||||||
if (!payer.email) {
|
if (!payer.email) {
|
||||||
toast.error("Cadastre um e-mail para este pagador antes de enviar.");
|
toast.error("Cadastre um e-mail para esta pessoa antes de enviar.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setConfirmOpen(true);
|
setConfirmOpen(true);
|
||||||
@@ -74,7 +74,7 @@ export function PayerHeaderCard({
|
|||||||
|
|
||||||
const handleSendSummary = () => {
|
const handleSendSummary = () => {
|
||||||
if (!payer.email) {
|
if (!payer.email) {
|
||||||
toast.error("Cadastre um e-mail para este pagador antes de enviar.");
|
toast.error("Cadastre um e-mail para esta pessoa antes de enviar.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export function PayerHistoryCard({ data }: PagadorHistoryCardProps) {
|
|||||||
Evolução (últimos 6 meses)
|
Evolução (últimos 6 meses)
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
Despesas registradas para este pagador ao longo do tempo.
|
Despesas registradas para esta pessoa ao longo do tempo.
|
||||||
</p>
|
</p>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export function PagadorInfoCard({ payer }: PayerInfoCardProps) {
|
|||||||
<Card className="border gap-4">
|
<Card className="border gap-4">
|
||||||
<CardHeader className="gap-1.5">
|
<CardHeader className="gap-1.5">
|
||||||
<CardTitle className="text-lg font-semibold">
|
<CardTitle className="text-lg font-semibold">
|
||||||
Detalhes do pagador
|
Detalhes da pessoa
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
{showSensitiveDetails
|
{showSensitiveDetails
|
||||||
@@ -106,7 +106,7 @@ export function PagadorInfoCard({ payer }: PayerInfoCardProps) {
|
|||||||
|
|
||||||
const resolveRoleLabel = (role: string | null) => {
|
const resolveRoleLabel = (role: string | null) => {
|
||||||
if (role === PAYER_ROLE_ADMIN) return "Administrador";
|
if (role === PAYER_ROLE_ADMIN) return "Administrador";
|
||||||
return "Pagador";
|
return "Pessoa";
|
||||||
};
|
};
|
||||||
|
|
||||||
type InfoItemProps = {
|
type InfoItemProps = {
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export function PayerSharingCard({
|
|||||||
</CardTitle>
|
</CardTitle>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Compartilhe o código abaixo com outra pessoa. Ela poderá adicioná-lo
|
Compartilhe o código abaixo com outra pessoa. Ela poderá adicioná-lo
|
||||||
na página de pagadores usando a opção Adicionar por código para ter
|
na página de pessoas usando a opção Adicionar por código para ter
|
||||||
acesso somente leitura.
|
acesso somente leitura.
|
||||||
</p>
|
</p>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ export function PayerDialog({
|
|||||||
const payerId = payer?.id;
|
const payerId = payer?.id;
|
||||||
|
|
||||||
if (mode === "update" && !payerId) {
|
if (mode === "update" && !payerId) {
|
||||||
const message = "Pagador inválido.";
|
const message = "Pessoa inválida.";
|
||||||
setErrorMessage(message);
|
setErrorMessage(message);
|
||||||
toast.error(message);
|
toast.error(message);
|
||||||
return;
|
return;
|
||||||
@@ -216,13 +216,12 @@ export function PayerDialog({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const title = mode === "create" ? "Novo pagador" : "Editar pagador";
|
const title = mode === "create" ? "Nova pessoa" : "Editar pessoa";
|
||||||
const description =
|
const description =
|
||||||
mode === "create"
|
mode === "create"
|
||||||
? "Selecione um avatar e informe os detalhes para criar um novo pagador."
|
? "Selecione um avatar e informe os detalhes para criar uma nova pessoa."
|
||||||
: "Atualize os detalhes do pagador selecionado.";
|
: "Atualize os detalhes da pessoa selecionada.";
|
||||||
const submitLabel =
|
const submitLabel = mode === "create" ? "Salvar pessoa" : "Atualizar pessoa";
|
||||||
mode === "create" ? "Salvar pagador" : "Atualizar pagador";
|
|
||||||
|
|
||||||
const isUploadSelected =
|
const isUploadSelected =
|
||||||
uploadedAvatar !== null && formState.avatarUrl === uploadedAvatar;
|
uploadedAvatar !== null && formState.avatarUrl === uploadedAvatar;
|
||||||
@@ -388,7 +387,7 @@ export function PayerDialog({
|
|||||||
id="payer-note"
|
id="payer-note"
|
||||||
value={formState.note}
|
value={formState.note}
|
||||||
onChange={(event) => updateField("note", event.target.value)}
|
onChange={(event) => updateField("note", event.target.value)}
|
||||||
placeholder="Observações sobre este pagador"
|
placeholder="Observações sobre esta pessoa"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export function PayersPage({ payers, avatarOptions }: PayersPageProps) {
|
|||||||
|
|
||||||
const handleRemoveRequest = (payer: Payer) => {
|
const handleRemoveRequest = (payer: Payer) => {
|
||||||
if (payer.role === PAYER_ROLE_ADMIN) {
|
if (payer.role === PAYER_ROLE_ADMIN) {
|
||||||
toast.error("Pagadores administradores não podem ser removidos.");
|
toast.error("Pessoas administradoras não podem ser removidas.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setPayerToRemove(payer);
|
setPayerToRemove(payer);
|
||||||
@@ -91,8 +91,8 @@ export function PayersPage({ payers, avatarOptions }: PayersPageProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const removeTitle = payerToRemove
|
const removeTitle = payerToRemove
|
||||||
? `Remover pagador "${payerToRemove.name}"?`
|
? `Remover pessoa "${payerToRemove.name}"?`
|
||||||
: "Remover pagador?";
|
: "Remover pessoa?";
|
||||||
|
|
||||||
const handleJoinByCode = (event: React.FormEvent<HTMLFormElement>) => {
|
const handleJoinByCode = (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -127,7 +127,7 @@ export function PayersPage({ payers, avatarOptions }: PayersPageProps) {
|
|||||||
trigger={
|
trigger={
|
||||||
<Button className="w-full sm:w-auto">
|
<Button className="w-full sm:w-auto">
|
||||||
<RiAddFill className="size-4" />
|
<RiAddFill className="size-4" />
|
||||||
Novo pagador
|
Nova pessoa
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -151,7 +151,7 @@ export function PayersPage({ payers, avatarOptions }: PayersPageProps) {
|
|||||||
{orderedPayers.length === 0 ? (
|
{orderedPayers.length === 0 ? (
|
||||||
<div className="flex min-h-[320px] items-center justify-center rounded-lg border border-dashed bg-muted/30">
|
<div className="flex min-h-[320px] items-center justify-center rounded-lg border border-dashed bg-muted/30">
|
||||||
<div className="max-w-sm text-center text-sm text-muted-foreground">
|
<div className="max-w-sm text-center text-sm text-muted-foreground">
|
||||||
Cadastre seu primeiro pagador para organizar cobranças e
|
Cadastre seu primeira pessoa para organizar cobranças e
|
||||||
pagamentos recorrentes.
|
pagamentos recorrentes.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -185,8 +185,8 @@ export function PayersPage({ payers, avatarOptions }: PayersPageProps) {
|
|||||||
open={removeOpen && !!payerToRemove}
|
open={removeOpen && !!payerToRemove}
|
||||||
onOpenChange={handleRemoveOpenChange}
|
onOpenChange={handleRemoveOpenChange}
|
||||||
title={removeTitle}
|
title={removeTitle}
|
||||||
description="Ao remover este pagador, os registros relacionados a ele deixarão de ser associados automaticamente."
|
description="Ao remover esta pessoa, os registros relacionados a ele deixarão de ser associados automaticamente."
|
||||||
confirmLabel="Remover pagador"
|
confirmLabel="Remover pessoa"
|
||||||
pendingLabel="Removendo..."
|
pendingLabel="Removendo..."
|
||||||
confirmVariant="destructive"
|
confirmVariant="destructive"
|
||||||
onConfirm={handleRemoveConfirm}
|
onConfirm={handleRemoveConfirm}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { formatDateTime } from "@/shared/utils/date";
|
|||||||
import { displayPeriod } from "@/shared/utils/period";
|
import { displayPeriod } from "@/shared/utils/period";
|
||||||
|
|
||||||
const inputSchema = z.object({
|
const inputSchema = z.object({
|
||||||
payerId: z.string().uuid("Payer inválido."),
|
payerId: z.string().uuid("Pessoa inválida."),
|
||||||
period: z
|
period: z
|
||||||
.string()
|
.string()
|
||||||
.regex(/^\d{4}-\d{2}$/, "Período inválido. Informe no formato AAAA-MM."),
|
.regex(/^\d{4}-\d{2}$/, "Período inválido. Informe no formato AAAA-MM."),
|
||||||
@@ -404,7 +404,7 @@ export async function sendPayerSummaryAction(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!pagadorRow) {
|
if (!pagadorRow) {
|
||||||
return { success: false, error: "Pagador não encontrado." };
|
return { success: false, error: "Pessoa não encontrada." };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pagadorRow.email) {
|
if (!pagadorRow.email) {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ async function resetUserAppData(
|
|||||||
const payerName =
|
const payerName =
|
||||||
(user.name && user.name.trim().length > 0
|
(user.name && user.name.trim().length > 0
|
||||||
? user.name.trim()
|
? user.name.trim()
|
||||||
: normalizeNameFromEmail(user.email)) || "Payer principal";
|
: normalizeNameFromEmail(user.email)) || "Pessoa principal";
|
||||||
const avatarUrl = user.image ?? DEFAULT_PAYER_AVATAR;
|
const avatarUrl = user.image ?? DEFAULT_PAYER_AVATAR;
|
||||||
const defaultPayerStatus = PAYER_STATUS_OPTIONS[0];
|
const defaultPayerStatus = PAYER_STATUS_OPTIONS[0];
|
||||||
|
|
||||||
@@ -176,7 +176,7 @@ export async function updateNameAction(
|
|||||||
.set({ name: fullName })
|
.set({ name: fullName })
|
||||||
.where(eq(schema.user.id, session.user.id));
|
.where(eq(schema.user.id, session.user.id));
|
||||||
|
|
||||||
// Sincronizar nome com o pagador admin
|
// Sincronizar nome com o pessoa admin
|
||||||
if (adminPayerId) {
|
if (adminPayerId) {
|
||||||
await db
|
await db
|
||||||
.update(payers)
|
.update(payers)
|
||||||
|
|||||||
@@ -94,12 +94,12 @@ export function DeleteAccountForm() {
|
|||||||
<ul className="list-disc list-inside text-sm text-muted-foreground space-y-1">
|
<ul className="list-disc list-inside text-sm text-muted-foreground space-y-1">
|
||||||
<li>Lançamentos, faturas, antecipações e pré-lançamentos</li>
|
<li>Lançamentos, faturas, antecipações e pré-lançamentos</li>
|
||||||
<li>Contas, cartões, orçamentos e anotações</li>
|
<li>Contas, cartões, orçamentos e anotações</li>
|
||||||
<li>Pagadores próprios e compartilhamentos recebidos</li>
|
<li>Pessoas próprios e compartilhamentos recebidos</li>
|
||||||
<li>
|
<li>
|
||||||
Preferências do app, insights salvos e tokens do Companion
|
Preferências do app, insights salvos e tokens do Companion
|
||||||
</li>
|
</li>
|
||||||
<li className="font-medium text-foreground">
|
<li className="font-medium text-foreground">
|
||||||
Categorias padrão e pagador admin serão recriados
|
Categorias padrão e pessoa admin serão recriadas
|
||||||
automaticamente
|
automaticamente
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -130,7 +130,7 @@ export function DeleteAccountForm() {
|
|||||||
<ul className="list-disc list-inside text-sm text-destructive space-y-1">
|
<ul className="list-disc list-inside text-sm text-destructive space-y-1">
|
||||||
<li>Lançamentos, orçamentos e anotações</li>
|
<li>Lançamentos, orçamentos e anotações</li>
|
||||||
<li>Contas, cartões e categorias</li>
|
<li>Contas, cartões e categorias</li>
|
||||||
<li>Pagadores, credenciais e configurações</li>
|
<li>Pessoas, credenciais e configurações</li>
|
||||||
<li className="font-medium">
|
<li className="font-medium">
|
||||||
Resumindo, sua conta irá de arrasta pra cima!
|
Resumindo, sua conta irá de arrasta pra cima!
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -602,7 +602,7 @@ export async function createMassTransactionsAction(
|
|||||||
if (transaction.payerId && invalidPayers.has(transaction.payerId)) {
|
if (transaction.payerId && invalidPayers.has(transaction.payerId)) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `Payer não encontrado na transação ${i + 1}.`,
|
error: `Pessoa não encontrado na transação ${i + 1}.`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -611,7 +611,7 @@ export async function createMassTransactionsAction(
|
|||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `Category não encontrada na transação ${i + 1}.`,
|
error: `Categoria não encontrada na transação ${i + 1}.`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,8 +189,8 @@ export async function validateAllOwnership(
|
|||||||
];
|
];
|
||||||
|
|
||||||
const errors = [
|
const errors = [
|
||||||
"Pagador não encontrado ou sem permissão.",
|
"Pessoa não encontrada ou sem permissão.",
|
||||||
"Pagador secundário não encontrado ou sem permissão.",
|
"Pessoa secundário não encontrado ou sem permissão.",
|
||||||
"Categoria não encontrada.",
|
"Categoria não encontrada.",
|
||||||
"Conta não encontrada.",
|
"Conta não encontrada.",
|
||||||
"Cartão não encontrado.",
|
"Cartão não encontrado.",
|
||||||
@@ -359,7 +359,7 @@ const refineLancamento = (
|
|||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
path: ["payerId"],
|
path: ["payerId"],
|
||||||
message: "Selecione o pagador principal para dividir o lançamento.",
|
message: "Selecione a pessoa principal para dividir o lançamento.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,13 +367,13 @@ const refineLancamento = (
|
|||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
path: ["secondaryPayerId"],
|
path: ["secondaryPayerId"],
|
||||||
message: "Selecione o pagador secundário para dividir o lançamento.",
|
message: "Selecione a pessoa secundário para dividir o lançamento.",
|
||||||
});
|
});
|
||||||
} else if (data.payerId && data.secondaryPayerId === data.payerId) {
|
} else if (data.payerId && data.secondaryPayerId === data.payerId) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
path: ["secondaryPayerId"],
|
path: ["secondaryPayerId"],
|
||||||
message: "Escolha um pagador diferente para dividir o lançamento.",
|
message: "Escolha uma pessoa diferente para dividir o lançamento.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export async function importTransactionsAction(
|
|||||||
validateCartaoOwnership(userId, cardId),
|
validateCartaoOwnership(userId, cardId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!payerOk) return { success: false, error: "Pagador não encontrado." };
|
if (!payerOk) return { success: false, error: "Pessoa não encontrada." };
|
||||||
if (!accountOk) return { success: false, error: "Conta não encontrada." };
|
if (!accountOk) return { success: false, error: "Conta não encontrada." };
|
||||||
if (!cardOk) return { success: false, error: "Cartão não encontrado." };
|
if (!cardOk) return { success: false, error: "Cartão não encontrado." };
|
||||||
|
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ export async function createInstallmentAnticipationAction(
|
|||||||
if (data.payerId && payer.length === 0) {
|
if (data.payerId && payer.length === 0) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: "Pagador inválido para esta conta.",
|
error: "Pessoa inválida para esta conta.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const LANCAMENTOS_COLUMN_LABELS: Record<string, string> = {
|
|||||||
condition: "Condição",
|
condition: "Condição",
|
||||||
paymentMethod: "Forma de Pagamento",
|
paymentMethod: "Forma de Pagamento",
|
||||||
categoriaName: "Categoria",
|
categoriaName: "Categoria",
|
||||||
pagadorName: "Pagador",
|
pagadorName: "Pessoa",
|
||||||
note: "Anotação",
|
note: "Anotação",
|
||||||
contaCartao: "Conta/Cartão",
|
contaCartao: "Conta/Cartão",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ export function AnticipateInstallmentsDialog({
|
|||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field className="gap-1">
|
<Field className="gap-1">
|
||||||
<FieldLabel htmlFor="anticipation-pagador">Pagador</FieldLabel>
|
<FieldLabel htmlFor="anticipation-pagador">Pessoa</FieldLabel>
|
||||||
<FieldContent>
|
<FieldContent>
|
||||||
<Select
|
<Select
|
||||||
value={formState.payerId}
|
value={formState.payerId}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ export function BulkActionDialog({
|
|||||||
htmlFor="period"
|
htmlFor="period"
|
||||||
className="text-sm cursor-pointer font-medium"
|
className="text-sm cursor-pointer font-medium"
|
||||||
>
|
>
|
||||||
Todos os pagadores deste período
|
Todas as pessoas deste período
|
||||||
</Label>
|
</Label>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
Aplica a todos os lançamentos deste mesmo mês na série
|
Aplica a todos os lançamentos deste mesmo mês na série
|
||||||
@@ -125,7 +125,7 @@ export function BulkActionDialog({
|
|||||||
<div className="mt-1.5 flex items-start gap-1.5 rounded-md bg-amber-50 px-2 py-1.5 text-amber-800 dark:bg-amber-950/40 dark:text-amber-300">
|
<div className="mt-1.5 flex items-start gap-1.5 rounded-md bg-amber-50 px-2 py-1.5 text-amber-800 dark:bg-amber-950/40 dark:text-amber-300">
|
||||||
<RiErrorWarningLine className="mt-0.5 size-3.5 shrink-0" />
|
<RiErrorWarningLine className="mt-0.5 size-3.5 shrink-0" />
|
||||||
<p className="text-xs">
|
<p className="text-xs">
|
||||||
Atenção: os valores individuais de cada pagador serão
|
Atenção: os valores individuais de cada pessoa serão
|
||||||
substituídos pelos valores deste lançamento.
|
substituídos pelos valores deste lançamento.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export function BulkImportDialog({
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (!payerId) {
|
if (!payerId) {
|
||||||
toast.error("Selecione o pagador.");
|
toast.error("Selecione a pessoa.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,16 +197,16 @@ export function BulkImportDialog({
|
|||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
Importando {itemCount}{" "}
|
Importando {itemCount}{" "}
|
||||||
{itemCount === 1 ? "lançamento" : "lançamentos"}. Selecione o
|
{itemCount === 1 ? "lançamento" : "lançamentos"}. Selecione o
|
||||||
pagador, categoria e forma de pagamento para aplicar a todos.
|
pessoa, categoria e forma de pagamento para aplicar a todos.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<form className="space-y-4" onSubmit={handleSubmit}>
|
<form className="space-y-4" onSubmit={handleSubmit}>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="pagador">Pagador *</Label>
|
<Label htmlFor="pagador">Pessoa *</Label>
|
||||||
<Select value={payerId} onValueChange={setPagadorId}>
|
<Select value={payerId} onValueChange={setPagadorId}>
|
||||||
<SelectTrigger id="pagador" className="w-full">
|
<SelectTrigger id="pagador" className="w-full">
|
||||||
<SelectValue placeholder="Selecione o pagador">
|
<SelectValue placeholder="Selecione a pessoa">
|
||||||
{payerId &&
|
{payerId &&
|
||||||
(() => {
|
(() => {
|
||||||
const selectedOption = payerOptions.find(
|
const selectedOption = payerOptions.find(
|
||||||
|
|||||||
@@ -525,7 +525,7 @@ export function MassAddDialog({
|
|||||||
htmlFor={`pagador-${transaction.id}`}
|
htmlFor={`pagador-${transaction.id}`}
|
||||||
className="sr-only"
|
className="sr-only"
|
||||||
>
|
>
|
||||||
Pagador {index + 1}
|
Pessoa {index + 1}
|
||||||
</Label>
|
</Label>
|
||||||
<Select
|
<Select
|
||||||
value={transaction.payerId}
|
value={transaction.payerId}
|
||||||
@@ -537,7 +537,7 @@ export function MassAddDialog({
|
|||||||
id={`pagador-${transaction.id}`}
|
id={`pagador-${transaction.id}`}
|
||||||
className="w-32 truncate"
|
className="w-32 truncate"
|
||||||
>
|
>
|
||||||
<SelectValue placeholder="Pagador">
|
<SelectValue placeholder="Pessoa">
|
||||||
{transaction.payerId &&
|
{transaction.payerId &&
|
||||||
(() => {
|
(() => {
|
||||||
const selectedOption = payerOptions.find(
|
const selectedOption = payerOptions.find(
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export function PayerSection({
|
|||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-foreground">Dividir lançamento</p>
|
<p className="text-sm text-foreground">Dividir lançamento</p>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
Atribuir parte do valor a outro pagador.
|
Atribuir parte do valor a outra pessoa.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -75,7 +75,7 @@ export function PayerSection({
|
|||||||
|
|
||||||
<div className="flex w-full flex-col gap-2 md:flex-row">
|
<div className="flex w-full flex-col gap-2 md:flex-row">
|
||||||
<div className="w-full space-y-1">
|
<div className="w-full space-y-1">
|
||||||
<Label htmlFor="payer">Pagador</Label>
|
<Label htmlFor="payer">Pessoa</Label>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Select
|
<Select
|
||||||
value={formState.payerId ?? ""}
|
value={formState.payerId ?? ""}
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ export function TransactionDialog({
|
|||||||
|
|
||||||
if (formState.isSplit && !formState.payerId) {
|
if (formState.isSplit && !formState.payerId) {
|
||||||
const message =
|
const message =
|
||||||
"Selecione o pagador principal para dividir o lançamento.";
|
"Selecione a pessoa principal para dividir o lançamento.";
|
||||||
setErrorMessage(message);
|
setErrorMessage(message);
|
||||||
toast.error(message);
|
toast.error(message);
|
||||||
return;
|
return;
|
||||||
@@ -238,7 +238,7 @@ export function TransactionDialog({
|
|||||||
|
|
||||||
if (formState.isSplit && !formState.secondaryPayerId) {
|
if (formState.isSplit && !formState.secondaryPayerId) {
|
||||||
const message =
|
const message =
|
||||||
"Selecione o pagador secundário para dividir o lançamento.";
|
"Selecione a pessoa secundário para dividir o lançamento.";
|
||||||
setErrorMessage(message);
|
setErrorMessage(message);
|
||||||
toast.error(message);
|
toast.error(message);
|
||||||
return;
|
return;
|
||||||
@@ -464,7 +464,7 @@ export function TransactionDialog({
|
|||||||
const description =
|
const description =
|
||||||
mode === "create"
|
mode === "create"
|
||||||
? isImportMode
|
? isImportMode
|
||||||
? "Importando lançamento de outro usuário. Ajuste a categoria, pagador e cartão/conta antes de salvar."
|
? "Importando lançamento de outro usuário. Ajuste a categoria, pessoa e cartão/conta antes de salvar."
|
||||||
: isCopyMode
|
: isCopyMode
|
||||||
? "Os dados do lançamento foram copiados. Revise e ajuste conforme necessário antes de salvar."
|
? "Os dados do lançamento foram copiados. Revise e ajuste conforme necessário antes de salvar."
|
||||||
: isNewWithType
|
: isNewWithType
|
||||||
@@ -519,7 +519,7 @@ export function TransactionDialog({
|
|||||||
|
|
||||||
<div className="border-t border-border/40 my-3" />
|
<div className="border-t border-border/40 my-3" />
|
||||||
|
|
||||||
{/* Pagador */}
|
{/* Pessoa */}
|
||||||
<PayerSection
|
<PayerSection
|
||||||
formState={formState}
|
formState={formState}
|
||||||
onFieldChange={handleFieldChange}
|
onFieldChange={handleFieldChange}
|
||||||
|
|||||||
@@ -123,13 +123,13 @@ export function GlobalFields({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex min-w-44 flex-col gap-1.5">
|
<div className="flex min-w-44 flex-col gap-1.5">
|
||||||
<Label>Pagador</Label>
|
<Label>Pessoa</Label>
|
||||||
<Select
|
<Select
|
||||||
value={payerId ?? ""}
|
value={payerId ?? ""}
|
||||||
onValueChange={(v) => onPayerChange(v || null)}
|
onValueChange={(v) => onPayerChange(v || null)}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Selecionar pagador…" />
|
<SelectValue placeholder="Selecionar pessoa…" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{payerOptions.map((opt) => (
|
{payerOptions.map((opt) => (
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ export function AnticipationCard({
|
|||||||
|
|
||||||
{anticipation.payer && (
|
{anticipation.payer && (
|
||||||
<div>
|
<div>
|
||||||
<dt className="text-muted-foreground">Pagador</dt>
|
<dt className="text-muted-foreground">Pessoa</dt>
|
||||||
<dd className="mt-1 font-medium">{anticipation.payer.name}</dd>
|
<dd className="mt-1 font-medium">{anticipation.payer.name}</dd>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -229,12 +229,12 @@ function buildColumns({
|
|||||||
aria-hidden
|
aria-hidden
|
||||||
/>
|
/>
|
||||||
<span className="sr-only">
|
<span className="sr-only">
|
||||||
Dividido entre pagadores
|
Dividido entre pessoas
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="top">
|
<TooltipContent side="top">
|
||||||
Dividido entre pagadores
|
Dividido entre pessoas
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
@@ -408,10 +408,10 @@ function buildColumns({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "pagadorName",
|
accessorKey: "pagadorName",
|
||||||
header: "Pagador",
|
header: "Pessoa",
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const { payerId, pagadorName, pagadorAvatar } = row.original;
|
const { payerId, pagadorName, pagadorAvatar } = row.original;
|
||||||
const label = pagadorName?.trim() || "Sem pagador";
|
const label = pagadorName?.trim() || "Sem pessoa";
|
||||||
const displayName = label.split(/\s+/)[0] ?? label;
|
const displayName = label.split(/\s+/)[0] ?? label;
|
||||||
const avatarSrc = getAvatarSrc(pagadorAvatar);
|
const avatarSrc = getAvatarSrc(pagadorAvatar);
|
||||||
const initial = displayName.charAt(0).toUpperCase() || "?";
|
const initial = displayName.charAt(0).toUpperCase() || "?";
|
||||||
|
|||||||
@@ -386,7 +386,7 @@ export function TransactionsFilters({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium">Pagador</label>
|
<label className="text-sm font-medium">Pessoa</label>
|
||||||
<Select
|
<Select
|
||||||
value={getParamValue("payer")}
|
value={getParamValue("payer")}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export function TransactionsExport({
|
|||||||
"Valor",
|
"Valor",
|
||||||
"Category",
|
"Category",
|
||||||
"Conta/Cartão",
|
"Conta/Cartão",
|
||||||
"Payer",
|
"Pessoa",
|
||||||
];
|
];
|
||||||
const rows: string[][] = [];
|
const rows: string[][] = [];
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ export function TransactionsExport({
|
|||||||
"Valor",
|
"Valor",
|
||||||
"Category",
|
"Category",
|
||||||
"Conta/Cartão",
|
"Conta/Cartão",
|
||||||
"Payer",
|
"Pessoa",
|
||||||
];
|
];
|
||||||
const rows: (string | number)[][] = [];
|
const rows: (string | number)[][] = [];
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@ export function TransactionsExport({
|
|||||||
"Valor",
|
"Valor",
|
||||||
"Categoria",
|
"Categoria",
|
||||||
"Conta/Cartão",
|
"Conta/Cartão",
|
||||||
"Payer",
|
"Pessoa",
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -317,7 +317,7 @@ export function TransactionsExport({
|
|||||||
5: { cellWidth: 24 }, // Valor
|
5: { cellWidth: 24 }, // Valor
|
||||||
6: { cellWidth: 30 }, // Categoria
|
6: { cellWidth: 30 }, // Categoria
|
||||||
7: { cellWidth: 30 }, // Conta/Cartão
|
7: { cellWidth: 30 }, // Conta/Cartão
|
||||||
8: { cellWidth: 31 }, // Payer
|
8: { cellWidth: 31 }, // Pessoa
|
||||||
},
|
},
|
||||||
didParseCell: (cellData) => {
|
didParseCell: (cellData) => {
|
||||||
if (cellData.section === "body" && cellData.column.index === 5) {
|
if (cellData.section === "body" && cellData.column.index === 5) {
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export const NAV_SECTIONS: NavSection[] = [
|
|||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
href: "/payers",
|
href: "/payers",
|
||||||
label: "Pagadores",
|
label: "Pessoas",
|
||||||
description: "Gerencie quem divide as despesas",
|
description: "Gerencie quem divide as despesas",
|
||||||
icon: <RiGroupLine className="size-4" />,
|
icon: <RiGroupLine className="size-4" />,
|
||||||
iconClass: "text-primary",
|
iconClass: "text-primary",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export function TransactionsTableSkeleton() {
|
|||||||
<TableHead className="w-[120px]">Valor</TableHead>
|
<TableHead className="w-[120px]">Valor</TableHead>
|
||||||
<TableHead className="w-[120px]">Condição</TableHead>
|
<TableHead className="w-[120px]">Condição</TableHead>
|
||||||
<TableHead className="w-[120px]">Pagamento</TableHead>
|
<TableHead className="w-[120px]">Pagamento</TableHead>
|
||||||
<TableHead className="w-[140px]">Pagador</TableHead>
|
<TableHead className="w-[140px]">Pessoa</TableHead>
|
||||||
<TableHead className="w-[140px]">Categoria</TableHead>
|
<TableHead className="w-[140px]">Categoria</TableHead>
|
||||||
<TableHead className="w-[140px]">Conta/Cartão</TableHead>
|
<TableHead className="w-[140px]">Conta/Cartão</TableHead>
|
||||||
<TableHead className="w-[80px]">Ações</TableHead>
|
<TableHead className="w-[80px]">Ações</TableHead>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export async function ensureDefaultPagadorForUser(user: SeedUserLike) {
|
|||||||
const name =
|
const name =
|
||||||
(user.name && user.name.trim().length > 0
|
(user.name && user.name.trim().length > 0
|
||||||
? user.name.trim()
|
? user.name.trim()
|
||||||
: normalizeNameFromEmail(user.email)) || "Payer principal";
|
: normalizeNameFromEmail(user.email)) || "Pessoa principal";
|
||||||
|
|
||||||
// Usa a imagem do Google se disponível, senão usa o avatar padrão
|
// Usa a imagem do Google se disponível, senão usa o avatar padrão
|
||||||
const avatarUrl = user.image ?? DEFAULT_PAYER_AVATAR;
|
const avatarUrl = user.image ?? DEFAULT_PAYER_AVATAR;
|
||||||
|
|||||||
@@ -53,11 +53,11 @@ export const normalizeNameFromEmail = (
|
|||||||
email: string | null | undefined,
|
email: string | null | undefined,
|
||||||
): string => {
|
): string => {
|
||||||
if (!email) {
|
if (!email) {
|
||||||
return "Novo pagador";
|
return "Nova pessoa";
|
||||||
}
|
}
|
||||||
const [local] = email.split("@");
|
const [local] = email.split("@");
|
||||||
if (!local) {
|
if (!local) {
|
||||||
return "Novo pagador";
|
return "Nova pessoa";
|
||||||
}
|
}
|
||||||
return local
|
return local
|
||||||
.split(".")
|
.split(".")
|
||||||
|
|||||||
Reference in New Issue
Block a user