mirror of
https://github.com/Pandipipas/scoreko-dev.git
synced 2026-06-06 03:32:06 +00:00
feat(players): add Challonge temporary imported-player expiration
This commit is contained in:
@@ -45,6 +45,7 @@ interface ChallongeImportedPlayer extends Player {
|
|||||||
const STARTGG_TOKEN_STORAGE_KEY = 'scoreko-dev.startgg-token';
|
const STARTGG_TOKEN_STORAGE_KEY = 'scoreko-dev.startgg-token';
|
||||||
const CHALLONGE_TOKEN_STORAGE_KEY = 'scoreko-dev.challonge-token';
|
const CHALLONGE_TOKEN_STORAGE_KEY = 'scoreko-dev.challonge-token';
|
||||||
const STARTGG_TEMP_PLAYERS_STORAGE_KEY = 'scoreko-dev.startgg-temp-players';
|
const STARTGG_TEMP_PLAYERS_STORAGE_KEY = 'scoreko-dev.startgg-temp-players';
|
||||||
|
const CHALLONGE_TEMP_PLAYERS_STORAGE_KEY = 'scoreko-dev.challonge-temp-players';
|
||||||
const STARTGG_TEMP_FALLBACK_DURATION_SECONDS = 12 * 60 * 60;
|
const STARTGG_TEMP_FALLBACK_DURATION_SECONDS = 12 * 60 * 60;
|
||||||
|
|
||||||
interface TemporaryStartGGPlayerMeta {
|
interface TemporaryStartGGPlayerMeta {
|
||||||
@@ -53,6 +54,7 @@ interface TemporaryStartGGPlayerMeta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TemporaryStartGGPlayersMap = Record<string, TemporaryStartGGPlayerMeta>;
|
type TemporaryStartGGPlayersMap = Record<string, TemporaryStartGGPlayerMeta>;
|
||||||
|
type TemporaryChallongePlayersMap = Record<string, TemporaryStartGGPlayerMeta>;
|
||||||
|
|
||||||
const playersStore = usePlayersStore();
|
const playersStore = usePlayersStore();
|
||||||
const rows = computed<PlayerRow[]>(() => playersStore.rows);
|
const rows = computed<PlayerRow[]>(() => playersStore.rows);
|
||||||
@@ -122,6 +124,7 @@ const selectedStartGGPlayerIds = ref<string[]>([]);
|
|||||||
const selectedTournamentSlug = ref('');
|
const selectedTournamentSlug = ref('');
|
||||||
const tournamentInput = ref('');
|
const tournamentInput = ref('');
|
||||||
const temporaryStartGGPlayers = ref<TemporaryStartGGPlayersMap>({});
|
const temporaryStartGGPlayers = ref<TemporaryStartGGPlayersMap>({});
|
||||||
|
const temporaryChallongePlayers = ref<TemporaryChallongePlayersMap>({});
|
||||||
let temporaryCleanupTimer: ReturnType<typeof setInterval> | null = null;
|
let temporaryCleanupTimer: ReturnType<typeof setInterval> | null = null;
|
||||||
|
|
||||||
const oauthLoading = ref(false);
|
const oauthLoading = ref(false);
|
||||||
@@ -171,6 +174,10 @@ const persistTemporaryStartGGPlayers = () => {
|
|||||||
localStorage.setItem(STARTGG_TEMP_PLAYERS_STORAGE_KEY, JSON.stringify(temporaryStartGGPlayers.value));
|
localStorage.setItem(STARTGG_TEMP_PLAYERS_STORAGE_KEY, JSON.stringify(temporaryStartGGPlayers.value));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const persistTemporaryChallongePlayers = () => {
|
||||||
|
localStorage.setItem(CHALLONGE_TEMP_PLAYERS_STORAGE_KEY, JSON.stringify(temporaryChallongePlayers.value));
|
||||||
|
};
|
||||||
|
|
||||||
const loadTemporaryStartGGPlayers = (): TemporaryStartGGPlayersMap => {
|
const loadTemporaryStartGGPlayers = (): TemporaryStartGGPlayersMap => {
|
||||||
try {
|
try {
|
||||||
const raw = localStorage.getItem(STARTGG_TEMP_PLAYERS_STORAGE_KEY);
|
const raw = localStorage.getItem(STARTGG_TEMP_PLAYERS_STORAGE_KEY);
|
||||||
@@ -205,6 +212,40 @@ const loadTemporaryStartGGPlayers = (): TemporaryStartGGPlayersMap => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadTemporaryChallongePlayers = (): TemporaryChallongePlayersMap => {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(CHALLONGE_TEMP_PLAYERS_STORAGE_KEY);
|
||||||
|
if (!raw) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const parsed = JSON.parse(raw) as unknown;
|
||||||
|
if (typeof parsed !== 'object' || parsed === null) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: TemporaryChallongePlayersMap = {};
|
||||||
|
Object.entries(parsed as Record<string, unknown>).forEach(([playerId, value]) => {
|
||||||
|
if (!playerId || typeof value !== 'object' || value === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const candidate = value as Record<string, unknown>;
|
||||||
|
const expiresAt = Number(candidate.expiresAt);
|
||||||
|
const tournamentSlug = String(candidate.tournamentSlug || '').trim();
|
||||||
|
if (!Number.isFinite(expiresAt) || expiresAt <= 0 || !tournamentSlug) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result[playerId] = {
|
||||||
|
expiresAt,
|
||||||
|
tournamentSlug,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const tournamentOptions = computed(() =>
|
const tournamentOptions = computed(() =>
|
||||||
recentTournaments.value.map((tournament) => ({
|
recentTournaments.value.map((tournament) => ({
|
||||||
label: tournament.name,
|
label: tournament.name,
|
||||||
@@ -276,22 +317,31 @@ const clearTemporaryCleanupTimer = () => {
|
|||||||
|
|
||||||
const cleanupExpiredTemporaryPlayers = () => {
|
const cleanupExpiredTemporaryPlayers = () => {
|
||||||
const now = Math.floor(Date.now() / 1000);
|
const now = Math.floor(Date.now() / 1000);
|
||||||
const expiredIds = Object.entries(temporaryStartGGPlayers.value)
|
const expiredStartGGIds = Object.entries(temporaryStartGGPlayers.value)
|
||||||
.filter(([, meta]) => meta.expiresAt <= now)
|
.filter(([, meta]) => meta.expiresAt <= now)
|
||||||
.map(([playerId]) => playerId);
|
.map(([playerId]) => playerId);
|
||||||
|
const expiredChallongeIds = Object.entries(temporaryChallongePlayers.value)
|
||||||
|
.filter(([, meta]) => meta.expiresAt <= now)
|
||||||
|
.map(([playerId]) => playerId);
|
||||||
|
|
||||||
|
const expiredIds = Array.from(new Set([...expiredStartGGIds, ...expiredChallongeIds]));
|
||||||
|
|
||||||
if (!expiredIds.length) {
|
if (!expiredIds.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextMeta = { ...temporaryStartGGPlayers.value };
|
const nextStartGGMeta = { ...temporaryStartGGPlayers.value };
|
||||||
|
const nextChallongeMeta = { ...temporaryChallongePlayers.value };
|
||||||
expiredIds.forEach((playerId) => {
|
expiredIds.forEach((playerId) => {
|
||||||
playersStore.removePlayer(playerId);
|
playersStore.removePlayer(playerId);
|
||||||
delete nextMeta[playerId];
|
delete nextStartGGMeta[playerId];
|
||||||
|
delete nextChallongeMeta[playerId];
|
||||||
});
|
});
|
||||||
|
|
||||||
temporaryStartGGPlayers.value = nextMeta;
|
temporaryStartGGPlayers.value = nextStartGGMeta;
|
||||||
|
temporaryChallongePlayers.value = nextChallongeMeta;
|
||||||
persistTemporaryStartGGPlayers();
|
persistTemporaryStartGGPlayers();
|
||||||
|
persistTemporaryChallongePlayers();
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkOAuthStatus = async () => {
|
const checkOAuthStatus = async () => {
|
||||||
@@ -569,6 +619,11 @@ const importSelectedChallongePlayers = () => {
|
|||||||
selectedChallongePlayerIds.value.includes(player.id),
|
selectedChallongePlayerIds.value.includes(player.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const nextMeta = { ...temporaryChallongePlayers.value };
|
||||||
|
const tournament = importingChallongeTournament.value;
|
||||||
|
const fallbackEndAt = (tournament?.startAt ?? Math.floor(Date.now() / 1000)) + STARTGG_TEMP_FALLBACK_DURATION_SECONDS;
|
||||||
|
const expiresAt = tournament?.endAt ?? fallbackEndAt;
|
||||||
|
|
||||||
selectedPlayers.forEach((player) => {
|
selectedPlayers.forEach((player) => {
|
||||||
playersStore.upsertPlayer(player.id, {
|
playersStore.upsertPlayer(player.id, {
|
||||||
gamertag: player.gamertag,
|
gamertag: player.gamertag,
|
||||||
@@ -577,8 +632,17 @@ const importSelectedChallongePlayers = () => {
|
|||||||
country: player.country,
|
country: player.country,
|
||||||
twitter: player.twitter,
|
twitter: player.twitter,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (tournament) {
|
||||||
|
nextMeta[player.id] = {
|
||||||
|
expiresAt,
|
||||||
|
tournamentSlug: tournament.slug,
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
temporaryChallongePlayers.value = nextMeta;
|
||||||
|
persistTemporaryChallongePlayers();
|
||||||
challongeImportDialogOpen.value = false;
|
challongeImportDialogOpen.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -718,6 +782,7 @@ const handleImport = async (event: Event) => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
temporaryStartGGPlayers.value = loadTemporaryStartGGPlayers();
|
temporaryStartGGPlayers.value = loadTemporaryStartGGPlayers();
|
||||||
|
temporaryChallongePlayers.value = loadTemporaryChallongePlayers();
|
||||||
cleanupExpiredTemporaryPlayers();
|
cleanupExpiredTemporaryPlayers();
|
||||||
temporaryCleanupTimer = setInterval(cleanupExpiredTemporaryPlayers, 60 * 1000);
|
temporaryCleanupTimer = setInterval(cleanupExpiredTemporaryPlayers, 60 * 1000);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user