build: actualizar dist con la versión de producción más reciente

This commit is contained in:
2026-08-14 16:34:38 -04:00
parent a5fe1f7b27
commit abfd2c4fae
15 changed files with 1794 additions and 350 deletions
+75 -8
View File
@@ -35,6 +35,7 @@ import {
deleteHubApp,
fetchHubApps,
fetchHubData,
fetchMyAppAccess,
migrateLocalAppsIfNeeded,
recordRecent,
saveHubApp,
@@ -536,14 +537,29 @@ function MobileNav({ user, view, onNavigate, onLogout }: MobileNavProps) {
);
}
type AccessState = boolean | null;
function AccessIndicator({ hasAccess }: { hasAccess: AccessState }) {
const label = hasAccess === null ? "Verificando acceso" : hasAccess ? "Disponible" : "Sin acceso";
const stateClass = hasAccess === null ? "access-indicator--checking" : hasAccess ? "access-indicator--granted" : "access-indicator--denied";
return (
<span className={`access-indicator ${stateClass}`} aria-label={label}>
<span aria-hidden="true" />
{label}
</span>
);
}
interface QuickLaunchProps {
app: HubApp;
isFavorite: boolean;
hasAccess: AccessState;
onActivate: (app: HubApp) => void;
onFavorite: (appId: string) => void;
}
function QuickLaunch({ app, isFavorite, onActivate, onFavorite }: QuickLaunchProps) {
function QuickLaunch({ app, isFavorite, hasAccess, onActivate, onFavorite }: QuickLaunchProps) {
const available = Boolean(getSafeUrl(app.url));
return (
<article className="quick-launch">
@@ -560,7 +576,10 @@ function QuickLaunch({ app, isFavorite, onActivate, onFavorite }: QuickLaunchPro
</button>
</div>
<div className="quick-launch__copy">
<span className="quick-launch__category">{app.category}</span>
<div className="quick-launch__meta">
<span className="quick-launch__category">{app.category}</span>
<AccessIndicator hasAccess={hasAccess} />
</div>
<h3>{app.name}</h3>
<p>{app.description}</p>
</div>
@@ -576,11 +595,12 @@ interface DirectoryRowProps {
app: HubApp;
index: number;
isFavorite: boolean;
hasAccess: AccessState;
onActivate: (app: HubApp) => void;
onFavorite: (appId: string) => void;
}
function DirectoryRow({ app, index, isFavorite, onActivate, onFavorite }: DirectoryRowProps) {
function DirectoryRow({ app, index, isFavorite, hasAccess, onActivate, onFavorite }: DirectoryRowProps) {
const available = Boolean(getSafeUrl(app.url));
return (
<article className="directory-row">
@@ -591,9 +611,8 @@ function DirectoryRow({ app, index, isFavorite, onActivate, onFavorite }: Direct
<p>{app.description}</p>
</div>
<span className="directory-row__category">{app.category}</span>
<span className={`availability ${available ? "availability--ready" : "availability--pending"}`}>
<span aria-hidden="true" />
{available ? "Disponible" : "Enlace pendiente"}
<span className="directory-row__status">
<AccessIndicator hasAccess={hasAccess} />
</span>
<button
type="button"
@@ -880,11 +899,13 @@ function Pagination({ currentPage, totalPages, onPageChange, compact = false, la
const HUB_ITEMS_PER_PAGE = 10;
const QUICK_ITEMS_PER_PAGE = 6;
const ADMIN_ITEMS_PER_PAGE = 10;
const ADMIN_ITEMS_PER_PAGE = 12;
interface HubViewProps {
user: HubUser;
data: HubData;
accessByApp: Record<string, boolean>;
accessReady: boolean;
storageWarning: string;
onActivate: (app: HubApp) => void;
onFavorite: (appId: string) => void;
@@ -892,7 +913,7 @@ interface HubViewProps {
onRequestAccess: (app: HubApp) => Promise<boolean>;
}
function HubView({ user, data, storageWarning, onActivate, onFavorite, onAdmin, onRequestAccess }: HubViewProps) {
function HubView({ user, data, accessByApp, accessReady, storageWarning, onActivate, onFavorite, onAdmin, onRequestAccess }: HubViewProps) {
const [categorySearches, setCategorySearches] = useState<Record<string, string>>({
Todas: "",
Administración: "",
@@ -1068,6 +1089,7 @@ function HubView({ user, data, storageWarning, onActivate, onFavorite, onAdmin,
key={app.id}
app={app}
isFavorite={favorites.has(app.id)}
hasAccess={accessReady ? accessByApp[app.id] === true : null}
onActivate={onActivate}
onFavorite={onFavorite}
/>
@@ -1152,6 +1174,7 @@ function HubView({ user, data, storageWarning, onActivate, onFavorite, onAdmin,
app={app}
index={(currentPage - 1) * HUB_ITEMS_PER_PAGE + index}
isFavorite={favorites.has(app.id)}
hasAccess={accessReady ? accessByApp[app.id] === true : null}
onActivate={onActivate}
onFavorite={onFavorite}
/>
@@ -1861,6 +1884,8 @@ function App() {
const [authReady, setAuthReady] = useState(false);
const [catalogReady, setCatalogReady] = useState(false);
const [catalogWarning, setCatalogWarning] = useState("");
const [accessByApp, setAccessByApp] = useState<Record<string, boolean>>({});
const [accessReady, setAccessReady] = useState(false);
const [loginError, setLoginError] = useState("");
const authorizationSequence = useRef(0);
const authorizedUserIdRef = useRef<string | null>(null);
@@ -2011,6 +2036,44 @@ function App() {
};
}, [activeUser?.id, activeUser?.role, initialLocalData.data.apps, notify]);
useEffect(() => {
if (!activeUser) {
setAccessByApp({});
setAccessReady(false);
return undefined;
}
let active = true;
let loading = false;
const refreshAccess = async () => {
if (loading) return;
loading = true;
try {
const accessMap = await fetchMyAppAccess();
if (!active) return;
setAccessByApp(accessMap);
setAccessReady(true);
} catch (error) {
console.warn("No se pudo verificar el acceso a las aplicaciones:", error);
if (active) setAccessReady(false);
} finally {
loading = false;
}
};
void refreshAccess();
const intervalId = window.setInterval(() => void refreshAccess(), 60_000);
const handleFocus = () => void refreshAccess();
window.addEventListener("focus", handleFocus);
return () => {
active = false;
window.clearInterval(intervalId);
window.removeEventListener("focus", handleFocus);
};
}, [activeUser?.id]);
useEffect(() => {
const syncViewWithHash = () => {
const requestedView: AppView = window.location.hash === "#admin" ? "admin" : "hub";
@@ -2240,6 +2303,8 @@ function App() {
}
setSession(null);
setCatalogReady(false);
setAccessByApp({});
setAccessReady(false);
setView("hub");
window.history.replaceState(null, "", getAppUrl());
};
@@ -2281,6 +2346,8 @@ function App() {
<HubView
user={session.user}
data={data}
accessByApp={accessByApp}
accessReady={accessReady}
storageWarning={catalogWarning}
onActivate={handleActivate}
onFavorite={(appId) => void handleFavorite(appId)}