feat: adição de novos ícones SVG e configuração do ambiente

- Adicionados ícones SVG para ChatGPT, Claude, Gemini e OpenRouter
- Implementados ícones para modos claro e escuro do ChatGPT
- Criado script de inicialização para PostgreSQL com extensão pgcrypto
- Adicionado script de configuração de ambiente que faz backup do .env
- Configurado tsconfig.json para TypeScript com opções de compilação
This commit is contained in:
Felipe Coutinho
2025-11-15 15:49:36 -03:00
commit ea0b8618e0
441 changed files with 53569 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
/**
* Categoria grouping and sorting helpers for lancamentos
*/
import type { SelectOption } from "@/components/lancamentos/types";
/**
* Capitalizes the first letter of a string
*/
function capitalize(value: string): string {
return value.length > 0 ? value[0]?.toUpperCase().concat(value.slice(1)) : value;
}
/**
* Group label for categorias
*/
type CategoriaGroup = {
label: string;
options: SelectOption[];
};
/**
* Normalizes category group labels (Despesa -> Despesas, Receita -> Receitas)
*/
function normalizeCategoryGroupLabel(value: string): string {
const lower = value.toLowerCase();
if (lower === "despesa") {
return "Despesas";
}
if (lower === "receita") {
return "Receitas";
}
return capitalize(value);
}
/**
* Groups and sorts categoria options by their group property
* @param categoriaOptions - Array of categoria select options
* @returns Array of grouped and sorted categoria options
*/
export function groupAndSortCategorias(
categoriaOptions: SelectOption[]
): CategoriaGroup[] {
// Group categorias by their group property
const groups = categoriaOptions.reduce<Record<string, SelectOption[]>>(
(acc, option) => {
const key = option.group ?? "Outros";
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(option);
return acc;
},
{}
);
// Define preferred order (Despesa first, then Receita, then others)
const preferredOrder = ["Despesa", "Receita"];
const orderedKeys = [
...preferredOrder.filter((key) => groups[key]?.length),
...Object.keys(groups).filter((key) => !preferredOrder.includes(key)),
];
// Map to final structure with normalized labels and sorted options
return orderedKeys.map((key) => ({
label: normalizeCategoryGroupLabel(key),
options: groups[key]
.slice()
.sort((a, b) =>
a.label.localeCompare(b.label, "pt-BR", { sensitivity: "base" })
),
}));
}
/**
* Filters secondary pagador options to exclude the primary pagador
*/
export function filterSecondaryPagadorOptions(
allOptions: SelectOption[],
primaryPagadorId?: string
): SelectOption[] {
return allOptions.filter((option) => option.value !== primaryPagadorId);
}

View File

@@ -0,0 +1,15 @@
export const LANCAMENTO_TRANSACTION_TYPES = ["Despesa", "Receita", "Transferência"] as const;
export const LANCAMENTO_CONDITIONS = [
"À vista",
"Parcelado",
"Recorrente",
] as const;
export const LANCAMENTO_PAYMENT_METHODS = [
"Cartão de crédito",
"Cartão de débito",
"Pix",
"Dinheiro",
"Boleto",
] as const;

View File

