| <template> |
| <div class="min-h-screen bg-gray-50 px-4 py-10 dark:bg-dark-900"> |
| <div class="mx-auto max-w-2xl"> |
| <div class="card p-6"> |
| <h1 class="text-lg font-semibold text-gray-900 dark:text-white">OAuth Callback</h1> |
| <p class="mt-2 text-sm text-gray-600 dark:text-gray-400"> |
| Copy the <code>code</code> (and <code>state</code> if needed) back to the admin |
| authorization flow. |
| </p> |
| |
| <div class="mt-6 space-y-4"> |
| <div> |
| <label class="input-label">{{ t('auth.oauth.code') }}</label> |
| <div class="flex gap-2"> |
| <input class="input flex-1 font-mono text-sm" :value="code" readonly /> |
| <button class="btn btn-secondary" type="button" :disabled="!code" @click="copy(code)"> |
| Copy |
| </button> |
| </div> |
| </div> |
| |
| <div> |
| <label class="input-label">{{ t('auth.oauth.state') }}</label> |
| <div class="flex gap-2"> |
| <input class="input flex-1 font-mono text-sm" :value="state" readonly /> |
| <button |
| class="btn btn-secondary" |
| type="button" |
| :disabled="!state" |
| @click="copy(state)" |
| > |
| Copy |
| </button> |
| </div> |
| </div> |
| |
| <div> |
| <label class="input-label">{{ t('auth.oauth.fullUrl') }}</label> |
| <div class="flex gap-2"> |
| <input class="input flex-1 font-mono text-xs" :value="fullUrl" readonly /> |
| <button |
| class="btn btn-secondary" |
| type="button" |
| :disabled="!fullUrl" |
| @click="copy(fullUrl)" |
| > |
| Copy |
| </button> |
| </div> |
| </div> |
| |
| <div |
| v-if="error" |
| class="rounded-lg border border-red-200 bg-red-50 p-3 dark:border-red-700 dark:bg-red-900/30" |
| > |
| <p class="text-sm text-red-600 dark:text-red-400">{{ error }}</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </template> |
| |
| <script setup lang="ts"> |
| import { computed } from 'vue' |
| import { useI18n } from 'vue-i18n' |
| import { useRoute } from 'vue-router' |
| import { useClipboard } from '@/composables/useClipboard' |
| |
| const route = useRoute() |
| const { t } = useI18n() |
| const { copyToClipboard } = useClipboard() |
| |
| const code = computed(() => (route.query.code as string) || '') |
| const state = computed(() => (route.query.state as string) || '') |
| const error = computed( |
| () => (route.query.error as string) || (route.query.error_description as string) || '' |
| ) |
| |
| const fullUrl = computed(() => { |
| if (typeof window === 'undefined') return '' |
| return window.location.href |
| }) |
| |
| const copy = (value: string) => { |
| if (!value) return |
| copyToClipboard(value, 'Copied') |
| } |
| </script> |
| |