✨ Sign up
This commit is contained in:
		@@ -9,7 +9,9 @@
 | 
				
			|||||||
        </v-alert>
 | 
					        </v-alert>
 | 
				
			||||||
      </v-expand-transition>
 | 
					      </v-expand-transition>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div class="flex justify-end">
 | 
					      <div class="flex justify-between">
 | 
				
			||||||
 | 
					        <v-btn type="button" variant="plain" color="grey-darken-3" :to="{ name: 'auth.sign-up' }">Sign up</v-btn>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <v-btn
 | 
					        <v-btn
 | 
				
			||||||
          type="submit"
 | 
					          type="submit"
 | 
				
			||||||
          variant="text"
 | 
					          variant="text"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								pkg/views/src/components/auth/CallbackNotify.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								pkg/views/src/components/auth/CallbackNotify.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="w-full max-w-[720px]">
 | 
				
			||||||
 | 
					    <v-expand-transition>
 | 
				
			||||||
 | 
					      <v-alert v-show="route.query['redirect_uri']" variant="tonal" type="info" class="text-xs">
 | 
				
			||||||
 | 
					        You need to sign in before access that page. After you signed in, we will redirect you to: <br />
 | 
				
			||||||
 | 
					        <span class="font-mono">{{ route.query["redirect_uri"] }}</span>
 | 
				
			||||||
 | 
					      </v-alert>
 | 
				
			||||||
 | 
					    </v-expand-transition>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { useRoute } from "vue-router"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const route = useRoute()
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@@ -15,8 +15,8 @@
 | 
				
			|||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <v-list density="compact">
 | 
					        <v-list density="compact">
 | 
				
			||||||
          <v-list-item title="Sign in" prepend-icon="mdi-login-variant" />
 | 
					          <v-list-item title="Sign in" prepend-icon="mdi-login-variant" :to="{ name: 'auth.sign-in' }" />
 | 
				
			||||||
          <v-list-item title="Create account" prepend-icon="mdi-account-plus" />
 | 
					          <v-list-item title="Create account" prepend-icon="mdi-account-plus" :to="{ name: 'auth.sign-up' }" />
 | 
				
			||||||
        </v-list>
 | 
					        </v-list>
 | 
				
			||||||
      </v-menu>
 | 
					      </v-menu>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ const router = createRouter({
 | 
				
			|||||||
      path: "/auth",
 | 
					      path: "/auth",
 | 
				
			||||||
      children: [
 | 
					      children: [
 | 
				
			||||||
        { path: "sign-in", name: "auth.sign-in", component: () => import("@/views/auth/sign-in.vue") },
 | 
					        { path: "sign-in", name: "auth.sign-in", component: () => import("@/views/auth/sign-in.vue") },
 | 
				
			||||||
        // { path: "sign-up", name: "auth.sign-up", component: () => import("@/views/auth/sign-up.vue") },
 | 
					        { path: "sign-up", name: "auth.sign-up", component: () => import("@/views/auth/sign-up.vue") },
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <v-container class="h-screen flex flex-col gap-3 items-center justify-center">
 | 
					  <v-container class="h-screen flex flex-col gap-3 items-center justify-center">
 | 
				
			||||||
 | 
					    <callback-notify />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <v-card class="w-full max-w-[720px]" :loading="loading">
 | 
					    <v-card class="w-full max-w-[720px]" :loading="loading">
 | 
				
			||||||
      <v-card-text class="card-grid pa-9">
 | 
					      <v-card-text class="card-grid pa-9">
 | 
				
			||||||
        <div>
 | 
					        <div>
 | 
				
			||||||
@@ -30,6 +32,7 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { ref, type Component } from "vue"
 | 
					import { ref, type Component } from "vue"
 | 
				
			||||||
import Copyright from "@/components/Copyright.vue"
 | 
					import Copyright from "@/components/Copyright.vue"
 | 
				
			||||||
 | 
					import CallbackNotify from "@/components/auth/CallbackNotify.vue"
 | 
				
			||||||
import AccountLocator from "@/components/auth/AccountLocator.vue"
 | 
					import AccountLocator from "@/components/auth/AccountLocator.vue"
 | 
				
			||||||
import FactorPicker from "@/components/auth/FactorPicker.vue"
 | 
					import FactorPicker from "@/components/auth/FactorPicker.vue"
 | 
				
			||||||
import FactorApplicator from "@/components/auth/FactorApplicator.vue"
 | 
					import FactorApplicator from "@/components/auth/FactorApplicator.vue"
 | 
				
			||||||
@@ -66,4 +69,3 @@ const panels: { [id: string]: Component } = {
 | 
				
			|||||||
  border-radius: 8px;
 | 
					  border-radius: 8px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
@/components/Copyright.vue
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										162
									
								
								pkg/views/src/views/auth/sign-up.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								pkg/views/src/views/auth/sign-up.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <v-container class="h-screen flex flex-col gap-3 items-center justify-center">
 | 
				
			||||||
 | 
					    <callback-notify />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <v-card class="w-full max-w-[720px]" :loading="loading">
 | 
				
			||||||
 | 
					      <v-card-text class="card-grid pa-9">
 | 
				
			||||||
 | 
					        <div>
 | 
				
			||||||
 | 
					          <v-avatar color="accent" icon="mdi-login-variant" size="large" class="card-rounded mb-2" />
 | 
				
			||||||
 | 
					          <h1 class="text-2xl">Create an account</h1>
 | 
				
			||||||
 | 
					          <p>Create an account on Solar Network. Then enjoy all our services.</p>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="flex items-center">
 | 
				
			||||||
 | 
					          <v-form class="flex-grow-1" @submit.prevent="submit">
 | 
				
			||||||
 | 
					            <v-row dense class="mb-3">
 | 
				
			||||||
 | 
					              <v-col :cols="6">
 | 
				
			||||||
 | 
					                <v-text-field
 | 
				
			||||||
 | 
					                  hide-details
 | 
				
			||||||
 | 
					                  label="Name"
 | 
				
			||||||
 | 
					                  autocomplete="username"
 | 
				
			||||||
 | 
					                  variant="solo"
 | 
				
			||||||
 | 
					                  density="comfortable"
 | 
				
			||||||
 | 
					                  v-model="data.name"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </v-col>
 | 
				
			||||||
 | 
					              <v-col :cols="6">
 | 
				
			||||||
 | 
					                <v-text-field
 | 
				
			||||||
 | 
					                  hide-details
 | 
				
			||||||
 | 
					                  label="Nick"
 | 
				
			||||||
 | 
					                  autocomplete="nickname"
 | 
				
			||||||
 | 
					                  variant="solo"
 | 
				
			||||||
 | 
					                  density="comfortable"
 | 
				
			||||||
 | 
					                  v-model="data.nick"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </v-col>
 | 
				
			||||||
 | 
					              <v-col :cols="12">
 | 
				
			||||||
 | 
					                <v-text-field
 | 
				
			||||||
 | 
					                  hide-details
 | 
				
			||||||
 | 
					                  label="Email Address"
 | 
				
			||||||
 | 
					                  type="email"
 | 
				
			||||||
 | 
					                  variant="solo"
 | 
				
			||||||
 | 
					                  density="comfortable"
 | 
				
			||||||
 | 
					                  v-model="data.email"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </v-col>
 | 
				
			||||||
 | 
					              <v-col :cols="12">
 | 
				
			||||||
 | 
					                <v-text-field
 | 
				
			||||||
 | 
					                  hide-details
 | 
				
			||||||
 | 
					                  label="Password"
 | 
				
			||||||
 | 
					                  type="password"
 | 
				
			||||||
 | 
					                  autocomplete="new-password"
 | 
				
			||||||
 | 
					                  variant="solo"
 | 
				
			||||||
 | 
					                  density="comfortable"
 | 
				
			||||||
 | 
					                  v-model="data.password"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </v-col>
 | 
				
			||||||
 | 
					            </v-row>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <v-expand-transition>
 | 
				
			||||||
 | 
					              <v-alert v-show="error" variant="tonal" type="error" class="text-xs mb-3">
 | 
				
			||||||
 | 
					                Something went wrong... {{ error }}
 | 
				
			||||||
 | 
					              </v-alert>
 | 
				
			||||||
 | 
					            </v-expand-transition>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <div class="flex justify-between">
 | 
				
			||||||
 | 
					              <v-btn type="button" variant="plain" color="grey-darken-3" :to="{ name: 'auth.sign-in' }">
 | 
				
			||||||
 | 
					                Sign in
 | 
				
			||||||
 | 
					              </v-btn>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <v-btn type="submit" variant="text" color="primary" append-icon="mdi-arrow-right" :disabled="loading">
 | 
				
			||||||
 | 
					                Next
 | 
				
			||||||
 | 
					              </v-btn>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </v-form>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </v-card-text>
 | 
				
			||||||
 | 
					    </v-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <v-dialog v-model="done" class="max-w-[560px]">
 | 
				
			||||||
 | 
					      <v-card title="Congratulations">
 | 
				
			||||||
 | 
					        <template #text>
 | 
				
			||||||
 | 
					          You successfully created an account on Solar Network. Now sign in to your account and start exploring!
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #actions>
 | 
				
			||||||
 | 
					          <div class="flex flex-grow-1 justify-end">
 | 
				
			||||||
 | 
					            <v-btn @click="callback">Let's go</v-btn>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					      </v-card>
 | 
				
			||||||
 | 
					    </v-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <copyright />
 | 
				
			||||||
 | 
					  </v-container>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { ref } from "vue"
 | 
				
			||||||
 | 
					import { request } from "@/scripts/request"
 | 
				
			||||||
 | 
					import { useRoute, useRouter } from "vue-router"
 | 
				
			||||||
 | 
					import Copyright from "@/components/Copyright.vue"
 | 
				
			||||||
 | 
					import CallbackNotify from "@/components/auth/CallbackNotify.vue"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const error = ref<string | null>(null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const route = useRoute()
 | 
				
			||||||
 | 
					const router = useRouter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const done = ref(false)
 | 
				
			||||||
 | 
					const loading = ref(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const data = ref({
 | 
				
			||||||
 | 
					  name: "",
 | 
				
			||||||
 | 
					  nick: "",
 | 
				
			||||||
 | 
					  email: "",
 | 
				
			||||||
 | 
					  password: "",
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function submit() {
 | 
				
			||||||
 | 
					  const payload = data.value
 | 
				
			||||||
 | 
					  if (!payload.name || !payload.nick || !payload.email || !payload.password) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loading.value = true
 | 
				
			||||||
 | 
					  const res = await request("/api/users", {
 | 
				
			||||||
 | 
					    method: "POST",
 | 
				
			||||||
 | 
					    headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    body: JSON.stringify(data),
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					  if (res.status !== 200) {
 | 
				
			||||||
 | 
					    error.value = await res.text()
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    done.value = true
 | 
				
			||||||
 | 
					    error.value = null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  loading.value = false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function callback() {
 | 
				
			||||||
 | 
					  if (route.params["closable"]) {
 | 
				
			||||||
 | 
					    window.close()
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    router.push({ name: "auth.sign-in" })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					.card-grid {
 | 
				
			||||||
 | 
					  display: grid;
 | 
				
			||||||
 | 
					  grid-template-columns: 1fr 1fr;
 | 
				
			||||||
 | 
					  gap: 1rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@media (max-width: 768px) {
 | 
				
			||||||
 | 
					  .card-grid {
 | 
				
			||||||
 | 
					    grid-template-columns: 1fr;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.card-rounded {
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
		Reference in New Issue
	
	Block a user