refactor: remover funções, tipos e exports não utilizados

Remove createActionHandler, validateHashToken, decimalSchema,
optionalPeriodSchema, dateStringSchema, amountSchema, FeedbackDialog
standalone, CalendarEventType, parseDateKey, entre outros.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-02-27 15:40:59 +00:00
parent e644d67022
commit 3f3488c8a0
12 changed files with 1 additions and 261 deletions

View File

@@ -3,8 +3,6 @@ import type {
SelectOption, SelectOption,
} from "@/components/lancamentos/types"; } from "@/components/lancamentos/types";
export type CalendarEventType = "lancamento" | "boleto" | "cartao";
export type CalendarEvent = export type CalendarEvent =
| { | {
id: string; id: string;

View File

@@ -2,15 +2,6 @@ import type { CalendarDay, CalendarEvent } from "@/components/calendario/types";
export const formatDateKey = (date: Date) => date.toISOString().slice(0, 10); export const formatDateKey = (date: Date) => date.toISOString().slice(0, 10);
export const parseDateKey = (value: string) => {
const [yearStr, monthStr, dayStr] = value.split("-");
const year = Number.parseInt(yearStr ?? "", 10);
const month = Number.parseInt(monthStr ?? "", 10);
const day = Number.parseInt(dayStr ?? "", 10);
return new Date(Date.UTC(year, (month ?? 1) - 1, day ?? 1));
};
const getWeekdayIndex = (date: Date) => { const getWeekdayIndex = (date: Date) => {
const day = date.getUTCDay(); // 0 (domingo) - 6 (sábado) const day = date.getUTCDay(); // 0 (domingo) - 6 (sábado)
// Ajusta para segunda-feira como primeiro dia // Ajusta para segunda-feira como primeiro dia

View File

@@ -8,21 +8,12 @@ import {
RiQuestionLine, RiQuestionLine,
RiStarLine, RiStarLine,
} from "@remixicon/react"; } from "@remixicon/react";
import { useState } from "react";
import { Button, buttonVariants } from "@/components/ui/button";
import { import {
Dialog,
DialogContent, DialogContent,
DialogDescription, DialogDescription,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
const GITHUB_REPO_BASE = "https://github.com/felipegcoutinho/openmonetis"; const GITHUB_REPO_BASE = "https://github.com/felipegcoutinho/openmonetis";
@@ -128,32 +119,3 @@ export function FeedbackDialogBody({ onClose }: { onClose?: () => void }) {
</DialogContent> </DialogContent>
); );
} }
export function FeedbackDialog() {
const [open, setOpen] = useState(false);
return (
<Dialog open={open} onOpenChange={setOpen}>
<Tooltip>
<TooltipTrigger asChild>
<DialogTrigger asChild>
<Button
variant="ghost"
size="icon"
className={cn(
buttonVariants({ variant: "ghost", size: "icon-sm" }),
"group relative text-muted-foreground transition-all duration-200",
"hover:text-foreground focus-visible:ring-2 focus-visible:ring-primary/40",
"data-[state=open]:bg-accent/60 data-[state=open]:text-foreground border",
)}
>
<RiMessageLine className="h-5 w-5" />
</Button>
</DialogTrigger>
</TooltipTrigger>
<TooltipContent>Enviar Feedback</TooltipContent>
</Tooltip>
<FeedbackDialogBody onClose={() => setOpen(false)} />
</Dialog>
);
}

View File

@@ -1,6 +1,5 @@
import { revalidatePath, revalidateTag } from "next/cache"; import { revalidatePath, revalidateTag } from "next/cache";
import { z } from "zod"; import { z } from "zod";
import { getUser } from "@/lib/auth/server";
import type { ActionResult } from "./types"; import type { ActionResult } from "./types";
import { errorResult } from "./types"; import { errorResult } from "./types";
@@ -58,72 +57,3 @@ export function revalidateForEntity(
revalidateTag("dashboard", "max"); revalidateTag("dashboard", "max");
} }
} }
/**
* Options for action handler
*/
interface ActionHandlerOptions {
/** Paths to revalidate after successful execution */
revalidatePaths?: string[];
/** Entity to revalidate (uses predefined config) */
revalidateEntity?: keyof typeof revalidateConfig;
}
/**
* Creates a standardized action handler with automatic user auth and error handling
*
* @param schema - Zod schema for input validation
* @param handler - Handler function that receives validated data and userId
* @param options - Additional options for the action
* @returns Action function that can be called from client
*
* @example
* ```ts
* export const createItemAction = createActionHandler(
* createItemSchema,
* async (data, userId) => {
* await db.insert(items).values({ ...data, userId });
* return "Item criado com sucesso.";
* },
* { revalidateEntity: 'items' }
* );
* ```
*/
export function createActionHandler<TInput, TResult = string>(
schema: z.ZodSchema<TInput>,
handler: (data: TInput, userId: string) => Promise<TResult>,
options?: ActionHandlerOptions,
) {
return async (input: unknown): Promise<ActionResult<TResult>> => {
try {
// Get authenticated user
const user = await getUser();
// Validate input
const data = schema.parse(input);
// Execute handler
const result = await handler(data, user.id);
// Revalidate paths if configured
if (options?.revalidateEntity) {
revalidateForEntity(options.revalidateEntity);
} else if (options?.revalidatePaths) {
options.revalidatePaths.forEach((path) => revalidatePath(path));
}
// Return success with message (if result is string) or data
if (typeof result === "string") {
return { success: true, message: result };
}
return {
success: true,
message: "Operação realizada com sucesso.",
data: result,
};
} catch (error) {
return handleActionError(error);
}
};
}

