mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-28 17:07:57 +00:00
cosmetic refactor (#3628)
## Description: The motivation is to have a single "cosmetic-button" element, so we can abstract out the cosmetic types. This will make it much easier to add new cosmetic types in the future. Unifies PatternButton and FlagButton into a single CosmeticButton component. Extracts a resolveCosmetics() function that flattens patterns × color palettes + flags into a ResolvedCosmetic[] with relationship status pre-computed, replacing duplicated resolution logic across four callers. * New CosmeticButton — renders patterns or flags based on ResolvedCosmetic.type * New resolveCosmetics() — centralizes ownership/purchase/blocked resolution * Extracted PatternPreview — canvas rendering split into its own module * Added type: "pattern" | "flag" discriminator to Zod cosmetic schemas * Deleted FlagButton.ts and PatternButton.ts * Added 320-line test suite for resolveCosmetics ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: evan
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { assetUrl } from "src/core/AssetUrls";
|
||||
import { UserMeResponse } from "../core/ApiSchemas";
|
||||
import {
|
||||
ColorPalette,
|
||||
Cosmetics,
|
||||
CosmeticsSchema,
|
||||
Flag,
|
||||
@@ -188,6 +189,90 @@ export function flagRelationship(
|
||||
);
|
||||
}
|
||||
|
||||
export type ResolvedCosmetic = {
|
||||
type: "pattern" | "flag";
|
||||
cosmetic: Pattern | Flag | null;
|
||||
colorPalette: ColorPalette | null;
|
||||
relationship: "owned" | "purchasable" | "blocked";
|
||||
/** Unique key for selection/identity, e.g. "pattern:hearts:red" or "flag:cool_flag" */
|
||||
key: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves all cosmetics into a flat display-ready list with relationship
|
||||
* status and resolved color palettes. Callers can filter by relationship.
|
||||
*/
|
||||
export function resolveCosmetics(
|
||||
cosmetics: Cosmetics | null,
|
||||
userMeResponse: UserMeResponse | false,
|
||||
affiliateCode: string | null,
|
||||
): ResolvedCosmetic[] {
|
||||
if (!cosmetics) return [];
|
||||
const result: ResolvedCosmetic[] = [];
|
||||
|
||||
// Default pattern (always owned)
|
||||
result.push({
|
||||
type: "pattern",
|
||||
cosmetic: null,
|
||||
colorPalette: null,
|
||||
relationship: "owned",
|
||||
key: "pattern:default",
|
||||
});
|
||||
|
||||
// Patterns × color palettes
|
||||
for (const [patternKey, pattern] of Object.entries(cosmetics.patterns)) {
|
||||
const colorPalettes = [...(pattern.colorPalettes ?? []), null];
|
||||
for (const cp of colorPalettes) {
|
||||
const rel = patternRelationship(
|
||||
pattern,
|
||||
cp,
|
||||
userMeResponse,
|
||||
affiliateCode,
|
||||
);
|
||||
const resolvedPalette = cp
|
||||
? (cosmetics.colorPalettes?.[cp.name] ?? null)
|
||||
: null;
|
||||
const key = cp
|
||||
? `pattern:${patternKey}:${cp.name}`
|
||||
: `pattern:${patternKey}`;
|
||||
result.push({
|
||||
type: "pattern",
|
||||
cosmetic: pattern,
|
||||
colorPalette: resolvedPalette,
|
||||
relationship: rel,
|
||||
key,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Flags
|
||||
for (const [flagKey, flag] of Object.entries(cosmetics.flags)) {
|
||||
const rel = flagRelationship(flag, userMeResponse, affiliateCode);
|
||||
result.push({
|
||||
type: "flag",
|
||||
cosmetic: flag,
|
||||
colorPalette: null,
|
||||
relationship: rel,
|
||||
key: `flag:${flagKey}`,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function resolvedToPlayerPattern(
|
||||
resolved: ResolvedCosmetic,
|
||||
): PlayerPattern | null {
|
||||
if (resolved.type !== "pattern") return null;
|
||||
const c = resolved.cosmetic;
|
||||
if (c === null) return null;
|
||||
return {
|
||||
name: c.name,
|
||||
patternData: (c as Pattern).pattern,
|
||||
colorPalette: resolved.colorPalette ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getPlayerCosmeticsRefs(): Promise<PlayerCosmeticRefs> {
|
||||
const userSettings = new UserSettings();
|
||||
const cosmetics = await fetchCosmetics();
|
||||
|
||||
Reference in New Issue
Block a user