profileShare

rasmusjy / splitapp-frontend-vue

Read-only snapshot

No repository description.

main default branch 96 files Expires Sep 13, 2026, 9:06 AM
RegisterView.vue 4,702 bytes
1 <script setup lang="ts">
2 import { ref } from 'vue'
3 import { useRouter } from 'vue-router'
4 import { useI18n } from 'vue-i18n'
5 import { useAuthStore } from '@/stores/auth'
6 import AccountService from '@/services/AccountService'
7
8 const router = useRouter()
9 const authStore = useAuthStore()
10 const { t } = useI18n()
11
12 const firstName = ref('')
13 const lastName = ref('')
14 const email = ref('')
15 const password = ref('')
16 const errors = ref<string[]>([])
17 const isLoading = ref(false)
18
19 async function handleRegister() {
20 errors.value = []
21 isLoading.value = true
22
23 const result = await AccountService.registerAsync(
24 email.value,
25 password.value,
26 firstName.value,
27 lastName.value,
28 )
29
30 if (result.errors) {
31 errors.value = result.errors
32 } else if (result.data) {
33 authStore.jwt = result.data.jwt
34 authStore.refreshToken = result.data.refreshToken
35 authStore.userName = `${result.data.firstName} ${result.data.lastName}`
36 router.push({ name: 'Home' })
37 }
38
39 isLoading.value = false
40 }
41 </script>
42
43 <template>
44 <div class="sa-auth-page">
45 <div class="sa-auth-card sa-card sa-animate-fade-in">
46 <div class="sa-card-body" style="padding: var(--sa-space-10) var(--sa-space-8)">
47 <!-- Brand -->
48 <div class="sa-auth-brand">
49 <div class="sa-auth-logo">
50 <i class="bi bi-airplane-fill"></i>
51 </div>
52 <h1 class="sa-text-primary">SplitApp</h1>
53 <p>{{ t('auth.register.getStarted') }}</p>
54 </div>
55
56 <!-- Errors -->
57 <div v-if="errors.length" class="sa-card-static sa-card-accent sa-card-accent-danger mb-4">
58 <div class="sa-card-body" style="padding: var(--sa-space-3) var(--sa-space-4)">
59 <div v-for="error in errors" :key="error" style="font-size: 0.875rem">
60 <i class="bi bi-exclamation-circle me-1"></i>{{ error }}
61 </div>
62 </div>
63 </div>
64
65 <!-- Form -->
66 <form @submit.prevent="handleRegister">
67 <div class="d-flex gap-3 mb-3">
68 <div class="flex-fill">
69 <label for="firstName" class="form-label">{{ t('auth.register.firstName') }}</label>
70 <input
71 id="firstName"
72 v-model="firstName"
73 type="text"
74 class="form-control"
75 :placeholder="t('auth.register.firstNamePlaceholder')"
76 required
77 />
78 </div>
79 <div class="flex-fill">
80 <label for="lastName" class="form-label">{{ t('auth.register.lastName') }}</label>
81 <input
82 id="lastName"
83 v-model="lastName"
84 type="text"
85 class="form-control"
86 :placeholder="t('auth.register.lastNamePlaceholder')"
87 required
88 />
89 </div>
90 </div>
91
92 <div class="mb-3">
93 <label for="email" class="form-label">{{ t('auth.register.email') }}</label>
94 <input
95 id="email"
96 v-model="email"
97 type="email"
98 class="form-control"
99 :placeholder="t('auth.register.emailPlaceholder')"
100 required
101 autocomplete="email"
102 />
103 </div>
104
105 <div class="mb-4">
106 <label for="password" class="form-label">{{ t('auth.register.password') }}</label>
107 <input
108 id="password"
109 v-model="password"
110 type="password"
111 class="form-control"
112 :placeholder="t('auth.register.passwordPlaceholder')"
113 required
114 minlength="6"
115 autocomplete="new-password"
116 />
117 </div>
118
119 <button
120 type="submit"
121 class="sa-btn sa-btn-primary w-100"
122 :class="{ 'sa-btn-loading': isLoading }"
123 :disabled="isLoading"
124 >
125 {{ isLoading ? t('auth.register.creatingAccount') : t('auth.register.createAccount') }}
126 </button>
127 </form>
128
129 <!-- Login link -->
130 <div class="text-center mt-4" style="font-size: 0.938rem; color: var(--sa-gray-500)">
131 {{ t('auth.register.haveAccount') }}
132 <RouterLink :to="{ name: 'Login' }" style="font-weight: 600">{{ t('auth.register.signIn') }}</RouterLink>
133 </div>
134 </div>
135 </div>
136 </div>
137 </template>
138
139 <style scoped>
140 .sa-auth-logo {
141 width: 56px;
142 height: 56px;
143 border-radius: 16px;
144 background: linear-gradient(135deg, #e8604c 0%, #d4456a 100%);
145 display: flex;
146 align-items: center;
147 justify-content: center;
148 font-size: 1.5rem;
149 color: #fff;
150 margin: 0 auto 16px;
151 }
152 </style>
153