mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-07-10 03:46:01 +00:00
chore: prepara versao 2.7.7
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
import { useState } from "react";
|
||||
import { AttachmentPreview } from "@/features/attachments/components/attachment-preview";
|
||||
import type { AttachmentForPeriod } from "@/features/attachments/queries";
|
||||
import { dashboardWidgetListStyles as styles } from "@/features/dashboard/components/dashboard-widget-list-styles";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
@@ -77,7 +78,7 @@ export function AttachmentsWidget({ snapshot }: AttachmentsWidgetProps) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSelectedIndex(index)}
|
||||
className="flex w-full items-center gap-2 py-2 text-left"
|
||||
className={`${styles.row} w-full text-left`}
|
||||
>
|
||||
<div className="shrink-0">
|
||||
{isPdf && <RiFilePdf2Line className="size-6 text-red-500" />}
|
||||
@@ -86,10 +87,10 @@ export function AttachmentsWidget({ snapshot }: AttachmentsWidgetProps) {
|
||||
<RiFileLine className="size-6 text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className={styles.textStack}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="block truncate text-sm font-medium text-foreground hover:underline">
|
||||
<span className={`${styles.title} block hover:underline`}>
|
||||
{attachment.fileName}
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
@@ -97,18 +98,18 @@ export function AttachmentsWidget({ snapshot }: AttachmentsWidgetProps) {
|
||||
{attachment.fileName}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<span className="block truncate text-xs text-muted-foreground">
|
||||
<span className={`${styles.meta} block truncate`}>
|
||||
{attachment.transactionName}
|
||||
</span>
|
||||
</div>
|
||||
<div className="shrink-0 text-right">
|
||||
<span className="block text-xs text-muted-foreground">
|
||||
<div className={styles.trailing}>
|
||||
<span className="block text-xs leading-4 text-muted-foreground">
|
||||
{formatDateOnly(attachment.purchaseDate, {
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
}) ?? "—"}
|
||||
</span>
|
||||
<span className="block text-xs text-muted-foreground/60">
|
||||
<span className="block text-xs leading-4 text-muted-foreground/60">
|
||||
{formatBytes(attachment.fileSize)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
RiLineChartLine,
|
||||
} from "@remixicon/react";
|
||||
import type { DashboardCategoryBreakdownItem } from "@/features/dashboard/categories/category-breakdown-helpers";
|
||||
import { dashboardWidgetListStyles as styles } from "@/features/dashboard/components/dashboard-widget-list-styles";
|
||||
import { PercentageChangeIndicator } from "@/features/dashboard/components/percentage-change-indicator";
|
||||
import { CategoryIconBadge } from "@/shared/components/entity-avatar";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
@@ -45,17 +46,15 @@ export function CategoryTrendsWidget({
|
||||
|
||||
return (
|
||||
<li key={category.categoryId}>
|
||||
<div className="-mx-2 flex items-center gap-3 rounded-md p-2">
|
||||
<div className={styles.row}>
|
||||
<CategoryIconBadge
|
||||
icon={category.categoryIcon}
|
||||
name={category.categoryName}
|
||||
size="md"
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate text-sm font-medium text-foreground">
|
||||
{category.categoryName}
|
||||
</p>
|
||||
<p className="flex items-center gap-1.5 text-xs text-muted-foreground">
|
||||
<div className={styles.textStack}>
|
||||
<p className={styles.title}>{category.categoryName}</p>
|
||||
<p className={styles.meta}>
|
||||
<span
|
||||
className="inline-flex items-center gap-1"
|
||||
title="Mês anterior"
|
||||
@@ -81,7 +80,9 @@ export function CategoryTrendsWidget({
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<span className="flex shrink-0 items-center gap-1 text-xs text-muted-foreground">
|
||||
<span
|
||||
className={`${styles.trailingMeta} min-w-[5.75rem] justify-end text-muted-foreground`}
|
||||
>
|
||||
<PercentageChangeIndicator
|
||||
value={change}
|
||||
label={formatPercentage(change, {
|
||||
|
||||
@@ -10,6 +10,7 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { dashboardWidgetListStyles as styles } from "@/features/dashboard/components/dashboard-widget-list-styles";
|
||||
import type { DashboardInboxSnapshot } from "@/features/dashboard/lib/inbox-snapshot-queries";
|
||||
import type { DashboardWidgetQuickActionOptions } from "@/features/dashboard/widget-registry/widget-config";
|
||||
import {
|
||||
@@ -201,8 +202,8 @@ export function InboxWidget({
|
||||
const displayLogo = logoSrc ?? DEFAULT_INBOX_APP_LOGO;
|
||||
|
||||
return (
|
||||
<div key={item.id} className="flex items-center justify-between py-2">
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||
<div key={item.id} className={styles.row}>
|
||||
<div className={styles.main}>
|
||||
<Image
|
||||
src={displayLogo}
|
||||
alt={item.sourceAppName ?? ""}
|
||||
@@ -212,11 +213,9 @@ export function InboxWidget({
|
||||
unoptimized
|
||||
/>
|
||||
|
||||
<div className="min-w-0">
|
||||
<p className="truncate text-sm font-medium text-foreground">
|
||||
{displayName}
|
||||
</p>
|
||||
<div className="flex min-w-0 items-center gap-2 text-xs text-muted-foreground">
|
||||
<div className={styles.textStack}>
|
||||
<p className={styles.title}>{displayName}</p>
|
||||
<div className={styles.meta}>
|
||||
{item.sourceAppName && (
|
||||
<span className="truncate">{item.sourceAppName}</span>
|
||||
)}
|
||||
@@ -227,9 +226,9 @@ export function InboxWidget({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ml-2 flex shrink-0 items-center gap-1">
|
||||
<div className="ml-2 flex min-w-[7.5rem] shrink-0 items-center justify-end gap-1">
|
||||
{amount !== null && (
|
||||
<MoneyValues className="font-medium" amount={amount} />
|
||||
<MoneyValues className={styles.trailingValue} amount={amount} />
|
||||
)}
|
||||
{amount === null && (
|
||||
<span className="max-w-20 text-right text-xs leading-tight text-muted-foreground">
|
||||
|
||||
@@ -10,6 +10,7 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useTransition } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { dashboardWidgetListStyles as styles } from "@/features/dashboard/components/dashboard-widget-list-styles";
|
||||
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";
|
||||
@@ -139,11 +140,8 @@ export function MyAccountsWidget({
|
||||
const logoSrc = resolveLogoSrc(account.logo);
|
||||
|
||||
return (
|
||||
<li
|
||||
key={account.id}
|
||||
className="flex items-center justify-between py-1.5 transition-all duration-300"
|
||||
>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2 py-1">
|
||||
<li key={account.id} className={styles.row}>
|
||||
<div className={styles.main}>
|
||||
<div className="relative flex size-9.5 shrink-0 items-center justify-center overflow-hidden rounded-full">
|
||||
{logoSrc ? (
|
||||
<Image
|
||||
@@ -161,18 +159,18 @@ export function MyAccountsWidget({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="min-w-0">
|
||||
<div className={styles.textStack}>
|
||||
<Link
|
||||
prefetch
|
||||
href={`/accounts/${
|
||||
account.id
|
||||
}/statement?periodo=${formatPeriodForUrl(period)}`}
|
||||
className="inline-flex max-w-full items-center gap-1 text-sm font-medium text-foreground underline-offset-2 hover:text-primary hover:underline"
|
||||
className={styles.titleLink}
|
||||
>
|
||||
<span className="truncate">{account.name}</span>
|
||||
</Link>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
||||
<div className={styles.meta}>
|
||||
<span className="truncate">{account.accountType}</span>
|
||||
{account.excludeFromBalance ? (
|
||||
<Tooltip>
|
||||
@@ -195,10 +193,10 @@ export function MyAccountsWidget({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-end gap-0.5 text-right">
|
||||
<div className={styles.trailing}>
|
||||
<MoneyValues
|
||||
className={cn(
|
||||
"font-medium",
|
||||
styles.trailingValue,
|
||||
account.balance < 0 && "text-destructive",
|
||||
)}
|
||||
amount={account.balance}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { RiGroupLine, RiVerifiedBadgeFill } from "@remixicon/react";
|
||||
import Link from "next/link";
|
||||
import { dashboardWidgetListStyles as styles } from "@/features/dashboard/components/dashboard-widget-list-styles";
|
||||
import { PercentageChangeIndicator } from "@/features/dashboard/components/percentage-change-indicator";
|
||||
import type { DashboardPagador } from "@/features/dashboard/lib/payers-queries";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
@@ -44,14 +45,9 @@ export function PayersWidget({ payers }: PayersWidgetProps) {
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={payer.id}
|
||||
className="flex items-center justify-between gap-2 transition-all duration-300 py-1.5"
|
||||
>
|
||||
<span className="w-3 shrink-0 text-left text-xs font-medium text-muted-foreground">
|
||||
{index + 1}
|
||||
</span>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2 py-1">
|
||||
<div key={payer.id} className={styles.row}>
|
||||
<span className={styles.rank}>{index + 1}</span>
|
||||
<div className={styles.main}>
|
||||
<Avatar className="size-9.5 shrink-0">
|
||||
<AvatarImage
|
||||
src={getAvatarSrc(payer.avatarUrl)}
|
||||
@@ -60,11 +56,11 @@ export function PayersWidget({ payers }: PayersWidgetProps) {
|
||||
<AvatarFallback>{initials}</AvatarFallback>
|
||||
</Avatar>
|
||||
|
||||
<div className="min-w-0">
|
||||
<div className={styles.textStack}>
|
||||
<Link
|
||||
prefetch
|
||||
href={`/payers/${payer.id}`}
|
||||
className="inline-flex max-w-full items-center gap-1 text-sm text-foreground underline-offset-2 hover:text-primary hover:underline"
|
||||
className={styles.titleLink}
|
||||
>
|
||||
<span className="truncate font-medium">{payer.name}</span>
|
||||
{payer.isAdmin && (
|
||||
@@ -84,18 +80,18 @@ export function PayersWidget({ payers }: PayersWidgetProps) {
|
||||
</Tooltip>
|
||||
)}
|
||||
</Link>
|
||||
<p className="truncate text-xs text-muted-foreground">
|
||||
Despesas no período
|
||||
</p>
|
||||
<p className={styles.meta}>Despesas no período</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 flex-col items-end">
|
||||
<div className={styles.trailing}>
|
||||
<MoneyValues
|
||||
className="font-medium"
|
||||
className={styles.trailingValue}
|
||||
amount={payer.totalExpenses}
|
||||
/>
|
||||
<div className="flex items-center gap-1 text-xs text-muted-foreground">
|
||||
<div
|
||||
className={`${styles.trailingMeta} text-muted-foreground`}
|
||||
>
|
||||
<PercentageChangeIndicator value={percentageChange} />
|
||||
{percentageChange !== null ? (
|
||||
<span>vs. mês ant.</span>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { RiFileList2Line, RiStore3Line } from "@remixicon/react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import type { PurchasesByCategoryData } from "@/features/dashboard/categories/purchases-by-category-queries";
|
||||
import { dashboardWidgetListStyles as styles } from "@/features/dashboard/components/dashboard-widget-list-styles";
|
||||
import { EstablishmentLogo } from "@/shared/components/entity-avatar";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
import {
|
||||
@@ -162,26 +163,21 @@ export function PurchasesByCategoryWidget({
|
||||
<div className="flex flex-col">
|
||||
{currentTransactions.map((transaction) => {
|
||||
return (
|
||||
<div
|
||||
key={transaction.id}
|
||||
className="flex items-center justify-between gap-2 transition-all duration-300 py-1.5"
|
||||
>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||
<div key={transaction.id} className={styles.row}>
|
||||
<div className={styles.main}>
|
||||
<EstablishmentLogo name={transaction.name} size={37} />
|
||||
|
||||
<div className="min-w-0">
|
||||
<p className="truncate text-sm font-medium text-foreground">
|
||||
{transaction.name}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<div className={styles.textStack}>
|
||||
<p className={styles.title}>{transaction.name}</p>
|
||||
<p className={styles.meta}>
|
||||
{formatTransactionDate(transaction.purchaseDate)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-foreground">
|
||||
<div className={styles.trailing}>
|
||||
<MoneyValues
|
||||
className="font-medium"
|
||||
className={styles.trailingValue}
|
||||
amount={transaction.amount}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { RiRefreshLine } from "@remixicon/react";
|
||||
import { dashboardWidgetListStyles as styles } from "@/features/dashboard/components/dashboard-widget-list-styles";
|
||||
import type { RecurringExpensesData } from "@/features/dashboard/expenses/recurring-expenses-queries";
|
||||
import { EstablishmentLogo } from "@/shared/components/entity-avatar";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
@@ -36,31 +37,27 @@ export function RecurringExpensesWidget({
|
||||
.sort((a, b) => b.amount - a.amount)
|
||||
.map((expense) => {
|
||||
return (
|
||||
<div
|
||||
key={expense.id}
|
||||
className="flex items-center gap-2 transition-all duration-300 py-1.5"
|
||||
>
|
||||
<EstablishmentLogo name={expense.name} size={37} />
|
||||
<div key={expense.id} className={styles.row}>
|
||||
<div className={styles.main}>
|
||||
<EstablishmentLogo name={expense.name} size={37} />
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="truncate text-foreground text-sm font-medium">
|
||||
{expense.name}
|
||||
</p>
|
||||
|
||||
<MoneyValues
|
||||
className="font-medium"
|
||||
amount={expense.amount}
|
||||
/>
|
||||
<div className={styles.textStack}>
|
||||
<p className={styles.title}>{expense.name}</p>
|
||||
<div className={styles.meta}>
|
||||
<span className="inline-flex min-w-0 items-center gap-1 [&_svg]:size-3.5">
|
||||
{getPaymentMethodIcon(expense.paymentMethod)}
|
||||
{expense.paymentMethod}
|
||||
</span>
|
||||
<span>{formatOccurrences(expense.recurrenceCount)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between text-xs text-muted-foreground">
|
||||
<span className="inline-flex items-center gap-1 [&_svg]:size-3.5">
|
||||
{getPaymentMethodIcon(expense.paymentMethod)}
|
||||
{expense.paymentMethod}
|
||||
</span>
|
||||
<span>{formatOccurrences(expense.recurrenceCount)}</span>
|
||||
</div>
|
||||
<div className={styles.trailing}>
|
||||
<MoneyValues
|
||||
className={styles.trailingValue}
|
||||
amount={expense.amount}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { RiStore2Line } from "@remixicon/react";
|
||||
import { dashboardWidgetListStyles as styles } from "@/features/dashboard/components/dashboard-widget-list-styles";
|
||||
import type { TopEstablishmentsData } from "@/features/dashboard/lib/top-establishments-queries";
|
||||
import { EstablishmentLogo } from "@/shared/components/entity-avatar";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
@@ -30,30 +31,23 @@ export function TopEstablishmentsWidget({
|
||||
<div className="flex flex-col">
|
||||
{data.establishments.map((establishment, index) => {
|
||||
return (
|
||||
<div
|
||||
key={establishment.id}
|
||||
className="flex items-center justify-between gap-2 transition-all duration-300 py-1.5"
|
||||
>
|
||||
<span className="w-3 shrink-0 text-left text-xs font-medium text-muted-foreground">
|
||||
{index + 1}
|
||||
</span>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||
<div key={establishment.id} className={styles.row}>
|
||||
<span className={styles.rank}>{index + 1}</span>
|
||||
<div className={styles.main}>
|
||||
<EstablishmentLogo name={establishment.name} size={37} />
|
||||
|
||||
<div className="min-w-0">
|
||||
<p className="truncate text-sm font-medium text-foreground">
|
||||
{establishment.name}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<div className={styles.textStack}>
|
||||
<p className={styles.title}>{establishment.name}</p>
|
||||
<p className={styles.meta}>
|
||||
{formatOccurrencesLabel(establishment.occurrences)} ·
|
||||
total acumulado
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-foreground">
|
||||
<div className={styles.trailing}>
|
||||
<MoneyValues
|
||||
className="font-medium"
|
||||
className={styles.trailingValue}
|
||||
amount={establishment.amount}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { RiArrowUpDoubleLine } from "@remixicon/react";
|
||||
import { useMemo } from "react";
|
||||
import { dashboardWidgetListStyles as styles } from "@/features/dashboard/components/dashboard-widget-list-styles";
|
||||
import type {
|
||||
TopExpense,
|
||||
TopExpensesData,
|
||||
@@ -49,29 +50,22 @@ export function TopExpensesWidget({ data }: TopExpensesWidgetProps) {
|
||||
<div className="flex flex-col">
|
||||
{expenses.map((expense, index) => {
|
||||
return (
|
||||
<div
|
||||
key={expense.id}
|
||||
className="flex items-center justify-between gap-2 transition-all duration-300 py-1.5"
|
||||
>
|
||||
<span className="w-3 shrink-0 text-left text-xs font-medium text-muted-foreground">
|
||||
{index + 1}
|
||||
</span>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||
<div key={expense.id} className={styles.row}>
|
||||
<span className={styles.rank}>{index + 1}</span>
|
||||
<div className={styles.main}>
|
||||
<EstablishmentLogo name={expense.name} size={37} />
|
||||
|
||||
<div className="min-w-0">
|
||||
<p className="truncate text-sm font-medium text-foreground">
|
||||
{expense.name}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<div className={styles.textStack}>
|
||||
<p className={styles.title}>{expense.name}</p>
|
||||
<p className={styles.meta}>
|
||||
{formatTransactionDate(expense.purchaseDate)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-foreground">
|
||||
<div className={styles.trailing}>
|
||||
<MoneyValues
|
||||
className="font-medium"
|
||||
className={styles.trailingValue}
|
||||
amount={expense.amount}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user