completed the frontend dashboard component and bound it to the tenant admin pwa for the optimal onboarding experience.. Added a profile page.
This commit is contained in:
86
resources/js/components/dashboard-language-switcher.tsx
Normal file
86
resources/js/components/dashboard-language-switcher.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { useState } from 'react';
|
||||
import { router, usePage } from '@inertiajs/react';
|
||||
import { Check, Languages } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { type SharedData } from '@/types';
|
||||
import { setLocale } from '@/routes';
|
||||
|
||||
export function DashboardLanguageSwitcher() {
|
||||
const page = usePage<SharedData>();
|
||||
const { locale, supportedLocales, translations } = page.props;
|
||||
const locales = supportedLocales && supportedLocales.length > 0 ? supportedLocales : ['de', 'en'];
|
||||
const activeLocale = locales.includes(locale as string) && typeof locale === 'string' ? locale : locales[0];
|
||||
const languageCopy = (translations?.dashboard?.language_switcher as Record<string, string | undefined>) ?? {};
|
||||
const label = languageCopy.label ?? 'Sprache';
|
||||
const changeLabel = languageCopy.change ?? 'Sprache wechseln';
|
||||
|
||||
const [pendingLocale, setPendingLocale] = useState<string | null>(null);
|
||||
|
||||
const handleChange = (nextLocale: string) => {
|
||||
if (nextLocale === activeLocale || pendingLocale === nextLocale || !locales.includes(nextLocale)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setPendingLocale(nextLocale);
|
||||
|
||||
router.post(
|
||||
setLocale().url,
|
||||
{ locale: nextLocale },
|
||||
{
|
||||
preserveScroll: true,
|
||||
preserveState: true,
|
||||
onFinish: () => setPendingLocale(null),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex items-center gap-2 rounded-full border-white/30 bg-white/80 px-3 text-xs font-semibold uppercase tracking-wide text-slate-900 backdrop-blur transition hover:bg-white dark:border-white/20 dark:bg-white/10 dark:text-white"
|
||||
aria-label={label}
|
||||
>
|
||||
<Languages className="size-4" />
|
||||
<span>{label}</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="min-w-[9rem]">
|
||||
<DropdownMenuLabel className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">
|
||||
{changeLabel}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{locales.map((code) => {
|
||||
const isActive = code === activeLocale;
|
||||
const isPending = code === pendingLocale;
|
||||
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={code}
|
||||
onSelect={(event) => {
|
||||
event.preventDefault();
|
||||
handleChange(code);
|
||||
}}
|
||||
disabled={isPending}
|
||||
className="flex items-center justify-between gap-3"
|
||||
>
|
||||
<span className="text-sm font-medium uppercase tracking-wide">{code}</span>
|
||||
{(isActive || isPending) && <Check className="size-4 text-pink-500" />}
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user