Merge pull request 'feat: Added Settings Page and Multi Language Support' (#6) from furqan into dev

Reviewed-on: https://gitea.maskantech.in/gitea_admin/saas_frontend/pulls/6
This commit is contained in:
furqan
2026-01-19 08:27:24 +00:00
4 changed files with 124 additions and 8 deletions
+107
View File
@@ -0,0 +1,107 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { toast } from 'react-toastify';
import { CustomDropdown, CustomConfirmationModal } from '../../components/custom';
import { useAuth } from '../../context/AuthContext';
import { languages } from '../../i18n/config';
import type { SupportedLanguage } from '../../i18n/config';
import { Globe } from 'lucide-react';
const SettingsPage: React.FC = () => {
const { t, i18n } = useTranslation('common');
const { user, updateLanguage } = useAuth();
const [isLoading, setIsLoading] = useState(false);
const [selectedLanguage] = useState<SupportedLanguage>(
(i18n.language as SupportedLanguage) || 'en'
);
const [pendingLanguage, setPendingLanguage] = useState<SupportedLanguage | null>(null);
const [showConfirmation, setShowConfirmation] = useState(false);
const handleLanguageChange = (newLanguage: SupportedLanguage) => {
if (newLanguage === selectedLanguage) return;
setPendingLanguage(newLanguage);
setShowConfirmation(true);
};
const handleConfirmLanguageChange = async () => {
if (!pendingLanguage) return;
setIsLoading(true);
setShowConfirmation(false);
try {
localStorage.setItem('preferred_language', pendingLanguage);
if (user) {
await updateLanguage(pendingLanguage);
}
window.location.reload();
} catch (error) {
console.error('Failed to update language:', error);
toast.error(t('messages.error'));
setIsLoading(false);
setPendingLanguage(null);
}
};
const handleCancelLanguageChange = () => {
setPendingLanguage(null);
setShowConfirmation(false);
};
return (
<div className="max-w-4xl mx-auto">
{/* Page Header */}
<div className="flex items-center gap-3 mb-6">
<div>
<h1 className="text-2xl font-bold text-(--text-primary)">
{t('settings.title')}
</h1>
</div>
</div>
{/* Language Settings Section */}
<div className="bg-(--card-bg) rounded-lg border border-(--card-border) p-6">
<div className="flex items-center gap-3 mb-4">
<Globe className="w-5 h-5 text-(--primary)" />
<h2 className="text-lg font-semibold text-(--text-primary)">
{t('settings.language.title')}
</h2>
</div>
<p className="text-sm text-(--text-secondary) mb-6">
{t('settings.language.description')}
</p>
<div className="max-w-md">
<CustomDropdown
label={t('settings.language.selectLabel') || "Select Language"}
options={(Object.keys(languages) as SupportedLanguage[]).map(lang => ({
label: languages[lang].name,
value: lang
}))}
value={selectedLanguage}
onChange={(e) => handleLanguageChange(e.target.value as SupportedLanguage)}
disabled={isLoading}
leftIcon={<Globe size={18} />}
/>
</div>
</div>
{/* Confirmation Modal */}
<CustomConfirmationModal
isOpen={showConfirmation}
onClose={handleCancelLanguageChange}
onConfirm={handleConfirmLanguageChange}
title={t('settings.language.confirmTitle') || 'Change Language?'}
description={t('settings.language.confirmMessage') || 'The page will reload to apply the new language settings. Continue?'}
confirmText={t('actions.confirm')}
cancelText={t('actions.cancel')}
/>
</div>
);
};
export default SettingsPage;
@@ -0,0 +1,9 @@
export interface LanguageSettings {
code: string;
name: string;
dir: 'ltr' | 'rtl';
}
export interface SettingsFormData {
language: string;
}
+6 -6
View File
@@ -51,18 +51,18 @@ const navItems: NavItem[] = [
path: "/tenants",
access: "superadmin.tenant.read",
},
{
icon: <UsersRound size={22} />,
name: "Users",
path: "/users",
access: "admin.user.read",
},
{
icon: <UserCog size={22} />,
name: "Roles",
path: "/roles",
access: "admin.role.read",
},
{
icon: <UsersRound size={22} />,
name: "Users",
path: "/users",
access: "admin.user.read",
},
{
icon: <Palette size={22} />,
name: "Themes",
+2 -2
View File
@@ -9,6 +9,7 @@ import ProfilePage from "../application/profile/ProfilePage";
import Tenants from "../application/tenants";
import ProtectedRoutes from "./ProtectedRoutes";
import Theme from "../application/theme";
import SettingsPage from "../application/settings/SettingsPage";
const AppRoutes = () => {
return (
<Routes>
@@ -24,11 +25,10 @@ const AppRoutes = () => {
<Route path="/tenants/*" element={<Tenants />} />
<Route path="/roles/*" element={<Roles />} />
<Route path="/theme/*" element={<Theme />} />
{/* Redirect root to dashboard if logged in (ProtectedRoutes handles auth check usually, or we redirect to signin if not) */}
<Route path="/settings" element={<SettingsPage />} />
<Route path="/" element={<Navigate to="/dashboard" replace />} />
</Route>
{/* Catch all - Redirect to dashboard which will handle auth or show dashboard */}
<Route path="*" element={<Navigate to="/dashboard" replace />} />
</Routes>
);