Login

This commit is contained in:
2025-09-20 02:13:02 +08:00
parent 48a9a97e18
commit e9c7559e38
15 changed files with 855 additions and 30 deletions

View File

@@ -0,0 +1,163 @@
<template>
<v-container class="d-flex align-center justify-center fill-height">
<v-card class="pa-4" max-width="500">
<v-card-title>Create a new Solar Network ID</v-card-title>
<v-overlay :model-value="isLoading" class="align-center justify-center">
<v-progress-circular indeterminate size="64" />
</v-overlay>
<v-form @submit.prevent="handleCreateAccount">
<v-text-field
v-model="formModel.name"
label="Username"
variant="outlined"
:rules="nameRules"
class="mb-4"
/>
<v-text-field
v-model="formModel.nick"
label="Nickname"
variant="outlined"
:rules="nickRules"
class="mb-4"
/>
<v-text-field
v-model="formModel.email"
label="Email"
placeholder="your@email.com"
variant="outlined"
:rules="emailRules"
class="mb-4"
/>
<v-text-field
v-model="formModel.password"
label="Password"
type="password"
placeholder="Enter your password"
variant="outlined"
:rules="passwordRules"
class="mb-4"
/>
<div class="d-flex justify-center mb-4">
<client-only>
<captcha-widget
:provider="captchaProvider"
:api-key="captchaApiKey"
@verified="onCaptchaVerified"
/>
</client-only>
</div>
<v-btn
type="submit"
color="primary"
block
size="large"
:disabled="isLoading"
>
Create Account
</v-btn>
<div class="mt-3 text-center text-body-2 opacity-75">
<v-btn
variant="text"
block
size="small"
to="/auth/login"
>
Already have an account? Login
</v-btn>
</div>
</v-form>
<v-alert
v-if="error"
type="error"
closable
class="mt-4"
@update:model-value="error = null"
>
{{ error }}
</v-alert>
</v-card>
</v-container>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue"
import { useRouter } from "vue-router"
import { useSolarNetwork } from "~/composables/useSolarNetwork"
import CaptchaWidget from "~/components/CaptchaWidget.vue"
const router = useRouter()
const api = useSolarNetwork()
const isLoading = ref(false)
const error = ref<string | null>(null)
const formModel = reactive({
name: "",
nick: "",
email: "",
password: "",
language: "en-us",
captchaToken: ""
})
// Get captcha provider and API key from global data
const captchaProvider = ref((window as { DyPrefetch?: { provider?: string } }).DyPrefetch?.provider || "")
const captchaApiKey = ref((window as { DyPrefetch?: { api_key?: string } }).DyPrefetch?.api_key || "")
const nameRules = [
(v: string) => !!v || "Please enter a username",
(v: string) =>
/^[A-Za-z0-9_-]+$/.test(v) ||
"Username can only contain letters, numbers, underscores, and hyphens."
]
const nickRules = [(v: string) => !!v || "Please enter a nickname"]
const emailRules = [
(v: string) => !!v || "Please enter your email",
(v: string) => /.+@.+\..+/.test(v) || "Please enter a valid email address"
]
const passwordRules = [
(v: string) => !!v || "Please enter a password",
(v: string) => v.length >= 4 || "Password must be at least 4 characters long"
]
const onCaptchaVerified = (token: string) => {
formModel.captchaToken = token
}
async function handleCreateAccount() {
isLoading.value = true
error.value = null
try {
await api("/id/accounts", {
method: "POST",
body: {
name: formModel.name,
nick: formModel.nick,
email: formModel.email,
password: formModel.password,
language: formModel.language,
captcha_token: formModel.captchaToken
}
})
// On success, redirect to login page
alert(
"Welcome to Solar Network! Your account has been created successfully. Don't forget to check your email for activation instructions."
)
router.push("/login")
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : 'An error occurred'
} finally {
isLoading.value = false
}
}
</script>