refactor: dependency injection to use a centralized Container class for managing application state and services
This commit is contained in:
parent
de2099011b
commit
c5fab7d61a
4
frontend/src/app.d.ts
vendored
4
frontend/src/app.d.ts
vendored
@ -5,9 +5,7 @@ declare global {
|
||||
// interface Error {}
|
||||
|
||||
interface Locals {
|
||||
authBloc: import('$lib/auth/adapter/presenter/authBloc').AuthBloc;
|
||||
postListBloc: import('$lib/post/adapter/presenter/postListBloc').PostListBloc;
|
||||
postBloc: import('$lib/post/adapter/presenter/postBloc').PostBloc;
|
||||
container: import('$lib/container').Container;
|
||||
}
|
||||
|
||||
// interface PageData {}
|
||||
|
@ -1,21 +1,8 @@
|
||||
import { sequence } from '@sveltejs/kit/hooks';
|
||||
import * as Sentry from '@sentry/sveltekit';
|
||||
import { PostRepositoryImpl } from '$lib/post/adapter/gateway/postRepositoryImpl';
|
||||
import { PostBloc } from '$lib/post/adapter/presenter/postBloc';
|
||||
import { PostListBloc } from '$lib/post/adapter/presenter/postListBloc';
|
||||
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 type { Handle } from '@sveltejs/kit';
|
||||
import { Environment } from '$lib/environment';
|
||||
import { AuthApiServiceImpl } from '$lib/auth/framework/api/authApiServiceImpl';
|
||||
import { AuthRepositoryImpl } from '$lib/auth/adapter/gateway/authRepositoryImpl';
|
||||
import type { AuthApiService } from '$lib/auth/adapter/gateway/authApiService';
|
||||
import type { AuthRepository } from '$lib/auth/application/gateway/authRepository';
|
||||
import type { PostApiService } from '$lib/post/adapter/gateway/postApiService';
|
||||
import type { PostRepository } from '$lib/post/application/gateway/postRepository';
|
||||
import { AuthBloc } from '$lib/auth/adapter/presenter/authBloc';
|
||||
import { GetCurrentUserUseCase } from '$lib/auth/application/useCase/getCurrentUserUseCase';
|
||||
import { Container } from '$lib/container';
|
||||
|
||||
Sentry.init({
|
||||
dsn: Environment.SENTRY_DSN,
|
||||
@ -24,18 +11,8 @@ Sentry.init({
|
||||
});
|
||||
|
||||
export const handle: Handle = sequence(Sentry.sentryHandle(), ({ event, resolve }) => {
|
||||
const authApiService: AuthApiService = new AuthApiServiceImpl(event.fetch);
|
||||
const authRepository: AuthRepository = new AuthRepositoryImpl(authApiService);
|
||||
const getCurrentUserUseCase = new GetCurrentUserUseCase(authRepository);
|
||||
|
||||
const postApiService: PostApiService = new PostApiServiceImpl(event.fetch);
|
||||
const postRepository: PostRepository = new PostRepositoryImpl(postApiService);
|
||||
const getAllPostsUseCase = new GetAllPostsUseCase(postRepository);
|
||||
const getPostUseCase = new GetPostUseCase(postRepository);
|
||||
|
||||
event.locals.authBloc = new AuthBloc(getCurrentUserUseCase);
|
||||
event.locals.postListBloc = new PostListBloc(getAllPostsUseCase);
|
||||
event.locals.postBloc = new PostBloc(getPostUseCase);
|
||||
const container = new Container(event.fetch);
|
||||
event.locals.container = container;
|
||||
|
||||
return resolve(event);
|
||||
});
|
||||
|
@ -12,15 +12,7 @@ export class AuthBloc {
|
||||
status: StatusType.Idle,
|
||||
});
|
||||
|
||||
constructor(
|
||||
private readonly getCurrentUserUseCase: GetCurrentUserUseCase,
|
||||
initialData?: AuthViewModel
|
||||
) {
|
||||
this.state.set({
|
||||
status: StatusType.Idle,
|
||||
data: initialData,
|
||||
});
|
||||
}
|
||||
constructor(private readonly getCurrentUserUseCase: GetCurrentUserUseCase) {}
|
||||
|
||||
get subscribe() {
|
||||
return this.state.subscribe;
|
||||
|
134
frontend/src/lib/container.ts
Normal file
134
frontend/src/lib/container.ts
Normal file
@ -0,0 +1,134 @@
|
||||
import type { AuthApiService } from '$lib/auth/adapter/gateway/authApiService';
|
||||
import { AuthRepositoryImpl } from '$lib/auth/adapter/gateway/authRepositoryImpl';
|
||||
import { AuthBloc } from '$lib/auth/adapter/presenter/authBloc';
|
||||
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 { ImageApiService } from '$lib/image/adapter/gateway/imageApiService';
|
||||
import { ImageRepositoryImpl } from '$lib/image/adapter/gateway/imageRepositoryImpl';
|
||||
import { ImageBloc } from '$lib/image/adapter/presenter/imageBloc';
|
||||
import type { ImageRepository } from '$lib/image/application/gateway/imageRepository';
|
||||
import { UploadImageUseCase } from '$lib/image/application/useCase/uploadImageUseCase';
|
||||
import { ImageApiServiceImpl } from '$lib/image/framework/api/imageApiServiceImpl';
|
||||
import type { PostApiService } from '$lib/post/adapter/gateway/postApiService';
|
||||
import { PostRepositoryImpl } from '$lib/post/adapter/gateway/postRepositoryImpl';
|
||||
import { PostBloc } from '$lib/post/adapter/presenter/postBloc';
|
||||
import type { PostInfoViewModel } from '$lib/post/adapter/presenter/postInfoViewModel';
|
||||
import { PostListBloc } from '$lib/post/adapter/presenter/postListBloc';
|
||||
import type { PostViewModel } from '$lib/post/adapter/presenter/postViewModel';
|
||||
import type { PostRepository } from '$lib/post/application/gateway/postRepository';
|
||||
import { GetAllPostsUseCase } from '$lib/post/application/useCase/getAllPostsUseCase';
|
||||
import { GetPostUseCase } from '$lib/post/application/useCase/getPostUseCase';
|
||||
import { PostApiServiceImpl } from '$lib/post/framework/api/postApiServiceImpl';
|
||||
|
||||
export class Container {
|
||||
private useCases: UseCases;
|
||||
|
||||
constructor(fetchFn: typeof fetch) {
|
||||
const apiServices = new ApiServices(fetchFn);
|
||||
const repositories = new Repositories(apiServices);
|
||||
this.useCases = new UseCases(repositories);
|
||||
}
|
||||
|
||||
createAuthBloc(): AuthBloc {
|
||||
return new AuthBloc(this.useCases.getCurrentUserUseCase);
|
||||
}
|
||||
|
||||
createImageBloc(): ImageBloc {
|
||||
return new ImageBloc(this.useCases.uploadImageUseCase);
|
||||
}
|
||||
|
||||
createPostListBloc(initialData?: readonly PostInfoViewModel[]): PostListBloc {
|
||||
return new PostListBloc(this.useCases.getAllPostsUseCase, initialData);
|
||||
}
|
||||
|
||||
createPostBloc(initialData?: PostViewModel): PostBloc {
|
||||
return new PostBloc(this.useCases.getPostUseCase, initialData);
|
||||
}
|
||||
}
|
||||
|
||||
class ApiServices {
|
||||
private fetchFn: typeof fetch;
|
||||
|
||||
private _authApiService?: AuthApiService;
|
||||
private _imageApiService?: ImageApiService;
|
||||
private _postApiService?: PostApiService;
|
||||
|
||||
constructor(fetchFn: typeof fetch) {
|
||||
this.fetchFn = fetchFn;
|
||||
}
|
||||
|
||||
get authApiService(): AuthApiService {
|
||||
this._authApiService ??= new AuthApiServiceImpl(this.fetchFn);
|
||||
return this._authApiService;
|
||||
}
|
||||
|
||||
get imageApiService(): ImageApiService {
|
||||
this._imageApiService ??= new ImageApiServiceImpl(this.fetchFn);
|
||||
return this._imageApiService;
|
||||
}
|
||||
|
||||
get postApiService(): PostApiService {
|
||||
this._postApiService ??= new PostApiServiceImpl(this.fetchFn);
|
||||
return this._postApiService;
|
||||
}
|
||||
}
|
||||
|
||||
class Repositories {
|
||||
private apiServices: ApiServices;
|
||||
|
||||
private _authRepository?: AuthRepository;
|
||||
private _imageRepository?: ImageRepository;
|
||||
private _postRepository?: PostRepository;
|
||||
|
||||
constructor(apiServices: ApiServices) {
|
||||
this.apiServices = apiServices;
|
||||
}
|
||||
|
||||
get authRepository(): AuthRepository {
|
||||
this._authRepository ??= new AuthRepositoryImpl(this.apiServices.authApiService);
|
||||
return this._authRepository;
|
||||
}
|
||||
|
||||
get imageRepository(): ImageRepository {
|
||||
this._imageRepository ??= new ImageRepositoryImpl(this.apiServices.imageApiService);
|
||||
return this._imageRepository;
|
||||
}
|
||||
|
||||
get postRepository(): PostRepository {
|
||||
this._postRepository ??= new PostRepositoryImpl(this.apiServices.postApiService);
|
||||
return this._postRepository;
|
||||
}
|
||||
}
|
||||
|
||||
class UseCases {
|
||||
private repositories: Repositories;
|
||||
|
||||
private _getCurrentUserUseCase?: GetCurrentUserUseCase;
|
||||
private _uploadImageUseCase?: UploadImageUseCase;
|
||||
private _getAllPostsUseCase?: GetAllPostsUseCase;
|
||||
private _getPostUseCase?: GetPostUseCase;
|
||||
|
||||
constructor(repositories: Repositories) {
|
||||
this.repositories = repositories;
|
||||
}
|
||||
|
||||
get getCurrentUserUseCase(): GetCurrentUserUseCase {
|
||||
this._getCurrentUserUseCase ??= new GetCurrentUserUseCase(this.repositories.authRepository);
|
||||
return this._getCurrentUserUseCase;
|
||||
}
|
||||
|
||||
get uploadImageUseCase(): UploadImageUseCase {
|
||||
this._uploadImageUseCase ??= new UploadImageUseCase(this.repositories.imageRepository);
|
||||
return this._uploadImageUseCase;
|
||||
}
|
||||
|
||||
get getAllPostsUseCase(): GetAllPostsUseCase {
|
||||
this._getAllPostsUseCase ??= new GetAllPostsUseCase(this.repositories.postRepository);
|
||||
return this._getAllPostsUseCase;
|
||||
}
|
||||
get getPostUseCase(): GetPostUseCase {
|
||||
this._getPostUseCase ??= new GetPostUseCase(this.repositories.postRepository);
|
||||
return this._getPostUseCase;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import MottoAnimatedMark from './MottoAnimatedMark.svelte';
|
||||
import MottoAnimatedMark from '$lib/home/framework/ui/MottoAnimatedMark.svelte';
|
||||
</script>
|
||||
|
||||
<div
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import UploadImageDialoag from './UploadImageDialoag.svelte';
|
||||
import UploadImageDialoag from '$lib/image/framework/ui/UploadImageDialoag.svelte';
|
||||
import { ImageBloc, ImageEventType } from '$lib/image/adapter/presenter/imageBloc';
|
||||
import { StatusType } from '$lib/common/adapter/presenter/asyncState';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
@ -57,7 +57,7 @@
|
||||
<DialogTitle>Upload Image</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<form id="upload-form" onsubmit={onSubmit}>
|
||||
<form id="upload-image-form" onsubmit={onSubmit}>
|
||||
<Label for="file-input" class="pb-2">
|
||||
{`Image File (${imageMimeTypes.join(', ')})`}
|
||||
</Label>
|
||||
@ -77,7 +77,7 @@
|
||||
|
||||
<DialogFooter class="mt-6">
|
||||
<Button variant="outline" onclick={close} {disabled}>Cancel</Button>
|
||||
<Button type="submit" form="upload-form" {disabled}>Submit</Button>
|
||||
<Button type="submit" form="upload-image-form" {disabled}>Submit</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
@ -5,6 +5,11 @@
|
||||
import '../app.css';
|
||||
import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||
import { Toaster } from '$lib/common/framework/components/ui/sonner';
|
||||
import { Container } from '$lib/container';
|
||||
import { setContext } from 'svelte';
|
||||
|
||||
const container = new Container(fetch);
|
||||
setContext(Container.name, container);
|
||||
</script>
|
||||
|
||||
<GoogleAnalytics />
|
||||
|
@ -1,24 +1,17 @@
|
||||
<script lang="ts">
|
||||
import type { AuthApiService } from '$lib/auth/adapter/gateway/authApiService';
|
||||
import { AuthRepositoryImpl } from '$lib/auth/adapter/gateway/authRepositoryImpl';
|
||||
import { AuthBloc, AuthEventType } from '$lib/auth/adapter/presenter/authBloc';
|
||||
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 { onMount, setContext } from 'svelte';
|
||||
import { getContext, onMount, setContext } from 'svelte';
|
||||
import type { LayoutProps } from './$types';
|
||||
import { StatusType } from '$lib/common/adapter/presenter/asyncState';
|
||||
import ErrorPage from '$lib/common/framework/ui/ErrorPage.svelte';
|
||||
import DashboardNavbar from '$lib/dashboard/framework/ui/DashboardNavbar.svelte';
|
||||
import type { DashboardLink } from '$lib/dashboard/framework/ui/dashboardLink';
|
||||
import { Container } from '$lib/container';
|
||||
|
||||
const { children }: LayoutProps = $props();
|
||||
const container = getContext<Container>(Container.name);
|
||||
|
||||
const authApiService: AuthApiService = new AuthApiServiceImpl(fetch);
|
||||
const authRepository: AuthRepository = new AuthRepositoryImpl(authApiService);
|
||||
const getcurrentUserUseCase = new GetCurrentUserUseCase(authRepository);
|
||||
const authBloc = new AuthBloc(getcurrentUserUseCase);
|
||||
|
||||
const authBloc = container.createAuthBloc();
|
||||
setContext(AuthBloc.name, authBloc);
|
||||
|
||||
onMount(() => authBloc.dispatch({ event: AuthEventType.CurrentUserLoadedEvent }));
|
||||
@ -49,7 +42,7 @@
|
||||
{:else if hasError}
|
||||
<ErrorPage />
|
||||
{:else}
|
||||
<div class="grid min-h-content-height grid-cols-[auto_1fr]">
|
||||
<div class="min-h-content-height grid grid-cols-[auto_1fr]">
|
||||
<DashboardNavbar {links} />
|
||||
{@render children()}
|
||||
</div>
|
||||
|
@ -2,7 +2,8 @@ import { PostListEventType } from '$lib/post/adapter/presenter/postListBloc';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async ({ locals }) => {
|
||||
const { postListBloc } = locals;
|
||||
const { container } = locals;
|
||||
const postListBloc = container.createPostListBloc();
|
||||
|
||||
const state = await postListBloc.dispatch({ event: PostListEventType.PostListLoadedEvent });
|
||||
|
||||
|
@ -1,24 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { PostRepositoryImpl } from '$lib/post/adapter/gateway/postRepositoryImpl';
|
||||
import { PostListBloc } from '$lib/post/adapter/presenter/postListBloc';
|
||||
import { GetAllPostsUseCase } from '$lib/post/application/useCase/getAllPostsUseCase';
|
||||
import { PostApiServiceImpl } from '$lib/post/framework/api/postApiServiceImpl';
|
||||
import { setContext } from 'svelte';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
import type { PageProps } from './$types';
|
||||
import { PostInfoViewModel } from '$lib/post/adapter/presenter/postInfoViewModel';
|
||||
import PostOverallPage from '$lib/post/framework/ui/PostOverallPage.svelte';
|
||||
import type { PostApiService } from '$lib/post/adapter/gateway/postApiService';
|
||||
import type { PostRepository } from '$lib/post/application/gateway/postRepository';
|
||||
import { Container } from '$lib/container';
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
const { data }: PageProps = $props();
|
||||
const container = getContext<Container>(Container.name);
|
||||
|
||||
const initialData = data.dehydratedData?.map((post) => PostInfoViewModel.rehydrate(post));
|
||||
|
||||
const postApiService: PostApiService = new PostApiServiceImpl(fetch);
|
||||
const postRepository: PostRepository = new PostRepositoryImpl(postApiService);
|
||||
const getAllPostsUseCase = new GetAllPostsUseCase(postRepository);
|
||||
const postListBloc = new PostListBloc(getAllPostsUseCase, initialData);
|
||||
|
||||
const postListBloc = container.createPostListBloc(initialData);
|
||||
setContext(PostListBloc.name, postListBloc);
|
||||
</script>
|
||||
|
||||
|
@ -3,7 +3,8 @@ import { error } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async ({ locals, params }) => {
|
||||
const { postBloc } = locals;
|
||||
const { container } = locals;
|
||||
const postBloc = container.createPostBloc();
|
||||
|
||||
const state = await postBloc.dispatch({
|
||||
event: PostEventType.PostLoadedEvent,
|
||||
|
@ -1,25 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { PostRepositoryImpl } from '$lib/post/adapter/gateway/postRepositoryImpl';
|
||||
import { PostBloc } from '$lib/post/adapter/presenter/postBloc';
|
||||
import { PostViewModel } from '$lib/post/adapter/presenter/postViewModel';
|
||||
import { GetPostUseCase } from '$lib/post/application/useCase/getPostUseCase';
|
||||
import { PostApiServiceImpl } from '$lib/post/framework/api/postApiServiceImpl';
|
||||
import { setContext } from 'svelte';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
import type { PageProps } from './$types';
|
||||
import PostContentPage from '$lib/post/framework/ui/PostContentPage.svelte';
|
||||
import type { PostApiService } from '$lib/post/adapter/gateway/postApiService';
|
||||
import type { PostRepository } from '$lib/post/application/gateway/postRepository';
|
||||
import { Container } from '$lib/container';
|
||||
|
||||
const { data, params }: PageProps = $props();
|
||||
const { id } = params;
|
||||
const container = getContext<Container>(Container.name);
|
||||
|
||||
const initialData = PostViewModel.rehydrate(data.dehydratedData!);
|
||||
|
||||
const postApiService: PostApiService = new PostApiServiceImpl(fetch);
|
||||
const postRepository: PostRepository = new PostRepositoryImpl(postApiService);
|
||||
const getPostUseCase = new GetPostUseCase(postRepository);
|
||||
const postBloc = new PostBloc(getPostUseCase, initialData);
|
||||
|
||||
const postBloc = container.createPostBloc(initialData);
|
||||
setContext(PostBloc.name, postBloc);
|
||||
</script>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user