View File

@@ -227,17 +227,3 @@ export function extractBearerToken(authHeader: string | null): string | null {
const match = authHeader.match(/^Bearer\s+(.+)$/i); const match = authHeader.match(/^Bearer\s+(.+)$/i);
return match ? match[1] : null; return match ? match[1] : null;
} }
/**
* Validate a hash-based API token (os_xxx format)
* Returns the token hash for database lookup
*/
export function validateHashToken(token: string): {
valid: boolean;
tokenHash?: string;
} {
if (!token || !token.startsWith("os_")) {
return { valid: false };
}
return { valid: true, tokenHash: hashToken(token) };
}

View File

@@ -3,7 +3,7 @@ import { categorias } from "@/db/schema";
import type { CategoryType } from "@/lib/categorias/constants"; import type { CategoryType } from "@/lib/categorias/constants";
import { db } from "@/lib/db"; import { db } from "@/lib/db";
export type DefaultCategory = { type DefaultCategory = {
name: string; name: string;
type: CategoryType; type: CategoryType;
icon: string | null; icon: string | null;

View File

@@ -68,20 +68,3 @@ export async function resetWidgetPreferences(): Promise<{
return { success: false, error: "Erro ao resetar preferências" }; return { success: false, error: "Erro ao resetar preferências" };
} }
} }
export async function getWidgetPreferences(): Promise<WidgetPreferences | null> {
try {
const user = await getUser();
const result = await db
.select({ dashboardWidgets: schema.preferenciasUsuario.dashboardWidgets })
.from(schema.preferenciasUsuario)
.where(eq(schema.preferenciasUsuario.userId, user.id))
.limit(1);
return result[0]?.dashboardWidgets ?? null;
} catch (error) {
console.error("Error getting widget preferences:", error);
return null;
}
}

View File

@@ -49,18 +49,3 @@ export type CreateAnticipationInput = {
export type CancelAnticipationInput = { export type CancelAnticipationInput = {
anticipationId: string; anticipationId: string;
}; };
/**
* Resumo de antecipação para exibição
*/
export type AnticipationSummary = {
id: string;
totalAmount: string;
installmentCount: number;
anticipationPeriod: string;
anticipationDate: Date;
note: string | null;
isSettled: boolean;
lancamentoId: string;
anticipatedInstallments: string[];
};

View File

@@ -86,17 +86,3 @@ export async function getPagadorAccess(userId: string, pagadorId: string) {
return { pagador, canEdit: false, share }; return { pagador, canEdit: false, share };
} }
export async function userCanEditPagador(userId: string, pagadorId: string) {
const pagadorRow = await db.query.pagadores.findFirst({
columns: { id: true },
where: and(eq(pagadores.id, pagadorId), eq(pagadores.userId, userId)),
});
return Boolean(pagadorRow);
}
export async function userHasPagadorAccess(userId: string, pagadorId: string) {
const access = await getPagadorAccess(userId, pagadorId);
return Boolean(access);
}

View File

