Files
money.sori.studio/pages/login.vue

101 lines
3.6 KiB
Vue

<template>
<section class="flex min-h-dvh flex-col justify-center px-5 py-6 md:mx-auto md:max-w-sm">
<div class="mb-6">
<p class="text-sm font-semibold text-brand-700">Money</p>
<h1 class="mt-2 text-2xl font-bold tracking-normal text-ink">빠르게 기록하는 개인 가계부</h1>
<p class="mt-2 text-sm leading-6 text-muted">계정을 만들면 내 자산, 카테고리, 거래 내역을 따로 관리할 수 있습니다.</p>
</div>
<div class="mb-4 grid grid-cols-2 gap-2">
<button
type="button"
class="segmented-button border border-line py-2.5"
:class="{ 'border-red-500 text-red-600': mode === 'login' }"
@click="mode = 'login'"
>
로그인
</button>
<button
type="button"
class="segmented-button border border-line py-2.5"
:class="{ 'border-red-500 text-red-600': mode === 'register' }"
@click="mode = 'register'"
>
회원가입
</button>
</div>
<form class="space-y-3" @submit.prevent="submit">
<div v-if="mode === 'register'">
<label class="label" for="name">이름</label>
<input id="name" v-model="name" class="field" autocomplete="name" placeholder="표시 이름">
</div>
<div>
<label class="label" for="email">이메일</label>
<input id="email" v-model="email" class="field" type="email" autocomplete="email" placeholder="you@example.com" required>
</div>
<div>
<label class="label" for="password">비밀번호</label>
<input
id="password"
v-model="password"
class="field"
type="password"
:autocomplete="mode === 'login' ? 'current-password' : 'new-password'"
placeholder="8자 이상"
required
>
</div>
<p v-if="error" class="text-sm font-medium text-red-600">{{ error }}</p>
<button class="btn-primary w-full" type="submit" :disabled="pending">
{{ pending ? '확인 중...' : mode === 'login' ? '로그인' : '가입하고 시작하기' }}
</button>
</form>
</section>
</template>
<script setup lang="ts">
type AuthMode = 'login' | 'register'
const mode = ref<AuthMode>('login')
const name = ref('')
const email = ref('')
const password = ref('')
const error = ref('')
const pending = ref(false)
const session = useState('session')
async function submit() {
pending.value = true
error.value = ''
try {
const endpoint = mode.value === 'login' ? '/api/auth/login' : '/api/auth/register'
session.value = await $fetch(endpoint, {
method: 'POST',
body: { name: name.value, email: email.value, password: password.value }
})
await navigateTo('/')
} catch (err: any) {
const status = err?.statusCode || err?.response?.status
const statusMessage = err?.statusMessage || err?.response?._data?.statusMessage || ''
if (mode.value === 'register' && status === 409) {
error.value = '이미 가입된 이메일입니다.'
} else if (mode.value === 'register' && statusMessage) {
error.value = statusMessage === 'Invalid registration'
? '이메일과 8자 이상 비밀번호를 확인해 주세요.'
: '가입 처리 중 문제가 생겼습니다. 잠시 후 다시 시도해 주세요.'
} else if (mode.value === 'register') {
error.value = '가입 처리 중 문제가 생겼습니다. 잠시 후 다시 시도해 주세요.'
} else {
error.value = '이메일 또는 비밀번호를 확인해 주세요.'
}
} finally {
pending.value = false
}
}
watch(mode, () => {
error.value = ''
})
</script>