refactor: everything to nuxt.js

This commit is contained in:
2026-03-19 14:30:36 -04:00
parent 6e1f58cd8e
commit bb3042014e
159 changed files with 6786 additions and 11198 deletions

127
app/pages/login.vue Normal file
View File

@@ -0,0 +1,127 @@
<script setup lang="ts">
import { ref } from 'vue';
import { Dialog, Notify } from 'quasar';
import { useAuthStore } from '~/stores/auth';
import { AppwriteException } from 'appwrite';
definePageMeta({ public: true, layout: false });
const email = ref('');
const token = ref('');
const userId = ref<string | undefined>();
const authStore = useAuthStore();
const sendMagicLink = async () => {
if (!email.value) {
Dialog.create({ message: 'Please enter your e-mail address.' });
return;
}
try {
await authStore.createMagicURLSession(email.value);
Dialog.create({ message: 'Check your e-mail for a magic login link.' });
} catch {
Dialog.create({ message: 'An error occurred. Please ask for help in Discord.' });
}
};
const doTokenLogin = async () => {
if (!userId.value) {
try {
const sessionToken = await authStore.createTokenSession(email.value);
userId.value = sessionToken.userId;
Dialog.create({ message: 'Check your e-mail for your login code.' });
} catch {
Dialog.create({ message: 'An error occurred. Please ask for help in Discord.' });
}
} else {
const notification = Notify.create({
type: 'primary',
position: 'top',
spinner: true,
message: 'Logging you in...',
timeout: 8000,
group: false,
});
try {
await authStore.tokenLogin(userId.value, token.value);
notification({ type: 'positive', message: 'Logged in!', timeout: 2000, spinner: false, icon: 'check_circle' });
await navigateTo('/');
} catch (error: unknown) {
if (error instanceof AppwriteException) {
if (error.type === 'user_session_already_exists') {
notification({ type: 'positive', message: 'Already logged in!', timeout: 2000, spinner: false, icon: 'check_circle' });
await navigateTo('/');
return;
}
Dialog.create({ title: 'Login Error!', message: error.message, persistent: true });
}
notification({ type: 'negative', message: 'Login failed.', timeout: 2000 });
}
}
};
</script>
<template>
<q-layout>
<q-page-container>
<q-page class="flex bg-image flex-center">
<q-card
v-bind:style="$q.screen.lt.sm ? { width: '80%' } : { width: '30%' }">
<q-card-section>
<q-img fit="scale-down" src="/oysqn_logo.png" />
</q-card-section>
<q-card-section>
<div class="text-center q-pt-sm">
<div class="col text-h6">Log in</div>
</div>
</q-card-section>
<q-form @keydown.enter.prevent="doTokenLogin">
<q-card-section class="q-gutter-md">
<q-input
v-model="email"
label="E-Mail"
type="email"
color="darkblue"
filled />
<q-input
v-if="userId"
v-model="token"
label="6-digit code"
type="number"
color="darkblue"
filled />
</q-card-section>
</q-form>
<q-card-section class="q-pa-none">
<div class="row justify-center q-ma-sm">
<q-btn
v-if="!userId"
type="button"
@click="sendMagicLink"
color="secondary"
label="Send Magic Link"
style="width: 300px" />
</div>
<div class="row justify-center q-ma-sm">
<q-btn
type="button"
@click="doTokenLogin"
color="primary"
:label="userId ? 'Login' : 'Send Code'"
style="width: 300px" />
</div>
</q-card-section>
</q-card>
</q-page>
</q-page-container>
</q-layout>
</template>
<style>
.bg-image {
background-image: url('~/assets/oys_lighthouse.jpg');
background-repeat: no-repeat;
background-position-x: center;
background-size: cover;
}
</style>