@@ -0,0 +1,192 @@
/**
* Form state management helpers for lancamentos
*/
import type { LancamentoItem } from "@/components/lancamentos/types";
import { LANCAMENTO_CONDITIONS, LANCAMENTO_PAYMENT_METHODS, LANCAMENTO_TRANSACTION_TYPES } from "./constants";
import { derivePeriodFromDate } from "@/lib/utils/period";
import { getTodayDateString } from "@/lib/utils/date";
/**
* Form state type for lancamento dialog
*/
export type LancamentoFormState = {
purchaseDate: string;
period: string;
name: string;
transactionType: string;
amount: string;
condition: string;
paymentMethod: string;
pagadorId: string | undefined;
secondaryPagadorId: string | undefined;
isSplit: boolean;
contaId: string | undefined;
cartaoId: string | undefined;
categoriaId: string | undefined;
installmentCount: string;
recurrenceCount: string;
dueDate: string;
boletoPaymentDate: string;
note: string;
isSettled: boolean | null;
};
/**
* Initial state overrides for lancamento form
*/
export type LancamentoFormOverrides = {
defaultCartaoId?: string | null;
defaultPaymentMethod?: string | null;
defaultPurchaseDate?: string | null;
};
/**
* Builds initial form state from lancamento data and defaults
*/
export function buildLancamentoInitialState(
lancamento?: LancamentoItem,
defaultPagadorId?: string | null,
preferredPeriod?: string,
overrides?: LancamentoFormOverrides
): LancamentoFormState {
const purchaseDate = lancamento?.purchaseDate
? lancamento.purchaseDate.slice(0, 10)
: overrides?.defaultPurchaseDate ?? "";
const paymentMethod =
lancamento?.paymentMethod ??
overrides?.defaultPaymentMethod ??
LANCAMENTO_PAYMENT_METHODS[0];
const derivedPeriod = derivePeriodFromDate(purchaseDate);
const fallbackPeriod =
preferredPeriod && /^\d{4}-\d{2}$/.test(preferredPeriod)
? preferredPeriod
: derivedPeriod;
const fallbackPagadorId = lancamento?.pagadorId ?? defaultPagadorId ?? null;
const boletoPaymentDate =
lancamento?.boletoPaymentDate ??
(paymentMethod === "Boleto" && (lancamento?.isSettled ?? false)
? getTodayDateString()
: "");
return {
purchaseDate,
period:
lancamento?.period && /^\d{4}-\d{2}$/.test(lancamento.period)
? lancamento.period
: fallbackPeriod,
name: lancamento?.name ?? "",
transactionType:
lancamento?.transactionType ?? LANCAMENTO_TRANSACTION_TYPES[0],
amount:
typeof lancamento?.amount === "number"
? (Math.round(Math.abs(lancamento.amount) * 100) / 100).toFixed(2)
: "",
condition: lancamento?.condition ?? LANCAMENTO_CONDITIONS[0],
paymentMethod,
pagadorId: fallbackPagadorId ?? undefined,
secondaryPagadorId: undefined,
isSplit: false,
contaId:
paymentMethod === "Cartão de crédito"
? undefined
: lancamento?.contaId ?? undefined,
cartaoId:
paymentMethod === "Cartão de crédito"
? lancamento?.cartaoId ?? overrides?.defaultCartaoId ?? undefined
: undefined,
categoriaId: lancamento?.categoriaId ?? undefined,
installmentCount: lancamento?.installmentCount
? String(lancamento.installmentCount)
: "",
recurrenceCount: lancamento?.recurrenceCount
? String(lancamento.recurrenceCount)
: "",
dueDate: lancamento?.dueDate ?? "",
boletoPaymentDate,
note: lancamento?.note ?? "",
isSettled:
paymentMethod === "Cartão de crédito"
? null
: lancamento?.isSettled ?? false,
};
}
/**
* Applies field dependencies when form state changes
* This function encapsulates the business logic for field interdependencies
*/
export function applyFieldDependencies(
key: keyof LancamentoFormState,
value: LancamentoFormState[keyof LancamentoFormState],
currentState: LancamentoFormState,
_periodDirty: boolean
): Partial<LancamentoFormState> {
const updates: Partial<LancamentoFormState> = {};
// Removed automatic period update when purchase date changes
// if (key === "purchaseDate" && typeof value === "string") {
// if (!periodDirty) {
// updates.period = derivePeriodFromDate(value);
// }
// }
// When condition changes, clear irrelevant fields
if (key === "condition" && typeof value === "string") {
if (value !== "Parcelado") {
updates.installmentCount = "";
}
if (value !== "Recorrente") {
updates.recurrenceCount = "";
}
}
// When payment method changes, adjust related fields
if (key === "paymentMethod" && typeof value === "string") {
if (value === "Cartão de crédito") {
updates.contaId = undefined;
updates.isSettled = null;
} else {
updates.cartaoId = undefined;
updates.isSettled = currentState.isSettled ?? false;
}
// Clear boleto-specific fields if not boleto
if (value !== "Boleto") {
updates.dueDate = "";
updates.boletoPaymentDate = "";
} else if (currentState.isSettled || (updates.isSettled !== null && updates.isSettled !== undefined)) {
// Set today's date for boleto payment if settled
const settled = updates.isSettled ?? currentState.isSettled;
if (settled) {
updates.boletoPaymentDate = currentState.boletoPaymentDate || getTodayDateString();
}
}
}
// When split is disabled, clear secondary pagador
if (key === "isSplit" && value === false) {
updates.secondaryPagadorId = undefined;
}
// When primary pagador changes, clear secondary if it matches
if (key === "pagadorId" && typeof value === "string") {
const secondaryValue = currentState.secondaryPagadorId;
if (secondaryValue && secondaryValue === value) {
updates.secondaryPagadorId = undefined;
}
}
// When isSettled changes and payment method is Boleto
if (key === "isSettled" && currentState.paymentMethod === "Boleto") {
if (value === true) {
updates.boletoPaymentDate = currentState.boletoPaymentDate || getTodayDateString();
} else if (value === false) {
updates.boletoPaymentDate = "";
}
}
return updates;
}

