feat: implement get label by ID functionality in label management
All checks were successful
Frontend CI / build (push) Successful in 1m38s
All checks were successful
Frontend CI / build (push) Successful in 1m38s
This commit is contained in:
parent
d20a210857
commit
4f23151439
@ -31,6 +31,8 @@ import { CreatePostUseCase } from '$lib/post/application/useCase/createPostUseCa
|
||||
import { GetAllPostsUseCase } from '$lib/post/application/useCase/getAllPostsUseCase';
|
||||
import { GetPostUseCase } from '$lib/post/application/useCase/getPostUseCase';
|
||||
import { PostApiServiceImpl } from '$lib/post/framework/api/postApiServiceImpl';
|
||||
import { GetLabelUseCase } from '$lib/label/application/useCase/getLabelUseCase';
|
||||
import { LabelLoadedStore } from '$lib/label/adapter/presenter/labelLoadedStore';
|
||||
|
||||
export class Container {
|
||||
private useCases: UseCases;
|
||||
@ -65,6 +67,10 @@ export class Container {
|
||||
return new LabelsListedStore(this.useCases.getAllLabelsUseCase, initialData);
|
||||
}
|
||||
|
||||
createLabelLoadedStore(initialData?: LabelViewModel): LabelLoadedStore {
|
||||
return new LabelLoadedStore(this.useCases.getLabelUseCase, initialData);
|
||||
}
|
||||
|
||||
createLabelCreatedStore(): LabelCreatedStore {
|
||||
return new LabelCreatedStore(this.useCases.createLabelUseCase);
|
||||
}
|
||||
@ -145,6 +151,7 @@ class UseCases {
|
||||
private _getPostUseCase?: GetPostUseCase;
|
||||
private _createPostUseCase?: CreatePostUseCase;
|
||||
private _getAllLabelsUseCase?: GetAllLabelsUseCase;
|
||||
private _getLabelUseCase?: GetLabelUseCase;
|
||||
private _createLabelUseCase?: CreateLabelUseCase;
|
||||
|
||||
constructor(repositories: Repositories) {
|
||||
@ -181,6 +188,11 @@ class UseCases {
|
||||
return this._getAllLabelsUseCase;
|
||||
}
|
||||
|
||||
get getLabelUseCase(): GetLabelUseCase {
|
||||
this._getLabelUseCase ??= new GetLabelUseCase(this.repositories.labelRepository);
|
||||
return this._getLabelUseCase;
|
||||
}
|
||||
|
||||
get createLabelUseCase(): CreateLabelUseCase {
|
||||
this._createLabelUseCase ??= new CreateLabelUseCase(this.repositories.labelRepository);
|
||||
return this._createLabelUseCase;
|
||||
|
@ -3,5 +3,6 @@ import type { LabelResponseDto } from '$lib/label/adapter/gateway/labelResponseD
|
||||
|
||||
export interface LabelApiService {
|
||||
getAllLabels(): Promise<LabelResponseDto[]>;
|
||||
getLabelById(id: number): Promise<LabelResponseDto | null>;
|
||||
createLabel(payload: CreateLabelRequestDto): Promise<LabelResponseDto>;
|
||||
}
|
||||
|
@ -14,6 +14,11 @@ export class LabelRepositoryImpl implements LabelRepository {
|
||||
return dtos.map((dto) => dto.toEntity());
|
||||
}
|
||||
|
||||
async getLabelById(id: number): Promise<Label | null> {
|
||||
const dto = await this.labelApiService.getLabelById(id);
|
||||
return dto?.toEntity() ?? null;
|
||||
}
|
||||
|
||||
async createLabel(params: CreateLabelParams): Promise<Label> {
|
||||
const requestDto = CreateLabelRequestDto.fromParams(params);
|
||||
const responseDto = await this.labelApiService.createLabel(requestDto);
|
||||
|
51
frontend/src/lib/label/adapter/presenter/labelLoadedStore.ts
Normal file
51
frontend/src/lib/label/adapter/presenter/labelLoadedStore.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { AsyncState } from '$lib/common/adapter/presenter/asyncState';
|
||||
import type { BaseStore } from '$lib/common/adapter/presenter/baseStore';
|
||||
import { LabelViewModel } from '$lib/label/adapter/presenter/labelViewModel';
|
||||
import type { GetLabelUseCase } from '$lib/label/application/useCase/getLabelUseCase';
|
||||
import { captureException } from '@sentry/sveltekit';
|
||||
import { get, writable } from 'svelte/store';
|
||||
|
||||
type LabelState = AsyncState<LabelViewModel>;
|
||||
|
||||
export class LabelLoadedStore implements BaseStore<LabelState, number> {
|
||||
private state = writable<LabelState>(AsyncState.idle<LabelViewModel>(null));
|
||||
|
||||
constructor(
|
||||
private readonly getLabelUseCase: GetLabelUseCase,
|
||||
initialData?: LabelViewModel
|
||||
) {
|
||||
if (initialData) {
|
||||
this.state.set(AsyncState.idle(initialData));
|
||||
}
|
||||
}
|
||||
|
||||
get subscribe() {
|
||||
return this.state.subscribe;
|
||||
}
|
||||
|
||||
get trigger() {
|
||||
return (id: number) => this.loadLabel(id);
|
||||
}
|
||||
|
||||
async loadLabel(id: number): Promise<LabelState> {
|
||||
this.state.set(AsyncState.loading<LabelViewModel>(get(this.state).data));
|
||||
|
||||
let result: LabelState;
|
||||
try {
|
||||
const label = await this.getLabelUseCase.execute(id);
|
||||
if (!label) {
|
||||
result = AsyncState.error(new Error('Label not found'), get(this.state).data);
|
||||
this.state.set(result);
|
||||
return result;
|
||||
}
|
||||
const labelViewModel = LabelViewModel.fromEntity(label);
|
||||
result = AsyncState.success(labelViewModel);
|
||||
} catch (e) {
|
||||
result = AsyncState.error(e, get(this.state).data);
|
||||
captureException(e);
|
||||
}
|
||||
|
||||
this.state.set(result);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ import type { Label } from '$lib/label/domain/entity/label';
|
||||
|
||||
export interface LabelRepository {
|
||||
getAllLabels(): Promise<Label[]>;
|
||||
getLabelById(id: number): Promise<Label | null>;
|
||||
createLabel(params: CreateLabelParams): Promise<Label>;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import type { Label } from '$lib/label/domain/entity/label';
|
||||
export class GetAllLabelsUseCase {
|
||||
constructor(private readonly labelRepository: LabelRepository) {}
|
||||
|
||||
execute(): Promise<Label[]> {
|
||||
async execute(): Promise<Label[]> {
|
||||
return this.labelRepository.getAllLabels();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
import type { LabelRepository } from '$lib/label/application/gateway/labelRepository';
|
||||
import type { Label } from '$lib/label/domain/entity/label';
|
||||
|
||||
export class GetLabelUseCase {
|
||||
constructor(private readonly labelRepository: LabelRepository) {}
|
||||
|
||||
async execute(id: number): Promise<Label | null> {
|
||||
return this.labelRepository.getLabelById(id);
|
||||
}
|
||||
}
|
@ -20,6 +20,22 @@ export class LabelApiServiceImpl implements LabelApiService {
|
||||
return data.map(LabelResponseDto.fromJson);
|
||||
}
|
||||
|
||||
async getLabelById(id: number): Promise<LabelResponseDto | null> {
|
||||
const url = new URL(`label/${id}`, Environment.API_BASE_URL);
|
||||
|
||||
const response = await this.fetchFn(url);
|
||||
|
||||
if (response.status === 404) {
|
||||
return null;
|
||||
}
|
||||
if (!response.ok) {
|
||||
throw new HttpError(response.status, url);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return LabelResponseDto.fromJson(data);
|
||||
}
|
||||
|
||||
async createLabel(payload: CreateLabelRequestDto): Promise<LabelResponseDto> {
|
||||
const url = new URL('label', Environment.API_BASE_URL);
|
||||
|
||||
|
23
frontend/src/routes/dashboard/label/[id]/+page.server.ts
Normal file
23
frontend/src/routes/dashboard/label/[id]/+page.server.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { error } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async ({ locals, params }) => {
|
||||
const { container } = locals;
|
||||
const store = container.createLabelLoadedStore();
|
||||
|
||||
const { trigger: loadLabel } = store;
|
||||
|
||||
const numericId = Number(params.id);
|
||||
if (isNaN(numericId)) {
|
||||
throw error(400, { message: 'Invalid label ID' });
|
||||
}
|
||||
|
||||
const state = await loadLabel(numericId);
|
||||
if (!state.data) {
|
||||
error(404, { message: 'Post not found' });
|
||||
}
|
||||
|
||||
return {
|
||||
dehydratedData: state.data.dehydrate(),
|
||||
};
|
||||
};
|
17
frontend/src/routes/dashboard/label/[id]/+page.svelte
Normal file
17
frontend/src/routes/dashboard/label/[id]/+page.svelte
Normal file
@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { getContext, setContext } from 'svelte';
|
||||
import type { PageProps } from './$types';
|
||||
import { Container } from '$lib/container';
|
||||
import { LabelViewModel } from '$lib/label/adapter/presenter/labelViewModel';
|
||||
import { LabelLoadedStore } from '$lib/label/adapter/presenter/labelLoadedStore';
|
||||
|
||||
const { data, params }: PageProps = $props();
|
||||
const { id } = params;
|
||||
const container = getContext<Container>(Container.name);
|
||||
|
||||
const initialData = LabelViewModel.rehydrate(data.dehydratedData!);
|
||||
const store = container.createLabelLoadedStore(initialData);
|
||||
setContext(LabelLoadedStore.name, store);
|
||||
</script>
|
||||
|
||||
<div>{id}</div>
|
Loading…
x
Reference in New Issue
Block a user