Refactor pgroup handling and routing logic.

Enable synchronization of active pgroup across components using a callback mechanism. Improve handling of query parameters, props, and redirection to ensure accurate user context and state across pages like ResultsView and BeamtimeOverview. Update ProtectedRoute to support additional props.
This commit is contained in:
GotthardG 2025-05-06 12:14:39 +02:00
parent a169a39edd
commit 26f8870d04
5 changed files with 88 additions and 23 deletions

View File

@ -66,10 +66,11 @@ const App: React.FC = () => {
}, []);
const handlePgroupChange = (newPgroup: string) => {
setActivePgroup(newPgroup);
setActivePgroup(newPgroup); // Updates active pgroup state in App
console.log(`pgroup changed to: ${newPgroup}`);
};
return (
<Router>
<ResponsiveAppBar
@ -85,9 +86,33 @@ const App: React.FC = () => {
<Route path="/" element={<ProtectedRoute element={<HomePage />} />} />
<Route path="/shipments" element={<ProtectedRoute element={<ShipmentView pgroups={pgroups} activePgroup={activePgroup} />} />} />
<Route path="/planning" element={<ProtectedRoute element={<PlanningView />} />} />
<Route path="/results/:beamtimeId" element={<ProtectedRoute element={<ResultsView pgroups={pgroups} activePgroup={activePgroup} />} />} />
<Route path="/beamtime-overview" element={<ProtectedRoute element={<BeamtimeOverview activePgroup={activePgroup} />} />} />
<Route path="/results" element={<ProtectedRoute element={<BeamtimeOverview activePgroup={activePgroup} />} />}/>
<Route
path="/results/:beamtimeId"
element={
<ProtectedRoute
element={
<ResultsView
onPgroupChange={handlePgroupChange}
currentPgroup={activePgroup}
/>
}
/>
}
/>
<Route
path="/beamtime-overview"
element={
<ProtectedRoute
element={
<BeamtimeOverview
activePgroup={activePgroup}
onPgroupChange={handlePgroupChange} // Pass this prop correctly
/>
}
/>
}
/>
<Route path="/results" element={<ProtectedRoute element={<BeamtimeOverview activePgroup={activePgroup} onPgroupChange={handlePgroupChange} />} />}/>
{/* Optionally, add a 404 fallback route */}
<Route path="*" element={<div>Page not found</div>} />

View File

@ -16,9 +16,10 @@ interface BeamtimeRecord {
interface BeamtimeOverviewProps {
activePgroup: string;
onPgroupChange: (pgroup: string) => void; // Add callback to update the selected pgroup
}
const BeamtimeOverview: React.FC<BeamtimeOverviewProps> = ({ activePgroup }) => {
const BeamtimeOverview: React.FC<BeamtimeOverviewProps> = ({ activePgroup, onPgroupChange }) => {
const [rows, setRows] = useState<BeamtimeRecord[]>([]);
const [isLoading, setIsLoading] = useState(false);
@ -101,7 +102,7 @@ const BeamtimeOverview: React.FC<BeamtimeOverviewProps> = ({ activePgroup }) =>
flex: 1,
renderCell: (params) => (
<button
onClick={() => handleViewResults(params.row.id)}
onClick={() => handleViewResults(params.row.id, params.row.pgroups)}
style={{
padding: '6px 12px',
backgroundColor: '#1976d2',
@ -118,8 +119,15 @@ const BeamtimeOverview: React.FC<BeamtimeOverviewProps> = ({ activePgroup }) =>
];
// Navigate to the ResultsView page for the selected beamtime
const handleViewResults = (beamtimeId: number) => {
navigate(`/results/${beamtimeId}?pgroup=${activePgroup}`);
const handleViewResults = (beamtimeId: number, pgroups: string) => {
const pgroupArray = pgroups.split(',').map((pgroup) => pgroup.trim());
const firstPgroup = pgroupArray[0] || ''; // Choose the first pgroup (or fallback to empty string)
// Ensure onPgroupChange is invoked correctly
onPgroupChange(firstPgroup);
// Navigate directly to the Results page with the correct pgroup in the query
navigate(`/results/${beamtimeId}?pgroup=${firstPgroup}`);
};
return (

View File

@ -3,16 +3,19 @@ import { Navigate } from 'react-router-dom';
interface ProtectedRouteProps {
element: JSX.Element;
[key: string]: any; // Allow additional props
}
const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ element }) => {
const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ element, ...rest }) => {
const isAuthenticated = () => {
const token = localStorage.getItem('token');
console.log("Is Authenticated: ", token !== null);
return token !== null;
};
const token = localStorage.getItem('token');
console.log("Is Authenticated: ", token !== null);
return token !== null;
};
return isAuthenticated() ? element : <Navigate to="/login" />;
return isAuthenticated()
? React.cloneElement(element, { ...rest }) // Pass all additional props
: <Navigate to="/login" />;
};
export default ProtectedRoute;

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
@ -38,6 +38,12 @@ const ResponsiveAppBar: React.FC<ResponsiveAppBarProps> = ({
const [anchorElNav, setAnchorElNav] = useState<null | HTMLElement>(null);
const [anchorElUser, setAnchorElUser] = useState<null | HTMLElement>(null);
const [selectedPgroup, setSelectedPgroup] = useState(currentPgroup);
useEffect(() => {
setSelectedPgroup(currentPgroup); // Sync local state with the global activePgroup
}, [currentPgroup]);
console.log('Active Pgroup:', activePgroup);
const handlePgroupChange = (event: React.ChangeEvent<{ value: unknown }>) => {
const newPgroup = event.target.value as string;

View File

@ -1,16 +1,39 @@
import React from 'react';
import { useParams, useSearchParams} from 'react-router-dom';
import React, { useEffect } from 'react';
import { useParams, useSearchParams, useNavigate } from 'react-router-dom';
import SampleTracker from '../components/SampleTracker';
import ResultGrid from '../components/ResultGrid';
interface ResultsViewProps {
onPgroupChange?: (pgroup: string) => void; // Callback to notify about pgroup changes
currentPgroup: string; // Currently selected pgroup
}
interface ResultsViewProps {}
const ResultsView: React.FC<ResultsViewProps> = () => {
// Get the selected beamtime ID from the URL
const ResultsView: React.FC<ResultsViewProps> = ({ onPgroupChange, currentPgroup }) => {
const { beamtimeId } = useParams();
const [searchParams] = useSearchParams();
const activePgroup = searchParams.get("pgroup") ?? '';
const navigate = useNavigate();
// Get the active pgroup for the experiment from the query params.
const activePgroup = searchParams.get("pgroup") ?? ''; // Default to an empty string if missing
// Redirect if the selected pgroup does not match the beamtime's pgroup
useEffect(() => {
if (!currentPgroup || currentPgroup !== activePgroup) {
console.warn(
`Redirecting to BeamtimeOverview because selected pgroup (${currentPgroup || "undefined"}) does not match beamtime's pgroup (${activePgroup})`
);
navigate('/beamtime-overview'); // Redirect to BeamtimeOverview
}
}, [currentPgroup, activePgroup, navigate]);
// Notify parent about the selected pgroup (if needed)
useEffect(() => {
// Synchronize the pgroup when the component loads
if (onPgroupChange && activePgroup !== currentPgroup) {
onPgroupChange(activePgroup); // Update the selected pgroup
}
}, [onPgroupChange, activePgroup, currentPgroup]);
return (
<div>
@ -24,4 +47,4 @@ const ResultsView: React.FC<ResultsViewProps> = () => {
);
};
export default ResultsView;
export default ResultsView;