added internationalization for backoffice

This commit is contained in:
mengstabketemaw
2026-06-15 16:56:39 +03:00
parent 7e6e9eb1a7
commit 76a8d034ee
9 changed files with 303 additions and 80 deletions

View File

@@ -1,4 +1,5 @@
import { useState, type ElementType, type ReactNode } from 'react';
import { useTranslation } from 'react-i18next';
import {
Paper,
Text,
@@ -64,21 +65,25 @@ const ROLES = [
{ name: 'Guest', value: 10, color: '#93c5fd' },
];
const KPIS = [
{ label: 'Total Users', value: '9,431', icon: IconUsers, color: 'blue', trend: '+12.5%', up: true },
{ label: 'Active Users', value: '7,218', icon: IconUserCheck, color: 'indigo', trend: '+8.2%', up: true },
{ label: 'New This Month', value: '642', icon: IconUserPlus, color: 'cyan', trend: '+23.1%', up: true },
{ label: 'Pending Approvals', value: '37', icon: IconClockHour4, color: 'orange', trend: '-4.0%', up: false },
];
function useKpis(t: (key: string) => string) {
return [
{ label: t('dashboard.kpis.totalUsers'), value: '9,431', icon: IconUsers, color: 'blue', trend: '+12.5%', up: true },
{ label: t('dashboard.kpis.activeUsers'), value: '7,218', icon: IconUserCheck, color: 'indigo', trend: '+8.2%', up: true },
{ label: t('dashboard.kpis.newThisMonth'), value: '642', icon: IconUserPlus, color: 'cyan', trend: '+23.1%', up: true },
{ label: t('dashboard.kpis.pendingApprovals'), value: '37', icon: IconClockHour4, color: 'orange', trend: '-4.0%', up: false },
];
}
const QUICK_LINKS = [
{ label: 'Add User', desc: 'Create a new account', icon: IconUserPlus, color: 'blue' },
{ label: 'Roles & Permissions', desc: 'Manage access levels', icon: IconShieldLock, color: 'indigo' },
{ label: 'Invite Members', desc: 'Send email invites', icon: IconMail, color: 'cyan' },
{ label: 'Import Users', desc: 'Bulk CSV import', icon: IconUpload, color: 'violet' },
{ label: 'Export Data', desc: 'Download reports', icon: IconDownload, color: 'blue' },
{ label: 'Audit Log', desc: 'Review activity', icon: IconClipboardList, color: 'grape' },
];
function useQuickLinks(t: (key: string) => string) {
return [
{ label: t('dashboard.quickLinks.addUser'), desc: t('dashboard.quickLinks.addUserDesc'), icon: IconUserPlus, color: 'blue' },
{ label: t('dashboard.quickLinks.rolesAndPermissions'), desc: t('dashboard.quickLinks.rolesAndPermissionsDesc'), icon: IconShieldLock, color: 'indigo' },
{ label: t('dashboard.quickLinks.inviteMembers'), desc: t('dashboard.quickLinks.inviteMembersDesc'), icon: IconMail, color: 'cyan' },
{ label: t('dashboard.quickLinks.importUsers'), desc: t('dashboard.quickLinks.importUsersDesc'), icon: IconUpload, color: 'violet' },
{ label: t('dashboard.quickLinks.exportData'), desc: t('dashboard.quickLinks.exportDataDesc'), icon: IconDownload, color: 'blue' },
{ label: t('dashboard.quickLinks.auditLog'), desc: t('dashboard.quickLinks.auditLogDesc'), icon: IconClipboardList, color: 'grape' },
];
}
type UserStatus = 'Active' | 'Pending' | 'Invited';
const STATUS_COLOR: Record<UserStatus, string> = {
@@ -214,16 +219,19 @@ function QuickLinkTile({
/* ------------------------------------------------------------------ */
export function DashboardPage() {
const { t } = useTranslation();
const [range, setRange] = useState('week');
const kpis = useKpis(t);
const quickLinks = useQuickLinks(t);
return (
<Stack gap="xl">
{/* header */}
<Group justify="space-between" align="flex-end" wrap="wrap">
<Stack gap={4}>
<Title order={2}>Overview</Title>
<Title order={2}>{t('dashboard.title')}</Title>
<Text c="dimmed" size="sm">
Welcome back here&apos;s what&apos;s happening across your platform.
{t('dashboard.subtitle')}
</Text>
</Stack>
<Group gap="sm">
@@ -232,20 +240,20 @@ export function DashboardPage() {
onChange={setRange}
radius="md"
data={[
{ label: 'Today', value: 'today' },
{ label: 'This Week', value: 'week' },
{ label: 'This Month', value: 'month' },
{ label: t('dashboard.timeRange.today'), value: 'today' },
{ label: t('dashboard.timeRange.thisWeek'), value: 'week' },
{ label: t('dashboard.timeRange.thisMonth'), value: 'month' },
]}
/>
<Button leftSection={<IconDownload size={16} />} radius="md">
Export
{t('common.export')}
</Button>
</Group>
</Group>
{/* KPIs */}
<SimpleGrid cols={{ base: 1, sm: 2, lg: 4 }} spacing="lg">
{KPIS.map((k) => (
{kpis.map((k) => (
<StatCard key={k.label} {...k} />
))}
</SimpleGrid>
@@ -256,15 +264,15 @@ export function DashboardPage() {
<SectionCard>
<Group justify="space-between" align="flex-start" mb="lg">
<CardHeading
title="User Registrations"
subtitle="New sign-ups over the last 8 months"
title={t('dashboard.charts.userRegistrations')}
subtitle={t('dashboard.charts.registrationsSubtitle')}
/>
<Stack gap={0} align="flex-end">
<Text fw={700} c="teal">
+18.2%
</Text>
<Text size="xs" c="dimmed">
vs previous period
{t('dashboard.charts.vsPreviousPeriod')}
</Text>
</Stack>
</Group>
@@ -309,7 +317,7 @@ export function DashboardPage() {
<Grid.Col span={{ base: 12, lg: 4 }}>
<SectionCard>
<CardHeading title="Users by Role" subtitle="Distribution across access levels" />
<CardHeading title={t('dashboard.charts.usersByRole')} subtitle={t('dashboard.charts.roleDistribution')} />
<Group mt="lg" justify="center" wrap="nowrap" gap="lg">
<Box pos="relative" w={168} h={168} style={{ flexShrink: 0 }}>
<ResponsiveContainer width="100%" height="100%">
@@ -348,7 +356,7 @@ export function DashboardPage() {
9,431
</Text>
<Text size="xs" c="dimmed">
Total users
{t('dashboard.charts.totalUsers')}
</Text>
</Stack>
</Box>
@@ -376,9 +384,9 @@ export function DashboardPage() {
<Grid gutter="lg" align="stretch">
<Grid.Col span={{ base: 12, lg: 8 }}>
<SectionCard>
<CardHeading title="Quick Links" subtitle="Common administrative shortcuts" />
<CardHeading title={t('dashboard.quickLinks.title')} subtitle={t('dashboard.quickLinks.subtitle')} />
<SimpleGrid cols={{ base: 2, sm: 3 }} spacing="md" mt="lg">
{QUICK_LINKS.map((q) => (
{quickLinks.map((q) => (
<QuickLinkTile key={q.label} {...q} />
))}
</SimpleGrid>
@@ -389,11 +397,11 @@ export function DashboardPage() {
<SectionCard>
<Group justify="space-between" mb="md">
<Text fw={700} fz="lg">
Recent Users
{t('dashboard.recentUsers.title')}
</Text>
<Anchor size="sm" fw={600}>
<Group gap={4} wrap="nowrap">
View all
{t('common.viewAll')}
<IconArrowRight size={14} />
</Group>
</Anchor>