feat: Translate Wallets page to multi-language
- Add useLanguage hook to Wallets page - Translate all UI text (buttons, labels, table headers) - Translate filter options and placeholders - Translate delete confirmation dialog - Support both Indonesian and English
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { useState, useEffect, useMemo } from "react"
|
import { useState, useEffect, useMemo } from "react"
|
||||||
|
import { useLanguage } from "@/contexts/LanguageContext"
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
@@ -49,6 +50,7 @@ interface Wallet {
|
|||||||
const API = "/api"
|
const API = "/api"
|
||||||
|
|
||||||
export function Wallets() {
|
export function Wallets() {
|
||||||
|
const { t } = useLanguage()
|
||||||
const [wallets, setWallets] = useState<Wallet[]>([])
|
const [wallets, setWallets] = useState<Wallet[]>([])
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [searchTerm, setSearchTerm] = useState("")
|
const [searchTerm, setSearchTerm] = useState("")
|
||||||
@@ -165,7 +167,7 @@ export function Wallets() {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => setWalletDialogOpen(true)}>
|
<Button onClick={() => setWalletDialogOpen(true)}>
|
||||||
<Plus className="mr-2 h-4 w-4" />
|
<Plus className="mr-2 h-4 w-4" />
|
||||||
Add Wallet
|
{t.wallets.addWallet}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -175,7 +177,7 @@ export function Wallets() {
|
|||||||
<div className="grid gap-4 grid-cols-2 lg:grid-cols-4">
|
<div className="grid gap-4 grid-cols-2 lg:grid-cols-4">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle className="text-sm font-medium">Total Wallets</CardTitle>
|
<CardTitle className="text-sm font-medium">{t.wallets.title}</CardTitle>
|
||||||
<Wallet className="h-4 w-4 text-muted-foreground" />
|
<Wallet className="h-4 w-4 text-muted-foreground" />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
@@ -185,7 +187,7 @@ export function Wallets() {
|
|||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle className="text-sm font-medium">Money Wallets</CardTitle>
|
<CardTitle className="text-sm font-medium">{t.wallets.moneyWallets}</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="text-2xl font-bold">{stats.moneyWallets}</div>
|
<div className="text-2xl font-bold">{stats.moneyWallets}</div>
|
||||||
@@ -194,7 +196,7 @@ export function Wallets() {
|
|||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle className="text-sm font-medium">Asset Wallets</CardTitle>
|
<CardTitle className="text-sm font-medium">{t.wallets.assetWallets}</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="text-2xl font-bold">{stats.assetWallets}</div>
|
<div className="text-2xl font-bold">{stats.assetWallets}</div>
|
||||||
@@ -203,7 +205,7 @@ export function Wallets() {
|
|||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle className="text-sm font-medium">Currencies</CardTitle>
|
<CardTitle className="text-sm font-medium">{t.wallets.currency}</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="text-2xl font-bold">{stats.currencyCount}</div>
|
<div className="text-2xl font-bold">{stats.currencyCount}</div>
|
||||||
@@ -216,12 +218,12 @@ export function Wallets() {
|
|||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<CardTitle className="text-base">Filters</CardTitle>
|
<CardTitle className="text-base">{t.common.filter}</CardTitle>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={clearFilters}
|
onClick={clearFilters}
|
||||||
className="h-8 text-xs"
|
className="h-7 px-2"
|
||||||
>
|
>
|
||||||
<X className="h-3 w-3 mr-1" />
|
<X className="h-3 w-3 mr-1" />
|
||||||
Clear All
|
Clear All
|
||||||
@@ -233,11 +235,11 @@ export function Wallets() {
|
|||||||
<div className="grid gap-3 md:grid-cols-3">
|
<div className="grid gap-3 md:grid-cols-3">
|
||||||
{/* Search */}
|
{/* Search */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-xs font-medium text-muted-foreground">Search Wallet</Label>
|
<Label className="text-xs font-medium text-muted-foreground">{t.common.search}</Label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||||
<Input
|
<Input
|
||||||
placeholder="Search wallets..."
|
placeholder={t.wallets.searchPlaceholder}
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
className="pl-9 h-9"
|
className="pl-9 h-9"
|
||||||
@@ -247,28 +249,28 @@ export function Wallets() {
|
|||||||
|
|
||||||
{/* Type Filter */}
|
{/* Type Filter */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-xs font-medium text-muted-foreground">Type</Label>
|
<Label className="text-xs font-medium text-muted-foreground">{t.wallets.type}</Label>
|
||||||
<Select value={kindFilter} onValueChange={setKindFilter}>
|
<Select value={kindFilter} onValueChange={setKindFilter}>
|
||||||
<SelectTrigger className="h-9">
|
<SelectTrigger className="h-9">
|
||||||
<SelectValue placeholder="All types" />
|
<SelectValue placeholder={t.common.all} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="all">All Types</SelectItem>
|
<SelectItem value="all">{t.common.all}</SelectItem>
|
||||||
<SelectItem value="money">Money</SelectItem>
|
<SelectItem value="money">{t.wallets.money}</SelectItem>
|
||||||
<SelectItem value="asset">Asset</SelectItem>
|
<SelectItem value="asset">{t.wallets.asset}</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Currency Filter */}
|
{/* Currency Filter */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-xs font-medium text-muted-foreground">Currency/Unit</Label>
|
<Label className="text-xs font-medium text-muted-foreground">{t.wallets.currency}/{t.wallets.unit}</Label>
|
||||||
<Select value={currencyFilter} onValueChange={setCurrencyFilter}>
|
<Select value={currencyFilter} onValueChange={setCurrencyFilter}>
|
||||||
<SelectTrigger className="h-9">
|
<SelectTrigger className="h-9">
|
||||||
<SelectValue placeholder="All currencies" />
|
<SelectValue placeholder={t.common.all} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="all">All Currencies/Units</SelectItem>
|
<SelectItem value="all">{t.common.all}</SelectItem>
|
||||||
{availableCurrencies.map(currency => (
|
{availableCurrencies.map(currency => (
|
||||||
<SelectItem key={currency} value={currency}>
|
<SelectItem key={currency} value={currency}>
|
||||||
{currency}
|
{currency}
|
||||||
@@ -316,7 +318,7 @@ export function Wallets() {
|
|||||||
{/* Wallets Table */}
|
{/* Wallets Table */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Wallets ({filteredWallets.length})</CardTitle>
|
<CardTitle>{t.wallets.title} ({filteredWallets.length})</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
{filteredWallets.length !== wallets.length
|
{filteredWallets.length !== wallets.length
|
||||||
? `Filtered from ${wallets.length} total wallets`
|
? `Filtered from ${wallets.length} total wallets`
|
||||||
@@ -328,11 +330,11 @@ export function Wallets() {
|
|||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Name</TableHead>
|
<TableHead>{t.wallets.name}</TableHead>
|
||||||
<TableHead>Currency/Unit</TableHead>
|
<TableHead>{t.wallets.currency}/{t.wallets.unit}</TableHead>
|
||||||
<TableHead>Type</TableHead>
|
<TableHead>{t.wallets.type}</TableHead>
|
||||||
<TableHead>Created</TableHead>
|
<TableHead>{t.common.date}</TableHead>
|
||||||
<TableHead className="text-right">Actions</TableHead>
|
<TableHead className="text-right">{t.common.actions}</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
@@ -340,8 +342,8 @@ export function Wallets() {
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={5} className="text-center py-8">
|
<TableCell colSpan={5} className="text-center py-8">
|
||||||
{filteredWallets.length !== wallets.length
|
{filteredWallets.length !== wallets.length
|
||||||
? "No wallets match your filters"
|
? t.wallets.noWallets
|
||||||
: "No wallets found. Create your first wallet!"
|
: t.wallets.createFirst
|
||||||
}
|
}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -380,15 +382,15 @@ export function Wallets() {
|
|||||||
</AlertDialogTrigger>
|
</AlertDialogTrigger>
|
||||||
<AlertDialogContent>
|
<AlertDialogContent>
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle>Delete Wallet</AlertDialogTitle>
|
<AlertDialogTitle>{t.common.delete} {t.wallets.title}</AlertDialogTitle>
|
||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
Are you sure you want to delete "{wallet.name}"? This action cannot be undone.
|
{t.wallets.deleteConfirm}
|
||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>{t.common.cancel}</AlertDialogCancel>
|
||||||
<AlertDialogAction onClick={() => deleteWallet(wallet.id)}>
|
<AlertDialogAction onClick={() => deleteWallet(wallet.id)}>
|
||||||
Delete
|
{t.common.delete}
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user