Fix jwt-token
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Outlet, Link, useLocation } from 'react-router-dom';
|
import { Outlet, Link, useLocation } from 'react-router-dom';
|
||||||
// import { useTranslation } from 'react-i18next'; // Commented out until Docker rebuild
|
// import { useTranslation } from 'react-i18next'; // Commented out until Docker rebuild
|
||||||
import { useAuth } from '../contexts/AuthContext';
|
import { useAuth } from '../contexts/AuthContext';
|
||||||
@@ -7,6 +7,7 @@ import DebugToggle from './DebugToggle';
|
|||||||
import LanguageSelector from './common/LanguageSelector';
|
import LanguageSelector from './common/LanguageSelector';
|
||||||
import { canAccessSettings, hasPermission } from '../utils/rbac';
|
import { canAccessSettings, hasPermission } from '../utils/rbac';
|
||||||
import { t } from '../utils/tempTranslations'; // Temporary translation system
|
import { t } from '../utils/tempTranslations'; // Temporary translation system
|
||||||
|
import api from '../services/api';
|
||||||
import {
|
import {
|
||||||
HomeIcon,
|
HomeIcon,
|
||||||
MapIcon,
|
MapIcon,
|
||||||
@@ -25,11 +26,29 @@ import classNames from 'classnames';
|
|||||||
|
|
||||||
const Layout = () => {
|
const Layout = () => {
|
||||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
|
const [tenantInfo, setTenantInfo] = useState(null);
|
||||||
// const { t } = useTranslation(); // Commented out until Docker rebuild
|
// const { t } = useTranslation(); // Commented out until Docker rebuild
|
||||||
const { user, logout } = useAuth();
|
const { user, logout } = useAuth();
|
||||||
const { connected, recentDetections } = useSocket();
|
const { connected, recentDetections } = useSocket();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
|
// Fetch tenant information for branding
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchTenantInfo = async () => {
|
||||||
|
try {
|
||||||
|
const response = await api.get('/tenant/info');
|
||||||
|
setTenantInfo(response.data.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch tenant info:', error);
|
||||||
|
// Don't show error toast as this is not critical
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
fetchTenantInfo();
|
||||||
|
}
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
// Build navigation based on user permissions with translations
|
// Build navigation based on user permissions with translations
|
||||||
const baseNavigation = [
|
const baseNavigation = [
|
||||||
{ name: t('navigation.dashboard'), href: '/', icon: HomeIcon },
|
{ name: t('navigation.dashboard'), href: '/', icon: HomeIcon },
|
||||||
@@ -78,7 +97,7 @@ const Layout = () => {
|
|||||||
<XMarkIcon className="h-6 w-6 text-white" />
|
<XMarkIcon className="h-6 w-6 text-white" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<SidebarContent navigation={navigation} />
|
<SidebarContent navigation={navigation} tenantInfo={tenantInfo} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -86,7 +105,7 @@ const Layout = () => {
|
|||||||
<div className="hidden md:flex md:flex-shrink-0">
|
<div className="hidden md:flex md:flex-shrink-0">
|
||||||
<div className="flex flex-col w-64">
|
<div className="flex flex-col w-64">
|
||||||
<div className="flex flex-col flex-grow pt-5 pb-4 overflow-y-auto bg-white border-r border-gray-200">
|
<div className="flex flex-col flex-grow pt-5 pb-4 overflow-y-auto bg-white border-r border-gray-200">
|
||||||
<SidebarContent navigation={navigation} />
|
<SidebarContent navigation={navigation} tenantInfo={tenantInfo} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,18 +193,32 @@ const Layout = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SidebarContent = ({ navigation }) => {
|
const SidebarContent = ({ navigation, tenantInfo }) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex items-center flex-shrink-0 px-4">
|
<div className="flex items-center flex-shrink-0 px-4">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div className="w-8 h-8 bg-primary-600 rounded-lg flex items-center justify-center">
|
{/* Display tenant logo if available, otherwise show default icon */}
|
||||||
|
{tenantInfo?.branding?.logo_url ? (
|
||||||
|
<img
|
||||||
|
src={tenantInfo.branding.logo_url}
|
||||||
|
alt={`${tenantInfo.name || 'Company'} Logo`}
|
||||||
|
className="w-8 h-8 object-contain"
|
||||||
|
onError={(e) => {
|
||||||
|
// Fallback to default icon if logo fails to load
|
||||||
|
e.target.style.display = 'none';
|
||||||
|
e.target.nextSibling.style.display = 'flex';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{/* Default icon (shown if no logo or logo fails to load) */}
|
||||||
|
<div className={`w-8 h-8 bg-primary-600 rounded-lg flex items-center justify-center ${tenantInfo?.branding?.logo_url ? 'hidden' : ''}`}>
|
||||||
<ExclamationTriangleIcon className="h-5 w-5 text-white" />
|
<ExclamationTriangleIcon className="h-5 w-5 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-lg font-bold text-gray-900">
|
<h1 className="text-lg font-bold text-gray-900">
|
||||||
Drone Detector
|
{tenantInfo?.name || 'Drone Detector'}
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -92,11 +92,33 @@ const Login = () => {
|
|||||||
<div className="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
<div className="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||||
<div className="max-w-md w-full space-y-8">
|
<div className="max-w-md w-full space-y-8">
|
||||||
<div>
|
<div>
|
||||||
|
{/* Display tenant logo if available, otherwise show default icon */}
|
||||||
|
{tenantConfig?.branding?.logo_url ? (
|
||||||
|
<div className="mx-auto h-16 w-auto flex items-center justify-center">
|
||||||
|
<img
|
||||||
|
src={tenantConfig.branding.logo_url}
|
||||||
|
alt={`${tenantConfig.tenant_name || 'Company'} Logo`}
|
||||||
|
className="h-16 w-auto max-w-48 object-contain"
|
||||||
|
onError={(e) => {
|
||||||
|
// Fallback to default icon if logo fails to load
|
||||||
|
e.target.style.display = 'none';
|
||||||
|
e.target.nextSibling.style.display = 'flex';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Hidden fallback icon */}
|
||||||
|
<div className="hidden mx-auto h-12 w-12 bg-primary-600 rounded-lg items-center justify-center">
|
||||||
|
<svg className="h-8 w-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<div className="mx-auto h-12 w-12 bg-primary-600 rounded-lg flex items-center justify-center">
|
<div className="mx-auto h-12 w-12 bg-primary-600 rounded-lg flex items-center justify-center">
|
||||||
<svg className="h-8 w-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="h-8 w-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
||||||
{tenantConfig?.tenant_name || 'Drone Detection System'}
|
{tenantConfig?.tenant_name || 'Drone Detection System'}
|
||||||
</h2>
|
</h2>
|
||||||
|
|||||||
@@ -201,11 +201,33 @@ const Register = () => {
|
|||||||
<div className="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
<div className="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||||
<div className="max-w-md w-full space-y-8">
|
<div className="max-w-md w-full space-y-8">
|
||||||
<div>
|
<div>
|
||||||
|
{/* Display tenant logo if available, otherwise show default icon */}
|
||||||
|
{tenantConfig?.branding?.logo_url ? (
|
||||||
|
<div className="mx-auto h-16 w-auto flex items-center justify-center">
|
||||||
|
<img
|
||||||
|
src={tenantConfig.branding.logo_url}
|
||||||
|
alt={`${tenantConfig.tenant_name || 'Company'} Logo`}
|
||||||
|
className="h-16 w-auto max-w-48 object-contain"
|
||||||
|
onError={(e) => {
|
||||||
|
// Fallback to default icon if logo fails to load
|
||||||
|
e.target.style.display = 'none';
|
||||||
|
e.target.nextSibling.style.display = 'flex';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Hidden fallback icon */}
|
||||||
|
<div className="hidden mx-auto h-12 w-12 bg-primary-600 rounded-lg items-center justify-center">
|
||||||
|
<svg className="h-8 w-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<div className="mx-auto h-12 w-12 bg-primary-600 rounded-lg flex items-center justify-center">
|
<div className="mx-auto h-12 w-12 bg-primary-600 rounded-lg flex items-center justify-center">
|
||||||
<svg className="h-8 w-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="h-8 w-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
||||||
Create your account
|
Create your account
|
||||||
</h2>
|
</h2>
|
||||||
|
|||||||
Reference in New Issue
Block a user