Include recent Magic app work: Tauri native shell, iOS device detection via supervise-magic sidecar, MDM client, local HTTP server, new pages (detect, enroll, supervise, sideload, pair, preflight, configure, done), and updated device section/status UI.
132 lines
3.5 KiB
Vue
132 lines
3.5 KiB
Vue
<template>
|
|
<div class="min-h-screen flex flex-col items-center justify-center bg-gray-50 p-6">
|
|
<div class="max-w-md w-full space-y-6">
|
|
<div class="text-center">
|
|
<h1 class="text-2xl font-bold text-gray-900">Pairing-Code</h1>
|
|
<p class="text-gray-600 mt-2">
|
|
Erstelle in der ReBreak-App einen 6-stelligen Pairing-Code.
|
|
</p>
|
|
</div>
|
|
|
|
<UCard>
|
|
<div class="space-y-6">
|
|
<div class="flex justify-center">
|
|
<UPinInput
|
|
v-model="code"
|
|
:length="6"
|
|
type="numeric"
|
|
otp
|
|
autofocus
|
|
placeholder="0"
|
|
class="font-mono text-lg"
|
|
:disabled="loading"
|
|
@complete="redeem"
|
|
/>
|
|
</div>
|
|
|
|
<UButton
|
|
color="primary"
|
|
block
|
|
:loading="loading"
|
|
:disabled="codeString.length < 6 || loading"
|
|
@click="redeem"
|
|
>
|
|
{{ loading ? "Wird geladen…" : "Koppeln" }}
|
|
</UButton>
|
|
|
|
<div v-if="loading && loadingMessage" class="flex items-center justify-center gap-2 text-sm text-gray-600">
|
|
<UIcon name="i-heroicons-arrow-path" class="w-4 h-4 animate-spin text-[var(--rebreak-primary)]" />
|
|
<span>{{ loadingMessage }}</span>
|
|
</div>
|
|
|
|
<p v-else-if="error" class="text-sm text-center text-red-600">
|
|
{{ error }}
|
|
</p>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UButton to="/" variant="ghost" color="neutral" block :disabled="loading">
|
|
Zurück
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed } from "vue";
|
|
import { useTauri } from "~/composables/useTauri";
|
|
import { useMagicSession, useMagicDevices } from "~/composables/useMagicState";
|
|
|
|
const {
|
|
redeemPairingCode,
|
|
getPlatform,
|
|
getHardwareId,
|
|
registerDevice,
|
|
fetchMe,
|
|
getMagicDevices,
|
|
getMagicStatus,
|
|
} = useTauri();
|
|
|
|
const session = useMagicSession();
|
|
const devices = useMagicDevices();
|
|
|
|
// UPinInput can return either a string or an array of characters
|
|
const code = ref<string | string[]>("");
|
|
const loading = ref(false);
|
|
const error = ref<string | null>(null);
|
|
const loadingMessage = ref<string | null>(null);
|
|
|
|
const codeString = computed(() => {
|
|
if (Array.isArray(code.value)) {
|
|
return code.value.join("");
|
|
}
|
|
return code.value;
|
|
});
|
|
|
|
async function redeem() {
|
|
const value = codeString.value;
|
|
if (value.length < 6) return;
|
|
|
|
loading.value = true;
|
|
loadingMessage.value = "Pairing-Code wird eingelöst…";
|
|
error.value = null;
|
|
|
|
try {
|
|
await redeemPairingCode(value);
|
|
|
|
loadingMessage.value = "Registriere dieses Gerät…";
|
|
const [platformInfo, hardwareId] = await Promise.all([
|
|
getPlatform(),
|
|
getHardwareId(),
|
|
]);
|
|
|
|
const registered = await registerDevice(platformInfo.platform, platformInfo.version);
|
|
|
|
session.value = {
|
|
deviceId: registered.deviceId,
|
|
hardwareId,
|
|
dnsToken: registered.dnsToken,
|
|
profileUrl: registered.profileUrl,
|
|
};
|
|
|
|
loadingMessage.value = "Lade Profil und Geräte…";
|
|
const [_, deviceList] = await Promise.all([
|
|
fetchMe(),
|
|
getMagicDevices(),
|
|
]);
|
|
|
|
devices.value = deviceList;
|
|
|
|
loadingMessage.value = "Prüfe Schutzstatus…";
|
|
await getMagicStatus(registered.dnsToken);
|
|
|
|
await navigateTo("/status");
|
|
} catch (e: any) {
|
|
error.value = e?.message ?? "Koppeln fehlgeschlagen";
|
|
loadingMessage.value = null;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
</script>
|