Agregar overrides de team/country y guardado desde ScoreboardPanel

This commit is contained in:
Pandipipas
2026-02-11 01:05:05 +01:00
parent b3f4aae68a
commit 04dbe94e34
5 changed files with 268 additions and 21 deletions
+24
View File
@@ -19,6 +19,22 @@
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"leftTeamOverride": {
"type": "string",
"default": ""
},
"rightTeamOverride": {
"type": "string",
"default": ""
},
"leftCountryOverride": {
"type": "string",
"default": ""
},
"rightCountryOverride": {
"type": "string",
"default": ""
},
"leftScore": { "leftScore": {
"type": "integer", "type": "integer",
"default": 0, "default": 0,
@@ -39,6 +55,10 @@
"rightPlayerId", "rightPlayerId",
"leftNameOverride", "leftNameOverride",
"rightNameOverride", "rightNameOverride",
"leftTeamOverride",
"rightTeamOverride",
"leftCountryOverride",
"rightCountryOverride",
"leftScore", "leftScore",
"rightScore", "rightScore",
"round" "round"
@@ -48,6 +68,10 @@
"rightPlayerId": "", "rightPlayerId": "",
"leftNameOverride": "", "leftNameOverride": "",
"rightNameOverride": "", "rightNameOverride": "",
"leftTeamOverride": "",
"rightTeamOverride": "",
"leftCountryOverride": "",
"rightCountryOverride": "",
"leftScore": 0, "leftScore": 0,
"rightScore": 0, "rightScore": 0,
"round": "" "round": ""
@@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, watchEffect } from 'vue'; import { computed, ref, watch, watchEffect, type Ref } from 'vue';
import type { Schemas } from '../../../types'; import type { Schemas } from '../../../types';
import { countryOptions, getCountryLabel } from '../../../shared/countries';
import { usePlayersStore } from '../stores/players'; import { usePlayersStore } from '../stores/players';
import { useScoreboardStore } from '../stores/scoreboard'; import { useScoreboardStore } from '../stores/scoreboard';
@@ -14,6 +15,11 @@ const rightInput = ref('');
const leftFocused = ref(false); const leftFocused = ref(false);
const rightFocused = ref(false); const rightFocused = ref(false);
const leftCountryInput = ref('');
const rightCountryInput = ref('');
const leftCountryOptions = ref(countryOptions);
const rightCountryOptions = ref(countryOptions);
const normalizeName = (value: string) => value.trim().toLowerCase(); const normalizeName = (value: string) => value.trim().toLowerCase();
const filterOptions = ( const filterOptions = (
@@ -27,6 +33,30 @@ const filterOptions = (
return options.filter((option) => option.label.toLowerCase().includes(lowerNeedle)); return options.filter((option) => option.label.toLowerCase().includes(lowerNeedle));
}; };
const filterCountries = (
value: string,
update: (callback: () => void) => void,
target: Ref<{ value: string; label: string }[]>,
) => {
update(() => {
const needle = value.toLowerCase().trim();
if (!needle) {
target.value = countryOptions;
return;
}
target.value = countryOptions.filter((country) => country.label.toLowerCase().includes(needle));
});
};
const onLeftCountryFilter = (value: string, update: (callback: () => void) => void) => {
filterCountries(value, update, leftCountryOptions);
};
const onRightCountryFilter = (value: string, update: (callback: () => void) => void) => {
filterCountries(value, update, rightCountryOptions);
};
const playerOptions = computed(() => { const playerOptions = computed(() => {
const base = [{ label: '(Sin asignar)', value: '' }]; const base = [{ label: '(Sin asignar)', value: '' }];
const entries = Object.entries(playersStore.players) as [string, Schemas.Players[string]][]; const entries = Object.entries(playersStore.players) as [string, Schemas.Players[string]][];
@@ -37,6 +67,9 @@ const playerOptions = computed(() => {
return base.concat(options); return base.concat(options);
}); });
const leftSelectedPlayer = computed(() => playersStore.players[scoreboardStore.scoreboard.leftPlayerId]);
const rightSelectedPlayer = computed(() => playersStore.players[scoreboardStore.scoreboard.rightPlayerId]);
const getPlayerLabel = (playerId: string) => { const getPlayerLabel = (playerId: string) => {
const match = playerOptions.value.find((option) => option.value === playerId); const match = playerOptions.value.find((option) => option.value === playerId);
return match ? match.label : ''; return match ? match.label : '';
@@ -63,6 +96,42 @@ const rightCanSave = computed(
&& !playerExistsByGamertag(scoreboardStore.scoreboard.rightNameOverride), && !playerExistsByGamertag(scoreboardStore.scoreboard.rightNameOverride),
); );
const leftPendingGamertag = computed(() => {
const override = scoreboardStore.scoreboard.leftNameOverride.trim();
if (override) {
return override;
}
return leftSelectedPlayer.value?.gamertag ?? '';
});
const rightPendingGamertag = computed(() => {
const override = scoreboardStore.scoreboard.rightNameOverride.trim();
if (override) {
return override;
}
return rightSelectedPlayer.value?.gamertag ?? '';
});
const leftHasSelectedPlayerChanges = computed(() => {
const player = leftSelectedPlayer.value;
if (!player) {
return false;
}
return player.gamertag !== leftPendingGamertag.value
|| player.team !== scoreboardStore.scoreboard.leftTeamOverride
|| player.country !== scoreboardStore.scoreboard.leftCountryOverride;
});
const rightHasSelectedPlayerChanges = computed(() => {
const player = rightSelectedPlayer.value;
if (!player) {
return false;
}
return player.gamertag !== rightPendingGamertag.value
|| player.team !== scoreboardStore.scoreboard.rightTeamOverride
|| player.country !== scoreboardStore.scoreboard.rightCountryOverride;
});
const leftPlayerOptions = computed(() => filterOptions(playerOptions.value, leftFilter.value)); const leftPlayerOptions = computed(() => filterOptions(playerOptions.value, leftFilter.value));
const rightPlayerOptions = computed(() => filterOptions(playerOptions.value, rightFilter.value)); const rightPlayerOptions = computed(() => filterOptions(playerOptions.value, rightFilter.value));
@@ -104,16 +173,32 @@ const onRightBlur = () => {
rightInput.value = rightDisplayName.value; rightInput.value = rightDisplayName.value;
}; };
const applyLeftPlayerData = (playerId: string) => {
const player = playersStore.players[playerId];
scoreboardStore.scoreboard.leftTeamOverride = player?.team ?? '';
scoreboardStore.scoreboard.leftCountryOverride = player?.country ?? '';
leftCountryInput.value = getCountryLabel(scoreboardStore.scoreboard.leftCountryOverride);
};
const applyRightPlayerData = (playerId: string) => {
const player = playersStore.players[playerId];
scoreboardStore.scoreboard.rightTeamOverride = player?.team ?? '';
scoreboardStore.scoreboard.rightCountryOverride = player?.country ?? '';
rightCountryInput.value = getCountryLabel(scoreboardStore.scoreboard.rightCountryOverride);
};
const onLeftSelect = () => { const onLeftSelect = () => {
scoreboardStore.scoreboard.leftNameOverride = ''; scoreboardStore.scoreboard.leftNameOverride = '';
leftFilter.value = ''; leftFilter.value = '';
leftInput.value = getPlayerLabel(scoreboardStore.scoreboard.leftPlayerId); leftInput.value = getPlayerLabel(scoreboardStore.scoreboard.leftPlayerId);
applyLeftPlayerData(scoreboardStore.scoreboard.leftPlayerId);
}; };
const onRightSelect = () => { const onRightSelect = () => {
scoreboardStore.scoreboard.rightNameOverride = ''; scoreboardStore.scoreboard.rightNameOverride = '';
rightFilter.value = ''; rightFilter.value = '';
rightInput.value = getPlayerLabel(scoreboardStore.scoreboard.rightPlayerId); rightInput.value = getPlayerLabel(scoreboardStore.scoreboard.rightPlayerId);
applyRightPlayerData(scoreboardStore.scoreboard.rightPlayerId);
}; };
const createPlayerId = (name: string) => { const createPlayerId = (name: string) => {
@@ -144,8 +229,8 @@ const saveLeftPlayer = () => {
playersStore.upsertPlayer(id, { playersStore.upsertPlayer(id, {
gamertag, gamertag,
name: '', name: '',
team: '', team: scoreboardStore.scoreboard.leftTeamOverride,
country: '', country: scoreboardStore.scoreboard.leftCountryOverride,
twitter: '', twitter: '',
}); });
scoreboardStore.scoreboard.leftPlayerId = id; scoreboardStore.scoreboard.leftPlayerId = id;
@@ -162,8 +247,8 @@ const saveRightPlayer = () => {
playersStore.upsertPlayer(id, { playersStore.upsertPlayer(id, {
gamertag, gamertag,
name: '', name: '',
team: '', team: scoreboardStore.scoreboard.rightTeamOverride,
country: '', country: scoreboardStore.scoreboard.rightCountryOverride,
twitter: '', twitter: '',
}); });
scoreboardStore.scoreboard.rightPlayerId = id; scoreboardStore.scoreboard.rightPlayerId = id;
@@ -171,6 +256,68 @@ const saveRightPlayer = () => {
rightInput.value = gamertag; rightInput.value = gamertag;
}; };
const saveLeftSelectedPlayerChanges = () => {
const playerId = scoreboardStore.scoreboard.leftPlayerId;
const player = playersStore.players[playerId];
if (!player) {
return;
}
playersStore.upsertPlayer(playerId, {
...player,
gamertag: leftPendingGamertag.value,
team: scoreboardStore.scoreboard.leftTeamOverride,
country: scoreboardStore.scoreboard.leftCountryOverride,
});
scoreboardStore.scoreboard.leftNameOverride = '';
};
const saveRightSelectedPlayerChanges = () => {
const playerId = scoreboardStore.scoreboard.rightPlayerId;
const player = playersStore.players[playerId];
if (!player) {
return;
}
playersStore.upsertPlayer(playerId, {
...player,
gamertag: rightPendingGamertag.value,
team: scoreboardStore.scoreboard.rightTeamOverride,
country: scoreboardStore.scoreboard.rightCountryOverride,
});
scoreboardStore.scoreboard.rightNameOverride = '';
};
watch(
() => scoreboardStore.scoreboard.leftPlayerId,
(playerId) => {
applyLeftPlayerData(playerId);
},
{ immediate: true },
);
watch(
() => scoreboardStore.scoreboard.rightPlayerId,
(playerId) => {
applyRightPlayerData(playerId);
},
{ immediate: true },
);
watch(
() => scoreboardStore.scoreboard.leftCountryOverride,
(value) => {
leftCountryInput.value = getCountryLabel(value);
},
{ immediate: true },
);
watch(
() => scoreboardStore.scoreboard.rightCountryOverride,
(value) => {
rightCountryInput.value = getCountryLabel(value);
},
{ immediate: true },
);
watchEffect(() => { watchEffect(() => {
if (!leftFocused.value) { if (!leftFocused.value) {
leftInput.value = leftDisplayName.value; leftInput.value = leftDisplayName.value;
@@ -240,6 +387,32 @@ watchEffect(() => {
@blur="onLeftBlur" @blur="onLeftBlur"
@update:model-value="onLeftSelect" @update:model-value="onLeftSelect"
/> />
<QInput
v-model="scoreboardStore.scoreboard.leftTeamOverride"
label="Team"
dense
outlined
class="q-mt-sm"
/>
<QSelect
v-model="scoreboardStore.scoreboard.leftCountryOverride"
v-model:input-value="leftCountryInput"
:options="leftCountryOptions"
option-value="value"
option-label="label"
emit-value
map-options
use-input
input-debounce="0"
hide-selected
fill-input
clearable
label="Country"
dense
outlined
class="q-mt-sm"
@filter="onLeftCountryFilter"
/>
<QBtn <QBtn
v-if="leftCanSave" v-if="leftCanSave"
color="primary" color="primary"
@@ -248,6 +421,14 @@ watchEffect(() => {
class="q-mt-sm" class="q-mt-sm"
@click="saveLeftPlayer" @click="saveLeftPlayer"
/> />
<QBtn
v-if="leftHasSelectedPlayerChanges"
color="primary"
icon="save"
label="Guardar cambios del jugador"
class="q-mt-sm q-ml-sm"
@click="saveLeftSelectedPlayerChanges"
/>
<QInput <QInput
v-model.number="scoreboardStore.leftScore" v-model.number="scoreboardStore.leftScore"
type="number" type="number"
@@ -291,6 +472,32 @@ watchEffect(() => {
@blur="onRightBlur" @blur="onRightBlur"
@update:model-value="onRightSelect" @update:model-value="onRightSelect"
/> />
<QInput
v-model="scoreboardStore.scoreboard.rightTeamOverride"
label="Team"
dense
outlined
class="q-mt-sm"
/>
<QSelect
v-model="scoreboardStore.scoreboard.rightCountryOverride"
v-model:input-value="rightCountryInput"
:options="rightCountryOptions"
option-value="value"
option-label="label"
emit-value
map-options
use-input
input-debounce="0"
hide-selected
fill-input
clearable
label="Country"
dense
outlined
class="q-mt-sm"
@filter="onRightCountryFilter"
/>
<QBtn <QBtn
v-if="rightCanSave" v-if="rightCanSave"
color="primary" color="primary"
@@ -299,6 +506,14 @@ watchEffect(() => {
class="q-mt-sm" class="q-mt-sm"
@click="saveRightPlayer" @click="saveRightPlayer"
/> />
<QBtn
v-if="rightHasSelectedPlayerChanges"
color="primary"
icon="save"
label="Guardar cambios del jugador"
class="q-mt-sm q-ml-sm"
@click="saveRightSelectedPlayerChanges"
/>
<QInput <QInput
v-model.number="scoreboardStore.rightScore" v-model.number="scoreboardStore.rightScore"
type="number" type="number"
@@ -12,6 +12,10 @@ const defaultScoreboard: Scoreboard = {
rightPlayerId: '', rightPlayerId: '',
leftNameOverride: '', leftNameOverride: '',
rightNameOverride: '', rightNameOverride: '',
leftTeamOverride: '',
rightTeamOverride: '',
leftCountryOverride: '',
rightCountryOverride: '',
leftScore: 0, leftScore: 0,
rightScore: 0, rightScore: 0,
round: '', round: '',
@@ -24,6 +28,10 @@ const normalizeScoreboard = (input: unknown): Scoreboard => {
rightPlayerId: typeof candidate.rightPlayerId === 'string' ? candidate.rightPlayerId : '', rightPlayerId: typeof candidate.rightPlayerId === 'string' ? candidate.rightPlayerId : '',
leftNameOverride: typeof candidate.leftNameOverride === 'string' ? candidate.leftNameOverride : '', leftNameOverride: typeof candidate.leftNameOverride === 'string' ? candidate.leftNameOverride : '',
rightNameOverride: typeof candidate.rightNameOverride === 'string' ? candidate.rightNameOverride : '', rightNameOverride: typeof candidate.rightNameOverride === 'string' ? candidate.rightNameOverride : '',
leftTeamOverride: typeof candidate.leftTeamOverride === 'string' ? candidate.leftTeamOverride : '',
rightTeamOverride: typeof candidate.rightTeamOverride === 'string' ? candidate.rightTeamOverride : '',
leftCountryOverride: typeof candidate.leftCountryOverride === 'string' ? candidate.leftCountryOverride : '',
rightCountryOverride: typeof candidate.rightCountryOverride === 'string' ? candidate.rightCountryOverride : '',
leftScore: typeof candidate.leftScore === 'number' ? Math.max(0, Math.floor(candidate.leftScore)) : 0, leftScore: typeof candidate.leftScore === 'number' ? Math.max(0, Math.floor(candidate.leftScore)) : 0,
rightScore: typeof candidate.rightScore === 'number' ? Math.max(0, Math.floor(candidate.rightScore)) : 0, rightScore: typeof candidate.rightScore === 'number' ? Math.max(0, Math.floor(candidate.rightScore)) : 0,
round: typeof candidate.round === 'string' ? candidate.round : '', round: typeof candidate.round === 'string' ? candidate.round : '',
@@ -105,6 +113,10 @@ export const useScoreboardStore = defineStore('scoreboard', () => {
rightPlayerId: scoreboard.value.leftPlayerId, rightPlayerId: scoreboard.value.leftPlayerId,
leftNameOverride: scoreboard.value.rightNameOverride, leftNameOverride: scoreboard.value.rightNameOverride,
rightNameOverride: scoreboard.value.leftNameOverride, rightNameOverride: scoreboard.value.leftNameOverride,
leftTeamOverride: scoreboard.value.rightTeamOverride,
rightTeamOverride: scoreboard.value.leftTeamOverride,
leftCountryOverride: scoreboard.value.rightCountryOverride,
rightCountryOverride: scoreboard.value.leftCountryOverride,
leftScore: scoreboard.value.rightScore, leftScore: scoreboard.value.rightScore,
rightScore: scoreboard.value.leftScore, rightScore: scoreboard.value.leftScore,
}; };
+8 -16
View File
@@ -12,6 +12,10 @@ const defaultScoreboard: Schemas.Scoreboard = {
rightPlayerId: '', rightPlayerId: '',
leftNameOverride: '', leftNameOverride: '',
rightNameOverride: '', rightNameOverride: '',
leftTeamOverride: '',
rightTeamOverride: '',
leftCountryOverride: '',
rightCountryOverride: '',
leftScore: 0, leftScore: 0,
rightScore: 0, rightScore: 0,
round: '', round: '',
@@ -36,15 +40,9 @@ const rightName = computed(() => {
return player?.gamertag || 'Jugador 2'; return player?.gamertag || 'Jugador 2';
}); });
const leftTeam = computed(() => { const leftTeam = computed(() => scoreboard.value.leftTeamOverride || '');
const player = players.value[scoreboard.value.leftPlayerId];
return player?.team || '';
});
const rightTeam = computed(() => { const rightTeam = computed(() => scoreboard.value.rightTeamOverride || '');
const player = players.value[scoreboard.value.rightPlayerId];
return player?.team || '';
});
const flagModules = import.meta.glob('/node_modules/flag-icons/flags/4x3/*.svg', { const flagModules = import.meta.glob('/node_modules/flag-icons/flags/4x3/*.svg', {
eager: true, eager: true,
@@ -73,15 +71,9 @@ const getFlagUrl = (country: string | undefined) => {
return flagByCode[code.toLowerCase()] ?? ''; return flagByCode[code.toLowerCase()] ?? '';
}; };
const leftFlagUrl = computed(() => { const leftFlagUrl = computed(() => getFlagUrl(scoreboard.value.leftCountryOverride));
const player = players.value[scoreboard.value.leftPlayerId];
return getFlagUrl(player?.country);
});
const rightFlagUrl = computed(() => { const rightFlagUrl = computed(() => getFlagUrl(scoreboard.value.rightCountryOverride));
const player = players.value[scoreboard.value.rightPlayerId];
return getFlagUrl(player?.country);
});
const roundText = computed(() => scoreboard.value.round || 'Round'); const roundText = computed(() => scoreboard.value.round || 'Round');
</script> </script>
+4
View File
@@ -11,6 +11,10 @@ export interface Scoreboard {
rightPlayerId: string; rightPlayerId: string;
leftNameOverride: string; leftNameOverride: string;
rightNameOverride: string; rightNameOverride: string;
leftTeamOverride: string;
rightTeamOverride: string;
leftCountryOverride: string;
rightCountryOverride: string;
leftScore: number; leftScore: number;
rightScore: number; rightScore: number;
round: string; round: string;