mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 11:01:45 +00:00
fix: corrige tipagem compartilhada e compatibilidade do typecheck
This commit is contained in:
@@ -231,7 +231,7 @@ export default async function Page() {
|
|||||||
<div className="mx-auto flex max-w-5xl flex-col items-center text-center gap-5 md:gap-6">
|
<div className="mx-auto flex max-w-5xl flex-col items-center text-center gap-5 md:gap-6">
|
||||||
<Logo variant="small" className="h-12 w-12 mb-1" />
|
<Logo variant="small" className="h-12 w-12 mb-1" />
|
||||||
|
|
||||||
<Badge variant="primary">
|
<Badge variant="default">
|
||||||
<RiGithubFill size={14} className="mr-1" />
|
<RiGithubFill size={14} className="mr-1" />
|
||||||
Projeto Open Source
|
Projeto Open Source
|
||||||
</Badge>
|
</Badge>
|
||||||
@@ -378,7 +378,7 @@ export default async function Page() {
|
|||||||
<div className="mx-auto max-w-6xl">
|
<div className="mx-auto max-w-6xl">
|
||||||
<AnimateOnScroll>
|
<AnimateOnScroll>
|
||||||
<div className="text-center mb-8 md:mb-12">
|
<div className="text-center mb-8 md:mb-12">
|
||||||
<Badge variant="primary" className="mb-4">
|
<Badge variant="default" className="mb-4">
|
||||||
Conheça as telas
|
Conheça as telas
|
||||||
</Badge>
|
</Badge>
|
||||||
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight mb-3 md:mb-4">
|
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight mb-3 md:mb-4">
|
||||||
@@ -430,7 +430,7 @@ export default async function Page() {
|
|||||||
<div className="mx-auto max-w-5xl">
|
<div className="mx-auto max-w-5xl">
|
||||||
<AnimateOnScroll>
|
<AnimateOnScroll>
|
||||||
<div className="text-center mb-8 md:mb-12">
|
<div className="text-center mb-8 md:mb-12">
|
||||||
<Badge variant="primary" className="mb-4">
|
<Badge variant="default" className="mb-4">
|
||||||
O que tem aqui
|
O que tem aqui
|
||||||
</Badge>
|
</Badge>
|
||||||
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight mb-3 md:mb-4">
|
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight mb-3 md:mb-4">
|
||||||
@@ -514,7 +514,7 @@ export default async function Page() {
|
|||||||
<div className="grid gap-8 md:gap-12 md:grid-cols-2 items-center">
|
<div className="grid gap-8 md:gap-12 md:grid-cols-2 items-center">
|
||||||
{/* Text content */}
|
{/* Text content */}
|
||||||
<div className="order-2 md:order-1">
|
<div className="order-2 md:order-1">
|
||||||
<Badge variant="primary" className="mb-4">
|
<Badge variant="default" className="mb-4">
|
||||||
<RiSmartphoneLine size={14} className="mr-1" />
|
<RiSmartphoneLine size={14} className="mr-1" />
|
||||||
App Android
|
App Android
|
||||||
</Badge>
|
</Badge>
|
||||||
@@ -625,7 +625,7 @@ export default async function Page() {
|
|||||||
<div className="mx-auto max-w-5xl">
|
<div className="mx-auto max-w-5xl">
|
||||||
<AnimateOnScroll>
|
<AnimateOnScroll>
|
||||||
<div className="text-center mb-8 md:mb-12">
|
<div className="text-center mb-8 md:mb-12">
|
||||||
<Badge variant="primary" className="mb-4">
|
<Badge variant="default" className="mb-4">
|
||||||
Stack técnica
|
Stack técnica
|
||||||
</Badge>
|
</Badge>
|
||||||
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight mb-3 md:mb-4">
|
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight mb-3 md:mb-4">
|
||||||
@@ -748,7 +748,7 @@ export default async function Page() {
|
|||||||
<div className="mx-auto max-w-3xl">
|
<div className="mx-auto max-w-3xl">
|
||||||
<AnimateOnScroll>
|
<AnimateOnScroll>
|
||||||
<div className="text-center mb-8 md:mb-12">
|
<div className="text-center mb-8 md:mb-12">
|
||||||
<Badge variant="primary" className="mb-4">
|
<Badge variant="default" className="mb-4">
|
||||||
Como usar
|
Como usar
|
||||||
</Badge>
|
</Badge>
|
||||||
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight mb-3 md:mb-4">
|
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight mb-3 md:mb-4">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { relations, sql } from "drizzle-orm";
|
import { relations, sql } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
|
type AnyPgColumn,
|
||||||
boolean,
|
boolean,
|
||||||
date,
|
date,
|
||||||
index,
|
index,
|
||||||
@@ -536,7 +537,7 @@ export const installmentAnticipations = pgTable(
|
|||||||
.default("0"),
|
.default("0"),
|
||||||
transactionId: uuid("lancamento_id")
|
transactionId: uuid("lancamento_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => transactions.id, { onDelete: "cascade" }),
|
.references((): AnyPgColumn => transactions.id, { onDelete: "cascade" }),
|
||||||
payerId: uuid("pagador_id").references(() => payers.id, {
|
payerId: uuid("pagador_id").references(() => payers.id, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
}),
|
||||||
@@ -585,7 +586,7 @@ export const transactions = pgTable(
|
|||||||
isDivided: boolean("dividido").default(false),
|
isDivided: boolean("dividido").default(false),
|
||||||
isAnticipated: boolean("antecipado").default(false),
|
isAnticipated: boolean("antecipado").default(false),
|
||||||
anticipationId: uuid("antecipacao_id").references(
|
anticipationId: uuid("antecipacao_id").references(
|
||||||
() => installmentAnticipations.id,
|
(): AnyPgColumn => installmentAnticipations.id,
|
||||||
{ onDelete: "set null" },
|
{ onDelete: "set null" },
|
||||||
),
|
),
|
||||||
createdAt: timestamp("created_at", {
|
createdAt: timestamp("created_at", {
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ export function CategoryHistoryWidget({ data }: CategoryHistoryWidgetProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={entry.dataKey}
|
key={String(entry.dataKey ?? entry.name)}
|
||||||
className="flex items-center justify-between gap-4"
|
className="flex items-center justify-between gap-4"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export function IncomeExpenseBalanceWidget({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={entry.dataKey}
|
key={String(entry.dataKey ?? entry.name)}
|
||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import {
|
|||||||
Area,
|
Area,
|
||||||
AreaChart,
|
AreaChart,
|
||||||
CartesianGrid,
|
CartesianGrid,
|
||||||
type TooltipProps,
|
type TooltipContentProps,
|
||||||
|
type TooltipPayloadEntry,
|
||||||
|
type TooltipValueType,
|
||||||
XAxis,
|
XAxis,
|
||||||
} from "recharts";
|
} from "recharts";
|
||||||
import type { CategoryChartData } from "@/features/reports/category-chart-queries";
|
import type { CategoryChartData } from "@/features/reports/category-chart-queries";
|
||||||
@@ -35,12 +37,19 @@ import {
|
|||||||
import { CATEGORY_COLORS } from "@/shared/utils/category-colors";
|
import { CATEGORY_COLORS } from "@/shared/utils/category-colors";
|
||||||
import { currencyFormatter } from "@/shared/utils/currency";
|
import { currencyFormatter } from "@/shared/utils/currency";
|
||||||
|
|
||||||
function AreaTooltip({ active, payload, label }: TooltipProps<number, string>) {
|
function AreaTooltip({
|
||||||
|
active,
|
||||||
|
payload,
|
||||||
|
label,
|
||||||
|
}: Partial<TooltipContentProps<TooltipValueType, string>>) {
|
||||||
if (!active || !payload?.length) return null;
|
if (!active || !payload?.length) return null;
|
||||||
|
|
||||||
const items = payload
|
const items = payload
|
||||||
.filter((entry) => Number(entry.value) > 0)
|
.filter((entry: TooltipPayloadEntry) => Number(entry.value) > 0)
|
||||||
.sort((a, b) => Number(b.value) - Number(a.value));
|
.sort(
|
||||||
|
(a: TooltipPayloadEntry, b: TooltipPayloadEntry) =>
|
||||||
|
Number(b.value) - Number(a.value),
|
||||||
|
);
|
||||||
|
|
||||||
if (items.length === 0) return null;
|
if (items.length === 0) return null;
|
||||||
|
|
||||||
@@ -50,9 +59,9 @@ function AreaTooltip({ active, payload, label }: TooltipProps<number, string>) {
|
|||||||
{label}
|
{label}
|
||||||
</p>
|
</p>
|
||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
{items.map((entry) => (
|
{items.map((entry: TooltipPayloadEntry) => (
|
||||||
<div
|
<div
|
||||||
key={entry.dataKey}
|
key={String(entry.dataKey ?? entry.name)}
|
||||||
className="flex items-center justify-between gap-6"
|
className="flex items-center justify-between gap-6"
|
||||||
>
|
>
|
||||||
<div className="flex min-w-0 items-center gap-1.5">
|
<div className="flex min-w-0 items-center gap-1.5">
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export function AnticipationCard({
|
|||||||
}: AnticipationCardProps) {
|
}: AnticipationCardProps) {
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
|
|
||||||
const isSettled = anticipation.transaction.isSettled === true;
|
const isSettled = anticipation.transaction?.isSettled === true;
|
||||||
const canCancel = !isSettled;
|
const canCancel = !isSettled;
|
||||||
|
|
||||||
const formatDate = (date: Date) => {
|
const formatDate = (date: Date) => {
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import type {
|
||||||
|
LegendPayload as RechartsLegendPayload,
|
||||||
|
LegendProps as RechartsLegendProps,
|
||||||
|
TooltipContentProps as RechartsTooltipContentProps,
|
||||||
|
TooltipPayloadEntry,
|
||||||
|
TooltipValueType,
|
||||||
|
} from "recharts";
|
||||||
import * as RechartsPrimitive from "recharts";
|
import * as RechartsPrimitive from "recharts";
|
||||||
|
|
||||||
import { cn } from "@/shared/utils/ui";
|
import { cn } from "@/shared/utils/ui";
|
||||||
@@ -134,7 +141,7 @@ function ChartTooltipContent({
|
|||||||
color,
|
color,
|
||||||
nameKey,
|
nameKey,
|
||||||
labelKey,
|
labelKey,
|
||||||
}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
|
}: Partial<RechartsTooltipContentProps<TooltipValueType, string | number>> &
|
||||||
React.ComponentProps<"div"> & {
|
React.ComponentProps<"div"> & {
|
||||||
hideLabel?: boolean;
|
hideLabel?: boolean;
|
||||||
hideIndicator?: boolean;
|
hideIndicator?: boolean;
|
||||||
@@ -197,21 +204,21 @@ function ChartTooltipContent({
|
|||||||
<div className="grid gap-1.5">
|
<div className="grid gap-1.5">
|
||||||
{payload
|
{payload
|
||||||
.filter((item) => item.type !== "none")
|
.filter((item) => item.type !== "none")
|
||||||
.map((item, index) => {
|
.map((item: TooltipPayloadEntry, index) => {
|
||||||
const key = `${nameKey || item.name || item.dataKey || "value"}`;
|
const key = `${nameKey || item.name || item.dataKey || "value"}`;
|
||||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
||||||
const indicatorColor = color || item.payload.fill || item.color;
|
const indicatorColor = color || item.payload.fill || item.color;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={item.dataKey}
|
key={String(item.dataKey ?? item.name ?? index)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
|
"[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
|
||||||
indicator === "dot" && "items-center",
|
indicator === "dot" && "items-center",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{formatter && item?.value !== undefined && item.name ? (
|
{formatter && item?.value !== undefined && item.name ? (
|
||||||
formatter(item.value, item.name, item, index, item.payload)
|
formatter(item.value, item.name, item, index, payload)
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{itemConfig?.icon ? (
|
{itemConfig?.icon ? (
|
||||||
@@ -250,7 +257,7 @@ function ChartTooltipContent({
|
|||||||
{itemConfig?.label || item.name}
|
{itemConfig?.label || item.name}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{item.value && (
|
{item.value !== undefined && item.value !== null && (
|
||||||
<span className="text-foreground font-mono font-medium tabular-nums">
|
<span className="text-foreground font-mono font-medium tabular-nums">
|
||||||
{item.value.toLocaleString()}
|
{item.value.toLocaleString()}
|
||||||
</span>
|
</span>
|
||||||
@@ -274,12 +281,14 @@ function ChartLegendContent({
|
|||||||
payload,
|
payload,
|
||||||
verticalAlign = "bottom",
|
verticalAlign = "bottom",
|
||||||
nameKey,
|
nameKey,
|
||||||
}: React.ComponentProps<"div"> &
|
}: React.ComponentProps<"div"> & {
|
||||||
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
|
payload?: ReadonlyArray<RechartsLegendPayload>;
|
||||||
hideIcon?: boolean;
|
verticalAlign?: RechartsLegendProps["verticalAlign"];
|
||||||
nameKey?: string;
|
hideIcon?: boolean;
|
||||||
}) {
|
nameKey?: string;
|
||||||
|
}) {
|
||||||
const { config } = useChart();
|
const { config } = useChart();
|
||||||
|
type LegendPayloadEntry = RechartsLegendPayload;
|
||||||
|
|
||||||
if (!payload?.length) {
|
if (!payload?.length) {
|
||||||
return null;
|
return null;
|
||||||
@@ -294,14 +303,14 @@ function ChartLegendContent({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{payload
|
{payload
|
||||||
.filter((item) => item.type !== "none")
|
.filter((item: LegendPayloadEntry) => item.type !== "none")
|
||||||
.map((item) => {
|
.map((item: LegendPayloadEntry) => {
|
||||||
const key = `${nameKey || item.dataKey || "value"}`;
|
const key = `${nameKey || item.dataKey || "value"}`;
|
||||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={item.value}
|
key={String(item.dataKey ?? item.value)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3",
|
"[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3",
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ export interface CurrencyInputProps
|
|||||||
> {
|
> {
|
||||||
value: string;
|
value: string;
|
||||||
onValueChange: (value: string) => void;
|
onValueChange: (value: string) => void;
|
||||||
|
onChange?: React.ComponentProps<typeof Input>["onChange"];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CurrencyInput = React.forwardRef<
|
export const CurrencyInput = React.forwardRef<
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { RiLoader4Line } from "@remixicon/react";
|
import { RiLoader4Line } from "@remixicon/react";
|
||||||
import { cn } from "@/shared/utils/ui";
|
import { cn } from "@/shared/utils/ui";
|
||||||
|
|
||||||
function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
|
function Spinner({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof RiLoader4Line>) {
|
||||||
return (
|
return (
|
||||||
<RiLoader4Line
|
<RiLoader4Line
|
||||||
role="status"
|
role="status"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export type EligibleInstallment = {
|
|||||||
* Antecipação com dados completos
|
* Antecipação com dados completos
|
||||||
*/
|
*/
|
||||||
export type InstallmentAnticipationWithRelations = InstallmentAnticipation & {
|
export type InstallmentAnticipationWithRelations = InstallmentAnticipation & {
|
||||||
transaction: Transaction;
|
transaction: Transaction | null;
|
||||||
payer: Payer | null;
|
payer: Payer | null;
|
||||||
category: Category | null;
|
category: Category | null;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user