function App()

in 7-reasoning/shipmentPlanning/frontend/src/App.js [36:288]


function App() {
  const [scenario, setScenario] = useState('');
  const [plan, setPlan] = useState('');
  const [executionMessages, setExecutionMessages] = useState([]);
  const [isProcessing, setIsProcessing] = useState(false);
  const [isGeneratingPlan, setIsGeneratingPlan] = useState(false); // State for loading spinner
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [errorMessage, setErrorMessage] = useState('');

  const toggleDrawer = () => {
    setDrawerOpen(!drawerOpen);
  };

  const handleScenarioSubmit = async (inputScenario) => {
    setScenario(inputScenario);
    setIsProcessing(true);
    setIsGeneratingPlan(true); // Show loading spinner
    setPlan('');
    setExecutionMessages([]);

    try {
      const response = await fetch('/api/process', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ scenario: inputScenario }),
      });

      const data = await response.json();

      if (data.error) {
        setErrorMessage(data.error);
        setIsProcessing(false);
        setIsGeneratingPlan(false);
        return;
      }

      // Corrected EventSource URL (single slash)
      const eventSource = new EventSource('http://localhost:5000/api/stream');

      eventSource.onmessage = (e) => {
        console.log('Received message:', e.data);
        const message = JSON.parse(e.data);

        if (message.type === 'plan') {
          setPlan((prevPlan) => prevPlan + '\n' + message.content);
          setIsGeneratingPlan(false); // Hide loading spinner
        } else if (
          message.type === 'assistant' ||
          message.type === 'function_call' ||
          message.type === 'tool_call' ||
          message.type === 'tool_response' ||
          message.type === 'error'
        ) {
          setExecutionMessages((prevMessages) => [...prevMessages, message]);
        } else if (message.type === 'status') {
          setExecutionMessages((prevMessages) => [
            ...prevMessages,
            { ...message, isStatus: true },
          ]);
        }

        if (message.message === 'Processing complete.') {
          eventSource.close();
          setIsProcessing(false);
        }
      };

      eventSource.onerror = (err) => {
        console.error('EventSource failed:', err);
        eventSource.close();
        setIsProcessing(false);
        setIsGeneratingPlan(false);
        setErrorMessage('An error occurred while processing the scenario.');
      };
    } catch (error) {
      console.error('Error:', error);
      setIsProcessing(false);
      setIsGeneratingPlan(false);
      setErrorMessage('An error occurred while submitting the scenario.');
    }
  };

  useEffect(() => {
    // Reset the backend state when the component mounts (page loads)
    fetch('/api/reset', {
      method: 'POST',
    })
      .then((response) => response.json())
      .then((data) => {
        console.log(data.status); // Optional: Log the response
      })
      .catch((error) => {
        console.error('Error resetting state:', error);
      });
  }, []);

  return (
    <Box
      sx={{
        display: 'flex',
        flexDirection: 'column',
        minHeight: '100vh',
      }}
    >
      {/* App Bar */}
      <AppBar
        position="fixed"
        color="primary"
        sx={{ zIndex: (theme) => theme.zIndex.drawer + 1 }}
      >
        <Toolbar>
          {/* Menu Icon for Side Drawer */}
          <IconButton
            edge="start"
            color="inherit"
            aria-label="menu"
            onClick={toggleDrawer}
            sx={{ mr: 2 }}
          >
            <MenuIcon />
          </IconButton>
          {/* Logo */}
          <Logo src={shippingLogo} alt="Shipping Logo" />
          <Typography
            variant="h6"
            sx={{
              flexGrow: 1,
              fontSize: { xs: '1rem', sm: '1.25rem', md: '1.5rem' },
            }}
          >
            ShipCo Logistics Planner
          </Typography>
          <Button
            variant="outlined"
            color="secondary"
            sx={{
              borderRadius: '8px',
              textTransform: 'none',
              transition: 'background-color 0.3s ease',
              '&:hover': {
                backgroundColor: 'secondary.dark',
              },
            }}
          >
            Login
          </Button>
        </Toolbar>
      </AppBar>

      {/* Side Drawer */}
      <Drawer anchor="left" open={drawerOpen} onClose={toggleDrawer}>
        <List sx={{ width: 250 }}>
          <ListItem button>
            <ListItemIcon>
              <DashboardIcon color="primary" />
            </ListItemIcon>
            <ListItemText primary="Dashboard" />
          </ListItem>
          {/* Add more navigation items as needed */}
          <ListItem button>
            <ListItemIcon>
              <SettingsIcon color="primary" />
            </ListItemIcon>
            <ListItemText primary="Settings" />
          </ListItem>
        </List>
      </Drawer>

      {/* Main Content */}
      <Box
        component="main"
        sx={{
          flexGrow: 1,
          mt: 8, // Offset for the fixed AppBar height
          mb: 4, // Space for the footer
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center',
        }}
      >
        <Container
          maxWidth="xl"
          sx={{
            flexGrow: 1,
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
          }}
        >
          {/* Scenario Input */}
          <Box sx={{ width: '100%', px: 4, py: 3 }}>
            <ScenarioInput onSubmit={handleScenarioSubmit} isProcessing={isProcessing} />
          </Box>

          {/* Execution Stream and Plan Display */}
          <Box sx={{ width: '100%', px: 4, pb: 3, flexGrow: 1 }}>
            <Grid container spacing={3} sx={{ height: '100%' }}>
              <Grid item xs={12} md={6}>
                <Box
                  sx={{
                    height: 'calc(70vh - 100px)', // Increased height by approximately 20%
                  }}
                >
                  <PlanDisplay plan={plan} isGeneratingPlan={isGeneratingPlan} />
                </Box>
              </Grid>
              <Grid item xs={12} md={6}>
                <Box
                  sx={{
                    height: 'calc(70vh - 100px)', // Increased height accordingly
                  }}
                >
                  <ExecutionStream messages={executionMessages} />
                </Box>
              </Grid>
            </Grid>
          </Box>
        </Container>
      </Box>

      {/* Footer */}
      <Box
        component="footer"
        sx={{
          py: 2,
          backgroundColor: '#f0f0f0',
          textAlign: 'center',
        }}
      >
        <Typography variant="body2" color="textSecondary">
          © {new Date().getFullYear()} High-Tech Shipping Company. All rights reserved.
        </Typography>
      </Box>

      {/* Error Snackbar */}
      <Snackbar
        open={!!errorMessage}
        autoHideDuration={6000}
        onClose={() => setErrorMessage('')}
        anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
      >
        <Alert
          onClose={() => setErrorMessage('')}
          severity="error"
          sx={{ width: '100%' }}
        >
          {errorMessage}
        </Alert>
      </Snackbar>
    </Box>
  );

}