mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 02:51:46 +00:00
refactor: faxina arquitetural — código morto, identificadores em inglês e estrutura padronizada
Refatoração estrutural sem mudanças funcionais. Saldo líquido: −428 linhas. Removido: - 14 funções/constantes mortas verificadas via grep no repo todo: validateCategoriaOwnership, getInstallmentAnticipationsAction, getAnticipationDetailsAction, formatDecimalForDb, currencyFormatterNoCents, optionalDecimalSchema, formatMonthLabel, getGoalProgressStatusColorClass, MONTH_PERIOD_PARAM, calculateRemainingInstallments, e 5 funções fetch* não usadas em inbox/queries.ts. - 1 tipo morto (ImportRow) + 2 órfãos consequentes (InstallmentAnticipationWithRelations, GoalProgressStatus convertido em interno). - ~30 export keywords desnecessários (símbolos usados apenas no próprio arquivo). - Re-exports mortos em barrels: EstablishmentLogoPicker, CategoryReportSkeleton, WidgetSkeleton, toNameKey. - Arquivo features/reports/types.ts (barrel inteiro era órfão). Padronizado (PT-BR→EN em identificadores expostos): - 4 constantes globais (LANCAMENTOS_* → TRANSACTIONS_*). - 12 tipos/interfaces (Lancamento*/Pagador*/Estabelecimento* → equivalentes EN). - 13 funções/components exportados (fetchPagador*, EstabelecimentoInput, PagadorInfoCard, etc.). - 5 props cross-file (preLancamentosCount → inboxPendingCount, pagadorAvatarUrl → payerAvatarUrl, etc.). - Mantidas em PT-BR conforme exceção do CLAUDE.md: variáveis locais (pagador, categoria, lancamento), accessor key pagadorName (persistida em preferências), strings de UI. Reorganizado: - transactions/: 14 helpers soltos na raiz movidos para lib/; barrel actions.ts reduzido de 76 linhas de wrappers para 14 linhas de re-exports puros; anticipation-actions.ts movido para actions/anticipation.ts. - dashboard/: 8 helpers soltos consolidados em dashboard/lib/. - reports/: 5 query files na raiz consolidados em reports/lib/. - payers/: detail-actions.ts (21KB) e detail-queries.ts movidos para payers/lib/. - shared/components/: 9 dos 16 componentes soltos agrupados em brand/, widgets/, feedback/. - shared/lib/fetch-json.ts movido para shared/utils/fetch-json.ts. Validação: pnpm exec tsc --noEmit (0 erros), biome check (0 issues), knip (sem unused). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -12,8 +12,10 @@
|
||||
],
|
||||
// PostCSS is inferred from the config file, but the project only depends on
|
||||
// the Tailwind PostCSS plugin directly.
|
||||
// `server-only` is provided implicitly by Next.js — no install needed.
|
||||
"ignoreDependencies": [
|
||||
"postcss"
|
||||
"postcss",
|
||||
"server-only"
|
||||
],
|
||||
"next": true,
|
||||
"postcss": true,
|
||||
|
||||
@@ -21,6 +21,7 @@ const nextConfig: NextConfig = {
|
||||
experimental: {
|
||||
prefetchInlining: true,
|
||||
turbopackFileSystemCacheForDev: true,
|
||||
optimizePackageImports: ["@remixicon/react"],
|
||||
},
|
||||
|
||||
// Headers for Safari compatibility
|
||||
|
||||
@@ -21,7 +21,7 @@ import type {
|
||||
PAYMENT_METHODS,
|
||||
TRANSACTION_CONDITIONS,
|
||||
TRANSACTION_TYPES,
|
||||
} from "@/features/transactions/constants";
|
||||
} from "@/features/transactions/lib/constants";
|
||||
import {
|
||||
buildInvoicePaymentNote,
|
||||
INITIAL_BALANCE_CATEGORY_NAME,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Logo } from "@/shared/components/logo";
|
||||
import { Logo } from "@/shared/components/brand/logo";
|
||||
|
||||
export default function AuthLayout({
|
||||
children,
|
||||
|
||||
@@ -7,8 +7,8 @@ import { AdjustBalanceDialog } from "@/features/accounts/components/adjust-balan
|
||||
import type { Account } from "@/features/accounts/components/types";
|
||||
import {
|
||||
fetchAccountData,
|
||||
fetchAccountLancamentosPage,
|
||||
fetchAccountSummary,
|
||||
fetchAccountTransactionsPage,
|
||||
} from "@/features/accounts/statement-queries";
|
||||
import { fetchUserPreferences } from "@/features/settings/queries";
|
||||
import { TransactionsPage as LancamentosSection } from "@/features/transactions/components/page/transactions-page";
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
mapTransactionsData,
|
||||
type ResolvedSearchParams,
|
||||
resolveTransactionPagination,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
fetchRecentEstablishments,
|
||||
fetchTransactionFilterSources,
|
||||
@@ -89,7 +89,7 @@ export default async function Page({ params, searchParams }: PageProps) {
|
||||
accountId: account.id,
|
||||
});
|
||||
|
||||
const transactionsPage = await fetchAccountLancamentosPage(
|
||||
const transactionsPage = await fetchAccountTransactionsPage(
|
||||
filters,
|
||||
pagination,
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { fetchCalendarData } from "@/features/calendar/queries";
|
||||
import {
|
||||
getSingleParam,
|
||||
type ResolvedSearchParams,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import MonthNavigation from "@/shared/components/month-picker/month-navigation";
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
import type { CalendarPeriod } from "@/shared/lib/types/calendar";
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
getSingleParam,
|
||||
mapTransactionsData,
|
||||
type ResolvedSearchParams,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
fetchRecentEstablishments,
|
||||
fetchTransactionFilterSources,
|
||||
|
||||
@@ -7,7 +7,7 @@ import { TransactionsPage } from "@/features/transactions/components/page/transa
|
||||
import {
|
||||
buildOptionSets,
|
||||
buildSluggedFilters,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
fetchRecentEstablishments,
|
||||
fetchTransactionFilterSources,
|
||||
|
||||
@@ -2,9 +2,9 @@ import { connection } from "next/server";
|
||||
import { DashboardGridEditable } from "@/features/dashboard/components/dashboard-grid-editable";
|
||||
import { DashboardMetricsCards } from "@/features/dashboard/components/dashboard-metrics-cards";
|
||||
import { DashboardWelcome } from "@/features/dashboard/components/dashboard-welcome";
|
||||
import { extractDashboardLogoNames } from "@/features/dashboard/extract-logo-names";
|
||||
import { extractDashboardLogoNames } from "@/features/dashboard/lib/extract-logo-names";
|
||||
import { fetchDashboardPageData } from "@/features/dashboard/page-data-queries";
|
||||
import { getSingleParam } from "@/features/transactions/page-helpers";
|
||||
import { getSingleParam } from "@/features/transactions/lib/page-helpers";
|
||||
import { LogoPrefetchProvider } from "@/shared/components/entity-avatar";
|
||||
import MonthNavigation from "@/shared/components/month-picker/month-navigation";
|
||||
import { getUser } from "@/shared/lib/auth/server";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { connection } from "next/server";
|
||||
import { fetchDashboardNavbarData } from "@/features/dashboard/navbar-queries";
|
||||
import { fetchDashboardNavbarData } from "@/features/dashboard/lib/navbar-queries";
|
||||
import { AppNavbar } from "@/shared/components/navigation/navbar/app-navbar";
|
||||
import { LogoDevProvider } from "@/shared/components/providers/logo-dev-provider";
|
||||
import { PrivacyProvider } from "@/shared/components/providers/privacy-provider";
|
||||
@@ -21,8 +21,8 @@ export default async function DashboardLayout({
|
||||
<PrivacyProvider>
|
||||
<AppNavbar
|
||||
user={{ ...session.user, image: session.user.image ?? null }}
|
||||
pagadorAvatarUrl={navbarData.pagadorAvatarUrl}
|
||||
preLancamentosCount={navbarData.preLancamentosCount}
|
||||
payerAvatarUrl={navbarData.payerAvatarUrl}
|
||||
inboxPendingCount={navbarData.inboxPendingCount}
|
||||
notificationsSnapshot={navbarData.notificationsSnapshot}
|
||||
/>
|
||||
<div className="relative flex flex-1 flex-col pt-16">
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Skeleton } from "@/shared/components/ui/skeleton";
|
||||
* Loading state para a página de detalhes do pagador.
|
||||
* Layout: navegação mensal + tabs com card compartilhado do pagador.
|
||||
*/
|
||||
export default function PagadorDetailsLoading() {
|
||||
export default function PayerDetailsLoading() {
|
||||
return (
|
||||
<main className="flex flex-col gap-6">
|
||||
<div className="h-[60px] animate-pulse rounded-md bg-foreground/10" />
|
||||
|
||||
@@ -8,7 +8,7 @@ import { connection } from "next/server";
|
||||
import { PayerCardUsageCard } from "@/features/payers/components/details/payer-card-usage-card";
|
||||
import { PayerHeaderCard } from "@/features/payers/components/details/payer-header-card";
|
||||
import { PayerHistoryCard } from "@/features/payers/components/details/payer-history-card";
|
||||
import { PagadorInfoCard } from "@/features/payers/components/details/payer-info-card";
|
||||
import { PayerInfoCard } from "@/features/payers/components/details/payer-info-card";
|
||||
import { PayerLeaveShareCard } from "@/features/payers/components/details/payer-leave-share-card";
|
||||
import { PayerMonthlySummaryCard } from "@/features/payers/components/details/payer-monthly-summary-card";
|
||||
import {
|
||||
@@ -16,12 +16,12 @@ import {
|
||||
PayerPaymentStatusCard,
|
||||
} from "@/features/payers/components/details/payer-payment-method-cards";
|
||||
import { PayerSharingCard } from "@/features/payers/components/details/payer-sharing-card";
|
||||
import { buildReadOnlyOptionSets } from "@/features/payers/lib/build-readonly-option-sets";
|
||||
import {
|
||||
fetchCurrentUserShare,
|
||||
fetchPagadorLancamentos,
|
||||
fetchPayerShares,
|
||||
} from "@/features/payers/detail-queries";
|
||||
import { buildReadOnlyOptionSets } from "@/features/payers/lib/build-readonly-option-sets";
|
||||
fetchPayerTransactions,
|
||||
} from "@/features/payers/lib/detail-queries";
|
||||
import { fetchUserPreferences } from "@/features/settings/queries";
|
||||
import { TransactionsPage as LancamentosSection } from "@/features/transactions/components/page/transactions-page";
|
||||
import {
|
||||
@@ -36,13 +36,12 @@ import {
|
||||
type SluggedFilters,
|
||||
type SlugMaps,
|
||||
type TransactionSearchFilters,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
fetchRecentEstablishments,
|
||||
fetchTransactionFilterSources,
|
||||
} from "@/features/transactions/queries";
|
||||
import { LogoPrefetchProvider } from "@/shared/components/entity-avatar";
|
||||
import { ExpandableWidgetCard } from "@/shared/components/expandable-widget-card";
|
||||
import MonthNavigation from "@/shared/components/month-picker/month-navigation";
|
||||
import {
|
||||
Tabs,
|
||||
@@ -50,16 +49,17 @@ import {
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@/shared/components/ui/tabs";
|
||||
import { ExpandableWidgetCard } from "@/shared/components/widgets/expandable-widget-card";
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
import { prefetchLogoMappings } from "@/shared/lib/logo/prefetch-server";
|
||||
import { getPayerAccess } from "@/shared/lib/payers/access";
|
||||
import {
|
||||
fetchPagadorBoletoItems,
|
||||
fetchPagadorBoletoStats,
|
||||
fetchPagadorCardUsage,
|
||||
fetchPagadorPaymentStatus,
|
||||
fetchPayerBoletoItems,
|
||||
fetchPayerBoletoStats,
|
||||
fetchPayerCardUsage,
|
||||
fetchPayerHistory,
|
||||
fetchPayerMonthlyBreakdown,
|
||||
fetchPayerPaymentStatus,
|
||||
type PayerCardUsageItem,
|
||||
} from "@/shared/lib/payers/details";
|
||||
import { parsePeriodParam } from "@/shared/utils/period";
|
||||
@@ -182,7 +182,7 @@ export default async function Page({ params, searchParams }: PageProps) {
|
||||
estabelecimentos,
|
||||
userPreferences,
|
||||
] = await Promise.all([
|
||||
fetchPagadorLancamentos(filters),
|
||||
fetchPayerTransactions(filters),
|
||||
fetchPayerMonthlyBreakdown({
|
||||
userId: dataOwnerId,
|
||||
payerId: pagador.id,
|
||||
@@ -193,22 +193,22 @@ export default async function Page({ params, searchParams }: PageProps) {
|
||||
payerId: pagador.id,
|
||||
period: selectedPeriod,
|
||||
}),
|
||||
fetchPagadorCardUsage({
|
||||
fetchPayerCardUsage({
|
||||
userId: dataOwnerId,
|
||||
payerId: pagador.id,
|
||||
period: selectedPeriod,
|
||||
}),
|
||||
fetchPagadorBoletoStats({
|
||||
fetchPayerBoletoStats({
|
||||
userId: dataOwnerId,
|
||||
payerId: pagador.id,
|
||||
period: selectedPeriod,
|
||||
}),
|
||||
fetchPagadorBoletoItems({
|
||||
fetchPayerBoletoItems({
|
||||
userId: dataOwnerId,
|
||||
payerId: pagador.id,
|
||||
period: selectedPeriod,
|
||||
}),
|
||||
fetchPagadorPaymentStatus({
|
||||
fetchPayerPaymentStatus({
|
||||
userId: dataOwnerId,
|
||||
payerId: pagador.id,
|
||||
period: selectedPeriod,
|
||||
@@ -333,7 +333,7 @@ export default async function Page({ params, searchParams }: PageProps) {
|
||||
/>
|
||||
|
||||
<TabsContent value="profile" className="space-y-4">
|
||||
<PagadorInfoCard payer={payerData} />
|
||||
<PayerInfoCard payer={payerData} />
|
||||
{canEdit && payerData.shareCode ? (
|
||||
<PayerSharingCard
|
||||
payerId={pagador.id}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Skeleton } from "@/shared/components/ui/skeleton";
|
||||
* Loading state para a página de pessoas
|
||||
* Layout: Header + Input de compartilhamento + Grid de cards
|
||||
*/
|
||||
export default function PagadoresLoading() {
|
||||
export default function PayersLoading() {
|
||||
return (
|
||||
<main className="flex flex-col items-start gap-6">
|
||||
<div className="w-full space-y-6">
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { RiBankCard2Line } from "@remixicon/react";
|
||||
import { connection } from "next/server";
|
||||
import { fetchCartoesReportData } from "@/features/reports/cards-report-queries";
|
||||
import { CardCategoryBreakdown } from "@/features/reports/components/cards/card-category-breakdown";
|
||||
import { CardInvoiceStatus } from "@/features/reports/components/cards/card-invoice-status";
|
||||
import { CardTopExpenses } from "@/features/reports/components/cards/card-top-expenses";
|
||||
import { CardUsageChart } from "@/features/reports/components/cards/card-usage-chart";
|
||||
import { CardsOverview } from "@/features/reports/components/cards/cards-overview";
|
||||
import { fetchCartoesReportData } from "@/features/reports/lib/cards-report-queries";
|
||||
import MonthNavigation from "@/shared/components/month-picker/month-navigation";
|
||||
import { Card } from "@/shared/components/ui/card";
|
||||
import { getUser } from "@/shared/lib/auth/server";
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { connection } from "next/server";
|
||||
import type { Category } from "@/db/schema";
|
||||
import { fetchCategoryChartData } from "@/features/reports/category-chart-queries";
|
||||
import { fetchCategoryReport } from "@/features/reports/category-report-queries";
|
||||
import { fetchUserCategories } from "@/features/reports/category-trends-queries";
|
||||
import { CategoryReportPage } from "@/features/reports/components/category-report-page";
|
||||
import type {
|
||||
CategoryOption,
|
||||
FilterState,
|
||||
} from "@/features/reports/components/types";
|
||||
import { validateDateRange } from "@/features/reports/utils";
|
||||
import { fetchCategoryChartData } from "@/features/reports/lib/category-chart-queries";
|
||||
import { fetchCategoryReport } from "@/features/reports/lib/category-report-queries";
|
||||
import { fetchUserCategories } from "@/features/reports/lib/category-trends-queries";
|
||||
import { validateDateRange } from "@/features/reports/lib/utils";
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
import type { CategoryReportFilters } from "@/shared/lib/types/reports";
|
||||
import { addMonthsToPeriod, getCurrentPeriod } from "@/shared/utils/period";
|
||||
|
||||
@@ -34,7 +34,7 @@ const validatePeriodFilter = (value: string | null): PeriodFilter => {
|
||||
return "6";
|
||||
};
|
||||
|
||||
export default async function TopEstabelecimentosPage({
|
||||
export default async function TopEstablishmentsPage({
|
||||
searchParams,
|
||||
}: PageProps) {
|
||||
await connection();
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ImportPage } from "@/features/transactions/components/import/import-pag
|
||||
import {
|
||||
buildOptionSets,
|
||||
buildSluggedFilters,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import { fetchTransactionFilterSources } from "@/features/transactions/queries";
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Skeleton } from "@/shared/components/ui/skeleton";
|
||||
* Loading state para a página de lançamentos
|
||||
* Mantém o mesmo layout da página final
|
||||
*/
|
||||
export default function LancamentosLoading() {
|
||||
export default function TransactionsLoading() {
|
||||
return (
|
||||
<main className="flex flex-col gap-6">
|
||||
{/* Month Picker placeholder */}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
mapTransactionsData,
|
||||
type ResolvedSearchParams,
|
||||
resolveTransactionPagination,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
fetchRecentEstablishments,
|
||||
fetchTransactionFilterSources,
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
import { landingImages } from "@/features/landing/images";
|
||||
import { fetchGitHubStats } from "@/features/landing/queries";
|
||||
import { AnimatedThemeToggler } from "@/shared/components/animated-theme-toggler";
|
||||
import { Logo } from "@/shared/components/logo";
|
||||
import { Logo } from "@/shared/components/brand/logo";
|
||||
import { NavbarShell } from "@/shared/components/navigation/navbar/navbar-shell";
|
||||
import { Badge } from "@/shared/components/ui/badge";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { fetchTransactionAttachments } from "@/features/transactions/attachment-queries";
|
||||
import { fetchTransactionAttachments } from "@/features/transactions/lib/attachment-queries";
|
||||
import { getOptionalUserSession } from "@/shared/lib/auth/server";
|
||||
|
||||
const PRIVATE_RESPONSE_HEADERS = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { fetchInstallmentAnticipations } from "@/features/transactions/anticipation-queries";
|
||||
import { fetchInstallmentAnticipations } from "@/features/transactions/lib/anticipation-queries";
|
||||
import { getOptionalUserSession } from "@/shared/lib/auth/server";
|
||||
|
||||
const PRIVATE_RESPONSE_HEADERS = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import StatusDot from "@/shared/components/status-dot";
|
||||
import StatusDot from "@/shared/components/feedback/status-dot";
|
||||
import { getAccountTypeIcon } from "@/shared/utils/icons";
|
||||
|
||||
export function AccountTypeSelectContent({ label }: { label: string }) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { toast } from "sonner";
|
||||
import { deleteAccountAction } from "@/features/accounts/actions";
|
||||
import { AccountCard } from "@/features/accounts/components/account-card";
|
||||
import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog";
|
||||
import { EmptyState } from "@/shared/components/empty-state";
|
||||
import { EmptyState } from "@/shared/components/feedback/empty-state";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { Card } from "@/shared/components/ui/card";
|
||||
import {
|
||||
|
||||
@@ -99,13 +99,13 @@ async function fetchAccountsByStatus(
|
||||
return { accounts, logoOptions };
|
||||
}
|
||||
|
||||
export async function fetchAccountsForUser(
|
||||
async function fetchAccountsForUser(
|
||||
userId: string,
|
||||
): Promise<{ accounts: AccountData[]; logoOptions: string[] }> {
|
||||
return fetchAccountsByStatus(userId, false);
|
||||
}
|
||||
|
||||
export async function fetchInactiveForUser(
|
||||
async function fetchInactiveForUser(
|
||||
userId: string,
|
||||
): Promise<{ accounts: AccountData[]; logoOptions: string[] }> {
|
||||
return fetchAccountsByStatus(userId, true);
|
||||
|
||||
@@ -154,7 +154,7 @@ export async function fetchAccountSummary(
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchAccountLancamentos(
|
||||
export async function fetchAccountTransactions(
|
||||
filters: SQL[],
|
||||
settledOnly = true,
|
||||
) {
|
||||
@@ -167,7 +167,7 @@ export async function fetchAccountLancamentos(
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchAccountLancamentosPage(
|
||||
export async function fetchAccountTransactionsPage(
|
||||
filters: SQL[],
|
||||
{
|
||||
page,
|
||||
|
||||
@@ -18,7 +18,7 @@ import { fetchTransactionDialogOptionsAction } from "@/features/transactions/act
|
||||
import { TransactionDetailsDialog } from "@/features/transactions/components/dialogs/transaction-details-dialog";
|
||||
import { TransactionDialog } from "@/features/transactions/components/dialogs/transaction-dialog/transaction-dialog";
|
||||
import type { TransactionItem } from "@/features/transactions/components/types";
|
||||
import { EmptyState } from "@/shared/components/empty-state";
|
||||
import { EmptyState } from "@/shared/components/feedback/empty-state";
|
||||
import { Card, CardContent } from "@/shared/components/ui/card";
|
||||
import { cn } from "@/shared/utils/ui";
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { fetchJson } from "@/shared/lib/fetch-json";
|
||||
import { fetchJson } from "@/shared/utils/fetch-json";
|
||||
|
||||
const ATTACHMENT_URL_STALE_TIME = 4 * 60 * 1000;
|
||||
|
||||
export const attachmentUrlQueryKey = (attachmentId: string) =>
|
||||
const attachmentUrlQueryKey = (attachmentId: string) =>
|
||||
["attachments", "url", attachmentId] as const;
|
||||
|
||||
export function useAttachmentUrlQuery(attachmentId: string, enabled: boolean) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
RiBarChart2Line,
|
||||
RiShieldCheckLine,
|
||||
} from "@remixicon/react";
|
||||
import { Logo } from "@/shared/components/logo";
|
||||
import { Logo } from "@/shared/components/brand/logo";
|
||||
import { DotPattern } from "@/shared/components/ui/dot-pattern";
|
||||
import { AuthSidebarInvoicesMock } from "./auth-sidebar-invoices-mock";
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
duplicatePreviousMonthBudgetsAction,
|
||||
} from "@/features/budgets/actions";
|
||||
import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog";
|
||||
import { EmptyState } from "@/shared/components/empty-state";
|
||||
import { EmptyState } from "@/shared/components/feedback/empty-state";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { Card } from "@/shared/components/ui/card";
|
||||
import { BudgetCard } from "./budget-card";
|
||||
|
||||
@@ -26,7 +26,7 @@ type BudgetData = {
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type CategoryOption = {
|
||||
type CategoryOption = {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string | null;
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
buildOptionSets,
|
||||
buildSluggedFilters,
|
||||
mapTransactionsData,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
fetchRecentEstablishments,
|
||||
fetchTransactionFilterSources,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { RiBankLine } from "@remixicon/react";
|
||||
import Image from "next/image";
|
||||
import StatusDot from "@/shared/components/status-dot";
|
||||
import StatusDot from "@/shared/components/feedback/status-dot";
|
||||
import { resolveCardBrandLogoSrc } from "@/shared/lib/cards/brand-assets";
|
||||
import { resolveLogoSrc } from "@/shared/lib/logo";
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { deleteCardAction } from "@/features/cards/actions";
|
||||
import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog";
|
||||
import { EmptyState } from "@/shared/components/empty-state";
|
||||
import { EmptyState } from "@/shared/components/feedback/empty-state";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { Card as UiCard } from "@/shared/components/ui/card";
|
||||
import {
|
||||
|
||||
@@ -19,7 +19,7 @@ type CardData = {
|
||||
accountName: string;
|
||||
};
|
||||
|
||||
export type AccountSimple = {
|
||||
type AccountSimple = {
|
||||
id: string;
|
||||
name: string;
|
||||
logo: string | null;
|
||||
@@ -121,7 +121,7 @@ async function fetchCardsByStatus(
|
||||
return { cards: cardList, accounts, logoOptions };
|
||||
}
|
||||
|
||||
export async function fetchCardsForUser(userId: string): Promise<{
|
||||
async function fetchCardsForUser(userId: string): Promise<{
|
||||
cards: CardData[];
|
||||
accounts: AccountSimple[];
|
||||
logoOptions: string[];
|
||||
@@ -129,7 +129,7 @@ export async function fetchCardsForUser(userId: string): Promise<{
|
||||
return fetchCardsByStatus(userId, false);
|
||||
}
|
||||
|
||||
export async function fetchInactiveForUser(userId: string): Promise<{
|
||||
async function fetchInactiveForUser(userId: string): Promise<{
|
||||
cards: CardData[];
|
||||
accounts: AccountSimple[];
|
||||
logoOptions: string[];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import StatusDot from "@/shared/components/status-dot";
|
||||
import StatusDot from "@/shared/components/feedback/status-dot";
|
||||
|
||||
export function TypeSelectContent({ label }: { label: string }) {
|
||||
const isReceita = label === "Receita";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { type Category, categories } from "@/db/schema";
|
||||
import type { CategoryType } from "@/shared/lib/categories/constants";
|
||||
import { db } from "@/shared/lib/db";
|
||||
|
||||
export type CategoryData = {
|
||||
type CategoryData = {
|
||||
id: string;
|
||||
name: string;
|
||||
type: CategoryType;
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from "@/shared/utils/financial-dates";
|
||||
|
||||
export type BillDialogState = PaymentDialogState;
|
||||
export type BillStatusDateItem = Pick<
|
||||
type BillStatusDateItem = Pick<
|
||||
DashboardBill,
|
||||
"dueDate" | "boletoPaymentDate" | "isSettled"
|
||||
>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, desc, eq, isNull, ne, or, sql } from "drizzle-orm";
|
||||
import { categories, financialAccounts, transactions } from "@/db/schema";
|
||||
import { mapTransactionsData } from "@/features/transactions/page-helpers";
|
||||
import { mapTransactionsData } from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
ACCOUNT_AUTO_INVOICE_NOTE_PREFIX,
|
||||
INITIAL_BALANCE_NOTE,
|
||||
@@ -17,7 +17,7 @@ import { getPreviousPeriod } from "@/shared/utils/period";
|
||||
|
||||
type MappedLancamentos = ReturnType<typeof mapTransactionsData>;
|
||||
|
||||
export type CategoryDetailData = {
|
||||
type CategoryDetailData = {
|
||||
category: {
|
||||
id: string;
|
||||
name: string;
|
||||
|
||||
@@ -11,14 +11,14 @@ import {
|
||||
formatPeriodMonthShort,
|
||||
} from "@/shared/utils/period";
|
||||
|
||||
export type CategoryOption = {
|
||||
type CategoryOption = {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string | null;
|
||||
type: "receita" | "despesa";
|
||||
};
|
||||
|
||||
export type CategoryHistoryItem = {
|
||||
type CategoryHistoryItem = {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string | null;
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
excludeInitialBalanceWhenConfigured,
|
||||
excludeRefundEntries,
|
||||
excludeTransactionsFromExcludedAccounts,
|
||||
} from "@/features/dashboard/transaction-filters";
|
||||
} from "@/features/dashboard/lib/transaction-filters";
|
||||
import { db } from "@/shared/lib/db";
|
||||
import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id";
|
||||
import { safeToNumber as toNumber } from "@/shared/utils/number";
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export type CategoryOption = {
|
||||
type CategoryOption = {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type CategoryTransaction = {
|
||||
type CategoryTransaction = {
|
||||
id: string;
|
||||
name: string;
|
||||
amount: number;
|
||||
|
||||
@@ -14,8 +14,8 @@ import type {
|
||||
} from "@/features/dashboard/bills/bills-queries";
|
||||
import { AccountCardSelectContent } from "@/features/transactions/components/select-items";
|
||||
import { EstablishmentLogo } from "@/shared/components/entity-avatar";
|
||||
import { PaymentSuccess } from "@/shared/components/feedback/payment-success";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import { PaymentSuccess } from "@/shared/components/payment-success";
|
||||
import { Badge } from "@/shared/components/ui/badge";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { Card } from "@/shared/components/ui/card";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RiBarcodeFill } from "@remixicon/react";
|
||||
import type { DashboardBill } from "@/features/dashboard/bills/bills-queries";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { BillListItem } from "./bill-list-item";
|
||||
|
||||
type BillsListProps = {
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@/shared/components/ui/tabs";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { formatPeriodForUrl } from "@/shared/utils/period";
|
||||
import { CategoryBreakdownChart } from "./category-breakdown-chart";
|
||||
import { CategoryBreakdownList } from "./category-breakdown-list";
|
||||
|
||||
@@ -40,8 +40,8 @@ import {
|
||||
} from "@/features/dashboard/widget-registry/widget-config";
|
||||
import { NoteDialog } from "@/features/notes/components/note-dialog";
|
||||
import { TransactionDialog } from "@/features/transactions/components/dialogs/transaction-dialog/transaction-dialog";
|
||||
import { ExpandableWidgetCard } from "@/shared/components/expandable-widget-card";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { ExpandableWidgetCard } from "@/shared/components/widgets/expandable-widget-card";
|
||||
|
||||
type DashboardGridEditableProps = {
|
||||
data: DashboardData;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RiFundsLine } from "@remixicon/react";
|
||||
import type { GoalProgressItem } from "@/features/dashboard/goals-progress/goals-progress-queries";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { GoalProgressItem as GoalProgressListItem } from "./goals-progress-item";
|
||||
|
||||
type GoalsProgressListProps = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RiNumbersLine } from "@remixicon/react";
|
||||
import type { InstallmentExpense } from "@/features/dashboard/expenses/installment-expenses-queries";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { InstallmentExpenseListItem } from "./installment-expense-list-item";
|
||||
|
||||
type InstallmentExpensesListProps = {
|
||||
|
||||
@@ -14,8 +14,8 @@ import type {
|
||||
InvoicePaymentAccountOption,
|
||||
} from "@/features/dashboard/invoices/invoices-queries";
|
||||
import { AccountCardSelectContent } from "@/features/transactions/components/select-items";
|
||||
import { PaymentSuccess } from "@/shared/components/feedback/payment-success";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import { PaymentSuccess } from "@/shared/components/payment-success";
|
||||
import { Badge } from "@/shared/components/ui/badge";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { Card } from "@/shared/components/ui/card";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RiBillLine } from "@remixicon/react";
|
||||
import type { DashboardInvoice } from "@/features/dashboard/invoices/invoices-queries";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { InvoiceListItem } from "./invoice-list-item";
|
||||
|
||||
type InvoicesListProps = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RiTodoLine } from "@remixicon/react";
|
||||
import type { Note } from "@/features/notes/components/types";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { NoteListItem } from "./note-list-item";
|
||||
|
||||
type NotesListProps = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import {
|
||||
PaymentBreakdownListItem,
|
||||
type PaymentBreakdownListItemData,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import StatusDot from "@/shared/components/feedback/status-dot";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import StatusDot from "@/shared/components/status-dot";
|
||||
import { Progress } from "@/shared/components/ui/progress";
|
||||
|
||||
type PaymentStatusCategorySectionProps = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { RiWallet3Line } from "@remixicon/react";
|
||||
import type { PaymentStatusData } from "@/features/dashboard/payments/payment-status-queries";
|
||||
import { CardContent } from "@/shared/components/ui/card";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { PaymentStatusCategorySection } from "./payment-status-category-section";
|
||||
|
||||
type PaymentStatusWidgetViewProps = {
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
import { formatPercentage } from "@/shared/utils/percentage";
|
||||
import { cn } from "@/shared/utils/ui";
|
||||
|
||||
export type PercentageChangeTrend = "up" | "down" | "flat";
|
||||
type PercentageChangeTrend = "up" | "down" | "flat";
|
||||
|
||||
type PercentageChangeIndicatorProps = {
|
||||
value?: number | null;
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/shared/components/ui/tooltip";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { formatDateOnly } from "@/shared/utils/date";
|
||||
import { formatBytes } from "@/shared/utils/number";
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/shared/components/ui/popover";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { CATEGORY_COLORS } from "@/shared/utils/category-colors";
|
||||
import { formatCurrency, formatCurrencyCompact } from "@/shared/utils/currency";
|
||||
import { getIconComponent } from "@/shared/utils/icons";
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { DashboardCategoryBreakdownItem } from "@/features/dashboard/catego
|
||||
import { PercentageChangeIndicator } from "@/features/dashboard/components/percentage-change-indicator";
|
||||
import { CategoryIconBadge } from "@/shared/components/entity-avatar";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { formatPercentage } from "@/shared/utils/percentage";
|
||||
|
||||
type CategoryTrendsWidgetProps = {
|
||||
|
||||
@@ -9,7 +9,7 @@ import Image from "next/image";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import type { DashboardInboxSnapshot } from "@/features/dashboard/inbox-snapshot-queries";
|
||||
import type { DashboardInboxSnapshot } from "@/features/dashboard/lib/inbox-snapshot-queries";
|
||||
import type { DashboardWidgetQuickActionOptions } from "@/features/dashboard/widget-registry/widget-config";
|
||||
import {
|
||||
discardInboxItemAction,
|
||||
@@ -19,7 +19,7 @@ import { TransactionDialog } from "@/features/transactions/components/dialogs/tr
|
||||
import { ConfirmActionDialog } from "@/shared/components/confirm-action-dialog";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { resolveLogoSrc } from "@/shared/lib/logo";
|
||||
|
||||
const DEFAULT_INBOX_APP_LOGO = "/avatars/default_icon.png";
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
} from "@/shared/components/ui/chart";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { formatCurrency } from "@/shared/utils/currency";
|
||||
|
||||
type IncomeExpenseBalanceWidgetProps = {
|
||||
|
||||
@@ -10,7 +10,7 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useTransition } from "react";
|
||||
import { toast } from "sonner";
|
||||
import type { DashboardAccount } from "@/features/dashboard/accounts-queries";
|
||||
import type { DashboardAccount } from "@/features/dashboard/lib/accounts-queries";
|
||||
import { updateMyAccountsWidgetPreference } from "@/features/dashboard/widget-registry/widget-actions";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import { Badge } from "@/shared/components/ui/badge";
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/shared/components/ui/tooltip";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { isAccountInactive } from "@/shared/lib/accounts/constants";
|
||||
import { resolveLogoSrc } from "@/shared/lib/logo";
|
||||
import { formatPeriodForUrl } from "@/shared/utils/period";
|
||||
|
||||
@@ -7,14 +7,14 @@ import {
|
||||
} from "@remixicon/react";
|
||||
import Link from "next/link";
|
||||
import { PercentageChangeIndicator } from "@/features/dashboard/components/percentage-change-indicator";
|
||||
import type { DashboardPagador } from "@/features/dashboard/payers-queries";
|
||||
import type { DashboardPagador } from "@/features/dashboard/lib/payers-queries";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "@/shared/components/ui/avatar";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { getAvatarSrc } from "@/shared/lib/payers/utils";
|
||||
import { buildInitials } from "@/shared/utils/initials";
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/shared/components/ui/select";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { CATEGORY_TYPE_LABEL } from "@/shared/lib/categories/constants";
|
||||
import { formatTransactionDate } from "@/shared/utils/date";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { RiRefreshLine } from "@remixicon/react";
|
||||
import type { RecurringExpensesData } from "@/features/dashboard/expenses/recurring-expenses-queries";
|
||||
import { EstablishmentLogo } from "@/shared/components/entity-avatar";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
|
||||
type RecurringExpensesWidgetProps = {
|
||||
data: RecurringExpensesData;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { RiArrowUpDoubleLine, RiStore2Line } from "@remixicon/react";
|
||||
import { useState } from "react";
|
||||
import type { TopExpensesData } from "@/features/dashboard/expenses/top-expenses-queries";
|
||||
import type { TopEstablishmentsData } from "@/features/dashboard/top-establishments-queries";
|
||||
import type { TopEstablishmentsData } from "@/features/dashboard/lib/top-establishments-queries";
|
||||
import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { RiStore2Line } from "@remixicon/react";
|
||||
import type { TopEstablishmentsData } from "@/features/dashboard/top-establishments-queries";
|
||||
import type { TopEstablishmentsData } from "@/features/dashboard/lib/top-establishments-queries";
|
||||
import { EstablishmentLogo } from "@/shared/components/entity-avatar";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
|
||||
type TopEstablishmentsWidgetProps = {
|
||||
data: TopEstablishmentsData;
|
||||
|
||||
@@ -9,7 +9,7 @@ import type {
|
||||
import { EstablishmentLogo } from "@/shared/components/entity-avatar";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import { Switch } from "@/shared/components/ui/switch";
|
||||
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
|
||||
import { WidgetEmptyState } from "@/shared/components/widgets/widget-empty-state";
|
||||
import { formatTransactionDate } from "@/shared/utils/date";
|
||||
|
||||
type TopExpensesWidgetProps = {
|
||||
|
||||
@@ -31,7 +31,7 @@ function calculateDueDate(period: string, dueDay: string | null): Date | null {
|
||||
}
|
||||
}
|
||||
|
||||
export type InstallmentDetail = {
|
||||
type InstallmentDetail = {
|
||||
id: string;
|
||||
currentInstallment: number;
|
||||
amount: number;
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
formatLastInstallmentDate,
|
||||
} from "@/shared/lib/installments/utils";
|
||||
|
||||
export type InstallmentExpenseDisplay = {
|
||||
type InstallmentExpenseDisplay = {
|
||||
compactLabel: string | null;
|
||||
isLast: boolean;
|
||||
remainingInstallments: number;
|
||||
@@ -13,7 +13,7 @@ export type InstallmentExpenseDisplay = {
|
||||
progress: number;
|
||||
};
|
||||
|
||||
export const buildInstallmentCompactLabel = (
|
||||
const buildInstallmentCompactLabel = (
|
||||
currentInstallment: number | null,
|
||||
installmentCount: number | null,
|
||||
) => {
|
||||
@@ -24,7 +24,7 @@ export const buildInstallmentCompactLabel = (
|
||||
return null;
|
||||
};
|
||||
|
||||
export const isInstallmentLast = (
|
||||
const isInstallmentLast = (
|
||||
currentInstallment: number | null,
|
||||
installmentCount: number | null,
|
||||
) => {
|
||||
@@ -35,7 +35,7 @@ export const isInstallmentLast = (
|
||||
return currentInstallment === installmentCount && installmentCount > 1;
|
||||
};
|
||||
|
||||
export const calculateInstallmentRemainingCount = (
|
||||
const calculateInstallmentRemainingCount = (
|
||||
currentInstallment: number | null,
|
||||
installmentCount: number | null,
|
||||
) => {
|
||||
@@ -46,7 +46,7 @@ export const calculateInstallmentRemainingCount = (
|
||||
return Math.max(0, installmentCount - currentInstallment);
|
||||
};
|
||||
|
||||
export const calculateInstallmentRemainingAmount = (
|
||||
const calculateInstallmentRemainingAmount = (
|
||||
amount: number,
|
||||
currentInstallment: number | null,
|
||||
installmentCount: number | null,
|
||||
@@ -54,7 +54,7 @@ export const calculateInstallmentRemainingAmount = (
|
||||
amount *
|
||||
calculateInstallmentRemainingCount(currentInstallment, installmentCount);
|
||||
|
||||
export const formatInstallmentEndDate = (
|
||||
const formatInstallmentEndDate = (
|
||||
period: string,
|
||||
currentInstallment: number | null,
|
||||
installmentCount: number | null,
|
||||
@@ -72,7 +72,7 @@ export const formatInstallmentEndDate = (
|
||||
return formatLastInstallmentDate(lastDate);
|
||||
};
|
||||
|
||||
export const buildInstallmentProgress = (
|
||||
const buildInstallmentProgress = (
|
||||
currentInstallment: number | null,
|
||||
installmentCount: number | null,
|
||||
) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type RecurringExpense = {
|
||||
type RecurringExpense = {
|
||||
id: string;
|
||||
name: string;
|
||||
amount: number;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { cacheLife, cacheTag } from "next/cache";
|
||||
import { fetchAttachmentsForPeriod } from "@/features/attachments/queries";
|
||||
import { fetchDashboardAccounts } from "./accounts-queries";
|
||||
import { fetchDashboardCategoryOverview } from "./categories/category-overview-queries";
|
||||
import { fetchDashboardInboxSnapshot } from "./inbox-snapshot-queries";
|
||||
import { fetchDashboardInvoices } from "./invoices/invoices-queries";
|
||||
import { fetchDashboardAccounts } from "./lib/accounts-queries";
|
||||
import { fetchDashboardInboxSnapshot } from "./lib/inbox-snapshot-queries";
|
||||
import { fetchDashboardPayers } from "./lib/payers-queries";
|
||||
import { fetchDashboardNotes } from "./notes/notes-queries";
|
||||
import { fetchDashboardCurrentPeriodOverview } from "./overview/current-period-overview-queries";
|
||||
import { fetchDashboardPeriodOverview } from "./overview/period-overview-queries";
|
||||
import { fetchDashboardPayers } from "./payers-queries";
|
||||
|
||||
async function fetchDashboardDataInternal(userId: string, period: string) {
|
||||
const [
|
||||
|
||||
@@ -5,7 +5,6 @@ import type {
|
||||
import type {
|
||||
GoalProgressCategory,
|
||||
GoalProgressItem,
|
||||
GoalProgressStatus,
|
||||
} from "@/features/dashboard/goals-progress/goals-progress-queries";
|
||||
import { formatPercentage } from "@/shared/utils/percentage";
|
||||
|
||||
@@ -18,9 +17,6 @@ export const formatGoalProgressPercentage = (value: number, withSign = false) =>
|
||||
signDisplay: withSign ? "always" : "auto",
|
||||
});
|
||||
|
||||
export const getGoalProgressStatusColorClass = (status: GoalProgressStatus) =>
|
||||
status === "exceeded" ? "text-destructive" : "";
|
||||
|
||||
export const mapGoalProgressCategoriesToBudgetCategories = (
|
||||
categories: GoalProgressCategory[],
|
||||
): BudgetCategory[] =>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type GoalProgressStatus = "on-track" | "critical" | "exceeded";
|
||||
type GoalProgressStatus = "on-track" | "critical" | "exceeded";
|
||||
|
||||
export type GoalProgressItem = {
|
||||
id: string;
|
||||
|
||||
@@ -55,7 +55,7 @@ type RawInvoiceBreakdownRow = {
|
||||
amount: number | string | null;
|
||||
};
|
||||
|
||||
export type InvoicePagadorBreakdown = {
|
||||
type InvoicePagadorBreakdown = {
|
||||
payerId: string | null;
|
||||
pagadorName: string;
|
||||
pagadorAvatar: string | null;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DashboardData } from "./fetch-dashboard-data";
|
||||
import type { DashboardData } from "../fetch-dashboard-data";
|
||||
|
||||
/**
|
||||
* Coleta todos os nomes de estabelecimentos exibidos nos widgets do
|
||||
@@ -3,7 +3,7 @@ import { cacheLife, cacheTag } from "next/cache";
|
||||
import { cards, financialAccounts, inboxItems } from "@/db/schema";
|
||||
import { db } from "@/shared/lib/db";
|
||||
|
||||
export type DashboardInboxItem = {
|
||||
type DashboardInboxItem = {
|
||||
id: string;
|
||||
sourceAppName: string | null;
|
||||
parsedName: string | null;
|
||||
@@ -8,11 +8,11 @@ import { getBusinessDateString } from "@/shared/utils/date";
|
||||
import {
|
||||
type DashboardNotificationsSnapshot,
|
||||
fetchDashboardNotifications,
|
||||
} from "./notifications/notifications-queries";
|
||||
} from "../notifications/notifications-queries";
|
||||
|
||||
type DashboardNavbarData = {
|
||||
pagadorAvatarUrl: string | null;
|
||||
preLancamentosCount: number;
|
||||
payerAvatarUrl: string | null;
|
||||
inboxPendingCount: number;
|
||||
notificationsSnapshot: DashboardNotificationsSnapshot;
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ async function fetchDashboardNavbarDataInternal(
|
||||
userId: string,
|
||||
): Promise<DashboardNavbarData> {
|
||||
const currentPeriod = getBusinessDateString().slice(0, 7);
|
||||
const [pagadorAvatarUrl, notificationsSnapshot, preLancamentosCount] =
|
||||
const [payerAvatarUrl, notificationsSnapshot, inboxPendingCount] =
|
||||
await Promise.all([
|
||||
fetchAdminPayerAvatarUrl(userId),
|
||||
fetchDashboardNotifications(userId, currentPeriod),
|
||||
@@ -47,8 +47,8 @@ async function fetchDashboardNavbarDataInternal(
|
||||
]);
|
||||
|
||||
return {
|
||||
pagadorAvatarUrl,
|
||||
preLancamentosCount,
|
||||
payerAvatarUrl,
|
||||
inboxPendingCount,
|
||||
notificationsSnapshot,
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { and, desc, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
||||
import { financialAccounts, payers, transactions } from "@/db/schema";
|
||||
import { excludeTransactionsFromExcludedAccounts } from "@/features/dashboard/transaction-filters";
|
||||
import { excludeTransactionsFromExcludedAccounts } from "@/features/dashboard/lib/transaction-filters";
|
||||
import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants";
|
||||
import { db } from "@/shared/lib/db";
|
||||
import { PAYER_ROLE_ADMIN } from "@/shared/lib/payers/constants";
|
||||
@@ -1,4 +1,4 @@
|
||||
export type TopEstablishment = {
|
||||
type TopEstablishment = {
|
||||
id: string;
|
||||
name: string;
|
||||
amount: number;
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { DashboardNote } from "@/features/dashboard/notes/notes-queries";
|
||||
import type { Note } from "@/features/notes/components/types";
|
||||
|
||||
export const mapDashboardNoteToNote = (note: DashboardNote): Note => ({
|
||||
const mapDashboardNoteToNote = (note: DashboardNote): Note => ({
|
||||
id: note.id,
|
||||
title: note.title,
|
||||
description: note.description,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { and, eq } from "drizzle-orm";
|
||||
import { notes } from "@/db/schema";
|
||||
import { db } from "@/shared/lib/db";
|
||||
|
||||
export type DashboardTask = {
|
||||
type DashboardTask = {
|
||||
id: string;
|
||||
text: string;
|
||||
completed: boolean;
|
||||
|
||||
@@ -31,13 +31,7 @@ import {
|
||||
getNextPeriod,
|
||||
} from "@/shared/utils/period";
|
||||
|
||||
export type {
|
||||
BudgetNotification,
|
||||
BudgetStatus,
|
||||
DashboardNotification,
|
||||
DashboardNotificationsSnapshot,
|
||||
NotificationType,
|
||||
} from "@/shared/lib/types/notifications";
|
||||
export type { DashboardNotificationsSnapshot } from "@/shared/lib/types/notifications";
|
||||
|
||||
const PAYMENT_METHOD_BOLETO = "Boleto";
|
||||
const BUDGET_CRITICAL_THRESHOLD = 80;
|
||||
|
||||
@@ -13,11 +13,11 @@ import type {
|
||||
TopExpense,
|
||||
TopExpensesData,
|
||||
} from "@/features/dashboard/expenses/top-expenses-queries";
|
||||
import type { TopEstablishmentsData } from "@/features/dashboard/lib/top-establishments-queries";
|
||||
import { excludeTransactionsFromExcludedAccounts } from "@/features/dashboard/lib/transaction-filters";
|
||||
import type { PaymentConditionsData } from "@/features/dashboard/payments/payment-conditions-queries";
|
||||
import type { PaymentMethodsData } from "@/features/dashboard/payments/payment-methods-queries";
|
||||
import type { PaymentStatusData } from "@/features/dashboard/payments/payment-status-queries";
|
||||
import type { TopEstablishmentsData } from "@/features/dashboard/top-establishments-queries";
|
||||
import { excludeTransactionsFromExcludedAccounts } from "@/features/dashboard/transaction-filters";
|
||||
import {
|
||||
ACCOUNT_AUTO_INVOICE_NOTE_PREFIX,
|
||||
INITIAL_BALANCE_NOTE,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { and, asc, eq, gte, inArray, lte, sql } from "drizzle-orm";
|
||||
import { financialAccounts, transactions } from "@/db/schema";
|
||||
import type { DashboardCardMetrics } from "@/features/dashboard/overview/dashboard-metrics-queries";
|
||||
import type {
|
||||
IncomeExpenseBalanceData,
|
||||
MonthData,
|
||||
} from "@/features/dashboard/overview/income-expense-balance-queries";
|
||||
import {
|
||||
buildDashboardAdminFilters,
|
||||
excludeAutoInvoiceEntries,
|
||||
excludeInitialBalanceWhenConfigured,
|
||||
excludeTransactionsFromExcludedAccounts,
|
||||
} from "@/features/dashboard/transaction-filters";
|
||||
} from "@/features/dashboard/lib/transaction-filters";
|
||||
import type { DashboardCardMetrics } from "@/features/dashboard/overview/dashboard-metrics-queries";
|
||||
import type {
|
||||
IncomeExpenseBalanceData,
|
||||
MonthData,
|
||||
} from "@/features/dashboard/overview/income-expense-balance-queries";
|
||||
import { REFUND_NOTE_PREFIX } from "@/shared/lib/accounts/constants";
|
||||
import { db } from "@/shared/lib/db";
|
||||
import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id";
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { cacheLife, cacheTag } from "next/cache";
|
||||
import { fetchDashboardData } from "@/features/dashboard/fetch-dashboard-data";
|
||||
import { fetchUserDashboardPreferences } from "@/features/dashboard/preferences-queries";
|
||||
import { fetchUserDashboardPreferences } from "@/features/dashboard/lib/preferences-queries";
|
||||
import {
|
||||
buildOptionSets,
|
||||
buildSluggedFilters,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
fetchRecentEstablishments,
|
||||
fetchTransactionFilterSources,
|
||||
@@ -52,7 +52,7 @@ async function fetchDashboardQuickActionOptionsInternal(
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchDashboardQuickActionOptions(userId: string) {
|
||||
async function fetchDashboardQuickActionOptions(userId: string) {
|
||||
"use cache";
|
||||
cacheTag(`dashboard-${userId}`);
|
||||
cacheLife({ revalidate: 3 });
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type PaymentConditionSummary = {
|
||||
type PaymentConditionSummary = {
|
||||
condition: string;
|
||||
amount: number;
|
||||
percentage: number;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type PaymentMethodSummary = {
|
||||
type PaymentMethodSummary = {
|
||||
paymentMethod: string;
|
||||
amount: number;
|
||||
percentage: number;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type PaymentStatusCategory = {
|
||||
type PaymentStatusCategory = {
|
||||
total: number;
|
||||
confirmed: number;
|
||||
pending: number;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { RiAtLine, RiCalendarEventLine } from "@remixicon/react";
|
||||
import { format } from "date-fns";
|
||||
import { ptBR } from "date-fns/locale";
|
||||
import { EmptyState } from "@/shared/components/empty-state";
|
||||
import { EmptyState } from "@/shared/components/feedback/empty-state";
|
||||
import { Card } from "@/shared/components/ui/card";
|
||||
import { InboxCard } from "./inbox-card";
|
||||
import type { InboxItem } from "./types";
|
||||
|
||||
@@ -4,10 +4,7 @@ import {
|
||||
RiArrowRightDoubleLine,
|
||||
RiArrowRightSLine,
|
||||
} from "@remixicon/react";
|
||||
import {
|
||||
INBOX_DEFAULT_PAGE_SIZE,
|
||||
INBOX_PAGE_SIZE_OPTIONS,
|
||||
} from "@/features/inbox/page-helpers";
|
||||
import { INBOX_PAGE_SIZE_OPTIONS } from "@/features/inbox/page-helpers";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import {
|
||||
Select,
|
||||
@@ -117,6 +114,3 @@ export function InboxPagination({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Re-export para facilitar uso externo
|
||||
export { INBOX_DEFAULT_PAGE_SIZE };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TabsList, TabsTrigger } from "@/shared/components/ui/tabs";
|
||||
import type { InboxStatus, InboxStatusCounts } from "./types";
|
||||
import type { InboxStatusCounts } from "./types";
|
||||
|
||||
type InboxTabsProps = {
|
||||
counts: InboxStatusCounts;
|
||||
@@ -36,5 +36,3 @@ export function InboxTabs({ counts, isPending }: InboxTabsProps) {
|
||||
</TabsList>
|
||||
);
|
||||
}
|
||||
|
||||
export type { InboxStatus, InboxStatusCounts };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { SelectOption as LancamentoSelectOption } from "@/features/transactions/components/types";
|
||||
import type { SelectOption as TransactionSelectOption } from "@/features/transactions/components/types";
|
||||
|
||||
export type InboxStatus = "pending" | "processed" | "discarded";
|
||||
|
||||
@@ -29,4 +29,4 @@ export type InboxPaginationState = {
|
||||
};
|
||||
|
||||
// Re-export the lancamentos SelectOption for use in inbox components
|
||||
export type SelectOption = LancamentoSelectOption;
|
||||
export type SelectOption = TransactionSelectOption;
|
||||
|
||||
@@ -7,9 +7,9 @@ export type ResolvedInboxSearchParams =
|
||||
export const INBOX_DEFAULT_PAGE_SIZE = 12;
|
||||
export const INBOX_PAGE_SIZE_OPTIONS = [12, 24, 48];
|
||||
|
||||
export const INBOX_STATUSES = ["pending", "processed", "discarded"] as const;
|
||||
const INBOX_STATUSES = ["pending", "processed", "discarded"] as const;
|
||||
|
||||
export const getSingleParam = (
|
||||
const getSingleParam = (
|
||||
params: ResolvedInboxSearchParams,
|
||||
key: string,
|
||||
): string | null => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { and, count, desc, eq } from "drizzle-orm";
|
||||
import { cards, categories, financialAccounts, inboxItems } from "@/db/schema";
|
||||
import { cards, financialAccounts, inboxItems } from "@/db/schema";
|
||||
import type {
|
||||
InboxItem,
|
||||
InboxPaginationState,
|
||||
@@ -10,29 +10,13 @@ import type {
|
||||
import {
|
||||
buildOptionSets,
|
||||
buildSluggedFilters,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
} from "@/features/transactions/lib/page-helpers";
|
||||
import {
|
||||
fetchRecentEstablishments,
|
||||
fetchTransactionFilterSources,
|
||||
} from "@/features/transactions/queries";
|
||||
import { db } from "@/shared/lib/db";
|
||||
|
||||
export async function fetchInboxItems(
|
||||
userId: string,
|
||||
status: InboxStatus = "pending",
|
||||
): Promise<InboxItem[]> {
|
||||
const items = await db
|
||||
.select()
|
||||
.from(inboxItems)
|
||||
.where(and(eq(inboxItems.userId, userId), eq(inboxItems.status, status)))
|
||||
.orderBy(
|
||||
desc(inboxItems.notificationTimestamp),
|
||||
desc(inboxItems.createdAt),
|
||||
);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
export async function fetchInboxItemsPage(
|
||||
userId: string,
|
||||
status: InboxStatus,
|
||||
@@ -126,65 +110,6 @@ export async function fetchInboxStatusCounts(
|
||||
return counts;
|
||||
}
|
||||
|
||||
export async function fetchInboxItemById(
|
||||
userId: string,
|
||||
itemId: string,
|
||||
): Promise<InboxItem | null> {
|
||||
const [item] = await db
|
||||
.select()
|
||||
.from(inboxItems)
|
||||
.where(and(eq(inboxItems.id, itemId), eq(inboxItems.userId, userId)))
|
||||
.limit(1);
|
||||
|
||||
return item ?? null;
|
||||
}
|
||||
|
||||
export async function fetchCategoriesForSelect(
|
||||
userId: string,
|
||||
type?: string,
|
||||
): Promise<SelectOption[]> {
|
||||
const rows = await db
|
||||
.select({ id: categories.id, name: categories.name })
|
||||
.from(categories)
|
||||
.where(
|
||||
type
|
||||
? and(eq(categories.userId, userId), eq(categories.type, type))
|
||||
: eq(categories.userId, userId),
|
||||
)
|
||||
.orderBy(categories.name);
|
||||
|
||||
return rows.map((row) => ({ value: row.id, label: row.name }));
|
||||
}
|
||||
|
||||
export async function fetchAccountsForSelect(
|
||||
userId: string,
|
||||
): Promise<SelectOption[]> {
|
||||
const rows = await db
|
||||
.select({ id: financialAccounts.id, name: financialAccounts.name })
|
||||
.from(financialAccounts)
|
||||
.where(
|
||||
and(
|
||||
eq(financialAccounts.userId, userId),
|
||||
eq(financialAccounts.status, "ativo"),
|
||||
),
|
||||
)
|
||||
.orderBy(financialAccounts.name);
|
||||
|
||||
return rows.map((row) => ({ value: row.id, label: row.name }));
|
||||
}
|
||||
|
||||
export async function fetchCardsForSelect(
|
||||
userId: string,
|
||||
): Promise<(SelectOption & { lastDigits?: string })[]> {
|
||||
const rows = await db
|
||||
.select({ id: cards.id, name: cards.name })
|
||||
.from(cards)
|
||||
.where(and(eq(cards.userId, userId), eq(cards.status, "ativo")))
|
||||
.orderBy(cards.name);
|
||||
|
||||
return rows.map((row) => ({ value: row.id, label: row.name }));
|
||||
}
|
||||
|
||||
export async function fetchAppLogoMap(
|
||||
userId: string,
|
||||
): Promise<Record<string, string>> {
|
||||
|
||||
@@ -1,32 +1,5 @@
|
||||
"use server";
|
||||
|
||||
import { generateInsightsAction as generateInsightsActionImpl } from "./actions/generate";
|
||||
import {
|
||||
deleteSavedInsightsAction as deleteSavedInsightsActionImpl,
|
||||
loadSavedInsightsAction as loadSavedInsightsActionImpl,
|
||||
saveInsightsAction as saveInsightsActionImpl,
|
||||
export { generateInsightsAction } from "./actions/generate";
|
||||
export {
|
||||
deleteSavedInsightsAction,
|
||||
saveInsightsAction,
|
||||
} from "./actions/storage";
|
||||
|
||||
export async function generateInsightsAction(
|
||||
...args: Parameters<typeof generateInsightsActionImpl>
|
||||
): ReturnType<typeof generateInsightsActionImpl> {
|
||||
return generateInsightsActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function saveInsightsAction(
|
||||
...args: Parameters<typeof saveInsightsActionImpl>
|
||||
): ReturnType<typeof saveInsightsActionImpl> {
|
||||
return saveInsightsActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function loadSavedInsightsAction(
|
||||
...args: Parameters<typeof loadSavedInsightsActionImpl>
|
||||
): ReturnType<typeof loadSavedInsightsActionImpl> {
|
||||
return loadSavedInsightsActionImpl(...args);
|
||||
}
|
||||
|
||||
export async function deleteSavedInsightsAction(
|
||||
...args: Parameters<typeof deleteSavedInsightsActionImpl>
|
||||
): ReturnType<typeof deleteSavedInsightsActionImpl> {
|
||||
return deleteSavedInsightsActionImpl(...args);
|
||||
}
|
||||
|
||||
@@ -5,10 +5,7 @@ import { z } from "zod";
|
||||
import { savedInsights } from "@/db/schema";
|
||||
import { getUser } from "@/shared/lib/auth/server";
|
||||
import { db } from "@/shared/lib/db";
|
||||
import {
|
||||
type InsightsResponse,
|
||||
InsightsResponseSchema,
|
||||
} from "@/shared/lib/schemas/insights";
|
||||
import type { InsightsResponse } from "@/shared/lib/schemas/insights";
|
||||
import type { ActionResult } from "./types";
|
||||
|
||||
const periodSchema = z
|
||||
@@ -115,62 +112,6 @@ export async function saveInsightsAction(
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadSavedInsightsAction(period: string): Promise<
|
||||
ActionResult<{
|
||||
insights: InsightsResponse;
|
||||
modelId: string;
|
||||
createdAt: Date;
|
||||
} | null>
|
||||
> {
|
||||
try {
|
||||
const user = await getUser();
|
||||
const validatedPeriod = periodSchema.safeParse(period);
|
||||
if (!validatedPeriod.success) {
|
||||
return {
|
||||
success: false,
|
||||
error: validatedPeriod.error.issues[0]?.message ?? "Período inválido",
|
||||
};
|
||||
}
|
||||
period = validatedPeriod.data;
|
||||
|
||||
const result = await db
|
||||
.select()
|
||||
.from(savedInsights)
|
||||
.where(
|
||||
and(
|
||||
eq(savedInsights.userId, user.id),
|
||||
eq(savedInsights.period, period),
|
||||
),
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (result.length === 0) {
|
||||
return {
|
||||
success: true,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
|
||||
const saved = result[0];
|
||||
const insights = InsightsResponseSchema.parse(JSON.parse(saved.data));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
insights,
|
||||
modelId: saved.modelId,
|
||||
createdAt: saved.createdAt,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error loading saved insights:", error);
|
||||
return {
|
||||
success: false,
|
||||
error: "Erro ao carregar análise salva. Tente novamente.",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteSavedInsightsAction(
|
||||
period: string,
|
||||
): Promise<ActionResult<void>> {
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
savedInsightsQueryKey,
|
||||
useSavedInsights,
|
||||
} from "@/features/insights/hooks/use-saved-insights";
|
||||
import { EmptyState } from "@/shared/components/empty-state";
|
||||
import { EmptyState } from "@/shared/components/feedback/empty-state";
|
||||
import { Alert, AlertDescription } from "@/shared/components/ui/alert";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { Card, CardContent, CardHeader } from "@/shared/components/ui/card";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user