diff --git a/src/events/character/create.ts b/src/events/character/create.ts index 8e5a909..c5060f7 100644 --- a/src/events/character/create.ts +++ b/src/events/character/create.ts @@ -1,4 +1,4 @@ -import { ZodError } from 'zod' +import { ZodError, z } from 'zod' import { BaseEvent } from '#application/base/baseEvent' import { ZCharacterCreate } from '#application/zodTypes' @@ -8,65 +8,77 @@ import CharacterTypeRepository from '#repositories/characterTypeRepository' import MapRepository from '#repositories/mapRepository' import UserRepository from '#repositories/userRepository' +const MAX_CHARACTERS = 4 + export default class CharacterCreateEvent extends BaseEvent { + private readonly userRepository: UserRepository = new UserRepository() + private readonly characterRepository: CharacterRepository = new CharacterRepository() + private readonly characterTypeRepository: CharacterTypeRepository = new CharacterTypeRepository() + private readonly mapRepository: MapRepository = new MapRepository() + public listen(): void { this.socket.on('character:create', this.handleEvent.bind(this)) } - private async handleEvent(data: any): Promise { - // zod validate + private async handleEvent(data: z.infer, callback: (success: boolean) => void): Promise { try { - data = ZCharacterCreate.parse(data) - - const userRepository = new UserRepository() - const characterRepository = new CharacterRepository() - const characterTypeRepository = new CharacterTypeRepository() - const mapRepository = new MapRepository() - - const user = await userRepository.getById(this.socket.userId!) - - if (!user) { - return this.socket.emit('notification', { title: 'Error', message: 'You are not logged in' }) - } - - // Check if character name already exists - const characterExists = await characterRepository.getByName(data.name) - - if (characterExists) { - return this.socket.emit('notification', { title: 'Error', message: 'Character name already exists' }) - } - - let characters: Character[] = await characterRepository.getByUserId(user.getId()) - - if (characters.length >= 4) { - return this.socket.emit('notification', { title: 'Error', message: 'You can only create 4 characters' }) - } - - // @TODO: Change to default location - const map = await mapRepository.getFirst() - - // @TODO: Change to selected character type - const characterType = await characterTypeRepository.getFirst() - - const newCharacter = new Character() - await newCharacter.setName(data.name).setUser(user).setMap(map!).setCharacterType(characterType).save() - - if (!newCharacter) { - return this.socket.emit('notification', { title: 'Error', message: 'Failed to create character. Please try again (later).' }) - } - - characters = [...characters, newCharacter] - - this.socket.emit('character:create:success') - this.socket.emit('character:list', characters) - - this.logger.info('character:create success') - } catch (error: any) { - this.logger.error(`character:create error: ${error.message}`) - if (error instanceof ZodError) { - return this.socket.emit('notification', { title: 'Error', message: error.issues[0]!.message }) - } - return this.socket.emit('notification', { title: 'Error', message: 'Could not create character. Please try again (later).' }) + const validatedData = ZCharacterCreate.parse(data) + await this.createCharacter(validatedData) + callback(true) + } catch (error: unknown) { + this.returnError(error) + callback(false) } } + + private async createCharacter(data: z.infer): Promise { + const user = await this.userRepository.getById(this.socket.userId!) + if (!user) { + throw new Error('You are not logged in') + } + + const characterExists = await this.characterRepository.getByName(data.name) + if (characterExists) { + throw new Error('Character name already exists') + } + + let characters = await this.characterRepository.getByUserId(user.getId()) + if (characters.length >= MAX_CHARACTERS) { + throw new Error(`You can only create ${MAX_CHARACTERS} characters`) + } + + const map = await this.mapRepository.getFirst() + if (!map) { + throw new Error('No default map found') + } + + const characterType = await this.characterTypeRepository.getFirst() + if (!characterType) { + throw new Error('No character type found') + } + + const newCharacter = new Character() + await newCharacter.setName(data.name).setUser(user).setMap(map).setCharacterType(characterType).save() + characters = await this.characterRepository.getByUserId(user.getId()) + + this.socket.emit('character:list', characters) + this.logger.info('character:create success') + } + + private returnError(error: unknown): void { + this.logger.error(`character:create error: ${error instanceof Error ? error.message : 'Unknown error'}`) + + let errorMessage = 'Could not create character. Please try again later.' + + if (error instanceof ZodError) { + errorMessage = error.issues[0]?.message || errorMessage + } else if (error instanceof Error) { + errorMessage = error.message + } + + this.socket.emit('notification', { + title: 'Error', + message: errorMessage + }) + } }