refactor: usecase usage example for calling with interface between controller and usecases

This commit is contained in:
Behnamrhp74 2025-03-08 22:25:29 +03:00
commit 4ee7d4b8e3
7 changed files with 52 additions and 30 deletions

View File

@ -1,8 +1,13 @@
"use server"; "use server";
import { ApiEither } from "@/feature/common/data/api-task"; import { ApiEither } from "@/feature/common/data/api-task";
import serverDi from "@/feature/common/server.di";
import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice.param"; import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice.param";
import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-invoice.usecase"; import {
CreateInvoiceUsecase,
createInvoiceUsecaseKey,
} from "@/feature/core/invoice/domain/usecase/create-invoice/create-invoice.usecase";
import { invoiceModuleKey } from "@/feature/core/invoice/invoice.module-key";
import { connection } from "next/server"; import { connection } from "next/server";
/** /**
@ -15,5 +20,8 @@ export default async function createInvoiceController(
params: InvoiceParam, params: InvoiceParam,
): Promise<ApiEither<string>> { ): Promise<ApiEither<string>> {
connection(); connection();
return createInvoiceUsecase(params); const usecase = serverDi(invoiceModuleKey).resolve<CreateInvoiceUsecase>(
createInvoiceUsecaseKey,
);
return usecase(params);
} }

View File

@ -1,6 +1,5 @@
import CreateRandomInvoiceButtonVM from "@/app/[lang]/dashboard/vm/create-random-invoice-button-vm"; import CreateRandomInvoiceButtonVM from "@/app/[lang]/dashboard/vm/create-random-invoice-button-vm";
import di from "@/bootstrap/di/init-di"; import di from "@/bootstrap/di/init-di";
// import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-invoice.usecase";
/** /**
* Each page can have its own di to connect all vms, usecases or controllers * Each page can have its own di to connect all vms, usecases or controllers
@ -8,9 +7,6 @@ import di from "@/bootstrap/di/init-di";
export default function dashboardAppModule() { export default function dashboardAppModule() {
const dashboardDi = di.createChildContainer(); const dashboardDi = di.createChildContainer();
// dashboardDi.register(createInvoiceUsecase.name, {
// useValue: createInvoiceUsecase,
// });
dashboardDi.register( dashboardDi.register(
CreateRandomInvoiceButtonVM, CreateRandomInvoiceButtonVM,
CreateRandomInvoiceButtonVM, CreateRandomInvoiceButtonVM,

View File

@ -5,7 +5,7 @@ import useThrottle from "@/bootstrap/helpers/hooks/use-throttle";
import BaseVM from "@/bootstrap/helpers/vm/base-vm"; import BaseVM from "@/bootstrap/helpers/vm/base-vm";
import langKey from "@/bootstrap/i18n/dictionaries/lang-key"; import langKey from "@/bootstrap/i18n/dictionaries/lang-key";
import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice.param"; import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice.param";
import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-invoice.usecase"; import { CreateInvoiceUsecase } from "@/feature/core/invoice/domain/usecase/create-invoice/create-invoice.usecase";
import { faker } from "@faker-js/faker"; import { faker } from "@faker-js/faker";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -16,7 +16,7 @@ import { useTranslation } from "react-i18next";
* in this layer. * in this layer.
*/ */
export default class CreateRandomInvoiceButtonVM extends BaseVM<ButtonVm> { export default class CreateRandomInvoiceButtonVM extends BaseVM<ButtonVm> {
private createInvoice: typeof createInvoiceUsecase; private createInvoice: CreateInvoiceUsecase;
constructor() { constructor() {
super(); super();

View File

@ -4,7 +4,7 @@ import { DiContext, useDI } from "@/bootstrap/di/di-context";
import mockedModuleDi from "@/bootstrap/di/mocked-module-di"; import mockedModuleDi from "@/bootstrap/di/mocked-module-di";
import Story from "@/bootstrap/helpers/view/storybook-base-template-type"; import Story from "@/bootstrap/helpers/view/storybook-base-template-type";
import getArgVM from "@/bootstrap/helpers/view/storybook-with-arg-vm"; import getArgVM from "@/bootstrap/helpers/view/storybook-with-arg-vm";
import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-invoice.usecase"; import { createInvoiceUsecaseKey } from "@/feature/core/invoice/domain/usecase/create-invoice/create-invoice.usecase";
import type { Meta } from "@storybook/react"; import type { Meta } from "@storybook/react";
import { useRef } from "react"; import { useRef } from "react";
@ -36,30 +36,32 @@ export const Primary: Story = {
export const WithVM: Story = { export const WithVM: Story = {
decorators: [ decorators: [
(Story) => { (Story) => {
const di = mockedModuleDi([ const di = useRef(
mockedModuleDi([
{ {
token: CreateRandomInvoiceButtonVM, token: CreateRandomInvoiceButtonVM,
provider: CreateRandomInvoiceButtonVM, provider: CreateRandomInvoiceButtonVM,
}, },
{ {
token: createInvoiceUsecase.name, token: createInvoiceUsecaseKey,
// eslint-disable-next-line @typescript-eslint/no-explicit-any, no-console // eslint-disable-next-line @typescript-eslint/no-explicit-any, no-console
provider: (args: any) => console.log("clicked", args), provider: (args: any) => console.log("clicked", args),
}, },
]); ]),
return <Story di={di} />; );
return (
<DiContext.Provider value={di.current}>
<Story di={di.current} />
</DiContext.Provider>
);
}, },
], ],
render: (_, globalProps) => { render: () => {
function Child() { function Child() {
const di = useDI(); const di = useDI();
const vm = useRef(di.resolve(CreateRandomInvoiceButtonVM)); const vm = useRef(di.resolve(CreateRandomInvoiceButtonVM));
return <Button vm={vm.current} memoizedByVM={false} />; return <Button vm={vm.current} memoizedByVM={false} />;
} }
return ( return <Child />;
<DiContext.Provider value={globalProps.di}>
<Child />
</DiContext.Provider>
);
}, },
}; };

View File

@ -1,11 +1,16 @@
import di from "@/bootstrap/di/init-di"; import di from "@/bootstrap/di/init-di";
import invoiceDbRepo from "@/feature/core/invoice/data/repo/invoice-db.repo"; import invoiceDbRepo from "@/feature/core/invoice/data/repo/invoice-db.repo";
import { invoiceRepoKey } from "@/feature/core/invoice/domain/i-repo/invoice.i-repo"; import { invoiceRepoKey } from "@/feature/core/invoice/domain/i-repo/invoice.i-repo";
import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-invoice/create-invoice-impl.usecase";
import { createInvoiceUsecaseKey } from "@/feature/core/invoice/domain/usecase/create-invoice/create-invoice.usecase";
import { DependencyContainer } from "tsyringe"; import { DependencyContainer } from "tsyringe";
export default function getInvoiceDi(): DependencyContainer { export default function getInvoiceDi(): DependencyContainer {
const invoiceDi = di.createChildContainer(); const invoiceDi = di.createChildContainer();
invoiceDi.register(invoiceRepoKey, invoiceDbRepo); invoiceDi.register(invoiceRepoKey, invoiceDbRepo);
invoiceDi.register(createInvoiceUsecaseKey, {
useValue: createInvoiceUsecase,
});
return invoiceDi; return invoiceDi;
} }

View File

@ -9,12 +9,13 @@ import {
invoiceSchema, invoiceSchema,
} from "@/feature/core/invoice/domain/param/invoice.param"; } from "@/feature/core/invoice/domain/param/invoice.param";
import { invoiceModuleKey } from "@/feature/core/invoice/invoice.module-key"; import { invoiceModuleKey } from "@/feature/core/invoice/invoice.module-key";
import { CreateInvoiceUsecase } from "@/feature/core/invoice/domain/usecase/create-invoice/create-invoice.usecase";
import { pipe } from "fp-ts/lib/function"; import { pipe } from "fp-ts/lib/function";
import { chain, fromNullable, left, map, right } from "fp-ts/lib/TaskEither"; import { chain, fromNullable, left, map, right } from "fp-ts/lib/TaskEither";
export default async function createInvoiceUsecase( const createInvoiceUsecase: CreateInvoiceUsecase = async (
params: InvoiceParam, params: InvoiceParam,
): Promise<ApiEither<string>> { ): Promise<ApiEither<string>> => {
const repo = serverDi(invoiceModuleKey).resolve<InvoiceRepo>(invoiceRepoKey); const repo = serverDi(invoiceModuleKey).resolve<InvoiceRepo>(invoiceRepoKey);
return pipe( return pipe(
@ -27,4 +28,6 @@ export default async function createInvoiceUsecase(
}), }),
chain((params) => repo.createInvoice(params)), chain((params) => repo.createInvoice(params)),
)(); )();
} };
export default createInvoiceUsecase;

View File

@ -0,0 +1,8 @@
import { ApiEither } from "@/feature/common/data/api-task";
import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice.param";
export type CreateInvoiceUsecase = (
param: InvoiceParam,
) => Promise<ApiEither<string>>;
export const createInvoiceUsecaseKey = "createInvoiceUsecaseKey";