View File

@@ -0,0 +1,94 @@
/**
* Formatting helpers for displaying lancamento data
*/
/**
* Capitalizes the first letter of a string
*/
function capitalize(value: string): string {
return value.length > 0 ? value[0]?.toUpperCase().concat(value.slice(1)) : value;
}
/**
* Currency formatter for pt-BR locale (BRL)
*/
export const currencyFormatter = new Intl.NumberFormat("pt-BR", {
style: "currency",
currency: "BRL",
});
/**
* Date formatter for pt-BR locale (dd/mm/yyyy)
*/
export const dateFormatter = new Intl.DateTimeFormat("pt-BR", {
day: "2-digit",
month: "2-digit",
year: "numeric",
});
/**
* Month formatter for pt-BR locale (Month Year)
*/
export const monthFormatter = new Intl.DateTimeFormat("pt-BR", {
month: "long",
year: "numeric",
});
/**
* Formats a date string to localized format
* @param value - ISO date string or null
* @returns Formatted date string or "—"
* @example formatDate("2024-01-15") => "15/01/2024"
*/
export function formatDate(value?: string | null): string {
if (!value) return "—";
const date = new Date(value);
if (Number.isNaN(date.getTime())) return "—";
return dateFormatter.format(date);
}
/**
* Formats a period (YYYY-MM) to localized month label
* @param value - Period string (YYYY-MM) or null
* @returns Formatted period string or "—"
* @example formatPeriod("2024-01") => "Janeiro 2024"
*/
export function formatPeriod(value?: string | null): string {
if (!value) return "—";
const [year, month] = value.split("-").map(Number);
if (!year || !month) return value;
const date = new Date(year, month - 1, 1);
return capitalize(monthFormatter.format(date));
}
/**
* Formats a condition string with proper capitalization
* @param value - Condition string or null
* @returns Formatted condition string or "—"
* @example formatCondition("vista") => "À vista"
*/
export function formatCondition(value?: string | null): string {
if (!value) return "—";
if (value.toLowerCase() === "vista") return "À vista";
return capitalize(value);
}
/**
* Gets the badge variant for a transaction type
* @param type - Transaction type (Receita/Despesa)
* @returns Badge variant
*/
export function getTransactionBadgeVariant(type?: string | null): "default" | "destructive" | "secondary" {
if (!type) return "secondary";
return type.toLowerCase() === "receita" ? "default" : "destructive";
}
/**
* Formats currency value
* @param value - Numeric value
* @returns Formatted currency string
* @example formatCurrency(1234.56) => "R$ 1.234,56"
*/
export function formatCurrency(value: number): string {
return currencyFormatter.format(value);
}

