giftcon_dev/resources/views/web/auth/register.blade.php
2026-01-26 12:59:59 +09:00

185 lines
7.3 KiB
PHP

@extends('web.layouts.auth')
@section('title', '회원가입 | PIN FOR YOU')
@section('meta_description', 'PIN FOR YOU 회원가입 페이지입니다.')
@section('canonical', url('/auth/register'))
@section('h1', '회원가입')
@section('desc', '휴대폰 번호로 가입 여부를 먼저 확인한 뒤, PASS 본인인증을 진행합니다.')
@section('card_aria', '회원가입 Step0 - 휴대폰 확인')
@section('show_cs_links', true)
@section('auth_content')
{{-- Step0 Hero Image + 안내문구 --}}
<img
class="reg-step0-hero__img"
src="{{ asset('assets/images/web/member/register.webp') }}"
alt=""
loading="lazy"
onerror="this.style.display='none';"
style="padding-bottom:15px"
/>
<form class="auth-form" id="regStep0Form" onsubmit="return false;">
@csrf
{{-- hidden input만 생성(토큰은 JS에서 발급 payload에 포함) --}}
<x-recaptcha-v3 />
<div class="auth-field">
<label class="auth-label" for="reg_phone">
휴대폰 번호 <small>가입 여부 확인</small>
</label>
<input class="auth-input" id="reg_phone" name="phone" type="tel"
placeholder="010-0000-0000"
autocomplete="tel"
inputmode="numeric"
maxlength="13">
<div class="auth-help" id="reg_phone_help" style="display:none;"></div>
</div>
<div class="auth-actions">
<button class="auth-btn auth-btn--primary" id="reg_next_btn" type="submit">다음</button>
<a class="auth-btn auth-btn--ghost" href="{{ route('web.auth.login') }}">
이미 계정이 있어요 (로그인)
</a>
</div>
</form>
{{-- reCAPTCHA 스크립트/공통함수는 페이지에서만 로드 --}}
@push('recaptcha')
<script>window.__recaptchaSiteKey = @json(config('services.recaptcha.site_key'));</script>
<script src="https://www.google.com/recaptcha/api.js?render={{ config('services.recaptcha.site_key') }}"></script>
<script src="{{ asset('assets/js/recaptcha-v3.js') }}"></script>
@endpush
<script>
(function () {
const form = document.getElementById('regStep0Form');
const input = document.getElementById('reg_phone');
const help = document.getElementById('reg_phone_help');
const btn = document.getElementById('reg_next_btn');
// 숫자만 남기고 010-0000-0000 형태로 포맷
function formatPhone(value) {
const digits = (value || '').replace(/\D/g, '').slice(0, 11);
if (digits.length <= 3) return digits;
if (digits.length <= 7) return digits.slice(0, 3) + '-' + digits.slice(3);
return digits.slice(0, 3) + '-' + digits.slice(3, 7) + '-' + digits.slice(7);
}
// 서버 전송용(숫자만)
function toDigits(value) {
return (value || '').replace(/\D/g, '');
}
input.addEventListener('input', function () {
const formatted = formatPhone(input.value);
if (input.value !== formatted) input.value = formatted;
});
input.addEventListener('keydown', function (e) {
const allowKeys = ['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab', 'Home', 'End'];
if (allowKeys.includes(e.key)) return;
if (e.ctrlKey || e.metaKey) return;
if (!/^\d$/.test(e.key)) e.preventDefault();
});
input.addEventListener('paste', function (e) {
e.preventDefault();
const text = (e.clipboardData || window.clipboardData).getData('text') || '';
const digits = text.replace(/\D/g, '');
input.value = formatPhone(digits);
});
form.addEventListener('submit', async function () {
clearMsg();
const phoneDigits = toDigits(input.value);
if (!phoneDigits) {
await showMsg('휴대폰 번호를 입력해 주세요.', { type:'alert', title:'입력오류' });
input.focus();
return;
}
if (phoneDigits.length < 10) {
await showMsg('휴대폰 번호를 끝까지 입력해 주세요.', { type:'alert', title:'입력오류' });
input.focus();
return;
}
btn.disabled = true;
try {
// ✅ 공통 함수로 토큰 발급 (한 줄)
const token = await window.recaptchaV3Token('register_phone_check', form);
const res = await fetch("{{ route('web.auth.register.phone_check') }}", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": "{{ csrf_token() }}",
"Accept": "application/json"
},
body: JSON.stringify({
phone: phoneDigits,
"g-recaptcha-response": token
})
});
// 422/403에서도 JSON 잘 파싱되게 안전 처리
const raw = await res.text();
let data = {};
try { data = JSON.parse(raw || "{}"); } catch (e) { data = {}; }
// 공통 메시지
const msg = data.message || '처리에 실패했습니다.';
// 1) 이미 가입(=confirm)
if (data.reason === 'already_member') {
await showMsg(msg, {
type: 'confirm',
title: '안내',
okText: '이동',
cancelText: '취소',
redirect: data.redirect,
});
return;
}
// 2) 성공(=confirm)
if (data.ok === true) {
await showMsg(msg || '회원가입 가능한 전화번호 입니다.\n\n인증페이지로 이동합니다.', {
type: 'confirm',
title: '안내',
okText: '이동',
cancelText: '취소',
redirect: data.redirect,
});
return;
}
// 3) 나머지 전부 실패(=alert)
await showMsg(msg, {
type: 'alert',
title: '안내',
});
} catch (e) {
await showMsg("네트워크 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.", {
type:'alert',
title:'네트워크오류'
});
} finally {
btn.disabled = false;
}
});
})();
</script>
@endsection
@section('auth_bottom')
@endsection