import React from "react";
import { ImageProps } from "next/image";
import ImageWithFallBack from "./ImageWithFallBack";
type ImgTypesWithoutOption = "pixel_head" | "skin";
type ImgTypesWithOption = "standing" | "mojavatar" | "reading" | "sit";
type ImgTypes = ImgTypesWithoutOption | ImgTypesWithOption;
type SkinTypeWithOption = { type: "full" | "bust" | "face" };
type MinecraftSkinProps = (
| {
skinType: ImgTypesWithOption;
skinOption?: SkinTypeWithOption;
}
| {
skinType: ImgTypesWithoutOption;
skinOption?: never;
}
) & {
player: string;
} & Omit<ImageProps, "src">;
const MINESKIN_BASE = process.env.NEXT_PUBLIC_MINESKIN_BASE_URL;
const STARLIGHT_BASE = process.env.NEXT_PUBLIC_STARTLIGHTSKINS_BASE_URL;
export const FALLBACK_PLAYER =
process.env.NEXT_PUBLIC_FALLBACK_PLAYER || "billetspara";
const MinecraftSkin = ({
player,
skinType,
skinOption,
...props
}: MinecraftSkinProps) => {
const generateUrl = (
playerName: string,
type: ImgTypes,
option?: SkinTypeWithOption
): string => {
if (typeof playerName === undefined) {
playerName = FALLBACK_PLAYER;
}
switch (type) {
case "pixel_head":
return `${MINESKIN_BASE}/helm/${playerName}/512`;
case "skin":
return `${STARLIGHT_BASE}/skin/${playerName}/default`;
case "standing":
return `${STARLIGHT_BASE}/ultimate/${playerName}/${
option?.type || "full"
}`;
case "mojavatar":
return `${STARLIGHT_BASE}/mojavatar/${playerName}/${
option?.type || "full"
}`;
case "reading":
return `${STARLIGHT_BASE}/reading/${playerName}/${
option?.type || "full"
}`;
case "sit":
return `${STARLIGHT_BASE}/criss_cross/${playerName}/${
option?.type || "full"
}`;
default:
const exhaustiveCheck: never = type;
throw new Error(`Unhandled skin type: ${exhaustiveCheck}`);
}
};
const playerSrc = generateUrl(player, skinType, skinOption);
const fallbackSrc = generateUrl(FALLBACK_PLAYER, skinType, skinOption);
return (
<ImageWithFallBack
key={`${player}-${skinType}-${skinOption?.type || "full"}`}
src={playerSrc}
fallback={fallbackSrc}
{...props}
/>
);
};
export default MinecraftSkin;
The MinecraftSkin component, used inside a .map function to fetch and display player skins, occasionally fails to load the requested skin due to a connection timeout error. When this happens, it defaults to the fallback skin