mirror of
https://github.com/marcogll/TaxHacker_s23.git
synced 2026-01-13 13:25:18 +00:00
fix: currency converter and auth apis
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { getSession } from "@/lib/auth"
|
import { getSession } from "@/lib/auth"
|
||||||
import { PoorManCache } from "@/lib/cache"
|
import { PoorManCache } from "@/lib/cache"
|
||||||
import { format } from "date-fns"
|
import { format, isSameDay, subDays } from "date-fns"
|
||||||
import { NextRequest, NextResponse } from "next/server"
|
import { NextRequest, NextResponse } from "next/server"
|
||||||
|
|
||||||
type HistoricRate = {
|
type HistoricRate = {
|
||||||
@@ -36,11 +36,17 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json({ error: "Missing required parameters: from, to, date" }, { status: 400 })
|
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())) {
|
if (isNaN(date.getTime())) {
|
||||||
return NextResponse.json({ error: "Invalid date format" }, { status: 400 })
|
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")
|
const formattedDate = format(date, "yyyy-MM-dd")
|
||||||
|
|
||||||
// Check cache first
|
// Check cache first
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import { FormError } from "@/components/forms/error"
|
||||||
import { formatCurrency } from "@/lib/utils"
|
import { formatCurrency } from "@/lib/utils"
|
||||||
import { format, startOfDay } from "date-fns"
|
import { format, startOfDay } from "date-fns"
|
||||||
import { Loader2 } from "lucide-react"
|
import { Loader2 } from "lucide-react"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
export const FormConvertCurrency = ({
|
export const FormConvertCurrency = ({
|
||||||
originalTotal,
|
originalTotal,
|
||||||
originalCurrencyCode,
|
originalCurrencyCode,
|
||||||
@@ -25,18 +25,23 @@ export const FormConvertCurrency = ({
|
|||||||
const [exchangeRate, setExchangeRate] = useState(0)
|
const [exchangeRate, setExchangeRate] = useState(0)
|
||||||
const [convertedTotal, setConvertedTotal] = useState(0)
|
const [convertedTotal, setConvertedTotal] = useState(0)
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
setError(null)
|
||||||
|
|
||||||
const exchangeRate = await getCurrencyRate(originalCurrencyCode, targetCurrencyCode, normalizedDate)
|
const exchangeRate = await getCurrencyRate(originalCurrencyCode, targetCurrencyCode, normalizedDate)
|
||||||
|
|
||||||
setExchangeRate(exchangeRate)
|
setExchangeRate(exchangeRate)
|
||||||
setConvertedTotal(Math.round(originalTotal * exchangeRate * 100) / 100)
|
setConvertedTotal(Math.round(originalTotal * exchangeRate * 100) / 100)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching currency rates:", error)
|
console.error("Error fetching currency rates:", error)
|
||||||
setExchangeRate(0)
|
setExchangeRate(0)
|
||||||
setConvertedTotal(0)
|
setConvertedTotal(0)
|
||||||
|
setError(error instanceof Error ? error.message : "Failed to fetch currency rate")
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
@@ -74,7 +79,10 @@ export const FormConvertCurrency = ({
|
|||||||
className="w-32 rounded-md border border-input px-2 py-1"
|
className="w-32 rounded-md border border-input px-2 py-1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{!error && (
|
||||||
<div className="text-xs text-muted-foreground">The exchange rate will be added to the transaction</div>
|
<div className="text-xs text-muted-foreground">The exchange rate will be added to the transaction</div>
|
||||||
|
)}
|
||||||
|
{error && <FormError className="mt-0 text-sm">{error}</FormError>}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -82,20 +90,15 @@ export const FormConvertCurrency = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getCurrencyRate(currencyCodeFrom: string, currencyCodeTo: string, date: Date): Promise<number> {
|
async function getCurrencyRate(currencyCodeFrom: string, currencyCodeTo: string, date: Date): Promise<number> {
|
||||||
try {
|
|
||||||
const formattedDate = format(date, "yyyy-MM-dd")
|
const formattedDate = format(date, "yyyy-MM-dd")
|
||||||
const response = await fetch(`/api/currency?from=${currencyCodeFrom}&to=${currencyCodeTo}&date=${formattedDate}`)
|
const response = await fetch(`/api/currency?from=${currencyCodeFrom}&to=${currencyCodeTo}&date=${formattedDate}`)
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response.json()
|
const errorData = await response.json()
|
||||||
console.error("Currency API error:", errorData.error)
|
console.log("Currency API error:", errorData.error)
|
||||||
return 0
|
throw new Error(errorData.error || "Failed to fetch currency rate")
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
return data.rate
|
return data.rate
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching currency rate:", error)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import config from "@/lib/config"
|
import config from "@/lib/config"
|
||||||
import { createUserDefaults } from "@/models/defaults"
|
import { createUserDefaults } from "@/models/defaults"
|
||||||
import { getSelfHostedUser } from "@/models/users"
|
import { getSelfHostedUser, getUserByEmail } from "@/models/users"
|
||||||
import { User } from "@prisma/client"
|
import { User } from "@prisma/client"
|
||||||
import { betterAuth } from "better-auth"
|
import { betterAuth } from "better-auth"
|
||||||
import { prismaAdapter } from "better-auth/adapters/prisma"
|
import { prismaAdapter } from "better-auth/adapters/prisma"
|
||||||
|
import { APIError } from "better-auth/api"
|
||||||
import { nextCookies } from "better-auth/next-js"
|
import { nextCookies } from "better-auth/next-js"
|
||||||
import { emailOTP } from "better-auth/plugins/email-otp"
|
import { emailOTP } from "better-auth/plugins/email-otp"
|
||||||
import { headers } from "next/headers"
|
import { headers } from "next/headers"
|
||||||
@@ -56,6 +57,10 @@ export const auth = betterAuth({
|
|||||||
otpLength: 6,
|
otpLength: 6,
|
||||||
expiresIn: 10 * 60, // 10 minutes
|
expiresIn: 10 * 60, // 10 minutes
|
||||||
sendVerificationOTP: async ({ email, otp }) => {
|
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 })
|
await sendOTPCodeEmail({ email, otp })
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user