From 0b2b377f7cbaa9727010ebd4b462d6bb259951ff Mon Sep 17 00:00:00 2001 From: v0 Date: Sat, 28 Jun 2025 16:50:48 +0000 Subject: [PATCH] refactor: convert project from TypeScript to JavaScript Remove type annotations and convert file extensions to JavaScript Co-authored-by: Tien Nguyen Minh <39063457+tiennm99@users.noreply.github.com> --- app/api/exchange/bidv/{route.ts => route.js} | 14 +- .../techcombank/{route.ts => route.js} | 4 +- app/{page.tsx => page.jsx} | 35 ++-- components/ui/select.jsx | 124 +++++++++++++++ components/ui/select.tsx | 33 ++-- components/ui/table.jsx | 57 +++++++ components/ui/table.tsx | 150 ++++++++++++------ 7 files changed, 323 insertions(+), 94 deletions(-) rename app/api/exchange/bidv/{route.ts => route.js} (86%) rename app/api/exchange/techcombank/{route.ts => route.js} (86%) rename app/{page.tsx => page.jsx} (93%) create mode 100644 components/ui/select.jsx create mode 100644 components/ui/table.jsx diff --git a/app/api/exchange/bidv/route.ts b/app/api/exchange/bidv/route.js similarity index 86% rename from app/api/exchange/bidv/route.ts rename to app/api/exchange/bidv/route.js index ea9094b..dced990 100644 --- a/app/api/exchange/bidv/route.ts +++ b/app/api/exchange/bidv/route.js @@ -1,16 +1,16 @@ -import { type NextRequest, NextResponse } from "next/server" +import { NextResponse } from "next/server" -async function safeFetch(bidvUrl: string, tries = 2) { +async function safeFetch(bidvUrl, tries = 2) { const headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125 Safari/537.36", Accept: "application/json, text/javascript, */*; q=0.01", Referer: "https://bidv.com.vn/", "X-Requested-With": "XMLHttpRequest", - } as const + } // 1️⃣ helper that really performs the fetch - const doFetch = (target: string) => + const doFetch = (target) => fetch(target, { headers, cache: "no-store", @@ -41,7 +41,7 @@ async function safeFetch(bidvUrl: string, tries = 2) { throw new Error("fetch failed") } -export async function GET(request: NextRequest) { +export async function GET(request) { const { searchParams } = new URL(request.url) const date = searchParams.get("date") @@ -69,7 +69,7 @@ export async function GET(request: NextRequest) { } // Step 2: Find the record with highest time value - const latestRecord = timeData.data.reduce((prev: any, current: any) => (current.time > prev.time ? current : prev)) + const latestRecord = timeData.data.reduce((prev, current) => (current.time > prev.time ? current : prev)) // Step 3: Get exchange rates using the namerecord const rateUrl = `https://bidv.com.vn/ServicesBIDV/ExchangeDetailServlet?date=${bidvDate}&time=${latestRecord.namerecord}` @@ -82,7 +82,7 @@ export async function GET(request: NextRequest) { const rateData = await rateRes.json() return NextResponse.json(rateData) } catch (error) { - console.error("BIDV API error:", (error as Error).message) + console.error("BIDV API error:", error.message) return NextResponse.json({ error: "Failed to fetch from BIDV" }, { status: 502 }) } } diff --git a/app/api/exchange/techcombank/route.ts b/app/api/exchange/techcombank/route.js similarity index 86% rename from app/api/exchange/techcombank/route.ts rename to app/api/exchange/techcombank/route.js index 0d7bf05..10853d7 100644 --- a/app/api/exchange/techcombank/route.ts +++ b/app/api/exchange/techcombank/route.js @@ -1,6 +1,6 @@ -import { type NextRequest, NextResponse } from "next/server" +import { NextResponse } from "next/server" -export async function GET(request: NextRequest) { +export async function GET(request) { const { searchParams } = new URL(request.url) const date = searchParams.get("date") diff --git a/app/page.tsx b/app/page.jsx similarity index 93% rename from app/page.tsx rename to app/page.jsx index 774d98b..60f2457 100644 --- a/app/page.tsx +++ b/app/page.jsx @@ -10,19 +10,6 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@ import { Download, Loader2 } from "lucide-react" import * as XLSX from "xlsx" -interface ExchangeRateData { - date: string - bank: string - currency: string - askRate: string - bidRateCK: string - bidRateTM: string - askRateTM: string - inputDate: string -} - -type BankType = "techcombank" | "bidv" - // Currency options for each bank const BANK_CURRENCIES = { techcombank: [ @@ -84,24 +71,24 @@ const getDefaultDates = () => { } export default function ExchangeRateExporter() { - const [bank, setBank] = useState("techcombank") + const [bank, setBank] = useState("techcombank") const [currency, setCurrency] = useState("USD (50,100)") const defaultDates = getDefaultDates() const [startDate, setStartDate] = useState(defaultDates.startDate) const [endDate, setEndDate] = useState(defaultDates.endDate) - const [data, setData] = useState([]) + const [data, setData] = useState([]) const [loading, setLoading] = useState(false) const [error, setError] = useState("") // Update currency when bank changes - const handleBankChange = (newBank: BankType) => { + const handleBankChange = (newBank) => { setBank(newBank) // Set default currency for the selected bank const defaultCurrency = newBank === "techcombank" ? "USD (50,100)" : "USD" setCurrency(defaultCurrency) } - const generateDateRange = (start: string, end: string): string[] => { + const generateDateRange = (start, end) => { const dates = [] const startDate = new Date(start) const endDate = new Date(end) @@ -113,7 +100,7 @@ export default function ExchangeRateExporter() { return dates } - const fetchTechcombankRate = async (date: string): Promise => { + const fetchTechcombankRate = async (date) => { try { const res = await fetch(`/api/exchange/techcombank?date=${date}`) if (!res.ok) { @@ -125,7 +112,7 @@ export default function ExchangeRateExporter() { } const result = await res.json() - const currencyData = result.exchangeRate?.data?.find((item: any) => item.label === currency) + const currencyData = result.exchangeRate?.data?.find((item) => item.label === currency) if (!currencyData) return null return { @@ -144,7 +131,7 @@ export default function ExchangeRateExporter() { } } - const fetchBIDVRate = async (date: string): Promise => { + const fetchBIDVRate = async (date) => { try { const res = await fetch(`/api/exchange/bidv?date=${date}`) if (!res.ok) { @@ -156,7 +143,7 @@ export default function ExchangeRateExporter() { } const result = await res.json() - const currencyData = result.data?.find((item: any) => item.currency === currency) + const currencyData = result.data?.find((item) => item.currency === currency) if (!currencyData) return null return { @@ -175,7 +162,7 @@ export default function ExchangeRateExporter() { } } - const fetchExchangeRate = async (date: string): Promise => { + const fetchExchangeRate = async (date) => { if (bank === "techcombank") { return fetchTechcombankRate(date) } else { @@ -200,7 +187,7 @@ export default function ExchangeRateExporter() { try { const dates = generateDateRange(startDate, endDate) - const results: ExchangeRateData[] = [] + const results = [] for (const date of dates) { const rateData = await fetchExchangeRate(date) @@ -293,7 +280,7 @@ export default function ExchangeRateExporter() { URL.revokeObjectURL(url) } - const formatNumber = (value: string) => { + const formatNumber = (value) => { if (value === "N/A" || !value || value === "-") return value // Remove commas and parse const numValue = Number.parseFloat(value.replace(/,/g, "")) diff --git a/components/ui/select.jsx b/components/ui/select.jsx new file mode 100644 index 0000000..fcc6779 --- /dev/null +++ b/components/ui/select.jsx @@ -0,0 +1,124 @@ +"use client" + +import * as React from "react" +import * as SelectPrimitive from "@radix-ui/react-select" +import { Check, ChevronDown, ChevronUp } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => ( + span]:line-clamp-1", + className, + )} + {...props} + > + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) => ( + + + +)) +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + +const SelectScrollDownButton = React.forwardRef(({ className, ...props }, ref) => ( + + + +)) +SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName + +const SelectContent = React.forwardRef(({ className, children, position = "popper", ...props }, ref) => ( + + + + + {children} + + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => ( + + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +} diff --git a/components/ui/select.tsx b/components/ui/select.tsx index 6138eb4..cbe5a36 100644 --- a/components/ui/select.tsx +++ b/components/ui/select.tsx @@ -20,7 +20,7 @@ const SelectTrigger = React.forwardRef< ref={ref} className={cn( "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", - className, + className )} {...props} > @@ -38,7 +38,10 @@ const SelectScrollUpButton = React.forwardRef< >(({ className, ...props }, ref) => ( @@ -52,13 +55,17 @@ const SelectScrollDownButton = React.forwardRef< >(({ className, ...props }, ref) => ( )) -SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName const SelectContent = React.forwardRef< React.ElementRef, @@ -71,7 +78,7 @@ const SelectContent = React.forwardRef< "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", - className, + className )} position={position} {...props} @@ -81,7 +88,7 @@ const SelectContent = React.forwardRef< className={cn( "p-1", position === "popper" && - "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]", + "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]" )} > {children} @@ -96,7 +103,11 @@ const SelectLabel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - + )) SelectLabel.displayName = SelectPrimitive.Label.displayName @@ -108,7 +119,7 @@ const SelectItem = React.forwardRef< ref={ref} className={cn( "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", - className, + className )} {...props} > @@ -127,7 +138,11 @@ const SelectSeparator = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - + )) SelectSeparator.displayName = SelectPrimitive.Separator.displayName diff --git a/components/ui/table.jsx b/components/ui/table.jsx new file mode 100644 index 0000000..d8c6db7 --- /dev/null +++ b/components/ui/table.jsx @@ -0,0 +1,57 @@ +import * as React from "react" +import { cn } from "@/lib/utils" + +const Table = React.forwardRef(({ className, ...props }, ref) => ( +
+ + +)) +Table.displayName = "Table" + +const TableHeader = React.forwardRef(({ className, ...props }, ref) => ( + +)) +TableHeader.displayName = "TableHeader" + +const TableBody = React.forwardRef(({ className, ...props }, ref) => ( + +)) +TableBody.displayName = "TableBody" + +const TableFooter = React.forwardRef(({ className, ...props }, ref) => ( + tr]:last:border-b-0", className)} {...props} /> +)) +TableFooter.displayName = "TableFooter" + +const TableRow = React.forwardRef(({ className, ...props }, ref) => ( + +)) +TableRow.displayName = "TableRow" + +const TableHead = React.forwardRef(({ className, ...props }, ref) => ( +
+)) +TableHead.displayName = "TableHead" + +const TableCell = React.forwardRef(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = "TableCell" + +const TableCaption = React.forwardRef(({ className, ...props }, ref) => ( +
+)) +TableCaption.displayName = "TableCaption" + +export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } diff --git a/components/ui/table.tsx b/components/ui/table.tsx index 5bde561..7f3502f 100644 --- a/components/ui/table.tsx +++ b/components/ui/table.tsx @@ -1,71 +1,117 @@ import * as React from "react" + import { cn } from "@/lib/utils" -const Table = React.forwardRef>( - ({ className, ...props }, ref) => ( -
- - - ), -) +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+
+ +)) Table.displayName = "Table" -const TableHeader = React.forwardRef>( - ({ className, ...props }, ref) => , -) +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) TableHeader.displayName = "TableHeader" -const TableBody = React.forwardRef>( - ({ className, ...props }, ref) => ( - - ), -) +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) TableBody.displayName = "TableBody" -const TableFooter = React.forwardRef>( - ({ className, ...props }, ref) => ( - tr]:last:border-b-0", className)} {...props} /> - ), -) +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + tr]:last:border-b-0", + className + )} + {...props} + /> +)) TableFooter.displayName = "TableFooter" -const TableRow = React.forwardRef>( - ({ className, ...props }, ref) => ( - - ), -) +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) TableRow.displayName = "TableRow" -const TableHead = React.forwardRef>( - ({ className, ...props }, ref) => ( -
- ), -) +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) TableHead.displayName = "TableHead" -const TableCell = React.forwardRef>( - ({ className, ...props }, ref) => ( - - ), -) +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) TableCell.displayName = "TableCell" -const TableCaption = React.forwardRef>( - ({ className, ...props }, ref) => ( -
- ), -) +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) TableCaption.displayName = "TableCaption" -export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +}