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:
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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) };
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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[];
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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.");
|
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
Reference in New Issue
Block a user