mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
Update use-directories.ts
This commit is contained in:
+97
-179
@@ -35,6 +35,7 @@ const CACHE_MAX_AGE_MS = 60 * 60 * 1000; // 1 hour
|
|||||||
|
|
||||||
let cacheCommunities: DirectoryCommunity[] | null = null;
|
let cacheCommunities: DirectoryCommunity[] | null = null;
|
||||||
let cacheMetadata: DirectoriesMetadata | null = null;
|
let cacheMetadata: DirectoriesMetadata | null = null;
|
||||||
|
let inFlightGitHubFetch: Promise<DirectoriesData> | null = null;
|
||||||
|
|
||||||
const getFromLocalStorage = (): DirectoriesData | null => {
|
const getFromLocalStorage = (): DirectoriesData | null => {
|
||||||
try {
|
try {
|
||||||
@@ -61,21 +62,24 @@ const saveToLocalStorage = (data: DirectoriesData) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchDirectoriesData = async (): Promise<DirectoriesData> => {
|
const fetchDirectoriesFromGitHub = async (): Promise<DirectoriesData> => {
|
||||||
try {
|
const response = await fetch(GITHUB_URL, { cache: 'no-cache' });
|
||||||
const response = await fetch(GITHUB_URL);
|
if (!response.ok) {
|
||||||
if (!response.ok) {
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
|
||||||
}
|
|
||||||
const data = await response.json();
|
|
||||||
// Save successful fetch to localStorage
|
|
||||||
saveToLocalStorage(data);
|
|
||||||
return data;
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('Failed to fetch directories from GitHub, using vendored fallback:', e);
|
|
||||||
// Fall back to vendored file
|
|
||||||
return directoriesData as DirectoriesData;
|
|
||||||
}
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
// Save successful fetch to localStorage
|
||||||
|
saveToLocalStorage(data);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchDirectoriesFromGitHubDeduped = async (): Promise<DirectoriesData> => {
|
||||||
|
if (!inFlightGitHubFetch) {
|
||||||
|
inFlightGitHubFetch = fetchDirectoriesFromGitHub().finally(() => {
|
||||||
|
inFlightGitHubFetch = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return inFlightGitHubFetch;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useDirectories = () => {
|
export const useDirectories = () => {
|
||||||
@@ -88,69 +92,42 @@ export const useDirectories = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cacheCommunities) {
|
|
||||||
setState({
|
|
||||||
communities: cacheCommunities,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isMounted = true;
|
let isMounted = true;
|
||||||
|
const hydrateCommunities = (data: DirectoriesData) => {
|
||||||
|
cacheCommunities = data.communities;
|
||||||
|
if (isMounted) {
|
||||||
|
setState({
|
||||||
|
communities: data.communities,
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
if (cacheCommunities) {
|
||||||
|
setState({
|
||||||
|
communities: cacheCommunities,
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
// Check localStorage first
|
// Check localStorage first
|
||||||
const cachedData = getFromLocalStorage();
|
const cachedData = getFromLocalStorage();
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
cacheCommunities = cachedData.communities;
|
hydrateCommunities(cachedData);
|
||||||
if (isMounted) {
|
|
||||||
setState({
|
|
||||||
communities: cachedData.communities,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Still try to fetch fresh data in background (don't await)
|
|
||||||
fetchDirectoriesData()
|
|
||||||
.then((data) => {
|
|
||||||
if (isMounted) {
|
|
||||||
cacheCommunities = data.communities;
|
|
||||||
setState({
|
|
||||||
communities: data.communities,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.warn('Background fetch failed:', e);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// No cache, fetch fresh data
|
try {
|
||||||
const directories = await fetchDirectoriesData();
|
// Always attempt a background refresh from GitHub to pick up list updates
|
||||||
if (isMounted) {
|
const directories = await fetchDirectoriesFromGitHubDeduped();
|
||||||
cacheCommunities = directories.communities;
|
hydrateCommunities(directories);
|
||||||
setState({
|
|
||||||
communities: directories.communities,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to load directories:', e);
|
console.warn('Failed to fetch directories from GitHub:', e);
|
||||||
// Fallback to vendored data
|
// Only fall back if we don't already have memory/localStorage data
|
||||||
const fallbackData = directoriesData as DirectoriesData;
|
if (!cacheCommunities) {
|
||||||
if (isMounted) {
|
hydrateCommunities(directoriesData as DirectoriesData);
|
||||||
cacheCommunities = fallbackData.communities;
|
|
||||||
setState({
|
|
||||||
communities: fallbackData.communities,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
@@ -175,69 +152,42 @@ export const useDirectoriesState = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cacheCommunities) {
|
|
||||||
setState({
|
|
||||||
communities: cacheCommunities,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isMounted = true;
|
let isMounted = true;
|
||||||
|
const hydrateCommunities = (data: DirectoriesData) => {
|
||||||
|
cacheCommunities = data.communities;
|
||||||
|
if (isMounted) {
|
||||||
|
setState({
|
||||||
|
communities: data.communities,
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
if (cacheCommunities) {
|
||||||
|
setState({
|
||||||
|
communities: cacheCommunities,
|
||||||
|
loading: false,
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
// Check localStorage first
|
// Check localStorage first
|
||||||
const cachedData = getFromLocalStorage();
|
const cachedData = getFromLocalStorage();
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
cacheCommunities = cachedData.communities;
|
hydrateCommunities(cachedData);
|
||||||
if (isMounted) {
|
|
||||||
setState({
|
|
||||||
communities: cachedData.communities,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Still try to fetch fresh data in background (don't await)
|
|
||||||
fetchDirectoriesData()
|
|
||||||
.then((data) => {
|
|
||||||
if (isMounted) {
|
|
||||||
cacheCommunities = data.communities;
|
|
||||||
setState({
|
|
||||||
communities: data.communities,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.warn('Background fetch failed:', e);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// No cache, fetch fresh data
|
try {
|
||||||
const directories = await fetchDirectoriesData();
|
// Always attempt a background refresh from GitHub to pick up list updates
|
||||||
if (isMounted) {
|
const directories = await fetchDirectoriesFromGitHubDeduped();
|
||||||
cacheCommunities = directories.communities;
|
hydrateCommunities(directories);
|
||||||
setState({
|
|
||||||
communities: directories.communities,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to load directories:', e);
|
console.warn('Failed to fetch directories from GitHub:', e);
|
||||||
// Fallback to vendored data
|
// Only fall back if we don't already have memory/localStorage data
|
||||||
const fallbackData = directoriesData as DirectoriesData;
|
if (!cacheCommunities) {
|
||||||
if (isMounted) {
|
hydrateCommunities(directoriesData as DirectoriesData);
|
||||||
cacheCommunities = fallbackData.communities;
|
|
||||||
setState({
|
|
||||||
communities: fallbackData.communities,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
@@ -259,72 +209,40 @@ export const useDirectoriesMetadata = () => {
|
|||||||
const [metadata, setMetadata] = useState<DirectoriesMetadata | null>(null);
|
const [metadata, setMetadata] = useState<DirectoriesMetadata | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cacheMetadata) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isMounted = true;
|
let isMounted = true;
|
||||||
|
const hydrateMetadata = (data: DirectoriesData) => {
|
||||||
|
const nextMetadata: DirectoriesMetadata = {
|
||||||
|
title: data.title,
|
||||||
|
description: data.description,
|
||||||
|
createdAt: data.createdAt,
|
||||||
|
updatedAt: data.updatedAt,
|
||||||
|
};
|
||||||
|
cacheMetadata = nextMetadata;
|
||||||
|
if (isMounted) {
|
||||||
|
setMetadata(nextMetadata);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
if (cacheMetadata) {
|
||||||
|
setMetadata(cacheMetadata);
|
||||||
|
} else {
|
||||||
// Check localStorage first
|
// Check localStorage first
|
||||||
const cachedData = getFromLocalStorage();
|
const cachedData = getFromLocalStorage();
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
const metadata: DirectoriesMetadata = {
|
hydrateMetadata(cachedData);
|
||||||
title: cachedData.title,
|
|
||||||
description: cachedData.description,
|
|
||||||
createdAt: cachedData.createdAt,
|
|
||||||
updatedAt: cachedData.updatedAt,
|
|
||||||
};
|
|
||||||
cacheMetadata = metadata;
|
|
||||||
if (isMounted) {
|
|
||||||
setMetadata(metadata);
|
|
||||||
}
|
|
||||||
// Still try to fetch fresh data in background (don't await)
|
|
||||||
fetchDirectoriesData()
|
|
||||||
.then((data) => {
|
|
||||||
if (isMounted) {
|
|
||||||
const freshMetadata: DirectoriesMetadata = {
|
|
||||||
title: data.title,
|
|
||||||
description: data.description,
|
|
||||||
createdAt: data.createdAt,
|
|
||||||
updatedAt: data.updatedAt,
|
|
||||||
};
|
|
||||||
cacheMetadata = freshMetadata;
|
|
||||||
setMetadata(freshMetadata);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.warn('Background metadata fetch failed:', e);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// No cache, fetch fresh data
|
try {
|
||||||
const directories = await fetchDirectoriesData();
|
// Always attempt a background refresh from GitHub to pick up metadata updates
|
||||||
if (isMounted) {
|
const directories = await fetchDirectoriesFromGitHubDeduped();
|
||||||
const metadata: DirectoriesMetadata = {
|
hydrateMetadata(directories);
|
||||||
title: directories.title,
|
|
||||||
description: directories.description,
|
|
||||||
createdAt: directories.createdAt,
|
|
||||||
updatedAt: directories.updatedAt,
|
|
||||||
};
|
|
||||||
cacheMetadata = metadata;
|
|
||||||
setMetadata(metadata);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to load metadata, using vendored fallback:', e);
|
console.warn('Failed to fetch directory metadata from GitHub:', e);
|
||||||
// Fallback to vendored data
|
// Only fall back if we don't already have memory/localStorage data
|
||||||
const fallbackData = directoriesData as DirectoriesData;
|
if (!cacheMetadata) {
|
||||||
if (isMounted) {
|
hydrateMetadata(directoriesData as DirectoriesData);
|
||||||
const metadata: DirectoriesMetadata = {
|
|
||||||
title: fallbackData.title,
|
|
||||||
description: fallbackData.description,
|
|
||||||
createdAt: fallbackData.createdAt,
|
|
||||||
updatedAt: fallbackData.updatedAt,
|
|
||||||
};
|
|
||||||
cacheMetadata = metadata;
|
|
||||||
setMetadata(metadata);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user