Files
UniVerse/frontend/src/api/mappers.ts
T

174 lines
5.4 KiB
TypeScript

import type {
Achievement,
CoinTransaction,
Lecture,
Notification,
Review,
User,
UserRole,
} from '@/types'
import type {
AchievementDto,
CoinTransactionDto,
LectureDto,
ReviewDto,
CurrentUserDto,
UserAuthDto,
UserDto,
UserStatsDto,
UserAchievementDto,
UserNotificationDto,
} from './types'
export function mapApiRole(role: string | undefined): UserRole {
if (role === 'Teacher') return 'teacher'
if (role === 'Admin') return 'admin'
return 'student'
}
function mapApiRoles(roles: string[] | undefined): UserRole[] {
if (!roles?.length) return ['student']
return Array.from(new Set(roles.map(mapApiRole)))
}
function getDefaultActiveRole(roles: UserRole[]): UserRole {
if (roles.includes('admin')) return 'admin'
if (roles.includes('teacher')) return 'teacher'
if (roles.includes('student')) return 'student'
return 'student'
}
export function mapApiUser(
user: UserAuthDto | UserDto | CurrentUserDto,
stats?: UserStatsDto,
): User {
const roles = mapApiRoles(user.roles)
return {
id: user.id,
name: user.displayName || user.email || 'Пользователь UniVerse',
email: user.email || '',
roles,
activeRole: getDefaultActiveRole(roles),
avatar: 'avatarUrl' in user ? (user.avatarUrl ?? undefined) : undefined,
institute: 'ЮФУ',
department: '',
year: 0,
direction: '',
coins: stats?.coins ?? ('coins' in user ? user.coins : 0),
level: stats?.level ?? ('level' in user ? user.level : 1),
xp: stats?.xp ?? ('xp' in user ? user.xp : 0),
currentLevelXp: stats?.currentLevelXp ?? 0,
nextLevelXp: stats?.nextLevelXp,
lecturesAttended: stats?.attendedLectures ?? 0,
hoursLearned: stats ? Math.round(stats.attendedLectures * 1.5 * 10) / 10 : 0,
achievements: stats
? Array.from({ length: stats.achievementsCount }, (_, index) => String(index + 1))
: [],
activeEnrollments: stats?.activeEnrollments,
enrollmentSlotLimit: stats?.enrollmentSlotLimit,
enrollmentSlotRules: stats?.enrollmentSlotRules,
}
}
export function mapApiLecture(lecture: LectureDto): Lecture {
const startsAt = new Date(lecture.startsAt)
const endsAt = new Date(lecture.endsAt)
const durationMs = endsAt.getTime() - startsAt.getTime()
const duration =
Number.isFinite(durationMs) && durationMs > 0 ? Math.round(durationMs / 60000) : 90
const totalSeats = lecture.maxEnrollments || 0
const enrolled = lecture.enrollmentsCount || 0
const freeSeats = Math.max(totalSeats - enrolled, 0)
const locationName =
lecture.locationName || (lecture.format === 'Online' ? 'Онлайн' : 'Аудитория уточняется')
return {
id: String(lecture.id),
teacherId: lecture.teacherId,
title: lecture.title || lecture.courseName || 'Лекция без названия',
description: lecture.description || 'Описание появится позже.',
teacher: lecture.teacherName || 'Преподаватель уточняется',
teacherTitle: '',
department: '',
institute: lecture.courseName || 'ЮФУ',
date: startsAt.toISOString().slice(0, 10),
time: startsAt.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }),
duration,
building: lecture.format === 'Online' ? 'Онлайн' : locationName,
room: undefined,
format: lecture.format === 'Online' ? 'online' : 'offline',
totalSeats,
enrolledSeats: enrolled,
freeSeats,
registrationClosed: !lecture.isOpen,
tags: lecture.courseName ? [`#${lecture.courseName}`] : [],
rating: 0,
reviewCount: 0,
status: startsAt.getTime() > Date.now() ? 'upcoming' : 'completed',
registered: lecture.isEnrolled,
}
}
export function mapApiReview(review: ReviewDto): Review {
const sentiment =
review.sentiment === 'Positive'
? 'positive'
: review.sentiment === 'Negative'
? 'negative'
: 'neutral'
const status =
review.llmStatus === 'Rejected'
? 'rejected'
: review.llmStatus === 'Analyzed'
? 'done'
: 'pending'
return {
id: String(review.id),
lectureId: String(review.lectureId),
userId: String(review.userId),
userName: review.userName || 'Анонимный отзыв',
text: review.text || '',
sentiment,
createdAt: review.createdAt,
status,
quality: review.qualityScore ?? undefined,
}
}
export function mapApiAchievement(input: AchievementDto | UserAchievementDto): Achievement {
const dto = 'achievement' in input ? input.achievement : input
const awardedAt = 'achievement' in input ? input.awardedAt : undefined
return {
id: String(dto.id),
title: dto.name || 'Достижение',
description: dto.description || dto.condition || '',
icon: dto.iconUrl || '⭐',
unlocked: Boolean(awardedAt),
unlockedAt: awardedAt,
coins: dto.coinReward,
}
}
export function mapApiCoinTransaction(transaction: CoinTransactionDto): CoinTransaction {
return {
id: String(transaction.id),
date: transaction.createdAt.slice(0, 10),
description: transaction.description || transaction.type,
amount: transaction.amount,
type: transaction.amount >= 0 ? 'earned' : 'spent',
}
}
export function mapApiNotification(notification: UserNotificationDto): Notification {
return {
id: String(notification.id),
type: notification.type,
title: notification.title,
body: notification.body,
read: notification.isRead,
createdAt: notification.createdAt,
}
}