222 lines
9.0 KiB
Vue
222 lines
9.0 KiB
Vue
<template>
|
||
<div class="register-area pt-120 pb-120">
|
||
<div class="container">
|
||
<div class="row justify-content-center">
|
||
<div class="col-lg-8 col-md-10">
|
||
<div class="register-form-wrap shadow-lg p-5 rounded bg-white">
|
||
<div class="register-header text-center mb-4">
|
||
<h2 class="mb-2">Hesap Oluşturun</h2>
|
||
<p>
|
||
Zaten hesabınız var mı?
|
||
<NuxtLink to="/auth/login" class="text-primary fw-bold">Giriş Yapın</NuxtLink>
|
||
</p>
|
||
</div>
|
||
|
||
<form @submit.prevent="handleRegister">
|
||
<div class="mb-3">
|
||
<label for="username" class="form-label">Kullanıcı Adı</label>
|
||
<div class="input-group">
|
||
<span class="input-group-text"><i class="fas fa-user"></i></span>
|
||
<input type="text" class="form-control" id="username" v-model="form.username"
|
||
placeholder="Kullanıcı adı seçin" required>
|
||
</div>
|
||
<div v-if="errors.username" class="text-danger small mt-1">{{ errors.username }}</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label for="first_name" class="form-label">Ad</label>
|
||
<input type="text" class="form-control" id="first_name" v-model="form.first_name"
|
||
placeholder="Adınız" required>
|
||
<div v-if="errors.first_name" class="text-danger small mt-1">{{ errors.first_name }}
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label for="last_name" class="form-label">Soyad</label>
|
||
<input type="text" class="form-control" id="last_name" v-model="form.last_name"
|
||
placeholder="Soyadınız" required>
|
||
<div v-if="errors.last_name" class="text-danger small mt-1">{{ errors.last_name }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label for="email" class="form-label">E-posta Adresi</label>
|
||
<div class="input-group">
|
||
<span class="input-group-text"><i class="fas fa-envelope"></i></span>
|
||
<input type="email" class="form-control" id="email" v-model="form.email"
|
||
placeholder="E-posta adresiniz" required>
|
||
</div>
|
||
<div v-if="errors.email" class="text-danger small mt-1">{{ errors.email }}</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label for="password" class="form-label">Şifre</label>
|
||
<div class="input-group">
|
||
<span class="input-group-text"><i class="fas fa-lock"></i></span>
|
||
<input type="password" class="form-control" id="password"
|
||
v-model="form.password" placeholder="Şifreniz" required>
|
||
</div>
|
||
<div v-if="errors.password" class="text-danger small mt-1">{{ errors.password }}
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label for="passwordConfirm" class="form-label">Şifre Tekrar</label>
|
||
<div class="input-group">
|
||
<span class="input-group-text"><i class="fas fa-lock"></i></span>
|
||
<input type="password" class="form-control" id="passwordConfirm"
|
||
v-model="form.passwordConfirm" placeholder="Şifrenizi tekrar girin"
|
||
required>
|
||
</div>
|
||
<div v-if="errors.passwordConfirm" class="text-danger small mt-1">{{
|
||
errors.passwordConfirm }}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Turnstile Component -->
|
||
<ClientOnly>
|
||
<div class="mb-4 d-flex justify-content-center">
|
||
<NuxtTurnstile v-model="turnstileToken" />
|
||
</div>
|
||
</ClientOnly>
|
||
|
||
<button type="submit" class="btn btn-success w-100 py-2" :disabled="loading">
|
||
<span v-if="loading" class="spinner-border spinner-border-sm me-2" role="status"
|
||
aria-hidden="true"></span>
|
||
{{ loading ? 'Kayıt Yapılıyor...' : 'Kayıt Ol' }}
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { registerSchema, type RegisterInput } from '~~/utils/validations';
|
||
import Swal from 'sweetalert2';
|
||
|
||
definePageMeta({
|
||
middleware: 'guest-only',
|
||
auth: { unauthenticatedOnly: true, navigateAuthenticatedTo: '/' }
|
||
});
|
||
|
||
const config = useRuntimeConfig();
|
||
const router = useRouter();
|
||
|
||
const form = reactive<RegisterInput>({
|
||
username: '',
|
||
first_name: '',
|
||
last_name: '',
|
||
email: '',
|
||
password: '',
|
||
passwordConfirm: ''
|
||
});
|
||
|
||
const errors = reactive<Partial<Record<keyof RegisterInput, string>>>({});
|
||
const loading = ref(false);
|
||
const turnstileToken = ref('');
|
||
|
||
const validate = () => {
|
||
// Zod validasyonu
|
||
const result = registerSchema.safeParse(form);
|
||
|
||
// Clear previous errors
|
||
Object.keys(errors).forEach(key => delete errors[key as keyof RegisterInput]);
|
||
|
||
if (!result.success) {
|
||
result.error.errors.forEach(err => {
|
||
if (err.path[0]) {
|
||
errors[err.path[0] as keyof RegisterInput] = err.message;
|
||
}
|
||
});
|
||
return false;
|
||
}
|
||
return true;
|
||
};
|
||
|
||
const handleRegister = async () => {
|
||
if (!validate()) return;
|
||
|
||
if (!turnstileToken.value) {
|
||
Swal.fire({
|
||
icon: 'warning',
|
||
title: 'Güvenlik Kontrolü',
|
||
text: 'Lütfen Turnstile güvenlik kontrolünü tamamlayın.',
|
||
timer: 3000,
|
||
toast: true,
|
||
position: 'top-end',
|
||
showConfirmButton: false
|
||
});
|
||
return;
|
||
}
|
||
|
||
loading.value = true;
|
||
|
||
try {
|
||
const apiUrl = config.public.NUXT_PUBLIC_API_BASE || 'http://127.0.0.1:8080';
|
||
|
||
// Backend API çağrısı
|
||
const response = await fetch(`${apiUrl}/api/v1/auth/register`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
username: form.username,
|
||
first_name: form.first_name,
|
||
last_name: form.last_name,
|
||
email: form.email,
|
||
password: form.password
|
||
})
|
||
});
|
||
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
|
||
Swal.fire({
|
||
icon: 'success',
|
||
title: 'Kayıt Başarılı!',
|
||
text: data.message || 'Lütfen e-posta adresinizi doğrulayın.',
|
||
confirmButtonText: 'Giriş Yap'
|
||
}).then((result) => {
|
||
if (result.isConfirmed) {
|
||
router.push('/auth/login');
|
||
}
|
||
});
|
||
} else {
|
||
const errorData = await response.json();
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Kayıt Hatası',
|
||
text: errorData.message || 'Kayıt işlemi sırasında bir hata oluştu.',
|
||
});
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error(error);
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Hata',
|
||
text: 'Sunucu ile iletişim hatası.',
|
||
});
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.register-area {
|
||
background-color: #f8f9fa;
|
||
min-height: 80vh;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.register-form-wrap {
|
||
border-top: 5px solid #198754;
|
||
}
|
||
</style> |