{t("common.morale")}
diff --git a/src/components/manager/ManagerTab.tsx b/src/components/manager/ManagerTab.tsx
index 14f1178ad..8e9ad5dc0 100644
--- a/src/components/manager/ManagerTab.tsx
+++ b/src/components/manager/ManagerTab.tsx
@@ -6,9 +6,15 @@ import { formatDate } from "../../lib/helpers";
import { useTranslation } from "react-i18next";
import { countryName, allNationalities } from "../../lib/countries";
import DashboardModalFrame from "../dashboard/DashboardModalFrame";
-import { Settings, X, ChevronDown, Check } from "lucide-react";
+import { Settings, X, ChevronDown, Check, ImagePlus } from "lucide-react";
import { resolveStaffPhoto } from "../../lib/playerPhotos";
+const MANAGER_ICONS = Array.from({ length: 29 }, (_, i) => {
+ // icons 0-28, skip 2 (doesn't exist)
+ if (i === 2) return null;
+ return `/manager-icons/${i}.webp`;
+}).filter(Boolean) as string[];
+
interface ManagerTabProps {
gameState: GameStateData;
}
@@ -22,6 +28,30 @@ export default function ManagerTab({ gameState }: ManagerTabProps) {
const fullName = `${mgr.first_name} ${mgr.last_name}`;
const displayName = mgr.nickname?.trim() || fullName;
+ // Avatar picker state
+ const [showAvatarPicker, setShowAvatarPicker] = useState(false);
+ const [isSavingAvatar, setIsSavingAvatar] = useState(false);
+
+ const handleSelectAvatar = async (avatarPath: string) => {
+ setIsSavingAvatar(true);
+ try {
+ await invoke("update_manager_profile", {
+ nickname: null, firstName: null, lastName: null,
+ dob: null, nationality: null,
+ avatarPath,
+ });
+ setGameState({
+ ...gameState,
+ manager: { ...mgr, avatar_path: avatarPath },
+ });
+ setShowAvatarPicker(false);
+ } catch (error) {
+ console.error("Failed to update avatar:", error);
+ } finally {
+ setIsSavingAvatar(false);
+ }
+ };
+
// Settings modal state
const [showSettings, setShowSettings] = useState(false);
const [isSaving, setIsSaving] = useState(false);
@@ -111,13 +141,20 @@ export default function ManagerTab({ gameState }: ManagerTabProps) {
{/* Profile card */}
-
+
setShowAvatarPicker(true)}
+ title={t("manager.changeAvatar", "Cambiar avatar")}
+ >
)
+
+
+
{displayName}
@@ -149,6 +186,50 @@ export default function ManagerTab({ gameState }: ManagerTabProps) {
+ {/* Avatar Picker Modal */}
+ {showAvatarPicker && (
+
+
+
+
+ {t("manager.changeAvatar", "Seleccionar avatar")}
+
+
+
+ {isSavingAvatar ? (
+
+ {t("common.saving", "Guardando...")}
+
+ ) : (
+
+ {MANAGER_ICONS.map((path) => (
+
+ ))}
+
+ )}
+
+
+ )}
+
{/* Settings Modal */}
{showSettings && (
diff --git a/src/components/match/ChampionDraft.tsx b/src/components/match/ChampionDraft.tsx
index 1f76c1b0b..0bb50efaa 100644
--- a/src/components/match/ChampionDraft.tsx
+++ b/src/components/match/ChampionDraft.tsx
@@ -5,8 +5,8 @@ import type { GameStateData, ScrimReportData } from "../../store/gameStore";
import { useSettingsStore } from "../../store/settingsStore";
import { getChampionTiming } from "../../lib/championTiming";
import { getLolStaffEffectsForTeam } from "../../lib/lolStaffEffects";
-import { resolvePlayerPhoto } from "../../lib/playerPhotos";
import { resolvePlayerLolRole } from "../../lib/lolIdentity";
+import { ROLE_ICON_PATHS } from "../../lib/roleIcons";
import teamsSeed from "../../../data/draft/teams.json";
import playersSeed from "../../../data/draft/players.json";
import championsSeed from "../../../data/draft/champions.json";
@@ -285,15 +285,7 @@ const ROLE_ORDER: Role[] = ["TOP", "JUNGLE", "MID", "ADC", "SUPPORT"];
const ASSISTANT_COACH_PLACEHOLDER = "/player-photos/103935359525547325.webp";
const LEC_LOGO_URL = "/lec-logo.svg";
const EMPTY_LOCKED_CHAMPION_IDS: string[] = [];
-const ROLE_ICON_URLS: Record = {
- TOP: "https://raw.communitydragon.org/latest/plugins/rcp-fe-lol-clash/global/default/assets/images/position-selector/positions/icon-position-top.webp",
- JUNGLE:
- "https://raw.communitydragon.org/latest/plugins/rcp-fe-lol-clash/global/default/assets/images/position-selector/positions/icon-position-jungle.webp",
- MID: "https://raw.communitydragon.org/latest/plugins/rcp-fe-lol-clash/global/default/assets/images/position-selector/positions/icon-position-middle.webp",
- ADC: "https://raw.communitydragon.org/latest/plugins/rcp-fe-lol-clash/global/default/assets/images/position-selector/positions/icon-position-bottom.webp",
- SUPPORT:
- "https://raw.communitydragon.org/latest/plugins/rcp-fe-lol-clash/global/default/assets/images/position-selector/positions/icon-position-utility.webp",
-};
+const ROLE_ICON_URLS: Record = ROLE_ICON_PATHS;
const DRAFT_SEQUENCE: DraftAction[] = [
{ type: "ban", side: "blue", label: "B1" },
@@ -706,12 +698,17 @@ function teamTriCode(name: string): string {
return cleaned.slice(0, 4).toUpperCase();
}
-function teamLogo(name: string): string | null {
+function teamLogo(name: string, teams?: import("../../store/types").TeamData[]): string | null {
+ const normalizedName = normalizeKey(name);
+ if (teams) {
+ const fromTeams = teams.find((t) => normalizeKey(t.name) === normalizedName);
+ if (fromTeams?.logo_url) return fromTeams.logo_url;
+ }
+
const key = name.trim().toLowerCase();
const known = TEAM_BRAND_MAP[key]?.logo;
if (known) return known;
- const normalizedName = normalizeKey(name);
const fromSeed = TEAM_SEEDS.find((team) => normalizeKey(team.name) === normalizedName);
if (fromSeed?.logo) {
const logoFileName = fromSeed.logo.split("/").pop();
@@ -2247,7 +2244,7 @@ export default function ChampionDraft({
const sourceRole = mapSeedRoleToDraftRole(String(matchedSeedPlayer?.role ?? "")) ?? ROLE_ORDER[index];
const sourceImage =
- resolvePlayerPhoto(player.id, player.name) ??
+ player.profile_image_url ??
playerSeedPhotoUrl(matchedSeedPlayer?.photo) ??
`/player-photos/${player.id}.webp`;
@@ -2384,7 +2381,7 @@ export default function ChampionDraft({
sourceName: fallbackPlayer.name,
sourceRole: mapSeedRoleToDraftRole(String(fallbackSeedPlayer?.role ?? "")) ?? ROLE_ORDER[0],
sourceImage:
- resolvePlayerPhoto(fallbackPlayer.id, fallbackPlayer.name) ??
+ fallbackPlayer.profile_image_url ??
playerSeedPhotoUrl(fallbackSeedPlayer?.photo) ??
`/player-photos/${fallbackPlayer.id}.webp`,
type: "pick",
@@ -2515,8 +2512,8 @@ export default function ChampionDraft({
const blueTriCode = teamTriCode(snapshot.home_team.name);
const redTriCode = teamTriCode(snapshot.away_team.name);
const controlledTriCode = controlledSide === "blue" ? blueTriCode : redTriCode;
- const blueLogo = teamLogo(snapshot.home_team.name);
- const redLogo = teamLogo(snapshot.away_team.name);
+ const blueLogo = teamLogo(snapshot.home_team.name, gameState?.teams);
+ const redLogo = teamLogo(snapshot.away_team.name, gameState?.teams);
const seriesSquares = seriesLength === 5 ? 3 : seriesLength === 3 ? 2 : 0;
const scoreDelta = controlledScore.total - rivalScore.total;
const blueWinProb = Math.max(5, Math.min(95, Math.round(50 + scoreDelta * 4)));
@@ -2548,11 +2545,11 @@ export default function ChampionDraft({
const topSectionHeightClass = seriesBansRequiresTwoRows ? "h-28" : "h-20";
return (
-
+
-
+
))}
-
+
{seriesSquares > 0 ? (
@@ -2768,11 +2765,11 @@ export default function ChampionDraft({
-
+