From c352f5eadd68b9849886956cfe18cd5a9812fbf1 Mon Sep 17 00:00:00 2001 From: vas3k Date: Tue, 20 May 2025 20:37:26 +0200 Subject: [PATCH] fix: restore from backup, restart button for tools, loader for fields --- app/(app)/settings/backups/page.tsx | 2 +- app/(app)/settings/danger/actions.ts | 16 +++- .../transactions/[transactionId]/page.tsx | 21 ++++- app/(app)/transactions/loading.tsx | 4 +- app/(app)/transactions/page.tsx | 2 +- app/(app)/unsorted/layout.tsx | 3 - app/(app)/unsorted/loading.tsx | 5 +- app/(app)/unsorted/page.tsx | 4 +- app/globals.css | 7 +- .../{agent-window.tsx => tool-window.tsx} | 2 +- components/forms/convert-currency.tsx | 79 +++++++++++-------- components/forms/simple.tsx | 7 +- components/transactions/edit.tsx | 72 +++++++++-------- components/transactions/fields-selector.tsx | 13 ++- components/transactions/list.tsx | 17 +--- components/unsorted/analyze-form.tsx | 6 +- lib/stats.ts | 20 ++++- models/transactions.ts | 10 +-- 18 files changed, 172 insertions(+), 118 deletions(-) delete mode 100644 app/(app)/unsorted/layout.tsx rename components/agents/{agent-window.tsx => tool-window.tsx} (79%) diff --git a/app/(app)/settings/backups/page.tsx b/app/(app)/settings/backups/page.tsx index b5b26de..d6708fe 100644 --- a/app/(app)/settings/backups/page.tsx +++ b/app/(app)/settings/backups/page.tsx @@ -44,7 +44,7 @@ export default function BackupSettingsPage() { progress?.current ? ( `Archiving ${progress.current}/${progress.total} files` ) : ( - "Preparing backup..." + "Preparing backup. Don't close the page..." ) ) : isDownloading ? ( "Archive is created. Downloading..." diff --git a/app/(app)/settings/danger/actions.ts b/app/(app)/settings/danger/actions.ts index 9c19fef..3261e81 100644 --- a/app/(app)/settings/danger/actions.ts +++ b/app/(app)/settings/danger/actions.ts @@ -24,10 +24,13 @@ export async function resetFieldsAndCategories(user: User) { for (const category of DEFAULT_CATEGORIES) { await prisma.category.upsert({ where: { userId_code: { code: category.code, userId: user.id } }, - update: { name: category.name, color: category.color, llm_prompt: category.llm_prompt }, - create: { ...category, userId: user.id }, + update: { name: category.name, color: category.color, llm_prompt: category.llm_prompt, createdAt: new Date() }, + create: { ...category, userId: user.id, createdAt: new Date() }, }) } + await prisma.category.deleteMany({ + where: { userId: user.id, code: { notIn: DEFAULT_CATEGORIES.map((category) => category.code) } }, + }) // Reset currencies for (const currency of DEFAULT_CURRENCIES) { @@ -37,6 +40,9 @@ export async function resetFieldsAndCategories(user: User) { create: { ...currency, userId: user.id }, }) } + await prisma.currency.deleteMany({ + where: { userId: user.id, code: { notIn: DEFAULT_CURRENCIES.map((currency) => currency.code) } }, + }) // Reset fields for (const field of DEFAULT_FIELDS) { @@ -46,14 +52,18 @@ export async function resetFieldsAndCategories(user: User) { name: field.name, type: field.type, llm_prompt: field.llm_prompt, + createdAt: new Date(), isVisibleInList: field.isVisibleInList, isVisibleInAnalysis: field.isVisibleInAnalysis, isRequired: field.isRequired, isExtra: field.isExtra, }, - create: { ...field, userId: user.id }, + create: { ...field, userId: user.id, createdAt: new Date() }, }) } + await prisma.field.deleteMany({ + where: { userId: user.id, code: { notIn: DEFAULT_FIELDS.map((field) => field.code) } }, + }) redirect("/settings/fields") } diff --git a/app/(app)/transactions/[transactionId]/page.tsx b/app/(app)/transactions/[transactionId]/page.tsx index a761673..32f67de 100644 --- a/app/(app)/transactions/[transactionId]/page.tsx +++ b/app/(app)/transactions/[transactionId]/page.tsx @@ -3,6 +3,7 @@ import TransactionEditForm from "@/components/transactions/edit" import TransactionFiles from "@/components/transactions/transaction-files" import { Card } from "@/components/ui/card" import { getCurrentUser } from "@/lib/auth" +import { incompleteTransactionFields } from "@/lib/stats" import { getCategories } from "@/models/categories" import { getCurrencies } from "@/models/currencies" import { getFields } from "@/models/fields" @@ -11,6 +12,7 @@ import { getProjects } from "@/models/projects" import { getSettings } from "@/models/settings" import { getTransactionById } from "@/models/transactions" import { notFound } from "next/navigation" +import Link from "next/link" export default async function TransactionPage({ params }: { params: Promise<{ transactionId: string }> }) { const { transactionId } = await params @@ -26,11 +28,26 @@ export default async function TransactionPage({ params }: { params: Promise<{ tr const settings = await getSettings(user.id) const fields = await getFields(user.id) const projects = await getProjects(user.id) + const incompleteFields = incompleteTransactionFields(fields, transaction) return (
- -
+ + {incompleteFields.length > 0 && ( +
+ + Some fields are incomplete: {incompleteFields.map((field) => field.name).join(", ")} + + + You can decide which fields are required for you in{" "} + + Fields settings + + . + +
+ )} +

Transactions - +

+
+ )}
)}
) } - -async function getCurrencyRate(currencyCodeFrom: string, currencyCodeTo: string, date: Date): Promise { - const formattedDate = format(date, "yyyy-MM-dd") - const response = await fetch(`/api/currency?from=${currencyCodeFrom}&to=${currencyCodeTo}&date=${formattedDate}`) - - if (!response.ok) { - const errorData = await response.json() - console.log("Currency API error:", errorData.error) - throw new Error(errorData.error || "Failed to fetch currency rate") - } - - const data = await response.json() - return data.rate -} diff --git a/components/forms/simple.tsx b/components/forms/simple.tsx index 4556e78..b6a402b 100644 --- a/components/forms/simple.tsx +++ b/components/forms/simple.tsx @@ -29,7 +29,11 @@ export function FormInput({ title, hideIfEmpty = false, isRequired = false, ...p return ( ) } @@ -70,6 +74,7 @@ export function FormTextarea({ title, hideIfEmpty = false, isRequired = false, . ref={textareaRef} {...props} className={cn("bg-background", isRequired && isEmpty && "bg-yellow-50", props.className)} + data-1p-ignore /> ) diff --git a/components/transactions/edit.tsx b/components/transactions/edit.tsx index 8e40d75..c169031 100644 --- a/components/transactions/edit.tsx +++ b/components/transactions/edit.tsx @@ -136,30 +136,6 @@ export default function TransactionEditForm({ />
- {formData.currencyCode !== settings.default_currency || formData.convertedTotal !== 0 ? ( -
- - {(!formData.convertedCurrencyCode || formData.convertedCurrencyCode !== settings.default_currency) && ( - - )} -
- ) : ( - <> - )} -
+ {formData.currencyCode !== settings.default_currency || formData.convertedTotal !== 0 ? ( + <> + + {(!formData.convertedCurrencyCode || formData.convertedCurrencyCode !== settings.default_currency) && ( + + )} + + ) : ( + <> + )}
@@ -195,16 +195,20 @@ export default function TransactionEditForm({ className="h-24" isRequired={fieldMap.note.isRequired} /> - {extraFields.map((field) => ( - - ))} + +
+ {extraFields.map((field) => ( + + ))} +
@@ -53,10 +53,9 @@ export function ColumnSelector({ fields, onChange }: { fields: Field[]; onChange key={field.code} checked={field.isVisibleInList} onCheckedChange={() => handleToggle(field.code, field.isVisibleInList)} - disabled={isLoading[field.code]} + disabled={isLoading} > {field.name} - {isLoading[field.code] && Saving...} ))} diff --git a/components/transactions/list.tsx b/components/transactions/list.tsx index f558271..584e955 100644 --- a/components/transactions/list.tsx +++ b/components/transactions/list.tsx @@ -4,7 +4,7 @@ import { BulkActionsMenu } from "@/components/transactions/bulk-actions" import { Badge } from "@/components/ui/badge" import { Checkbox } from "@/components/ui/checkbox" import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@/components/ui/table" -import { calcTotalPerCurrency } from "@/lib/stats" +import { calcTotalPerCurrency, isTransactionIncomplete } from "@/lib/stats" import { cn, formatCurrency } from "@/lib/utils" import { Category, Field, Project, Transaction } from "@/prisma/client" import { formatDate } from "date-fns" @@ -230,19 +230,6 @@ export function TransactionList({ transactions, fields = [] }: { transactions: T ) : null } - // Function to check if a transaction is incomplete - const isTransactionIncomplete = (transaction: Transaction): boolean => { - const requiredFields = fields.filter((field) => field.isRequired) - - return requiredFields.some((field) => { - const value = field.isExtra - ? (transaction.extra as Record)?.[field.code] - : transaction[field.code as keyof Transaction] - - return value === undefined || value === null || value === "" || value === 0 - }) - } - return (
@@ -271,7 +258,7 @@ export function TransactionList({ transactions, fields = [] }: { transactions: T {formData.total != 0 && formData.currencyCode && formData.currencyCode !== settings.default_currency && ( - + setFormData((prev) => ({ ...prev, convertedTotal: value }))} /> - + )}
diff --git a/lib/stats.ts b/lib/stats.ts index fa0062b..74ed6d6 100644 --- a/lib/stats.ts +++ b/lib/stats.ts @@ -1,4 +1,4 @@ -import { Transaction } from "@/prisma/client" +import { Field, Transaction } from "@/prisma/client" export function calcTotalPerCurrency(transactions: Transaction[]): Record { return transactions.reduce( @@ -15,3 +15,21 @@ export function calcTotalPerCurrency(transactions: Transaction[]): Record ) } + +export const isTransactionIncomplete = (fields: Field[], transaction: Transaction): boolean => { + const incompleteFields = incompleteTransactionFields(fields, transaction) + + return incompleteFields.length > 0 +} + +export const incompleteTransactionFields = (fields: Field[], transaction: Transaction): Field[] => { + const requiredFields = fields.filter((field) => field.isRequired) + + return requiredFields.filter((field) => { + const value = field.isExtra + ? (transaction.extra as Record)?.[field.code] + : transaction[field.code as keyof Transaction] + + return value === undefined || value === null || value === "" + }) +} diff --git a/models/transactions.ts b/models/transactions.ts index 6e2f72c..f57d8f2 100644 --- a/models/transactions.ts +++ b/models/transactions.ts @@ -38,11 +38,11 @@ export const getTransactions = cache( if (filters) { if (filters.search) { where.OR = [ - { name: { contains: filters.search } }, - { merchant: { contains: filters.search } }, - { description: { contains: filters.search } }, - { note: { contains: filters.search } }, - { text: { contains: filters.search } }, + { name: { contains: filters.search, mode: 'insensitive' } }, + { merchant: { contains: filters.search, mode: 'insensitive' } }, + { description: { contains: filters.search, mode: 'insensitive' } }, + { note: { contains: filters.search, mode: 'insensitive' } }, + { text: { contains: filters.search, mode: 'insensitive' } }, ] }