mirror of
https://github.com/Pandipipas/scoreko-dev.git
synced 2026-06-06 03:32:06 +00:00
fix(players): improve Challonge auth UX and manual token flow
This commit is contained in:
@@ -128,6 +128,8 @@ const oauthLoading = ref(false);
|
||||
const challongeOauthLoading = ref(false);
|
||||
const isManualTokenDialogOpen = ref(false);
|
||||
const manualTokenDraft = ref('');
|
||||
const isChallongeManualTokenDialogOpen = ref(false);
|
||||
const challongeManualTokenDraft = ref('');
|
||||
const oauthSessionId = ref('');
|
||||
const challongeOauthSessionId = ref('');
|
||||
let oauthPollingTimer: ReturnType<typeof setInterval> | null = null;
|
||||
@@ -143,6 +145,7 @@ const selectedChallongePlayerIds = ref<string[]>([]);
|
||||
const challongeImportDialogOpen = ref(false);
|
||||
const loadingChallongeTournamentPlayers = ref(false);
|
||||
const importingChallongeTournament = ref<ChallongeTournament | null>(null);
|
||||
const hasValidatedChallongeToken = ref(false);
|
||||
|
||||
interface OAuthSessionResponse {
|
||||
sessionId: string;
|
||||
@@ -161,6 +164,7 @@ watch(startGGToken, (value) => {
|
||||
|
||||
watch(challongeToken, (value) => {
|
||||
localStorage.setItem(CHALLONGE_TOKEN_STORAGE_KEY, value);
|
||||
hasValidatedChallongeToken.value = false;
|
||||
});
|
||||
|
||||
const persistTemporaryStartGGPlayers = () => {
|
||||
@@ -463,6 +467,8 @@ const selectedChallongeTournamentOption = computed(() =>
|
||||
const canImportSelectedChallongeTournament = computed(() => Boolean(selectedChallongeTournamentOption.value));
|
||||
const hasChallongeTokenConfigured = computed(() => Boolean(challongeToken.value.trim()));
|
||||
|
||||
const challongeConnectionLabel = computed(() => (hasValidatedChallongeToken.value ? 'Connected' : 'Token set'));
|
||||
|
||||
const filterChallongeTournaments = (value: string, update: (callback: () => void) => void) => {
|
||||
update(() => {
|
||||
const needle = value.toLowerCase().trim();
|
||||
@@ -491,18 +497,41 @@ const loadChallongeRecentTournaments = async () => {
|
||||
const tournaments = await sendNodeCGMessage<ChallongeTournament[]>('challonge:fetchRecentTournaments', {
|
||||
token,
|
||||
});
|
||||
hasValidatedChallongeToken.value = true;
|
||||
challongeRecentTournaments.value = tournaments;
|
||||
if (!tournaments.length) {
|
||||
challongeTournamentsError.value = 'There are no recent tournaments for this account.';
|
||||
}
|
||||
} catch (error) {
|
||||
challongeTournamentsError.value = error instanceof Error ? error.message : 'Could not load tournaments.';
|
||||
hasValidatedChallongeToken.value = false;
|
||||
const message = error instanceof Error ? error.message : 'Could not load tournaments.';
|
||||
challongeTournamentsError.value = message.includes('401')
|
||||
? 'Challonge rejected the token (401 Unauthorized). Verify OAuth callback/client credentials or paste a valid personal API token.'
|
||||
: message;
|
||||
challongeRecentTournaments.value = [];
|
||||
} finally {
|
||||
challongeLoadingTournaments.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const openChallongeManualTokenDialog = () => {
|
||||
challongeManualTokenDraft.value = challongeToken.value;
|
||||
isChallongeManualTokenDialogOpen.value = true;
|
||||
};
|
||||
|
||||
const saveChallongeManualToken = () => {
|
||||
challongeToken.value = challongeManualTokenDraft.value.trim();
|
||||
|
||||
if (!challongeToken.value) {
|
||||
challongeRecentTournaments.value = [];
|
||||
selectedChallongeTournamentSlug.value = '';
|
||||
challongeTournamentInput.value = '';
|
||||
challongeTournamentsError.value = '';
|
||||
}
|
||||
|
||||
isChallongeManualTokenDialogOpen.value = false;
|
||||
};
|
||||
|
||||
const openChallongeImportDialog = async (tournament: ChallongeTournament) => {
|
||||
importingChallongeTournament.value = tournament;
|
||||
challongeImportDialogOpen.value = true;
|
||||
@@ -932,9 +961,19 @@ onBeforeUnmount(() => {
|
||||
<QBtn
|
||||
v-else
|
||||
outline
|
||||
color="positive"
|
||||
:color="hasValidatedChallongeToken ? 'positive' : 'warning'"
|
||||
icon="check_circle"
|
||||
label="Connected"
|
||||
:label="challongeConnectionLabel"
|
||||
@click="openChallongeManualTokenDialog"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<QBtn
|
||||
outline
|
||||
color="white"
|
||||
icon="vpn_key"
|
||||
label="Use personal API"
|
||||
@click="openChallongeManualTokenDialog"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1147,6 +1186,49 @@ onBeforeUnmount(() => {
|
||||
</QCard>
|
||||
</QDialog>
|
||||
|
||||
<QDialog v-model="isChallongeManualTokenDialogOpen">
|
||||
<QCard class="players-dialog">
|
||||
<QCardSection>
|
||||
<div class="text-h6">
|
||||
Personal Challonge API
|
||||
</div>
|
||||
</QCardSection>
|
||||
<QSeparator />
|
||||
<QCardSection>
|
||||
<div class="text-body2 q-mb-sm">
|
||||
If OAuth fails, paste a personal Challonge API token.
|
||||
</div>
|
||||
<QInput
|
||||
v-model="challongeManualTokenDraft"
|
||||
label="Paste your personal Challonge token"
|
||||
dense
|
||||
outlined
|
||||
type="password"
|
||||
/>
|
||||
</QCardSection>
|
||||
<QSeparator />
|
||||
<QCardActions align="right">
|
||||
<QBtn
|
||||
flat
|
||||
label="Cancel"
|
||||
color="secondary"
|
||||
@click="isChallongeManualTokenDialogOpen = false"
|
||||
/>
|
||||
<QBtn
|
||||
flat
|
||||
color="negative"
|
||||
label="Delete token"
|
||||
@click="challongeManualTokenDraft = ''; saveChallongeManualToken()"
|
||||
/>
|
||||
<QBtn
|
||||
color="primary"
|
||||
label="Save token"
|
||||
@click="saveChallongeManualToken"
|
||||
/>
|
||||
</QCardActions>
|
||||
</QCard>
|
||||
</QDialog>
|
||||
|
||||
<QDialog v-model="isDialogOpen">
|
||||
<QCard class="players-dialog">
|
||||
<QCardSection>
|
||||
|
||||
Reference in New Issue
Block a user