+ {/* Header */}
+
+
Exchange Rate Export
+
+ Fetch USD exchange rates from Vietnamese banks and export to CSV.
+
+
+
+ {/* Controls card */}
+
+
+ {/* Inputs row */}
+
+
+
+
+
+
+
+ setStartDate(date)}
+ maxDate={endDate || new Date()}
+ dateFormat="yyyy-MM-dd"
+ className="border rounded-lg px-3 py-2 text-sm w-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500/30"
+ placeholderText="Select start date"
+ />
+
+
+
+ setEndDate(date)}
+ minDate={startDate}
+ maxDate={new Date()}
+ dateFormat="yyyy-MM-dd"
+ className="border rounded-lg px-3 py-2 text-sm w-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500/30"
+ placeholderText="Select end date"
+ />
+
+
+
+ {/* Buttons row */}
+
+
+
-
-
- setStartDate(date)}
- maxDate={endDate || new Date()}
- dateFormat="yyyy-MM-dd"
- className="border rounded p-2 w-full"
- placeholderText="Select start date"
- />
-
-
-
- setEndDate(date)}
- minDate={startDate}
- maxDate={new Date()}
- dateFormat="yyyy-MM-dd"
- className="border rounded p-2 w-full"
- placeholderText="Select end date"
- />
-
-
- {/* Row 2: Fetch & Export Buttons aligned with End Date */}
-
-
-
- {error &&
{error}
}
- {isLoading && (
-
Loading data, please wait...
- )}
- {showTable && (
-
- {selectedBank === "bidv" ? (
-
-
-
- | Date |
- NameVI |
- MuaTm |
- MuaCk |
- Currency |
- NameEN |
- Ban |
-
-
-
- {results.map((result, idx) => (
-
- | {result.date} |
- {result.nameVI} |
- {result.muaTm} |
- {result.muaCk} |
- {result.currency} |
- {result.nameEN} |
- {result.ban} |
-
- ))}
-
-
- ) : (
-
-
-
- | Date |
- Label |
- AskRate |
- BidRateCK |
- BidRateTM |
- SourceCurrency |
- TargetCurrency |
- AskRateTM |
-
-
-
- {results.map((result, idx) => (
-
- | {result.date} |
- {result.label} |
- {result.askRate} |
- {result.bidRateCK} |
- {result.bidRateTM} |
-
- {result.sourceCurrency}
- |
-
- {result.targetCurrency}
- |
- {result.askRateTM} |
-
- ))}
-
-
- )}
+
+ {/* Status area - announced to screen readers */}
+
+ {error &&
}
+ {isLoading &&
}
+ {!isLoading && showTable && results.length === 0 &&
}
+ {!isLoading && showTable && results.length > 0 && (
+
+
+
+ {results.length} {results.length === 1 ? "record" : "records"} found
+
+
+
)}
+
);
}
diff --git a/src/app/globals.css b/src/app/globals.css
index a2dc41e..f93f598 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -1,8 +1,17 @@
@import "tailwindcss";
:root {
- --background: #ffffff;
+ --background: #f8fafc;
--foreground: #171717;
+ --card-bg: #ffffff;
+ --card-border: #e2e8f0;
+ --input-bg: #ffffff;
+ --input-border: #cbd5e1;
+ --input-focus: #3b82f6;
+ --table-header-bg: #f1f5f9;
+ --table-row-hover: #e2e8f0;
+ --table-row-stripe: #f1f5f9;
+ --muted: #64748b;
}
@theme inline {
@@ -16,6 +25,15 @@
:root {
--background: #0a0a0a;
--foreground: #ededed;
+ --card-bg: #18181b;
+ --card-border: #27272a;
+ --input-bg: #1e1e22;
+ --input-border: #3f3f46;
+ --input-focus: #60a5fa;
+ --table-header-bg: #1e1e22;
+ --table-row-hover: #27272a;
+ --table-row-stripe: #141416;
+ --muted: #a1a1aa;
}
}
@@ -24,3 +42,60 @@ body {
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}
+
+/* Date picker dark mode support */
+.react-datepicker-wrapper {
+ width: 100%;
+}
+
+.react-datepicker__input-container input {
+ background: var(--input-bg) !important;
+ color: var(--foreground) !important;
+ border-color: var(--input-border) !important;
+}
+
+.react-datepicker {
+ background-color: var(--card-bg) !important;
+ border-color: var(--card-border) !important;
+ color: var(--foreground) !important;
+ font-family: inherit !important;
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12) !important;
+}
+
+.react-datepicker__header {
+ background-color: var(--table-header-bg) !important;
+ border-bottom-color: var(--card-border) !important;
+}
+
+.react-datepicker__current-month,
+.react-datepicker__day-name {
+ color: var(--foreground) !important;
+}
+
+.react-datepicker__day {
+ color: var(--foreground) !important;
+ border-radius: 6px !important;
+}
+
+.react-datepicker__day:hover {
+ background-color: var(--table-row-hover) !important;
+}
+
+.react-datepicker__day--selected,
+.react-datepicker__day--keyboard-selected {
+ background-color: #3b82f6 !important;
+ color: #fff !important;
+}
+
+.react-datepicker__day--disabled {
+ color: var(--muted) !important;
+ opacity: 0.4;
+}
+
+.react-datepicker__navigation-icon::before {
+ border-color: var(--muted) !important;
+}
+
+.react-datepicker__triangle {
+ display: none !important;
+}
diff --git a/src/app/layout.js b/src/app/layout.js
index bb0c64c..a4f308c 100644
--- a/src/app/layout.js
+++ b/src/app/layout.js
@@ -14,8 +14,8 @@ const geistMono = Geist_Mono({
});
export const metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "Exchange Rate Export",
+ description: "Fetch exchange rates from BIDV or Techcombank and export to CSV",
};
export default function RootLayout({ children }) {