diff --git a/app/(app)/dashboard/page.tsx b/app/(app)/dashboard/page.tsx index 80267b3..3e9b91a 100644 --- a/app/(app)/dashboard/page.tsx +++ b/app/(app)/dashboard/page.tsx @@ -4,7 +4,7 @@ import DashboardUnsortedWidget from "@/components/dashboard/unsorted-widget" import { WelcomeWidget } from "@/components/dashboard/welcome-widget" import { Separator } from "@/components/ui/separator" import { getCurrentUser } from "@/lib/auth" -import { APP_DESCRIPTION } from "@/lib/constants" +import config from "@/lib/config" import { getUnsortedFiles } from "@/models/files" import { getSettings } from "@/models/settings" import { TransactionFilters } from "@/models/transactions" @@ -12,7 +12,7 @@ import { Metadata } from "next" export const metadata: Metadata = { title: "Dashboard", - description: APP_DESCRIPTION, + description: config.app.description, } export default async function Dashboard({ searchParams }: { searchParams: Promise }) { diff --git a/app/(app)/layout.tsx b/app/(app)/layout.tsx index e927e64..a1c3b7f 100644 --- a/app/(app)/layout.tsx +++ b/app/(app)/layout.tsx @@ -4,7 +4,7 @@ import { AppSidebar } from "@/components/sidebar/sidebar" import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar" import { Toaster } from "@/components/ui/sonner" import { getCurrentUser } from "@/lib/auth" -import { APP_DESCRIPTION, APP_TITLE } from "@/lib/constants" +import config from "@/lib/config" import { getUnsortedFilesCount } from "@/models/files" import type { Metadata, Viewport } from "next" import "../globals.css" @@ -13,9 +13,9 @@ import { NotificationProvider } from "./context" export const metadata: Metadata = { title: { template: "%s | TaxHacker", - default: APP_TITLE, + default: config.app.title, }, - description: APP_DESCRIPTION, + description: config.app.description, icons: { icon: "/favicon.ico", shortcut: "/favicon.ico", @@ -38,13 +38,14 @@ export default async function RootLayout({ children }: { children: React.ReactNo {children} diff --git a/app/(app)/settings/llm/page.tsx b/app/(app)/settings/llm/page.tsx index eee2ee3..7e03191 100644 --- a/app/(app)/settings/llm/page.tsx +++ b/app/(app)/settings/llm/page.tsx @@ -1,5 +1,6 @@ import LLMSettingsForm from "@/components/settings/llm-settings-form" import { getCurrentUser } from "@/lib/auth" +import config from "@/lib/config" import { getFields } from "@/models/fields" import { getSettings } from "@/models/settings" @@ -11,7 +12,7 @@ export default async function LlmSettingsPage() { return ( <>
- +
) diff --git a/app/(app)/unsorted/actions.ts b/app/(app)/unsorted/actions.ts index 23a1d89..18c3b43 100644 --- a/app/(app)/unsorted/actions.ts +++ b/app/(app)/unsorted/actions.ts @@ -6,7 +6,7 @@ import { buildLLMPrompt } from "@/ai/prompt" import { fieldsToJsonSchema } from "@/ai/schema" import { transactionFormSchema } from "@/forms/transactions" import { getCurrentUser } from "@/lib/auth" -import { IS_SELF_HOSTED_MODE } from "@/lib/constants" +import config from "@/lib/config" import { getTransactionFileUploadPath, getUserUploadsDirectory } from "@/lib/files" import { DEFAULT_PROMPT_ANALYSE_NEW_FILE } from "@/models/defaults" import { deleteFile, getFileById, updateFile } from "@/models/files" @@ -50,7 +50,7 @@ export async function analyzeFileAction( prompt, schema, attachments, - IS_SELF_HOSTED_MODE ? settings.openai_api_key : process.env.OPENAI_API_KEY || "" + config.selfHosted.isEnabled ? settings.openai_api_key : process.env.OPENAI_API_KEY || "" ) console.log("Analysis results:", results) diff --git a/app/(app)/unsorted/page.tsx b/app/(app)/unsorted/page.tsx index 53e4aa1..b796733 100644 --- a/app/(app)/unsorted/page.tsx +++ b/app/(app)/unsorted/page.tsx @@ -5,7 +5,7 @@ import { Button } from "@/components/ui/button" import { Card } from "@/components/ui/card" import AnalyzeForm from "@/components/unsorted/analyze-form" import { getCurrentUser } from "@/lib/auth" -import { IS_SELF_HOSTED_MODE } from "@/lib/constants" +import config from "@/lib/config" import { getCategories } from "@/models/categories" import { getCurrencies } from "@/models/currencies" import { getFields } from "@/models/fields" @@ -36,7 +36,7 @@ export default async function UnsortedPage() {

You have {files.length} unsorted files

- {IS_SELF_HOSTED_MODE && !settings.openai_api_key && ( + {config.selfHosted.isEnabled && !settings.openai_api_key && (
diff --git a/app/(auth)/enter/page.tsx b/app/(auth)/enter/page.tsx index eb2e8e4..821b5c9 100644 --- a/app/(auth)/enter/page.tsx +++ b/app/(auth)/enter/page.tsx @@ -1,12 +1,12 @@ import { LoginForm } from "@/components/auth/login-form" import { Card, CardContent, CardTitle } from "@/components/ui/card" import { ColoredText } from "@/components/ui/colored-text" -import { IS_SELF_HOSTED_MODE, SELF_HOSTED_REDIRECT_URL } from "@/lib/constants" +import config from "@/lib/config" import { redirect } from "next/navigation" export default async function LoginPage() { - if (IS_SELF_HOSTED_MODE) { - redirect(SELF_HOSTED_REDIRECT_URL) + if (config.selfHosted.isEnabled) { + redirect(config.selfHosted.redirectUrl) } return ( diff --git a/app/(auth)/self-hosted/page.tsx b/app/(auth)/self-hosted/page.tsx index fad9a7d..d019da5 100644 --- a/app/(auth)/self-hosted/page.tsx +++ b/app/(auth)/self-hosted/page.tsx @@ -3,7 +3,7 @@ import { FormInput } from "@/components/forms/simple" import { Button } from "@/components/ui/button" import { Card, CardDescription, CardTitle } from "@/components/ui/card" import { ColoredText } from "@/components/ui/colored-text" -import { IS_SELF_HOSTED_MODE, SELF_HOSTED_REDIRECT_URL } from "@/lib/constants" +import config from "@/lib/config" import { DEFAULT_CURRENCIES, DEFAULT_SETTINGS } from "@/models/defaults" import { getSelfHostedUser } from "@/models/users" import { ShieldAlert } from "lucide-react" @@ -11,7 +11,7 @@ import { redirect } from "next/navigation" import { selfHostedGetStartedAction } from "../actions" export default async function SelfHostedWelcomePage() { - if (!IS_SELF_HOSTED_MODE) { + if (!config.selfHosted.isEnabled) { return ( @@ -31,7 +31,7 @@ export default async function SelfHostedWelcomePage() { const user = await getSelfHostedUser() if (user) { - redirect(SELF_HOSTED_REDIRECT_URL) + redirect(config.selfHosted.redirectUrl) } return ( diff --git a/app/(auth)/self-hosted/redirect/route.ts b/app/(auth)/self-hosted/redirect/route.ts index b19254e..671c281 100644 --- a/app/(auth)/self-hosted/redirect/route.ts +++ b/app/(auth)/self-hosted/redirect/route.ts @@ -1,17 +1,17 @@ -import { AUTH_LOGIN_URL, IS_SELF_HOSTED_MODE, SELF_HOSTED_WELCOME_URL } from "@/lib/constants" +import config from "@/lib/config" import { createUserDefaults, isDatabaseEmpty } from "@/models/defaults" import { getSelfHostedUser } from "@/models/users" import { revalidatePath } from "next/cache" import { redirect } from "next/navigation" export async function GET(request: Request) { - if (!IS_SELF_HOSTED_MODE) { - redirect(AUTH_LOGIN_URL) + if (!config.selfHosted.isEnabled) { + redirect(config.auth.loginUrl) } const user = await getSelfHostedUser() if (!user) { - redirect(SELF_HOSTED_WELCOME_URL) + redirect(config.selfHosted.welcomeUrl) } if (await isDatabaseEmpty(user.id)) { diff --git a/app/(auth)/signup/page.tsx b/app/(auth)/signup/page.tsx index 4c1b1f3..b1d0e6b 100644 --- a/app/(auth)/signup/page.tsx +++ b/app/(auth)/signup/page.tsx @@ -1,11 +1,12 @@ +import SignupForm from "@/components/auth/signup-form" import { Card, CardContent, CardTitle } from "@/components/ui/card" import { ColoredText } from "@/components/ui/colored-text" -import { IS_SELF_HOSTED_MODE, SELF_HOSTED_REDIRECT_URL } from "@/lib/constants" +import config from "@/lib/config" import { redirect } from "next/navigation" export default async function LoginPage() { - if (IS_SELF_HOSTED_MODE) { - redirect(SELF_HOSTED_REDIRECT_URL) + if (config.selfHosted.isEnabled) { + redirect(config.selfHosted.redirectUrl) } return ( @@ -15,10 +16,13 @@ export default async function LoginPage() { TaxHacker: Cloud Edition -
- Creating new account is disabled for now. Please use the self-hosted version. -
- {/* */} + {config.auth.disableSignup ? ( +
+ Creating new account is disabled for now. Please use the self-hosted version. +
+ ) : ( + + )}
) diff --git a/app/landing/actions.ts b/app/landing/actions.ts index 9f649fe..2be5d7a 100644 --- a/app/landing/actions.ts +++ b/app/landing/actions.ts @@ -1,5 +1,6 @@ "use server" +import config from "@/lib/config" import { resend, sendNewsletterWelcomeEmail } from "@/lib/email" export async function subscribeToNewsletterAction(email: string) { @@ -9,7 +10,7 @@ export async function subscribeToNewsletterAction(email: string) { } const existingContacts = await resend.contacts.list({ - audienceId: process.env.RESEND_AUDIENCE_ID as string, + audienceId: config.email.audienceId, }) if (existingContacts.data) { @@ -22,7 +23,7 @@ export async function subscribeToNewsletterAction(email: string) { await resend.contacts.create({ email, - audienceId: process.env.RESEND_AUDIENCE_ID as string, + audienceId: config.email.audienceId, unsubscribed: false, }) diff --git a/app/layout.tsx b/app/layout.tsx index 561efae..14eff72 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,13 +1,13 @@ +import config from "@/lib/config" import type { Metadata, Viewport } from "next" import "./globals.css" -import { APP_DESCRIPTION, APP_TITLE } from "@/lib/constants" export const metadata: Metadata = { title: { template: "%s | TaxHacker", - default: APP_TITLE, + default: config.app.title, }, - description: APP_DESCRIPTION, + description: config.app.description, icons: { icon: "/favicon.ico", shortcut: "/favicon.ico", diff --git a/app/page.tsx b/app/page.tsx index 2efda84..a072dd1 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,13 +1,13 @@ import LandingPage from "@/app/landing/landing" import { getSession } from "@/lib/auth" -import { IS_SELF_HOSTED_MODE, SELF_HOSTED_REDIRECT_URL } from "@/lib/constants" +import config from "@/lib/config" import { redirect } from "next/navigation" export default async function Home() { const session = await getSession() if (!session) { - if (IS_SELF_HOSTED_MODE) { - redirect(SELF_HOSTED_REDIRECT_URL) + if (config.selfHosted.isEnabled) { + redirect(config.selfHosted.redirectUrl) } return } diff --git a/components/dashboard/drop-zone-widget.tsx b/components/dashboard/drop-zone-widget.tsx index 92c8e3a..f67d815 100644 --- a/components/dashboard/drop-zone-widget.tsx +++ b/components/dashboard/drop-zone-widget.tsx @@ -3,7 +3,7 @@ import { useNotification } from "@/app/(app)/context" import { uploadFilesAction } from "@/app/(app)/files/actions" import { FormError } from "@/components/forms/error" -import { FILE_ACCEPTED_MIMETYPES } from "@/lib/constants" +import config from "@/lib/config" import { Camera, Loader2 } from "lucide-react" import { useRouter } from "next/navigation" import { startTransition, useState } from "react" @@ -48,7 +48,7 @@ export default function DashboardDropZoneWidget() { id="fileInput" className="hidden" multiple - accept={FILE_ACCEPTED_MIMETYPES} + accept={config.upload.acceptedMimeTypes} onChange={handleFileChange} />
diff --git a/components/files/upload-button.tsx b/components/files/upload-button.tsx index d6e7417..e9d7a78 100644 --- a/components/files/upload-button.tsx +++ b/components/files/upload-button.tsx @@ -3,7 +3,7 @@ import { useNotification } from "@/app/(app)/context" import { uploadFilesAction } from "@/app/(app)/files/actions" import { Button } from "@/components/ui/button" -import { FILE_ACCEPTED_MIMETYPES } from "@/lib/constants" +import config from "@/lib/config" import { Loader2 } from "lucide-react" import { useRouter } from "next/navigation" import { ComponentProps, startTransition, useRef, useState } from "react" @@ -54,7 +54,7 @@ export function UploadButton({ children, ...props }: { children: React.ReactNode id="fileInput" className="hidden" multiple - accept={FILE_ACCEPTED_MIMETYPES} + accept={config.upload.acceptedMimeTypes} onChange={handleFileChange} /> diff --git a/components/settings/llm-settings-form.tsx b/components/settings/llm-settings-form.tsx index 0f42272..466b2ea 100644 --- a/components/settings/llm-settings-form.tsx +++ b/components/settings/llm-settings-form.tsx @@ -6,29 +6,40 @@ import { FormError } from "@/components/forms/error" import { FormInput, FormTextarea } from "@/components/forms/simple" import { Button } from "@/components/ui/button" import { Card, CardTitle } from "@/components/ui/card" -import { IS_SELF_HOSTED_MODE } from "@/lib/constants" import { Field } from "@prisma/client" import { CircleCheckBig, Edit } from "lucide-react" import Link from "next/link" import { useActionState } from "react" -export default function LLMSettingsForm({ settings, fields }: { settings: Record; fields: Field[] }) { +export default function LLMSettingsForm({ + settings, + fields, + showApiKey = true, +}: { + settings: Record + fields: Field[] + showApiKey?: boolean +}) { const [saveState, saveAction, pending] = useActionState(saveSettingsAction, null) return ( <>
- {IS_SELF_HOSTED_MODE && ( - - )} + {showApiKey && ( + <> + - {IS_SELF_HOSTED_MODE && ( - - Get your API key from{" "} - - OpenAI Platform Console - - + + Get your API key from{" "} + + OpenAI Platform Console + + + )} AI - {APP_TITLE} + {config.app.title} { await authClient.signOut({}) redirect("/") @@ -61,14 +60,16 @@ export default function SidebarUser({ profile }: { profile: UserProfile }) { */} - - {!IS_SELF_HOSTED_MODE && ( - - - - Log out - - + {!isSelfHosted && ( + <> + + + + + Log out + + + )} diff --git a/components/sidebar/sidebar.tsx b/components/sidebar/sidebar.tsx index 8c094d1..71a318d 100644 --- a/components/sidebar/sidebar.tsx +++ b/components/sidebar/sidebar.tsx @@ -17,7 +17,7 @@ import { useSidebar, } from "@/components/ui/sidebar" import { UserProfile } from "@/lib/auth" -import { APP_TITLE, IS_SELF_HOSTED_MODE } from "@/lib/constants" +import config from "@/lib/config" import { ClockArrowUp, FileText, Import, LayoutDashboard, Settings, Sparkles, Upload } from "lucide-react" import Image from "next/image" import Link from "next/link" @@ -28,7 +28,15 @@ import { Blinker } from "./blinker" import { SidebarMenuItemWithHighlight } from "./sidebar-item" import SidebarUser from "./sidebar-user" -export function AppSidebar({ unsortedFilesCount, profile }: { unsortedFilesCount: number; profile: UserProfile }) { +export function AppSidebar({ + profile, + unsortedFilesCount, + isSelfHosted, +}: { + profile: UserProfile + unsortedFilesCount: number + isSelfHosted: boolean +}) { const { open, setOpenMobile } = useSidebar() const pathname = usePathname() const { notification } = useNotification() @@ -46,7 +54,7 @@ export function AppSidebar({ unsortedFilesCount, profile }: { unsortedFilesCount Logo
- {APP_TITLE} + {config.app.title}
@@ -124,7 +132,7 @@ export function AppSidebar({ unsortedFilesCount, profile }: { unsortedFilesCount - {IS_SELF_HOSTED_MODE && ( + {isSelfHosted && ( @@ -146,7 +154,7 @@ export function AppSidebar({ unsortedFilesCount, profile }: { unsortedFilesCount - + diff --git a/components/transactions/transaction-files.tsx b/components/transactions/transaction-files.tsx index 2d91230..6ad52b9 100644 --- a/components/transactions/transaction-files.tsx +++ b/components/transactions/transaction-files.tsx @@ -4,7 +4,7 @@ import { deleteTransactionFileAction, uploadTransactionFilesAction } from "@/app import { FilePreview } from "@/components/files/preview" import { Button } from "@/components/ui/button" import { Card } from "@/components/ui/card" -import { FILE_ACCEPTED_MIMETYPES } from "@/lib/constants" +import config from "@/lib/config" import { File, Transaction } from "@prisma/client" import { Loader2, Upload, X } from "lucide-react" import { useState } from "react" @@ -72,7 +72,7 @@ export default function TransactionFiles({ transaction, files }: { transaction: name="file" className="absolute inset-0 top-0 left-0 w-full h-full opacity-0" onChange={handleFileChange} - accept={FILE_ACCEPTED_MIMETYPES} + accept={config.upload.acceptedMimeTypes} /> diff --git a/lib/auth.ts b/lib/auth.ts index 335b248..352f883 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -1,6 +1,6 @@ -import { AUTH_LOGIN_URL, IS_SELF_HOSTED_MODE, SELF_HOSTED_REDIRECT_URL } from "@/lib/constants" +import config from "@/lib/config" import { createUserDefaults } from "@/models/defaults" -import { getSelfHostedUser, getUserByEmail } from "@/models/users" +import { getSelfHostedUser } from "@/models/users" import { User } from "@prisma/client" import { betterAuth } from "better-auth" import { prismaAdapter } from "better-auth/adapters/prisma" @@ -22,7 +22,7 @@ export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: "postgresql" }), email: { provider: "resend", - from: process.env.RESEND_FROM_EMAIL!, + from: config.email.from, resend, }, session: { @@ -49,14 +49,10 @@ export const auth = betterAuth({ }, plugins: [ emailOTP({ - disableSignUp: true, + disableSignUp: config.auth.disableSignup, otpLength: 6, expiresIn: 10 * 60, // 10 minutes sendVerificationOTP: async ({ email, otp }) => { - const user = await getUserByEmail(email as string) - if (!user) { - throw new Error("User with this email does not exist") - } await sendOTPCodeEmail({ email, otp }) }, }), @@ -65,7 +61,7 @@ export const auth = betterAuth({ }) export async function getSession() { - if (IS_SELF_HOSTED_MODE) { + if (config.selfHosted.isEnabled) { const user = await getSelfHostedUser() return user ? { user } : null } @@ -78,10 +74,10 @@ export async function getSession() { export async function getCurrentUser(): Promise { const session = await getSession() if (!session || !session.user) { - if (IS_SELF_HOSTED_MODE) { - redirect(SELF_HOSTED_REDIRECT_URL) + if (config.selfHosted.isEnabled) { + redirect(config.selfHosted.redirectUrl) } else { - redirect(AUTH_LOGIN_URL) + redirect(config.auth.loginUrl) } } return session.user as User diff --git a/lib/config.ts b/lib/config.ts new file mode 100644 index 0000000..8e5f199 --- /dev/null +++ b/lib/config.ts @@ -0,0 +1,26 @@ +const config = { + app: { + title: "TaxHacker", + description: "Your personal AI accountant", + version: process.env.npm_package_version || "0.0.1", + }, + upload: { + acceptedMimeTypes: "image/*,.pdf,.doc,.docx,.xls,.xlsx", + }, + selfHosted: { + isEnabled: process.env.SELF_HOSTED_MODE === "true", + redirectUrl: "/self-hosted/redirect", + welcomeUrl: "/self-hosted", + }, + auth: { + loginUrl: "/enter", + disableSignup: process.env.DISABLE_SIGNUP === "true" || process.env.SELF_HOSTED_MODE === "true", + }, + email: { + apiKey: process.env.RESEND_API_KEY || "", + from: process.env.RESEND_FROM_EMAIL || "", + audienceId: process.env.RESEND_AUDIENCE_ID || "", + }, +} + +export default config diff --git a/lib/constants.ts b/lib/constants.ts deleted file mode 100644 index 091cad3..0000000 --- a/lib/constants.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const APP_TITLE = "TaxHacker" -export const APP_DESCRIPTION = "Your personal AI accountant" -export const FILE_ACCEPTED_MIMETYPES = "image/*,.pdf,.doc,.docx,.xls,.xlsx" -export const IS_SELF_HOSTED_MODE = process.env.SELF_HOSTED_MODE === "true" -export const SELF_HOSTED_REDIRECT_URL = "/self-hosted/redirect" -export const SELF_HOSTED_WELCOME_URL = "/self-hosted" -export const AUTH_LOGIN_URL = "/enter" diff --git a/lib/currency-scraper.ts b/lib/currency-scraper.ts index e609f9d..4b2712a 100644 --- a/lib/currency-scraper.ts +++ b/lib/currency-scraper.ts @@ -27,9 +27,6 @@ export async function getCurrencyRate(currencyCodeFrom: string, currencyCodeTo: export async function fetchHistoricalCurrencyRates(currency: string = "USD", date: Date): Promise { const formattedDate = format(date, "yyyy-MM-dd") - console.log("DATE", formattedDate) - console.log("QUERY", encodeURIComponent(`https://www.xe.com/currencytables/?from=${currency}&date=${formattedDate}`)) - const url = `https://corsproxy.io/?url=${encodeURIComponent( `https://www.xe.com/currencytables/?from=${currency}&date=${formattedDate}` )}` diff --git a/lib/email.ts b/lib/email.ts index 2fac423..38ce551 100644 --- a/lib/email.ts +++ b/lib/email.ts @@ -2,14 +2,15 @@ import { NewsletterWelcomeEmail } from "@/components/emails/newsletter-welcome-e import { OTPEmail } from "@/components/emails/otp-email" import React from "react" import { Resend } from "resend" +import config from "./config" -export const resend = new Resend(process.env.RESEND_API_KEY) +export const resend = new Resend(config.email.apiKey) export async function sendOTPCodeEmail({ email, otp }: { email: string; otp: string }) { const html = React.createElement(OTPEmail, { otp }) return await resend.emails.send({ - from: process.env.RESEND_FROM_EMAIL!, + from: config.email.from, to: email, subject: "Your TaxHacker verification code", react: html, @@ -20,7 +21,7 @@ export async function sendNewsletterWelcomeEmail(email: string) { const html = React.createElement(NewsletterWelcomeEmail) return await resend.emails.send({ - from: process.env.RESEND_FROM_EMAIL as string, + from: config.email.from, to: email, subject: "Welcome to TaxHacker Newsletter!", react: html, diff --git a/middleware.ts b/middleware.ts index 0877f23..1bfee86 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1,15 +1,15 @@ +import { default as globalConfig } from "@/lib/config" import { getSessionCookie } from "better-auth/cookies" import { NextRequest, NextResponse } from "next/server" -import { AUTH_LOGIN_URL, IS_SELF_HOSTED_MODE } from "./lib/constants" export default async function middleware(request: NextRequest) { - if (IS_SELF_HOSTED_MODE) { + if (globalConfig.selfHosted.isEnabled) { return NextResponse.next() } const sessionCookie = getSessionCookie(request, { cookiePrefix: "taxhacker" }) if (!sessionCookie) { - return NextResponse.redirect(new URL(AUTH_LOGIN_URL, request.url)) + return NextResponse.redirect(new URL(globalConfig.auth.loginUrl, request.url)) } return NextResponse.next() } diff --git a/models/backups.ts b/models/backups.ts index 5a7085c..48a9c73 100644 --- a/models/backups.ts +++ b/models/backups.ts @@ -3,8 +3,8 @@ import { prisma } from "@/lib/db" type BackupSetting = { filename: string model: any - recordToBackup: (userId: string, row: any) => Record - backupToRecord: (userId: string, json: Record) => any + backup: (userId: string, row: any) => Record + restore: (userId: string, json: Record) => any } // Ordering is important here @@ -12,7 +12,7 @@ export const MODEL_BACKUP: BackupSetting[] = [ { filename: "settings.json", model: prisma.setting, - recordToBackup: (userId: string, row: any) => { + backup: (userId: string, row: any) => { return { id: row.id, code: row.code, @@ -21,9 +21,8 @@ export const MODEL_BACKUP: BackupSetting[] = [ value: row.value, } }, - backupToRecord: (userId: string, json: any) => { + restore: (userId: string, json: any) => { return { - id: json.id, code: json.code, name: json.name, description: json.description, @@ -39,16 +38,15 @@ export const MODEL_BACKUP: BackupSetting[] = [ { filename: "currencies.json", model: prisma.currency, - recordToBackup: (userId: string, row: any) => { + backup: (userId: string, row: any) => { return { id: row.id, code: row.code, name: row.name, } }, - backupToRecord: (userId: string, json: any) => { + restore: (userId: string, json: any) => { return { - id: json.id, code: json.code, name: json.name, user: { @@ -62,7 +60,7 @@ export const MODEL_BACKUP: BackupSetting[] = [ { filename: "categories.json", model: prisma.category, - recordToBackup: (userId: string, row: any) => { + backup: (userId: string, row: any) => { return { id: row.id, code: row.code, @@ -72,9 +70,8 @@ export const MODEL_BACKUP: BackupSetting[] = [ createdAt: row.createdAt, } }, - backupToRecord: (userId: string, json: any) => { + restore: (userId: string, json: any) => { return { - id: json.id, code: json.code, name: json.name, color: json.color, @@ -91,7 +88,7 @@ export const MODEL_BACKUP: BackupSetting[] = [ { filename: "projects.json", model: prisma.project, - recordToBackup: (userId: string, row: any) => { + backup: (userId: string, row: any) => { return { id: row.id, code: row.code, @@ -101,9 +98,8 @@ export const MODEL_BACKUP: BackupSetting[] = [ createdAt: row.createdAt, } }, - backupToRecord: (userId: string, json: any) => { + restore: (userId: string, json: any) => { return { - id: json.id, code: json.code, name: json.name, color: json.color, @@ -120,7 +116,7 @@ export const MODEL_BACKUP: BackupSetting[] = [ { filename: "fields.json", model: prisma.field, - recordToBackup: (userId: string, row: any) => { + backup: (userId: string, row: any) => { return { id: row.id, code: row.code, @@ -134,9 +130,8 @@ export const MODEL_BACKUP: BackupSetting[] = [ isExtra: row.isExtra, } }, - backupToRecord: (userId: string, json: any) => { + restore: (userId: string, json: any) => { return { - id: json.id, code: json.code, name: json.name, type: json.type, @@ -157,7 +152,7 @@ export const MODEL_BACKUP: BackupSetting[] = [ { filename: "files.json", model: prisma.file, - recordToBackup: (userId: string, row: any) => { + backup: (userId: string, row: any) => { return { id: row.id, filename: row.filename, @@ -168,7 +163,7 @@ export const MODEL_BACKUP: BackupSetting[] = [ createdAt: row.createdAt, } }, - backupToRecord: (userId: string, json: any) => { + restore: (userId: string, json: any) => { return { id: json.id, filename: json.filename, @@ -187,7 +182,7 @@ export const MODEL_BACKUP: BackupSetting[] = [ { filename: "transactions.json", model: prisma.transaction, - recordToBackup: (userId: string, row: any) => { + backup: (userId: string, row: any) => { return { id: row.id, name: row.name, @@ -209,7 +204,7 @@ export const MODEL_BACKUP: BackupSetting[] = [ text: row.text, } }, - backupToRecord: (userId: string, json: any) => { + restore: (userId: string, json: any) => { return { id: json.id, name: json.name, @@ -244,21 +239,25 @@ export const MODEL_BACKUP: BackupSetting[] = [ }, ] -export async function modelToJSON(userId: string, backup: BackupSetting): Promise { - const data = await backup.model.findMany({ where: { userId } }) +export async function modelToJSON(userId: string, backupSettings: BackupSetting): Promise { + const data = await backupSettings.model.findMany({ where: { userId } }) if (!data || data.length === 0) { return "[]" } return JSON.stringify( - data.map((row: any) => backup.recordToBackup(userId, row)), + data.map((row: any) => backupSettings.backup(userId, row)), null, 2 ) } -export async function modelFromJSON(userId: string, backup: BackupSetting, jsonContent: string): Promise { +export async function modelFromJSON( + userId: string, + backupSettings: BackupSetting, + jsonContent: string +): Promise { if (!jsonContent) return 0 try { @@ -273,8 +272,8 @@ export async function modelFromJSON(userId: string, backup: BackupSetting, jsonC const record = preprocessRowData(rawRecord) try { - const data = await backup.backupToRecord(userId, record) - await backup.model.create({ data }) + const data = await backupSettings.restore(userId, record) + await backupSettings.model.create({ data }) } catch (error) { console.error(`Error importing record:`, error) }