mirror of
https://github.com/walkxcode/dashboard-icons.git
synced 2025-11-19 01:57:29 +01:00
VIbe-code some optimizations
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import { unstable_cache } from "next/cache"
|
import { unstable_cache } from "next/cache";
|
||||||
import { cache } from "react"
|
import { cache } from "react";
|
||||||
import { METADATA_URL } from "@/constants"
|
import { METADATA_URL } from "@/constants";
|
||||||
import { ApiError } from "@/lib/errors"
|
import { ApiError } from "@/lib/errors";
|
||||||
import type { AuthorData, IconFile, IconWithName } from "@/types/icons"
|
import type { AuthorData, IconFile, IconWithName } from "@/types/icons";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw fetch function for icon data (without caching)
|
* Raw fetch function for icon data (without caching)
|
||||||
@@ -11,19 +11,22 @@ async function fetchAllIconsRaw(): Promise<IconFile> {
|
|||||||
try {
|
try {
|
||||||
const response = await fetch(METADATA_URL, {
|
const response = await fetch(METADATA_URL, {
|
||||||
next: { revalidate: 3600 },
|
next: { revalidate: 3600 },
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new ApiError(`Failed to fetch icons: ${response.statusText}`, response.status)
|
throw new ApiError(
|
||||||
|
`Failed to fetch icons: ${response.statusText}`,
|
||||||
|
response.status,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (await response.json()) as IconFile
|
return (await response.json()) as IconFile;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof ApiError) {
|
if (error instanceof ApiError) {
|
||||||
throw error
|
throw error;
|
||||||
}
|
}
|
||||||
console.error("Error fetching icons:", error)
|
console.error("Error fetching icons:", error);
|
||||||
throw new ApiError("Failed to fetch icons data. Please try again later.")
|
throw new ApiError("Failed to fetch icons data. Please try again later.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,10 +34,14 @@ async function fetchAllIconsRaw(): Promise<IconFile> {
|
|||||||
* Cached version using unstable_cache for build-time caching
|
* Cached version using unstable_cache for build-time caching
|
||||||
* Revalidates every hour (3600 seconds)
|
* Revalidates every hour (3600 seconds)
|
||||||
*/
|
*/
|
||||||
const getAllIconsCached = unstable_cache(async () => fetchAllIconsRaw(), ["all-icons"], {
|
const getAllIconsCached = unstable_cache(
|
||||||
revalidate: 3600,
|
async () => fetchAllIconsRaw(),
|
||||||
tags: ["icons"],
|
["all-icons"],
|
||||||
})
|
{
|
||||||
|
revalidate: 3600,
|
||||||
|
tags: ["icons"],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches all icon data from the metadata.json file
|
* Fetches all icon data from the metadata.json file
|
||||||
@@ -42,63 +49,65 @@ const getAllIconsCached = unstable_cache(async () => fetchAllIconsRaw(), ["all-i
|
|||||||
* This prevents duplicate fetches within the same request and across builds
|
* This prevents duplicate fetches within the same request and across builds
|
||||||
*/
|
*/
|
||||||
export const getAllIcons = cache(async (): Promise<IconFile> => {
|
export const getAllIcons = cache(async (): Promise<IconFile> => {
|
||||||
return getAllIconsCached()
|
return getAllIconsCached();
|
||||||
})
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of all icon names.
|
* Gets a list of all icon names.
|
||||||
*/
|
*/
|
||||||
export const getIconNames = async (): Promise<string[]> => {
|
export const getIconNames = async (): Promise<string[]> => {
|
||||||
try {
|
try {
|
||||||
const iconsData = await getAllIcons()
|
const iconsData = await getAllIcons();
|
||||||
return Object.keys(iconsData)
|
return Object.keys(iconsData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error getting icon names:", error)
|
console.error("Error getting icon names:", error);
|
||||||
throw error
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts icon data to an array format for easier rendering
|
* Converts icon data to an array format for easier rendering
|
||||||
*/
|
*/
|
||||||
export async function getIconsArray(): Promise<IconWithName[]> {
|
export async function getIconsArray(): Promise<IconWithName[]> {
|
||||||
try {
|
try {
|
||||||
const iconsData = await getAllIcons()
|
const iconsData = await getAllIcons();
|
||||||
|
|
||||||
return Object.entries(iconsData)
|
return Object.entries(iconsData)
|
||||||
.map(([name, data]) => ({
|
.map(([name, data]) => ({
|
||||||
name,
|
name,
|
||||||
data,
|
data,
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => a.name.localeCompare(b.name))
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error getting icons array:", error)
|
console.error("Error getting icons array:", error);
|
||||||
throw error
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches data for a specific icon
|
* Fetches data for a specific icon
|
||||||
*/
|
*/
|
||||||
export async function getIconData(iconName: string): Promise<IconWithName | null> {
|
export async function getIconData(
|
||||||
|
iconName: string,
|
||||||
|
): Promise<IconWithName | null> {
|
||||||
try {
|
try {
|
||||||
const iconsData = await getAllIcons()
|
const iconsData = await getAllIcons();
|
||||||
const iconData = iconsData[iconName]
|
const iconData = iconsData[iconName];
|
||||||
|
|
||||||
if (!iconData) {
|
if (!iconData) {
|
||||||
throw new ApiError(`Icon '${iconName}' not found`, 404)
|
throw new ApiError(`Icon '${iconName}' not found`, 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: iconName,
|
name: iconName,
|
||||||
data: iconData,
|
data: iconData,
|
||||||
}
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof ApiError && error.status === 404) {
|
if (error instanceof ApiError && error.status === 404) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
console.error("Error getting icon data:", error)
|
console.error("Error getting icon data:", error);
|
||||||
throw error
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,26 +120,31 @@ async function fetchAuthorData(authorId: number) {
|
|||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
// If unauthorized or other error, return a default user object
|
// If unauthorized or other error, return a default user object
|
||||||
if (response.status === 401 || response.status === 403) {
|
if (response.status === 401 || response.status === 403) {
|
||||||
console.warn(`GitHub API rate limit or authorization issue: ${response.statusText}`)
|
console.warn(
|
||||||
|
`GitHub API rate limit or authorization issue: ${response.statusText}`,
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
login: "unknown",
|
login: "unknown",
|
||||||
avatar_url: "https://avatars.githubusercontent.com/u/0",
|
avatar_url: "https://avatars.githubusercontent.com/u/0",
|
||||||
html_url: "https://github.com",
|
html_url: "https://github.com",
|
||||||
name: "Unknown User",
|
name: "Unknown User",
|
||||||
bio: null,
|
bio: null,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
throw new ApiError(`Failed to fetch author data: ${response.statusText}`, response.status)
|
throw new ApiError(
|
||||||
|
`Failed to fetch author data: ${response.statusText}`,
|
||||||
|
response.status,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json()
|
return response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching author data:", error)
|
console.error("Error fetching author data:", error);
|
||||||
// Even for unexpected errors, return a default user to prevent page failures
|
// Even for unexpected errors, return a default user to prevent page failures
|
||||||
return {
|
return {
|
||||||
login: "unknown",
|
login: "unknown",
|
||||||
@@ -138,11 +152,11 @@ async function fetchAuthorData(authorId: number) {
|
|||||||
html_url: "https://github.com",
|
html_url: "https://github.com",
|
||||||
name: "Unknown User",
|
name: "Unknown User",
|
||||||
bio: null,
|
bio: null,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const authorDataCache: Record<number, AuthorData> = {}
|
const authorDataCache: Record<number, AuthorData> = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cached version of fetchAuthorData
|
* Cached version of fetchAuthorData
|
||||||
@@ -155,12 +169,12 @@ const authorDataCache: Record<number, AuthorData> = {}
|
|||||||
*/
|
*/
|
||||||
export async function getAuthorData(authorId: number): Promise<AuthorData> {
|
export async function getAuthorData(authorId: number): Promise<AuthorData> {
|
||||||
if (authorDataCache[authorId]) {
|
if (authorDataCache[authorId]) {
|
||||||
return authorDataCache[authorId]
|
return authorDataCache[authorId];
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchAuthorData(authorId)
|
const data = await fetchAuthorData(authorId);
|
||||||
authorDataCache[authorId] = data
|
authorDataCache[authorId] = data;
|
||||||
return data
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,32 +182,37 @@ export async function getAuthorData(authorId: number): Promise<AuthorData> {
|
|||||||
*/
|
*/
|
||||||
export async function getTotalIcons() {
|
export async function getTotalIcons() {
|
||||||
try {
|
try {
|
||||||
const iconsData = await getAllIcons()
|
const iconsData = await getAllIcons();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
totalIcons: Object.keys(iconsData).length,
|
totalIcons: Object.keys(iconsData).length,
|
||||||
}
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error getting total icons:", error)
|
console.error("Error getting total icons:", error);
|
||||||
throw error
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches recently added icons sorted by timestamp
|
* Fetches recently added icons sorted by timestamp
|
||||||
*/
|
*/
|
||||||
export async function getRecentlyAddedIcons(limit = 8): Promise<IconWithName[]> {
|
export async function getRecentlyAddedIcons(
|
||||||
|
limit = 8,
|
||||||
|
): Promise<IconWithName[]> {
|
||||||
try {
|
try {
|
||||||
const icons = await getIconsArray()
|
const icons = await getIconsArray();
|
||||||
|
|
||||||
return icons
|
return icons
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
// Sort by timestamp in descending order (newest first)
|
// Sort by timestamp in descending order (newest first)
|
||||||
return new Date(b.data.update.timestamp).getTime() - new Date(a.data.update.timestamp).getTime()
|
return (
|
||||||
|
new Date(b.data.update.timestamp).getTime() -
|
||||||
|
new Date(a.data.update.timestamp).getTime()
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.slice(0, limit)
|
.slice(0, limit);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error getting recently added icons:", error)
|
console.error("Error getting recently added icons:", error);
|
||||||
throw error
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user