Newer
Older
bugtrail / packages / web / src / pages / RegisterPage.vue
<script setup lang="ts">
import { ref } from "vue";
import { useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import { GnButton, GnInput, GnCard, useToast } from "gnexus-ui-kit/vue";
import { useAuth } from "../stores/auth";

const auth = useAuth();
const router = useRouter();
const toast = useToast();
const { t } = useI18n();

const nickname = ref("");
const email = ref("");
const password = ref("");
const submitting = ref(false);
const error = ref<string | null>(null);

async function submit() {
  submitting.value = true;
  error.value = null;
  try {
    await auth.register(nickname.value, email.value, password.value);
    await router.push("/");
    toast.success({
      title: t("auth.registerTitle"),
      text: t("auth.welcome", { name: auth.user.value?.nickname }),
    });
  } catch (e) {
    error.value =
      e instanceof Error && e.message.includes("409")
        ? t("auth.emailTaken")
        : t("auth.error");
  } finally {
    submitting.value = false;
  }
}
</script>

<template>
  <div class="auth-page">
    <GnCard class="register-card">
      <h1 class="register-title">{{ t("auth.registerTitle") }}</h1>
      <form class="register-form" @submit.prevent="submit">
        <GnInput v-model="nickname" :label="t('auth.nickname')" icon="ph-user" required />
        <GnInput v-model="email" :label="t('auth.email')" icon="ph-envelope" type="email" required />
        <GnInput
          v-model="password"
          :label="t('auth.password')"
          icon="ph-key"
          type="password"
          :help="t('auth.passwordHint')"
          required
        />
        <p v-if="error" class="register-error">{{ error }}</p>
        <GnButton type="submit" variant="accent" :loading="submitting" icon="ph-user-plus">
          {{ t("auth.registerSubmit") }}
        </GnButton>
      </form>
    </GnCard>
    <p class="auth-page-alt">
      {{ t("auth.haveAccount") }}
      <RouterLink to="/login">
        <GnButton variant="secondary" size="sm">{{ t("nav.login") }}</GnButton>
      </RouterLink>
    </p>
  </div>
</template>

<style scoped>
.auth-page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 24px;
}
.register-card {
  width: min(420px, 100%);
  padding: 24px;
}
.register-title {
  margin: 0 0 16px;
  font-size: 18px;
}
.register-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: flex-start;
}
.register-form > :deep(*) {
  width: 100%;
}
.register-error {
  color: var(--color-error, #f7768e);
  font-size: 12px;
  margin: 0;
}
.auth-page-alt {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  opacity: 0.8;
}
.auth-page-alt a {
  text-decoration: none;
}
</style>