diff --git a/app/api/currency/route.ts b/app/api/currency/route.ts index 91e7724..eb00d39 100644 --- a/app/api/currency/route.ts +++ b/app/api/currency/route.ts @@ -1,6 +1,6 @@ import { getSession } from "@/lib/auth" import { PoorManCache } from "@/lib/cache" -import { format } from "date-fns" +import { format, isSameDay, subDays } from "date-fns" import { NextRequest, NextResponse } from "next/server" type HistoricRate = { @@ -36,11 +36,17 @@ export async function GET(request: NextRequest) { return NextResponse.json({ error: "Missing required parameters: from, to, date" }, { status: 400 }) } - const date = new Date(dateParam) + let date = new Date(dateParam) + if (isNaN(date.getTime())) { return NextResponse.json({ error: "Invalid date format" }, { status: 400 }) } + // hack to get yesterday's rate if it's today + if (isSameDay(date, new Date())) { + date = subDays(date, 1) + } + const formattedDate = format(date, "yyyy-MM-dd") // Check cache first diff --git a/components/forms/convert-currency.tsx b/components/forms/convert-currency.tsx index 8b3fe71..2e3f4d5 100644 --- a/components/forms/convert-currency.tsx +++ b/components/forms/convert-currency.tsx @@ -1,8 +1,8 @@ +import { FormError } from "@/components/forms/error" import { formatCurrency } from "@/lib/utils" import { format, startOfDay } from "date-fns" import { Loader2 } from "lucide-react" import { useEffect, useState } from "react" - export const FormConvertCurrency = ({ originalTotal, originalCurrencyCode, @@ -25,18 +25,23 @@ export const FormConvertCurrency = ({ const [exchangeRate, setExchangeRate] = useState(0) const [convertedTotal, setConvertedTotal] = useState(0) const [isLoading, setIsLoading] = useState(false) + const [error, setError] = useState(null) useEffect(() => { const fetchData = async () => { try { setIsLoading(true) + setError(null) + const exchangeRate = await getCurrencyRate(originalCurrencyCode, targetCurrencyCode, normalizedDate) + setExchangeRate(exchangeRate) setConvertedTotal(Math.round(originalTotal * exchangeRate * 100) / 100) } catch (error) { console.error("Error fetching currency rates:", error) setExchangeRate(0) setConvertedTotal(0) + setError(error instanceof Error ? error.message : "Failed to fetch currency rate") } finally { setIsLoading(false) } @@ -74,7 +79,10 @@ export const FormConvertCurrency = ({ className="w-32 rounded-md border border-input px-2 py-1" /> -
The exchange rate will be added to the transaction
+ {!error && ( +
The exchange rate will be added to the transaction
+ )} + {error && {error}} )} @@ -82,20 +90,15 @@ export const FormConvertCurrency = ({ } async function getCurrencyRate(currencyCodeFrom: string, currencyCodeTo: string, date: Date): Promise { - try { - const formattedDate = format(date, "yyyy-MM-dd") - const response = await fetch(`/api/currency?from=${currencyCodeFrom}&to=${currencyCodeTo}&date=${formattedDate}`) + 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.error("Currency API error:", errorData.error) - return 0 - } - - const data = await response.json() - return data.rate - } catch (error) { - console.error("Error fetching currency rate:", error) - return 0 + 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/lib/auth.ts b/lib/auth.ts index 3ef62ab..fe753d1 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -1,9 +1,10 @@ import config from "@/lib/config" import { createUserDefaults } from "@/models/defaults" -import { getSelfHostedUser } from "@/models/users" +import { getSelfHostedUser, getUserByEmail } from "@/models/users" import { User } from "@prisma/client" import { betterAuth } from "better-auth" import { prismaAdapter } from "better-auth/adapters/prisma" +import { APIError } from "better-auth/api" import { nextCookies } from "better-auth/next-js" import { emailOTP } from "better-auth/plugins/email-otp" import { headers } from "next/headers" @@ -56,6 +57,10 @@ export const auth = betterAuth({ otpLength: 6, expiresIn: 10 * 60, // 10 minutes sendVerificationOTP: async ({ email, otp }) => { + const user = await getUserByEmail(email) + if (!user) { + throw new APIError("NOT_FOUND", { message: "User with this email does not exist" }) + } await sendOTPCodeEmail({ email, otp }) }, }),