View File

@@ -0,0 +1,521 @@
import type { SelectOption } from "@/components/lancamentos/types";
import {
cartoes,
categorias,
contas,
lancamentos,
pagadores,
} from "@/db/schema";
import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/lib/accounts/constants";
import { db } from "@/lib/db";
import {
LANCAMENTO_CONDITIONS,
LANCAMENTO_PAYMENT_METHODS,
LANCAMENTO_TRANSACTION_TYPES,
} from "@/lib/lancamentos/constants";
import { PAGADOR_ROLE_ADMIN, PAGADOR_ROLE_TERCEIRO } from "@/lib/pagadores/constants";
import type { SQL } from "drizzle-orm";
import { eq, ilike, or } from "drizzle-orm";
type PagadorRow = typeof pagadores.$inferSelect;
type ContaRow = typeof contas.$inferSelect;
type CartaoRow = typeof cartoes.$inferSelect;
type CategoriaRow = typeof categorias.$inferSelect;
export type ResolvedSearchParams =
| Record<string, string | string[] | undefined>
| undefined;
export type LancamentoSearchFilters = {
transactionFilter: string | null;
conditionFilter: string | null;
paymentFilter: string | null;
pagadorFilter: string | null;
categoriaFilter: string | null;
contaCartaoFilter: string | null;
searchFilter: string | null;
};
type BaseSluggedOption = {
id: string;
label: string;
slug: string;
};
type PagadorSluggedOption = BaseSluggedOption & {
role: string | null;
avatarUrl: string | null;
};
type CategoriaSluggedOption = BaseSluggedOption & {
type: string | null;
icon: string | null;
};
type ContaSluggedOption = BaseSluggedOption & {
kind: "conta";
logo: string | null;
};
type CartaoSluggedOption = BaseSluggedOption & {
kind: "cartao";
logo: string | null;
};
export type SluggedFilters = {
pagadorFiltersRaw: PagadorSluggedOption[];
categoriaFiltersRaw: CategoriaSluggedOption[];
contaFiltersRaw: ContaSluggedOption[];
cartaoFiltersRaw: CartaoSluggedOption[];
};
export type SlugMaps = {
pagador: Map<string, string>;
categoria: Map<string, string>;
conta: Map<string, string>;
cartao: Map<string, string>;
};
export type FilterOption = {
slug: string;
label: string;
};
export type ContaCartaoFilterOption = FilterOption & {
kind: "conta" | "cartao";
};
export type LancamentoOptionSets = {
pagadorOptions: SelectOption[];
splitPagadorOptions: SelectOption[];
defaultPagadorId: string | null;
contaOptions: SelectOption[];
cartaoOptions: SelectOption[];
categoriaOptions: SelectOption[];
pagadorFilterOptions: FilterOption[];
categoriaFilterOptions: FilterOption[];
contaCartaoFilterOptions: ContaCartaoFilterOption[];
};
export const getSingleParam = (
params: ResolvedSearchParams,
key: string
): string | null => {
const value = params?.[key];
if (!value) {
return null;
}
return Array.isArray(value) ? value[0] ?? null : value;
};
export const extractLancamentoSearchFilters = (
params: ResolvedSearchParams
): LancamentoSearchFilters => ({
transactionFilter: getSingleParam(params, "transacao"),
conditionFilter: getSingleParam(params, "condicao"),
paymentFilter: getSingleParam(params, "pagamento"),
pagadorFilter: getSingleParam(params, "pagador"),
categoriaFilter: getSingleParam(params, "categoria"),
contaCartaoFilter: getSingleParam(params, "contaCartao"),
searchFilter: getSingleParam(params, "q"),
});
const normalizeLabel = (value: string | null | undefined) =>
value?.trim().length ? value.trim() : "Sem descrição";
const slugify = (value: string) => {
const base = value
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
return base || "item";
};
const createSlugGenerator = () => {
const seen = new Map<string, number>();
return (label: string) => {
const base = slugify(label);
const count = seen.get(base) ?? 0;
seen.set(base, count + 1);
if (count === 0) {
return base;
}
return `${base}-${count + 1}`;
};
};
export const toOption = (
value: string,
label: string | null | undefined,
role?: string | null,
group?: string | null,
slug?: string | null,
avatarUrl?: string | null,
logo?: string | null,
icon?: string | null
): SelectOption => ({
value,
label: normalizeLabel(label),
role: role ?? null,
group: group ?? null,
slug: slug ?? null,
avatarUrl: avatarUrl ?? null,
logo: logo ?? null,
icon: icon ?? null,
});
export const fetchLancamentoFilterSources = async (userId: string) => {
const [pagadorRows, contaRows, cartaoRows, categoriaRows] = await Promise.all(
[
db.query.pagadores.findMany({
where: eq(pagadores.userId, userId),
}),
db.query.contas.findMany({
where: (contas, { eq, and }) =>
and(eq(contas.userId, userId), eq(contas.status, "Ativa")),
}),
db.query.cartoes.findMany({
where: (cartoes, { eq, and }) =>
and(eq(cartoes.userId, userId), eq(cartoes.status, "Ativo")),
}),
db.query.categorias.findMany({
where: eq(categorias.userId, userId),
}),
]
);
return { pagadorRows, contaRows, cartaoRows, categoriaRows };
};
export const buildSluggedFilters = ({
pagadorRows,
categoriaRows,
contaRows,
cartaoRows,
}: {
pagadorRows: PagadorRow[];
categoriaRows: CategoriaRow[];
contaRows: ContaRow[];
cartaoRows: CartaoRow[];
}): SluggedFilters => {
const pagadorSlugger = createSlugGenerator();
const categoriaSlugger = createSlugGenerator();
const contaCartaoSlugger = createSlugGenerator();
const pagadorFiltersRaw = pagadorRows.map((pagador) => {
const label = normalizeLabel(pagador.name);
return {
id: pagador.id,
label,
slug: pagadorSlugger(label),
role: pagador.role ?? null,
avatarUrl: pagador.avatarUrl ?? null,
};
});
const categoriaFiltersRaw = categoriaRows.map((categoria) => {
const label = normalizeLabel(categoria.name);
return {
id: categoria.id,
label,
slug: categoriaSlugger(label),
type: categoria.type ?? null,
icon: categoria.icon ?? null,
};
});
const contaFiltersRaw = contaRows.map((conta) => {
const label = normalizeLabel(conta.name);
return {
id: conta.id,
label,
slug: contaCartaoSlugger(label),
kind: "conta" as const,
logo: conta.logo ?? null,
};
});
const cartaoFiltersRaw = cartaoRows.map((cartao) => {
const label = normalizeLabel(cartao.name);
return {
id: cartao.id,
label,
slug: contaCartaoSlugger(label),
kind: "cartao" as const,
logo: cartao.logo ?? null,
};
});
return {
pagadorFiltersRaw,
categoriaFiltersRaw,
contaFiltersRaw,
cartaoFiltersRaw,
};
};
export const buildSlugMaps = ({
pagadorFiltersRaw,
categoriaFiltersRaw,
contaFiltersRaw,
cartaoFiltersRaw,
}: SluggedFilters): SlugMaps => ({
pagador: new Map(pagadorFiltersRaw.map(({ slug, id }) => [slug, id])),
categoria: new Map(categoriaFiltersRaw.map(({ slug, id }) => [slug, id])),
conta: new Map(contaFiltersRaw.map(({ slug, id }) => [slug, id])),
cartao: new Map(cartaoFiltersRaw.map(({ slug, id }) => [slug, id])),
});
const isValidTransaction = (
value: string | null
): value is (typeof LANCAMENTO_TRANSACTION_TYPES)[number] =>
!!value &&
(LANCAMENTO_TRANSACTION_TYPES as readonly string[]).includes(value ?? "");
const isValidCondition = (
value: string | null
): value is (typeof LANCAMENTO_CONDITIONS)[number] =>
!!value && (LANCAMENTO_CONDITIONS as readonly string[]).includes(value ?? "");
const isValidPaymentMethod = (
value: string | null
): value is (typeof LANCAMENTO_PAYMENT_METHODS)[number] =>
!!value &&
(LANCAMENTO_PAYMENT_METHODS as readonly string[]).includes(value ?? "");
const buildSearchPattern = (value: string | null) =>
value ? `%${value.trim().replace(/\s+/g, "%")}%` : null;
export const buildLancamentoWhere = ({
userId,
period,
filters,
slugMaps,
cardId,
accountId,
pagadorId,
}: {
userId: string;
period: string;
filters: LancamentoSearchFilters;
slugMaps: SlugMaps;
cardId?: string;
accountId?: string;
pagadorId?: string;
}): SQL[] => {
const where: SQL[] = [
eq(lancamentos.userId, userId),
eq(lancamentos.period, period),
];
if (pagadorId) {
where.push(eq(lancamentos.pagadorId, pagadorId));
}
if (cardId) {
where.push(eq(lancamentos.cartaoId, cardId));
}
if (accountId) {
where.push(eq(lancamentos.contaId, accountId));
}
if (isValidTransaction(filters.transactionFilter)) {
where.push(eq(lancamentos.transactionType, filters.transactionFilter));
}
if (isValidCondition(filters.conditionFilter)) {
where.push(eq(lancamentos.condition, filters.conditionFilter));
}
if (isValidPaymentMethod(filters.paymentFilter)) {
where.push(eq(lancamentos.paymentMethod, filters.paymentFilter));
}
if (!pagadorId && filters.pagadorFilter) {
const id = slugMaps.pagador.get(filters.pagadorFilter);
if (id) {
where.push(eq(lancamentos.pagadorId, id));
}
}
if (filters.categoriaFilter) {
const id = slugMaps.categoria.get(filters.categoriaFilter);
if (id) {
where.push(eq(lancamentos.categoriaId, id));
}
}
if (filters.contaCartaoFilter) {
const contaId = slugMaps.conta.get(filters.contaCartaoFilter);
const relatedCartaoId = contaId
? null
: slugMaps.cartao.get(filters.contaCartaoFilter);
if (contaId) {
where.push(eq(lancamentos.contaId, contaId));
}
if (!contaId && relatedCartaoId) {
where.push(eq(lancamentos.cartaoId, relatedCartaoId));
}
}
const searchPattern = buildSearchPattern(filters.searchFilter);
if (searchPattern) {
where.push(
or(
ilike(lancamentos.name, searchPattern),
ilike(lancamentos.note, searchPattern)
)
);
}
return where;
};
type LancamentoRowWithRelations = typeof lancamentos.$inferSelect & {
pagador?: PagadorRow | null;
conta?: ContaRow | null;
cartao?: CartaoRow | null;
categoria?: CategoriaRow | null;
};
export const mapLancamentosData = (rows: LancamentoRowWithRelations[]) =>
rows.map((item) => ({
id: item.id,
name: item.name,
purchaseDate: item.purchaseDate?.toISOString() ?? new Date().toISOString(),
period: item.period ?? "",
transactionType: item.transactionType,
amount: Number(item.amount ?? 0),
condition: item.condition,
paymentMethod: item.paymentMethod,
pagadorId: item.pagadorId ?? null,
pagadorName: item.pagador?.name ?? null,
pagadorAvatar: item.pagador?.avatarUrl ?? null,
pagadorRole: item.pagador?.role ?? null,
contaId: item.contaId ?? null,
contaName: item.conta?.name ?? null,
contaLogo: item.conta?.logo ?? null,
cartaoId: item.cartaoId ?? null,
cartaoName: item.cartao?.name ?? null,
cartaoLogo: item.cartao?.logo ?? null,
categoriaId: item.categoriaId ?? null,
categoriaName: item.categoria?.name ?? null,
categoriaType: item.categoria?.type ?? null,
installmentCount: item.installmentCount ?? null,
recurrenceCount: item.recurrenceCount ?? null,
currentInstallment: item.currentInstallment ?? null,
dueDate: item.dueDate ? item.dueDate.toISOString().slice(0, 10) : null,
boletoPaymentDate: item.boletoPaymentDate
? item.boletoPaymentDate.toISOString().slice(0, 10)
: null,
note: item.note ?? null,
isSettled: item.isSettled ?? null,
isDivided: item.isDivided ?? false,
isAnticipated: item.isAnticipated ?? false,
anticipationId: item.anticipationId ?? null,
seriesId: item.seriesId ?? null,
readonly:
Boolean(item.note?.startsWith(ACCOUNT_AUTO_INVOICE_NOTE_PREFIX)) ||
item.categoria?.name === "Saldo inicial" ||
item.categoria?.name === "Pagamentos",
}));
const sortByLabel = <T extends { label: string }>(items: T[]) =>
items.sort((a, b) =>
a.label.localeCompare(b.label, "pt-BR", { sensitivity: "base" })
);
export const buildOptionSets = ({
pagadorFiltersRaw,
categoriaFiltersRaw,
contaFiltersRaw,
cartaoFiltersRaw,
pagadorRows,
limitCartaoId,
limitContaId,
}: SluggedFilters & {
pagadorRows: PagadorRow[];
limitCartaoId?: string;
limitContaId?: string;
}): LancamentoOptionSets => {
const pagadorOptions = sortByLabel(
pagadorFiltersRaw.map(({ id, label, role, slug, avatarUrl }) =>
toOption(id, label, role, undefined, slug, avatarUrl)
)
);
const pagadorFilterOptions = sortByLabel(
pagadorFiltersRaw.map(({ slug, label, avatarUrl }) => ({
slug,
label,
avatarUrl,
}))
);
const defaultPagadorId =
pagadorRows.find((pagador) => pagador.role === PAGADOR_ROLE_ADMIN)?.id ??
null;
const splitPagadorOptions = pagadorOptions.filter(
(option) => option.role === PAGADOR_ROLE_TERCEIRO
);
const contaOptionsSource = limitContaId
? contaFiltersRaw.filter((conta) => conta.id === limitContaId)
: contaFiltersRaw;
const contaOptions = sortByLabel(
contaOptionsSource.map(({ id, label, slug, logo }) =>
toOption(id, label, undefined, undefined, slug, undefined, logo)
)
);
const cartaoOptionsSource = limitCartaoId
? cartaoFiltersRaw.filter((cartao) => cartao.id === limitCartaoId)
: cartaoFiltersRaw;
const cartaoOptions = sortByLabel(
cartaoOptionsSource.map(({ id, label, slug, logo }) =>
toOption(id, label, undefined, undefined, slug, undefined, logo)
)
);
const categoriaOptions = sortByLabel(
categoriaFiltersRaw.map(({ id, label, type, slug, icon }) =>
toOption(id, label, undefined, type, slug, undefined, undefined, icon)
)
);
const categoriaFilterOptions = sortByLabel(
categoriaFiltersRaw.map(({ slug, label, icon }) => ({ slug, label, icon }))
);
const contaCartaoFilterOptions = sortByLabel(
[...contaFiltersRaw, ...cartaoFiltersRaw]
.filter(
(option) =>
(limitCartaoId && option.kind === "cartao"
? option.id === limitCartaoId
: true) &&
(limitContaId && option.kind === "conta"
? option.id === limitContaId
: true)
)
.map(({ slug, label, kind, logo }) => ({ slug, label, kind, logo }))
);
return {
pagadorOptions,
splitPagadorOptions,
defaultPagadorId,
contaOptions,
cartaoOptions,
categoriaOptions,
pagadorFilterOptions,
categoriaFilterOptions,
contaCartaoFilterOptions,
};
};