You've already forked AstralRinth
forked from didirus/AstralRinth
bacc10d2f5
* add log * add log * Revert "add log" This reverts commit 2412a3de5f58fa6937b33b8e9c13fc47756670df. * add new minecraft auth error modal * add other auth errors * polish the styles * update link text * add unknown error state * pnpm prepr * fix link * fix lint
185 lines
5.3 KiB
Vue
185 lines
5.3 KiB
Vue
<script setup lang="ts">
|
||
import {
|
||
CheckIcon,
|
||
CopyIcon,
|
||
DropdownIcon,
|
||
LogInIcon,
|
||
MessagesSquareIcon,
|
||
WrenchIcon,
|
||
} from '@modrinth/assets'
|
||
import { Admonition, ButtonStyled, Collapsible, NewModal } from '@modrinth/ui'
|
||
import { computed, ref } from 'vue'
|
||
|
||
import { login as login_flow, set_default_user } from '@/helpers/auth.js'
|
||
import { handleSevereError } from '@/store/error.js'
|
||
|
||
import { type MinecraftAuthError, minecraftAuthErrors } from './minecraft-auth-errors'
|
||
|
||
const modal = ref<InstanceType<typeof NewModal>>()
|
||
const rawError = ref<string>('')
|
||
const matchedError = ref<MinecraftAuthError | null>(null)
|
||
const debugCollapsed = ref(true)
|
||
const copied = ref(false)
|
||
const loadingSignIn = ref(false)
|
||
|
||
function show(errorVal: { message?: string }) {
|
||
rawError.value = errorVal?.message ?? String(errorVal)
|
||
|
||
matchedError.value = minecraftAuthErrors.find((e) => rawError.value.includes(e.errorCode)) ?? null
|
||
|
||
debugCollapsed.value = true
|
||
modal.value?.show()
|
||
}
|
||
|
||
function hide() {
|
||
modal.value?.hide()
|
||
}
|
||
|
||
defineExpose({
|
||
show,
|
||
hide,
|
||
})
|
||
|
||
async function signInAgain() {
|
||
try {
|
||
loadingSignIn.value = true
|
||
const loggedIn = await login_flow()
|
||
if (loggedIn) {
|
||
await set_default_user(loggedIn.profile.id)
|
||
}
|
||
loadingSignIn.value = false
|
||
modal.value?.hide()
|
||
} catch (err) {
|
||
loadingSignIn.value = false
|
||
handleSevereError(err)
|
||
}
|
||
}
|
||
|
||
const debugInfo = computed(() => rawError.value || 'No error message.')
|
||
|
||
async function copyToClipboard(text: string) {
|
||
await navigator.clipboard.writeText(text)
|
||
copied.value = true
|
||
setTimeout(() => {
|
||
copied.value = false
|
||
}, 3000)
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<NewModal ref="modal" header="Sign in Failed" :max-width="'548px'">
|
||
<div class="flex flex-col gap-6">
|
||
<Admonition
|
||
type="warning"
|
||
body=" We couldn't sign you into your Microsoft account. This may be due to account restrictions or
|
||
regional limitations."
|
||
>
|
||
</Admonition>
|
||
|
||
<!-- Matched error details -->
|
||
<div class="bg-surface-2 rounded-2xl p-4 px-5 flex flex-col gap-3">
|
||
<template v-if="matchedError">
|
||
<div class="flex flex-col gap-1.5">
|
||
<h3 class="text-base font-bold m-0">What we think happened</h3>
|
||
<p class="text-sm text-secondary m-0">
|
||
{{ matchedError.whatHappened }}
|
||
</p>
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-1.5">
|
||
<h3 class="text-base font-bold m-0">How to fix it</h3>
|
||
<ol class="list-none flex flex-col gap-2 m-0 pl-0">
|
||
<li
|
||
v-for="(step, index) in matchedError.stepsToFix"
|
||
:key="index"
|
||
class="flex items-baseline gap-2"
|
||
>
|
||
<span
|
||
class="inline-flex items-center justify-center shrink-0 w-5 h-5 rounded-full bg-surface-4 border border-solid border-surface-5 text-xs font-medium"
|
||
>
|
||
{{ index + 1 }}
|
||
</span>
|
||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||
<span
|
||
class="text-sm [&_a]:text-info [&_a]:font-medium [&_a]:underline"
|
||
v-html="step"
|
||
/>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
</template>
|
||
<template v-else>
|
||
<div class="flex flex-col gap-1.5">
|
||
<h3 class="text-base font-bold m-0">Unknown error</h3>
|
||
<p class="text-sm text-secondary m-0">
|
||
We don’t recognize this error and can’t recommend specific steps to resolve it.
|
||
</p>
|
||
<p class="text-sm text-secondary m-0">
|
||
Try visiting
|
||
<a
|
||
class="text-info font-medium underline hover:underline"
|
||
href="https://www.minecraft.net/en-us/login"
|
||
>Minecraft Login</a
|
||
>
|
||
and signing in, as it may prompt you with the necessary steps. You can also contact
|
||
support and we can look into it further.
|
||
</p>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
|
||
<!-- Action buttons -->
|
||
<div class="flex items-center gap-2">
|
||
<ButtonStyled>
|
||
<a href="https://support.modrinth.com" class="!w-full" @click="modal?.hide()">
|
||
<MessagesSquareIcon /> Contact support
|
||
</a>
|
||
</ButtonStyled>
|
||
<ButtonStyled color="brand">
|
||
<button :disabled="loadingSignIn" class="!w-full" @click="signInAgain">
|
||
<LogInIcon /> Sign in again
|
||
</button>
|
||
</ButtonStyled>
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-2">
|
||
<div class="w-full h-[1px] bg-surface-5"></div>
|
||
|
||
<!-- Debug info -->
|
||
<div class="overflow-clip">
|
||
<button
|
||
class="flex items-center justify-between w-full bg-transparent border-0 py-4 cursor-pointer"
|
||
@click="debugCollapsed = !debugCollapsed"
|
||
>
|
||
<span class="flex items-center gap-2 text-contrast font-extrabold m-0">
|
||
<WrenchIcon class="h-4 w-4" />
|
||
Debug information
|
||
</span>
|
||
<DropdownIcon
|
||
class="h-5 w-5 text-secondary transition-transform"
|
||
:class="{ 'rotate-180': !debugCollapsed }"
|
||
/>
|
||
</button>
|
||
<Collapsible :collapsed="debugCollapsed">
|
||
<div class="p-3 bg-surface-2 rounded-2xl text-xs flex items-start">
|
||
<div class="m-0 p-0 rounded-none bg-transparent text-sm font-mono">
|
||
{{ debugInfo }}
|
||
</div>
|
||
<ButtonStyled circular>
|
||
<button
|
||
v-tooltip="'Copy debug info'"
|
||
:disabled="copied"
|
||
@click="copyToClipboard(debugInfo)"
|
||
>
|
||
<template v-if="copied"> <CheckIcon class="text-green" /> </template>
|
||
<template v-else> <CopyIcon /> </template>
|
||
</button>
|
||
</ButtonStyled>
|
||
</div>
|
||
</Collapsible>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</NewModal>
|
||
</template>
|