Ctrl K
ComunidadGuías…

dashboard/src/components/RouteError.tsx

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { useEffect, useState } from 'react';
import { isRouteErrorResponse, useRouteError } from 'react-router-dom';
import styled from 'styled-components';
import { LoadingSpinner } from '@/components/LoadingSpinner';

// Chrome, Firefox, Safari and Vite's CSS preload wording for a lazy chunk that no longer exists after a redeploy
const staleChunkPattern = /dynamically imported module|Importing a module script failed|Unable to preload CSS/i;
const reloadKey = 'staleChunkReloadFor';

const staleChunkMessage = (error: unknown) =>
  error instanceof Error && staleChunkPattern.test(error.message) ? error.message : '';

// One reload per failing chunk per build: import.meta.url is this build's hashed entry chunk, so a
// chunk still missing after the reload stops here however long the reload took, while a later deploy
// reloads again even when the browser (Safari) reports no chunk URL in the message.
const shouldReload = (message: string) => {
  const guard = `${import.meta.url} ${message}`;
  try {
    if (sessionStorage.getItem(reloadKey) === guard) return false;
    sessionStorage.setItem(reloadKey, guard);
    return true;
  } catch {
    return false;
  }
};

const Container = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  height: 100vh;
  padding: 0 16px;
  text-align: center;
  color: var(--text-primary);
  background: linear-gradient(135deg, var(--bg-gradient-start), var(--bg-gradient-end));
`;

const Title = styled.h1`
  font-size: 24px;
  font-weight: 700;
`;

const Message = styled.p`
  max-width: 560px;
  opacity: 0.8;
  word-break: break-word;
`;

const ReloadButton = styled.button`
  padding: 10px 24px;
  border-radius: 8px;
  border: 1px solid var(--text-primary);
  color: var(--text-primary);
  background: transparent;
  font-weight: 600;
  cursor: pointer;
`;

export const RouteError = () => {
  const error = useRouteError();
  const staleMessage = staleChunkMessage(error);
  const stale = staleMessage !== '';
  const [reloadSkipped, setReloadSkipped] = useState(false);

  useEffect(() => {
    if (!staleMessage) return;
    if (shouldReload(staleMessage)) window.location.reload();
    else setReloadSkipped(true);
  }, [staleMessage]);

  if (stale && !reloadSkipped) return <LoadingSpinner />;

  const message = stale
    ? 'A new version of the dashboard was deployed. Reload the page to continue.'
    : isRouteErrorResponse(error)
      ? `${error.status} ${error.statusText}`
      : error instanceof Error
        ? error.message
        : 'Unexpected error';

  return (
    <Container>
      <Title>{stale ? 'Dashboard updated' : 'Something went wrong'}</Title>
      <Message>{message}</Message>
      <ReloadButton onClick={() => window.location.reload()}>Reload</ReloadButton>
    </Container>
  );
};