@@ -12,19 +12,6 @@ export const uuidSchema = (entityName: string = "ID") =>
.string({ message: `${entityName} inválido.` }) .string({ message: `${entityName} inválido.` })
.uuid(`${entityName} inválido.`); .uuid(`${entityName} inválido.`);
/**
* Decimal string schema - parses string with comma/period to number
*/
export const decimalSchema = z
.string()
.trim()
.transform((value) => value.replace(/\s/g, "").replace(",", "."))
.refine(
(value) => !Number.isNaN(Number.parseFloat(value)),
"Informe um valor numérico válido.",
)
.transform((value) => Number.parseFloat(value));
/** /**
* Optional/nullable decimal string schema * Optional/nullable decimal string schema
*/ */
@@ -61,38 +48,6 @@ export const periodSchema = z
.trim() .trim()
.regex(/^\d{4}-(0[1-9]|1[0-2])$/, "Período inválido."); .regex(/^\d{4}-(0[1-9]|1[0-2])$/, "Período inválido.");
/**
* Optional period schema
*/
export const optionalPeriodSchema = z
.string()
.trim()
.regex(/^(\d{4})-(\d{2})$/, {
message: "Selecione um período válido.",
})
.optional();
/**
* Date string schema
*/
export const dateStringSchema = z
.string({ message: "Informe a data." })
.trim()
.refine((value) => !Number.isNaN(new Date(value).getTime()), {
message: "Data inválida.",
});
/**
* Optional date string schema
*/
export const optionalDateStringSchema = z
.string()
.trim()
.refine((value) => !value || !Number.isNaN(new Date(value).getTime()), {
message: "Informe uma data válida.",
})
.optional();
/** /**
* Note/observation schema (max 500 chars, trimmed, nullable) * Note/observation schema (max 500 chars, trimmed, nullable)
*/ */
@@ -102,35 +57,3 @@ export const noteSchema = z
.max(500, "A anotação deve ter no máximo 500 caracteres.") .max(500, "A anotação deve ter no máximo 500 caracteres.")
.optional() .optional()
.transform((value) => (value && value.length > 0 ? value : null)); .transform((value) => (value && value.length > 0 ? value : null));
/**
* Optional string that becomes null if empty
*/
export const optionalStringToNull = z
.string()
.trim()
.optional()
.transform((value) => (value && value.length > 0 ? value : null));
/**
* Required non-empty string schema
*/
export const requiredStringSchema = (fieldName: string) =>
z
.string({ message: `Informe ${fieldName}.` })
.trim()
.min(1, `Informe ${fieldName}.`);
/**
* Amount schema with minimum value validation
*/
export const amountSchema = z.coerce
.number({ message: "Informe o valor." })
.min(0, "Informe um valor maior ou igual a zero.");
/**
* Positive amount schema
*/
export const positiveAmountSchema = z.coerce
.number({ message: "Informe o valor." })
.positive("Informe um valor maior que zero.");

View File

@@ -64,6 +64,4 @@ export const InsightsResponseSchema = z.object({
/** /**
* TypeScript types derived from schemas * TypeScript types derived from schemas
*/ */
export type InsightItem = z.infer<typeof InsightItemSchema>;
export type InsightCategory = z.infer<typeof InsightCategorySchema>;
export type InsightsResponse = z.infer<typeof InsightsResponseSchema>; export type InsightsResponse = z.infer<typeof InsightsResponseSchema>;

View File

@@ -1,7 +1,5 @@
export const TRANSFER_CATEGORY_NAME = "Transferência interna"; export const TRANSFER_CATEGORY_NAME = "Transferência interna";
export const TRANSFER_ESTABLISHMENT = "Transf. entre contas";
export const TRANSFER_ESTABLISHMENT_SAIDA = "Saída - Transf. entre contas"; export const TRANSFER_ESTABLISHMENT_SAIDA = "Saída - Transf. entre contas";
export const TRANSFER_ESTABLISHMENT_ENTRADA = "Entrada - Transf. entre contas"; export const TRANSFER_ESTABLISHMENT_ENTRADA = "Entrada - Transf. entre contas";
export const TRANSFER_PAGADOR = "Admin";
export const TRANSFER_PAYMENT_METHOD = "Pix"; export const TRANSFER_PAYMENT_METHOD = "Pix";
export const TRANSFER_CONDITION = "À vista"; export const TRANSFER_CONDITION = "À vista";