refactor(core): move app para src e padroniza estrutura

This commit is contained in:
Felipe Coutinho
2026-03-12 19:22:50 +00:00
parent d92e70f1b9
commit b0fbb1062a
567 changed files with 8981 additions and 5014 deletions

View File

@@ -0,0 +1,70 @@
import { RiPencilLine } from "@remixicon/react";
import { CategoryIconBadge } from "@/features/categories/components/category-icon-badge";
import {
clampGoalProgress,
formatGoalProgressPercentage,
getGoalProgressStatusColorClass,
} from "@/features/dashboard/goals-progress-helpers";
import type { GoalProgressItem as GoalProgressItemData } from "@/features/dashboard/goals-progress-queries";
import MoneyValues from "@/shared/components/money-values";
import { Button } from "@/shared/components/ui/button";
import { Progress } from "@/shared/components/ui/progress";
type GoalProgressItemProps = {
item: GoalProgressItemData;
index: number;
onEdit: (item: GoalProgressItemData) => void;
};
export function GoalProgressItem({
item,
index,
onEdit,
}: GoalProgressItemProps) {
const statusColor = getGoalProgressStatusColorClass(item.status);
const progressValue = clampGoalProgress(item.usedPercentage, 0, 100);
const percentageDelta = item.usedPercentage - 100;
return (
<li className="border-b border-dashed py-2 last:border-b-0 last:pb-0">
<div className="flex items-start justify-between gap-3">
<div className="flex min-w-0 flex-1 items-start gap-2">
<CategoryIconBadge
icon={item.categoryIcon}
name={item.categoryName}
colorIndex={index}
size="md"
/>
<div className="min-w-0 flex-1">
<p className="truncate text-sm font-medium text-foreground">
{item.categoryName}
</p>
<p className="mt-0.5 text-xs text-muted-foreground">
<MoneyValues amount={item.spentAmount} /> de{" "}
<MoneyValues amount={item.budgetAmount} />
</p>
</div>
</div>
<div className="flex shrink-0 items-center gap-2">
<span className={`text-xs font-medium ${statusColor}`}>
{formatGoalProgressPercentage(percentageDelta, true)}
</span>
<Button
type="button"
variant="ghost"
size="icon-sm"
className="size-7 text-muted-foreground hover:text-foreground"
onClick={() => onEdit(item)}
aria-label={`Editar orçamento de ${item.categoryName}`}
>
<RiPencilLine className="size-3.5" />
</Button>
</div>
</div>
<div className="ml-11 mt-1.5">
<Progress value={progressValue} />
</div>
</li>
);
}

View File

@@ -0,0 +1,34 @@
import { RiFundsLine } from "@remixicon/react";
import type { GoalProgressItem } from "@/features/dashboard/goals-progress-queries";
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
import { GoalProgressItem as GoalProgressListItem } from "./goal-progress-item";
type GoalsProgressListProps = {
items: GoalProgressItem[];
onEdit: (item: GoalProgressItem) => void;
};
export function GoalsProgressList({ items, onEdit }: GoalsProgressListProps) {
if (items.length === 0) {
return (
<WidgetEmptyState
icon={<RiFundsLine className="size-6 text-muted-foreground" />}
title="Nenhum orçamento para o período"
description="Cadastre orçamentos para acompanhar o progresso das metas."
/>
);
}
return (
<ul className="flex flex-col">
{items.map((item, index) => (
<GoalProgressListItem
key={item.id}
item={item}
index={index}
onEdit={onEdit}
/>
))}
</ul>
);
}

View File

@@ -0,0 +1,32 @@
import { BudgetDialog } from "@/features/budgets/components/budget-dialog";
import type {
Budget,
BudgetCategory,
} from "@/features/budgets/components/types";
type GoalsProgressWidgetDialogsProps = {
selectedBudget: Budget | null;
editOpen: boolean;
categories: BudgetCategory[];
defaultPeriod: string;
onEditOpenChange: (open: boolean) => void;
};
export function GoalsProgressWidgetDialogs({
selectedBudget,
editOpen,
categories,
defaultPeriod,
onEditOpenChange,
}: GoalsProgressWidgetDialogsProps) {
return (
<BudgetDialog
mode="update"
budget={selectedBudget ?? undefined}
categories={categories}
defaultPeriod={defaultPeriod}
open={editOpen && !!selectedBudget}
onOpenChange={onEditOpenChange}
/>
);
}

View File

@@ -0,0 +1,44 @@
import type {
Budget,
BudgetCategory,
} from "@/features/budgets/components/types";
import type {
GoalProgressItem,
GoalsProgressData,
} from "@/features/dashboard/goals-progress-queries";
import { GoalsProgressList } from "./goals-progress-list";
import { GoalsProgressWidgetDialogs } from "./goals-progress-widget-dialogs";
type GoalsProgressWidgetViewProps = {
data: GoalsProgressData;
selectedBudget: Budget | null;
editOpen: boolean;
categories: BudgetCategory[];
defaultPeriod: string;
onEdit: (item: GoalProgressItem) => void;
onEditOpenChange: (open: boolean) => void;
};
export function GoalsProgressWidgetView({
data,
selectedBudget,
editOpen,
categories,
defaultPeriod,
onEdit,
onEditOpenChange,
}: GoalsProgressWidgetViewProps) {
return (
<div className="flex flex-col gap-4 px-0">
<GoalsProgressList items={data.items} onEdit={onEdit} />
<GoalsProgressWidgetDialogs
selectedBudget={selectedBudget}
editOpen={editOpen}
categories={categories}
defaultPeriod={defaultPeriod}
onEditOpenChange={onEditOpenChange}
/>
</div>
);
}