diff --git a/frontend/src/lib/auth/adapter/gateway/userResponseDto.ts b/frontend/src/lib/auth/adapter/gateway/userResponseDto.ts index 8f64369..dff2c4e 100644 --- a/frontend/src/lib/auth/adapter/gateway/userResponseDto.ts +++ b/frontend/src/lib/auth/adapter/gateway/userResponseDto.ts @@ -1,7 +1,7 @@ import { User } from '$lib/auth/domain/entity/user'; import z from 'zod'; -export const UserResponseSchema = z.object({ +export const userResponseSchema = z.object({ id: z.int32(), displayed_name: z.string(), email: z.email(), @@ -19,7 +19,7 @@ export class UserResponseDto { } static fromJson(json: unknown): UserResponseDto { - const parsedJson = UserResponseSchema.parse(json); + const parsedJson = userResponseSchema.parse(json); return new UserResponseDto({ id: parsedJson.id, displayedName: parsedJson.displayed_name, diff --git a/frontend/src/lib/container.ts b/frontend/src/lib/container.ts index cb9cc20..078015c 100644 --- a/frontend/src/lib/container.ts +++ b/frontend/src/lib/container.ts @@ -4,6 +4,15 @@ import { AuthLoadedStore } from '$lib/auth/adapter/presenter/authLoadedStore'; import type { AuthRepository } from '$lib/auth/application/gateway/authRepository'; import { GetCurrentUserUseCase } from '$lib/auth/application/useCase/getCurrentUserUseCase'; import { AuthApiServiceImpl } from '$lib/auth/framework/api/authApiServiceImpl'; +import type { LabelApiService } from '$lib/label/adapter/gateway/labelApiService'; +import { LabelRepositoryImpl } from '$lib/label/adapter/gateway/labelRepositoryImpl'; +import { LabelCreatedStore } from '$lib/label/adapter/presenter/labelCreatedStore'; +import type { LabelViewModel } from '$lib/label/adapter/presenter/labelViewModel'; +import { LabelsListedStore } from '$lib/label/adapter/presenter/labelsListedStore'; +import type { LabelRepository } from '$lib/label/application/gateway/labelRepository'; +import { CreateLabelUseCase } from '$lib/label/application/useCase/createLabelUseCase'; +import { GetAllLabelsUseCase } from '$lib/label/application/useCase/getAllLabelsUseCase'; +import { LabelApiServiceImpl } from '$lib/label/framework/api/labelApiServiceImpl'; import type { ImageApiService } from '$lib/image/adapter/gateway/imageApiService'; import { ImageRepositoryImpl } from '$lib/image/adapter/gateway/imageRepositoryImpl'; import { ImageUploadedStore } from '$lib/image/adapter/presenter/imageUploadedStore'; @@ -48,8 +57,16 @@ export class Container { return new PostLoadedStore(this.useCases.getPostUseCase, initialData); } - createPostCreatedStore(initialData?: PostViewModel): PostCreatedStore { - return new PostCreatedStore(this.useCases.createPostUseCase, initialData); + createPostCreatedStore(): PostCreatedStore { + return new PostCreatedStore(this.useCases.createPostUseCase); + } + + createLabelsListedStore(initialData?: readonly LabelViewModel[]): LabelsListedStore { + return new LabelsListedStore(this.useCases.getAllLabelsUseCase, initialData); + } + + createLabelCreatedStore(): LabelCreatedStore { + return new LabelCreatedStore(this.useCases.createLabelUseCase); } } @@ -59,6 +76,7 @@ class ApiServices { private _authApiService?: AuthApiService; private _imageApiService?: ImageApiService; private _postApiService?: PostApiService; + private _labelApiService?: LabelApiService; constructor(fetchFn: typeof fetch) { this.fetchFn = fetchFn; @@ -78,6 +96,11 @@ class ApiServices { this._postApiService ??= new PostApiServiceImpl(this.fetchFn); return this._postApiService; } + + get labelApiService(): LabelApiService { + this._labelApiService ??= new LabelApiServiceImpl(this.fetchFn); + return this._labelApiService; + } } class Repositories { @@ -86,6 +109,7 @@ class Repositories { private _authRepository?: AuthRepository; private _imageRepository?: ImageRepository; private _postRepository?: PostRepository; + private _labelRepository?: LabelRepository; constructor(apiServices: ApiServices) { this.apiServices = apiServices; @@ -105,6 +129,11 @@ class Repositories { this._postRepository ??= new PostRepositoryImpl(this.apiServices.postApiService); return this._postRepository; } + + get labelRepository(): LabelRepository { + this._labelRepository ??= new LabelRepositoryImpl(this.apiServices.labelApiService); + return this._labelRepository; + } } class UseCases { @@ -115,6 +144,8 @@ class UseCases { private _getAllPostsUseCase?: GetAllPostsUseCase; private _getPostUseCase?: GetPostUseCase; private _createPostUseCase?: CreatePostUseCase; + private _getAllLabelsUseCase?: GetAllLabelsUseCase; + private _createLabelUseCase?: CreateLabelUseCase; constructor(repositories: Repositories) { this.repositories = repositories; @@ -144,4 +175,14 @@ class UseCases { this._createPostUseCase ??= new CreatePostUseCase(this.repositories.postRepository); return this._createPostUseCase; } + + get getAllLabelsUseCase(): GetAllLabelsUseCase { + this._getAllLabelsUseCase ??= new GetAllLabelsUseCase(this.repositories.labelRepository); + return this._getAllLabelsUseCase; + } + + get createLabelUseCase(): CreateLabelUseCase { + this._createLabelUseCase ??= new CreateLabelUseCase(this.repositories.labelRepository); + return this._createLabelUseCase; + } } diff --git a/frontend/src/lib/image/adapter/gateway/imageInfoResponseDto.ts b/frontend/src/lib/image/adapter/gateway/imageInfoResponseDto.ts index ad7a5ba..bdc8d23 100644 --- a/frontend/src/lib/image/adapter/gateway/imageInfoResponseDto.ts +++ b/frontend/src/lib/image/adapter/gateway/imageInfoResponseDto.ts @@ -1,6 +1,6 @@ import z from 'zod'; -export const ImageInfoResponseSchema = z.object({ +export const imageInfoResponseSchema = z.object({ id: z.int32(), mime_type: z.string(), }); @@ -15,7 +15,7 @@ export class ImageInfoResponseDto { } static fromJson(json: unknown): ImageInfoResponseDto { - const parsedJson = ImageInfoResponseSchema.parse(json); + const parsedJson = imageInfoResponseSchema.parse(json); return new ImageInfoResponseDto({ id: parsedJson.id, mimeType: parsedJson.mime_type, diff --git a/frontend/src/lib/label/adapter/gateway/colorResponseDto.ts b/frontend/src/lib/label/adapter/gateway/colorDto.ts similarity index 67% rename from frontend/src/lib/label/adapter/gateway/colorResponseDto.ts rename to frontend/src/lib/label/adapter/gateway/colorDto.ts index 9d2f75f..7952cdd 100644 --- a/frontend/src/lib/label/adapter/gateway/colorResponseDto.ts +++ b/frontend/src/lib/label/adapter/gateway/colorDto.ts @@ -1,14 +1,14 @@ import { Color } from '$lib/label/domain/entity/color'; import z from 'zod'; -export const ColorResponseSchema = z.object({ +export const colorResponseSchema = z.object({ red: z.number().int().min(0).max(255), green: z.number().int().min(0).max(255), blue: z.number().int().min(0).max(255), alpha: z.number().int().min(0).max(255), }); -export class ColorResponseDto { +export class ColorDto { readonly red: number; readonly green: number; readonly blue: number; @@ -21,9 +21,13 @@ export class ColorResponseDto { this.alpha = props.alpha; } - static fromJson(json: unknown): ColorResponseDto { - const parsedJson = ColorResponseSchema.parse(json); - return new ColorResponseDto({ + static fromEntity(color: Color): ColorDto { + return new ColorDto(color); + } + + static fromJson(json: unknown): ColorDto { + const parsedJson = colorResponseSchema.parse(json); + return new ColorDto({ red: parsedJson.red, green: parsedJson.green, blue: parsedJson.blue, @@ -39,4 +43,13 @@ export class ColorResponseDto { alpha: this.alpha, }); } + + toJson() { + return { + red: this.red, + green: this.green, + blue: this.blue, + alpha: this.alpha, + }; + } } diff --git a/frontend/src/lib/label/adapter/gateway/createLabelRequestDto.ts b/frontend/src/lib/label/adapter/gateway/createLabelRequestDto.ts new file mode 100644 index 0000000..cc40e8c --- /dev/null +++ b/frontend/src/lib/label/adapter/gateway/createLabelRequestDto.ts @@ -0,0 +1,26 @@ +import { ColorDto } from '$lib/label/adapter/gateway/colorDto'; +import type { CreateLabelParams } from '$lib/label/application/gateway/labelRepository'; + +export class CreateLabelRequestDto { + readonly name: string; + readonly color: ColorDto; + + private constructor(props: { name: string; color: ColorDto }) { + this.name = props.name; + this.color = props.color; + } + + static fromParams(params: CreateLabelParams): CreateLabelRequestDto { + return new CreateLabelRequestDto({ + name: params.name, + color: ColorDto.fromEntity(params.color), + }); + } + + toJson() { + return { + name: this.name, + color: this.color.toJson(), + }; + } +} diff --git a/frontend/src/lib/label/adapter/gateway/labelApiService.ts b/frontend/src/lib/label/adapter/gateway/labelApiService.ts new file mode 100644 index 0000000..e17b297 --- /dev/null +++ b/frontend/src/lib/label/adapter/gateway/labelApiService.ts @@ -0,0 +1,7 @@ +import type { CreateLabelRequestDto } from '$lib/label/adapter/gateway/createLabelRequestDto'; +import type { LabelResponseDto } from '$lib/label/adapter/gateway/labelResponseDto'; + +export interface LabelApiService { + getAllLabels(): Promise; + createLabel(payload: CreateLabelRequestDto): Promise; +} diff --git a/frontend/src/lib/label/adapter/gateway/labelRepositoryImpl.ts b/frontend/src/lib/label/adapter/gateway/labelRepositoryImpl.ts new file mode 100644 index 0000000..8c8bc8d --- /dev/null +++ b/frontend/src/lib/label/adapter/gateway/labelRepositoryImpl.ts @@ -0,0 +1,22 @@ +import { CreateLabelRequestDto } from '$lib/label/adapter/gateway/createLabelRequestDto'; +import type { LabelApiService } from '$lib/label/adapter/gateway/labelApiService'; +import type { + CreateLabelParams, + LabelRepository, +} from '$lib/label/application/gateway/labelRepository'; +import type { Label } from '$lib/label/domain/entity/label'; + +export class LabelRepositoryImpl implements LabelRepository { + constructor(private readonly labelApiService: LabelApiService) {} + + async getAllLabels(): Promise { + const dtos = await this.labelApiService.getAllLabels(); + return dtos.map((dto) => dto.toEntity()); + } + + async createLabel(params: CreateLabelParams): Promise