fix: align frontend types and forms with api_yal backend (name→first_name+last_name, token→access_token)

This commit is contained in:
valitovgaziz
2026-06-12 01:41:23 +05:00
parent ba7b757541
commit 9c793bad1b
7 changed files with 61 additions and 49 deletions
@@ -31,8 +31,7 @@
<span v-if="notifCount" class="badge">{{ notifCount }}</span> <span v-if="notifCount" class="badge">{{ notifCount }}</span>
</NuxtLink> </NuxtLink>
<NuxtLink to="/profile" class="header__profile"> <NuxtLink to="/profile" class="header__profile">
<img v-if="user?.avatar" :src="user.avatar" alt="" class="avatar avatar--sm" /> <span class="avatar avatar--sm header__avatar-placeholder">{{ userInitials }}</span>
<span v-else class="avatar avatar--sm header__avatar-placeholder">{{ userInitials }}</span>
</NuxtLink> </NuxtLink>
</template> </template>
<template v-else> <template v-else>
@@ -62,8 +61,8 @@ const menuOpen = ref(false)
const notifCount = ref(0) const notifCount = ref(0)
const userInitials = computed(() => { const userInitials = computed(() => {
if (!user.value?.name) return '?' if (!user.value?.full_name) return '?'
return user.value.name.charAt(0).toUpperCase() return user.value.full_name.charAt(0).toUpperCase()
}) })
</script> </script>
@@ -12,11 +12,10 @@ export const useAuth = () => {
} }
const register = async (data: { const register = async (data: {
name: string first_name: string
last_name: string
email: string email: string
password: string password: string
password_confirm: string
phone?: string
}) => { }) => {
await authStore.register(data) await authStore.register(data)
} }
@@ -7,14 +7,27 @@
<div class="form-group"> <div class="form-group">
<label class="form-label">Имя</label> <label class="form-label">Имя</label>
<input <input
v-model="name" v-model="firstName"
type="text" type="text"
class="form-input" class="form-input"
:class="{ 'form-input--error': errors.name }" :class="{ 'form-input--error': errors.firstName }"
placeholder="Ваше имя" placeholder="Ваше имя"
required required
/> />
<span v-if="errors.name" class="form-error">{{ errors.name }}</span> <span v-if="errors.firstName" class="form-error">{{ errors.firstName }}</span>
</div>
<div class="form-group">
<label class="form-label">Фамилия</label>
<input
v-model="lastName"
type="text"
class="form-input"
:class="{ 'form-input--error': errors.lastName }"
placeholder="Ваша фамилия"
required
/>
<span v-if="errors.lastName" class="form-error">{{ errors.lastName }}</span>
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -30,16 +43,6 @@
<span v-if="errors.email" class="form-error">{{ errors.email }}</span> <span v-if="errors.email" class="form-error">{{ errors.email }}</span>
</div> </div>
<div class="form-group">
<label class="form-label">Телефон</label>
<input
v-model="phone"
type="tel"
class="form-input"
placeholder="+7 (XXX) XXX-XX-XX"
/>
</div>
<div class="form-group"> <div class="form-group">
<label class="form-label">Пароль</label> <label class="form-label">Пароль</label>
<input <input
@@ -91,13 +94,14 @@ definePageMeta({
middleware: 'guest', middleware: 'guest',
}) })
const name = ref('') const firstName = ref('')
const lastName = ref('')
const email = ref('') const email = ref('')
const phone = ref('')
const password = ref('') const password = ref('')
const passwordConfirm = ref('') const passwordConfirm = ref('')
const errors = reactive({ const errors = reactive({
name: '', firstName: '',
lastName: '',
email: '', email: '',
password: '', password: '',
passwordConfirm: '', passwordConfirm: '',
@@ -108,13 +112,15 @@ const loading = ref(false)
const { register } = useAuth() const { register } = useAuth()
async function handleRegister() { async function handleRegister() {
errors.name = '' errors.firstName = ''
errors.lastName = ''
errors.email = '' errors.email = ''
errors.password = '' errors.password = ''
errors.passwordConfirm = '' errors.passwordConfirm = ''
apiError.value = '' apiError.value = ''
if (!name.value) { errors.name = 'Введите имя'; return } if (!firstName.value) { errors.firstName = 'Введите имя'; return }
if (!lastName.value) { errors.lastName = 'Введите фамилию'; return }
if (!email.value) { errors.email = 'Введите email'; return } if (!email.value) { errors.email = 'Введите email'; return }
if (!password.value || password.value.length < 6) { if (!password.value || password.value.length < 6) {
errors.password = 'Пароль минимум 6 символов' errors.password = 'Пароль минимум 6 символов'
@@ -128,11 +134,10 @@ async function handleRegister() {
loading.value = true loading.value = true
try { try {
await register({ await register({
name: name.value, first_name: firstName.value,
last_name: lastName.value,
email: email.value, email: email.value,
password: password.value, password: password.value,
password_confirm: passwordConfirm.value,
phone: phone.value || undefined,
}) })
navigateTo('/') navigateTo('/')
} catch (e: any) { } catch (e: any) {
@@ -18,13 +18,12 @@
<template v-else-if="user"> <template v-else-if="user">
<div class="profile__header"> <div class="profile__header">
<div class="profile__avatar"> <div class="profile__avatar">
<img v-if="user.avatar" :src="user.avatar" alt="" class="avatar avatar--lg" /> <span class="avatar avatar--lg profile__avatar-placeholder">
<span v-else class="avatar avatar--lg profile__avatar-placeholder">
{{ userInitials }} {{ userInitials }}
</span> </span>
</div> </div>
<div class="profile__info"> <div class="profile__info">
<h2>{{ user.name }}</h2> <h2>{{ user.full_name }}</h2>
<p class="body-text--gray">{{ user.email }}</p> <p class="body-text--gray">{{ user.email }}</p>
<span class="tag" style="margin-top: 8px"> <span class="tag" style="margin-top: 8px">
{{ user.role === 'admin' ? 'Администратор' : user.role === 'moderator' ? 'Модератор' : 'Пользователь' }} {{ user.role === 'admin' ? 'Администратор' : user.role === 'moderator' ? 'Модератор' : 'Пользователь' }}
@@ -82,8 +81,8 @@ const reviewsCount = ref(0)
const favoritesCount = ref(0) const favoritesCount = ref(0)
const userInitials = computed(() => { const userInitials = computed(() => {
if (!user.value?.name) return '?' if (!user.value?.full_name) return '?'
return user.value.name.charAt(0).toUpperCase() return user.value.full_name.charAt(0).toUpperCase()
}) })
function handleLogout() { function handleLogout() {
@@ -1,5 +1,5 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import type { User, LoginRequest, RegisterRequest } from '~/types' import type { User, LoginRequest, RegisterRequest, AuthResponse } from '~/types'
interface AuthState { interface AuthState {
user: User | null user: User | null
@@ -23,8 +23,8 @@ export const useAuthStore = defineStore('auth', {
this.loading = true this.loading = true
try { try {
const api = useApi() const api = useApi()
const response = await api.post<{ access_token: string; user: User }>('/auth/login', { email, password }) const response = await api.post<AuthResponse>('/auth/login', { email, password })
this.token = response.access_token this.token = response.token
this.user = response.user this.user = response.user
await this.fetchUser() await this.fetchUser()
} finally { } finally {
@@ -36,8 +36,8 @@ export const useAuthStore = defineStore('auth', {
this.loading = true this.loading = true
try { try {
const api = useApi() const api = useApi()
const response = await api.post<{ access_token: string; user: User }>('/auth/register', data) const response = await api.post<AuthResponse>('/auth/register', data)
this.token = response.access_token this.token = response.token
this.user = response.user this.user = response.user
} finally { } finally {
this.loading = false this.loading = false
@@ -48,7 +48,8 @@ export const useAuthStore = defineStore('auth', {
if (!this.token) return if (!this.token) return
try { try {
const api = useApi() const api = useApi()
this.user = await api.get<User>('/me') const profile = await api.get<Partial<User>>('/me')
this.user = this.user ? { ...this.user, ...profile } : (profile as User)
} catch { } catch {
this.token = null this.token = null
this.user = null this.user = null
@@ -58,8 +59,8 @@ export const useAuthStore = defineStore('auth', {
async refreshToken(): Promise<boolean> { async refreshToken(): Promise<boolean> {
try { try {
const api = useApi() const api = useApi()
const response = await api.post<{ access_token: string }>('/auth/refresh') const response = await api.post<{ token: string }>('/auth/refresh')
this.token = response.access_token this.token = response.token
return true return true
} catch { } catch {
this.token = null this.token = null
@@ -1,16 +1,19 @@
export interface User { export interface User {
id: number id: number
name: string
email: string email: string
phone?: string first_name: string
avatar?: string last_name: string
full_name: string
role: 'user' | 'admin' | 'moderator' role: 'user' | 'admin' | 'moderator'
phone?: string
city?: string
created_at?: string created_at?: string
updated_at?: string
} }
export interface AuthTokens { export interface AuthTokens {
access_token: string token: string
refresh_token?: string expires_at: string
} }
export interface LoginRequest { export interface LoginRequest {
@@ -19,11 +22,10 @@ export interface LoginRequest {
} }
export interface RegisterRequest { export interface RegisterRequest {
name: string first_name: string
last_name: string
email: string email: string
password: string password: string
password_confirm: string
phone?: string
} }
export interface ResetPasswordRequest { export interface ResetPasswordRequest {
@@ -98,6 +100,12 @@ export interface Review {
comments_count?: number comments_count?: number
} }
export interface AuthResponse {
token: string
expires_at: string
user: User
}
export interface ApiError { export interface ApiError {
message: string message: string
errors?: Record<string, string[]> errors?: Record<string, string[]>
+1
View File
@@ -1,4 +1,5 @@
{ {
"$schema": "https://opencode.ai/config.json",
"agent": { "agent": {
"build": { "build": {
"temperature": 0.4 "temperature": 0.4