Add default theme management to branding settings and admin interface
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m14s
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m14s
This commit is contained in:
@@ -3,18 +3,19 @@ import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Users, Shield, Search, Trash2, ChevronDown, Loader2,
|
||||
MoreVertical, Key, UserCheck, UserX, UserPlus, Mail, Lock, User,
|
||||
Upload, X as XIcon, Image, Type,
|
||||
Upload, X as XIcon, Image, Type, Palette,
|
||||
} from 'lucide-react';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import { useLanguage } from '../contexts/LanguageContext';
|
||||
import { useBranding } from '../contexts/BrandingContext';
|
||||
import { themes } from '../themes';
|
||||
import api from '../services/api';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
export default function Admin() {
|
||||
const { user } = useAuth();
|
||||
const { t, language } = useLanguage();
|
||||
const { appName, hasLogo, logoUrl, refreshBranding } = useBranding();
|
||||
const { appName, hasLogo, logoUrl, defaultTheme, refreshBranding } = useBranding();
|
||||
const navigate = useNavigate();
|
||||
const [users, setUsers] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -31,6 +32,8 @@ export default function Admin() {
|
||||
const [savingName, setSavingName] = useState(false);
|
||||
const [uploadingLogo, setUploadingLogo] = useState(false);
|
||||
const logoInputRef = useRef(null);
|
||||
const [editDefaultTheme, setEditDefaultTheme] = useState('');
|
||||
const [savingDefaultTheme, setSavingDefaultTheme] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (user?.role !== 'admin') {
|
||||
@@ -44,6 +47,10 @@ export default function Admin() {
|
||||
setEditAppName(appName || 'Redlight');
|
||||
}, [appName]);
|
||||
|
||||
useEffect(() => {
|
||||
setEditDefaultTheme(defaultTheme || 'dark');
|
||||
}, [defaultTheme]);
|
||||
|
||||
const fetchUsers = async () => {
|
||||
try {
|
||||
const res = await api.get('/admin/users');
|
||||
@@ -135,6 +142,20 @@ export default function Admin() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleDefaultThemeSave = async () => {
|
||||
if (!editDefaultTheme) return;
|
||||
setSavingDefaultTheme(true);
|
||||
try {
|
||||
await api.put('/branding/default-theme', { defaultTheme: editDefaultTheme });
|
||||
toast.success(t('admin.defaultThemeSaved'));
|
||||
refreshBranding();
|
||||
} catch {
|
||||
toast.error(t('admin.defaultThemeUpdateFailed'));
|
||||
} finally {
|
||||
setSavingDefaultTheme(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateUser = async (e) => {
|
||||
e.preventDefault();
|
||||
setCreatingUser(true);
|
||||
@@ -266,6 +287,35 @@ export default function Admin() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Default theme */}
|
||||
<div className="mt-6 pt-6 border-t border-th-border">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<Palette size={16} className="text-th-accent" />
|
||||
<label className="block text-sm font-medium text-th-text">{t('admin.defaultThemeLabel')}</label>
|
||||
</div>
|
||||
<p className="text-xs text-th-text-s mb-3">{t('admin.defaultThemeDesc')}</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<select
|
||||
value={editDefaultTheme}
|
||||
onChange={e => setEditDefaultTheme(e.target.value)}
|
||||
className="input-field text-sm flex-1"
|
||||
>
|
||||
{themes.map(th => (
|
||||
<option key={th.id} value={th.id}>
|
||||
{th.name} ({th.type === 'light' ? t('themes.light') : t('themes.dark')})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
onClick={handleDefaultThemeSave}
|
||||
disabled={savingDefaultTheme || editDefaultTheme === (defaultTheme || 'dark')}
|
||||
className="btn-primary text-sm px-4 flex-shrink-0"
|
||||
>
|
||||
{savingDefaultTheme ? <Loader2 size={14} className="animate-spin" /> : t('common.save')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Search */}
|
||||
|
||||
Reference in New Issue
Block a user