Select a file from the repository tree to inspect its code.
resources/js/pages/dashboard/converter.tsx
Copy Code
import { Head } from '@inertiajs/react';
import {
ArrowRightLeft,
Terminal,
Code,
Globe,
Copy,
Check,
} from 'lucide-react';
import React, { useState, useMemo } from 'react';
import { toast } from 'sonner';
import { Button } from '@/components/ui/button';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { Combobox } from '@/components/ui/combobox';
interface Currency {
id: number;
code: string;
name: string;
country: string | null;
rate: number;
active: boolean;
}
interface Token {
id: number;
name: string;
token: string;
default_currency: string;
active: boolean;
created_at: string;
updated_at: string;
}
interface ConverterPageProps {
tokens: Token[];
currencies: Currency[];
}
export default function ConverterPage({
tokens = [],
currencies = [],
}: ConverterPageProps) {
const [calcAmount, setCalcAmount] = useState<number>(100);
const [calcFrom, setCalcFrom] = useState<string>('USD');
const [calcTo, setCalcTo] = useState<string>('INR');
const [copiedText, setCopiedText] = useState<string | null>(null);
// Prepare options for searchable Combobox
const currencyOptions = useMemo(() => {
return currencies.map((c) => ({
value: c.code,
label: `${c.code} - ${c.name}`,
searchTerms: `${c.code} ${c.name} ${c.country || ''}`,
}));
}, [currencies]);
// Map currency code to rate
const ratesMap = useMemo(() => {
const map: Record<string, number> = {};
currencies.forEach((c) => {
map[c.code] = c.rate;
});
return map;
}, [currencies]);
// Live conversion value
const calculatedValue = useMemo(() => {
if (!ratesMap[calcFrom] || !ratesMap[calcTo]) {
return 0;
}
const fromRate = ratesMap[calcFrom];
const toRate = ratesMap[calcTo];
return (calcAmount / fromRate) * toRate;
}, [calcAmount, calcFrom, calcTo, ratesMap]);
// Get active token string for code snippets
const activeTokenStr = useMemo(() => {
const activeToken = tokens.find((t) => t.active);
return activeToken ? activeToken.token : 'YOUR_API_TOKEN';
}, [tokens]);
// Copy snippet to clipboard
const copyCodeSnippet = (text: string, label: string) => {
navigator.clipboard.writeText(text);
setCopiedText(label);
toast.success(`${label} snippet copied!`);
setTimeout(() => setCopiedText(null), 2000);
};
// Code snippets
const curlSnippet = `curl -X POST \\
-H "Authorization: Bearer ${activeTokenStr}" \\
-H "Content-Type: application/json" \\
-d '{"amount": ${calcAmount}}' \\
"${window.location.origin}/api/v1/${calcFrom}/${calcTo}"`;
const jsSnippet = `fetch('${window.location.origin}/api/v1/${calcFrom}/${calcTo}', {
method: 'POST',
headers: {
'Authorization': 'Bearer ${activeTokenStr}',
'Content-Type': 'application/json'
},
body: JSON.stringify({ amount: ${calcAmount} })
})
.then(res => res.json())
.then(data => console.log(data));`;
return (
<>
<Head title="Currency Converter Calculator" />
<div className="min-h-screen w-full space-y-6 bg-background p-4 text-foreground md:p-6">
{/* Header */}
<div className="flex flex-col gap-2 border-b border-border pb-6">
<div className="flex items-center gap-2">
<span className="rounded-lg bg-primary/10 p-1.5 text-primary">
<ArrowRightLeft className="h-5 w-5" />
</span>
<h1 className="text-3xl font-extrabold tracking-tight text-foreground">
Currency Converter
</h1>
</div>
<p className="text-sm text-muted-foreground">
Test and verify conversion rates instantly. Copy
integration code snippets to query rates in your apps.
</p>
</div>
{/* Page Content Layout (Full Width Grid) */}
<div className="grid gap-6 lg:grid-cols-3">
{/* Live Calculator Widget */}
<div className="lg:col-span-1">
<Card className="border border-border bg-card text-card-foreground shadow-xs">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-lg font-bold">
<ArrowRightLeft className="h-5 w-5 text-primary" />{' '}
Live Test Converter
</CardTitle>
<CardDescription>
Test conversion outputs relative to local
rates.
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<label className="text-xs font-semibold text-muted-foreground uppercase">
Amount
</label>
<input
type="number"
value={calcAmount}
onChange={(e) =>
setCalcAmount(
parseFloat(e.target.value) || 0,
)
}
className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-xs transition-colors focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-hidden"
/>
</div>
<div className="grid grid-cols-2 gap-3">
<div className="space-y-2">
<label className="text-xs font-semibold text-muted-foreground uppercase">
From
</label>
<Combobox
options={currencyOptions}
value={calcFrom}
onChange={setCalcFrom}
placeholder="From..."
/>
</div>
<div className="space-y-2">
<label className="text-xs font-semibold text-muted-foreground uppercase">
To
</label>
<Combobox
options={currencyOptions}
value={calcTo}
onChange={setCalcTo}
placeholder="To..."
/>
</div>
</div>
{/* Conversion Display Panel */}
<div className="mt-2 flex flex-col items-center justify-center gap-1.5 rounded-lg border border-border bg-muted p-4 text-center">
<span className="text-xs font-semibold tracking-wider text-muted-foreground uppercase">
Conversion Result
</span>
<span className="text-xl font-bold text-foreground">
{calcAmount.toLocaleString(undefined, {
minimumFractionDigits: 2,
})}{' '}
{calcFrom} =
</span>
<span className="text-2xl font-black text-primary">
{calculatedValue.toLocaleString(
undefined,
{
minimumFractionDigits: 2,
maximumFractionDigits: 4,
},
)}{' '}
{calcTo}
</span>
<span className="mt-1 flex items-center gap-1 font-mono text-[10px] text-muted-foreground">
1 {calcFrom} ={' '}
{(
ratesMap[calcTo] /
ratesMap[calcFrom]
).toFixed(6)}{' '}
{calcTo}
</span>
</div>
</CardContent>
</Card>
</div>
{/* Developer Code Snippets */}
<div className="lg:col-span-2">
<Card className="border border-border bg-card text-card-foreground shadow-xs">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-lg font-bold">
<Terminal className="h-5 w-5 text-primary" />{' '}
API Explorer
</CardTitle>
<CardDescription>
Integrate the conversion service directly
into your codebases.
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="flex items-center gap-1 text-xs font-semibold text-muted-foreground uppercase">
<Code className="h-3.5 w-3.5" />{' '}
cURL Command
</span>
<Button
variant="ghost"
size="sm"
className="h-7 text-xs text-primary"
onClick={() =>
copyCodeSnippet(
curlSnippet,
'cURL',
)
}
>
{copiedText === 'cURL' ? (
<Check className="mr-1 h-3.5 w-3.5 text-emerald-500" />
) : (
<Copy className="mr-1 h-3.5 w-3.5" />
)}
{copiedText === 'cURL'
? 'Copied'
: 'Copy'}
</Button>
</div>
<pre className="overflow-x-auto rounded-lg border border-neutral-800 bg-neutral-900 p-3 font-mono text-xs leading-relaxed text-neutral-100 select-all">
{curlSnippet}
</pre>
<div className="flex items-center justify-between pt-1">
<span className="flex items-center gap-1 text-xs font-semibold text-muted-foreground uppercase">
<Globe className="h-3.5 w-3.5" />{' '}
JavaScript (Fetch)
</span>
<Button
variant="ghost"
size="sm"
className="h-7 text-xs text-primary"
onClick={() =>
copyCodeSnippet(
jsSnippet,
'JavaScript',
)
}
>
{copiedText === 'JavaScript' ? (
<Check className="mr-1 h-3.5 w-3.5 text-emerald-500" />
) : (
<Copy className="mr-1 h-3.5 w-3.5" />
)}
{copiedText === 'JavaScript'
? 'Copied'
: 'Copy'}
</Button>
</div>
<pre className="overflow-x-auto rounded-lg border border-neutral-800 bg-neutral-900 p-3 font-mono text-xs leading-relaxed text-neutral-100 select-all">
{jsSnippet}
</pre>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
</>
);
}
ConverterPage.layout = {
breadcrumbs: [
{
title: 'Dashboard',
href: '/dashboard',
},
{
title: 'Currency Converter',
href: '/dashboard/converter',
},
],
};