From 4306ea1bdcfeefbfc96e56a8b010189dfcf705ba Mon Sep 17 00:00:00 2001 From: Behnamrhp74 Date: Sat, 8 Mar 2025 22:16:29 +0300 Subject: [PATCH] refactor: structure of calling usecases to just be from controller --- .../components/server/{card => }/card.tsx | 2 +- .../components/server/{cards => }/cards.tsx | 4 ++-- .../{latest-invoices => }/latest-invoices.tsx | 2 +- .../{revenue-chart => }/revenue-chart.tsx | 2 +- .../server/{skeletons => }/skeletons.tsx | 0 .../card => controller}/card.controller.ts | 3 +++ .../cards => controller}/cards.controller.ts | 3 +++ .../controller/create-invoice.controller.ts | 19 +++++++++++++++ .../latest-invoices.controller.ts | 3 +++ .../revenue-chart.controller.ts | 3 +++ src/app/[lang]/dashboard/loading.tsx | 2 +- .../dashboard/module/dashboard.app-module.ts | 8 +++---- src/app/[lang]/dashboard/page.tsx | 8 +++---- .../vm/create-random-invoice-button-vm.ts | 3 ++- src/app/[lang]/layout.tsx | 6 ++--- src/bootstrap/i18n/i18n-provider.tsx | 23 ++++++++++++------- src/bootstrap/i18n/store-lang-action.ts | 9 ++++++++ .../fetch-customer-invoices.usecase.ts | 1 - .../usecase/fetch-customers-amount-usecase.ts | 1 - .../domain/usecase/fetch-customers-usecase.ts | 1 - .../core/invoice/data/repo/invoice-db.repo.ts | 1 + .../domain/usecase/create-invoice.usecase.ts | 2 -- .../fetch-all-invoices-amount.usecase.ts | 1 - .../fetch-invoices-status-summary.usecase.ts | 1 - .../domain/usecase/fetch-revenues.usecase.ts | 1 - .../usecase/fetch-summary-info.usecase.ts | 1 - 26 files changed, 74 insertions(+), 36 deletions(-) rename src/app/[lang]/dashboard/components/server/{card => }/card.tsx (86%) rename src/app/[lang]/dashboard/components/server/{cards => }/cards.tsx (83%) rename src/app/[lang]/dashboard/components/server/{latest-invoices => }/latest-invoices.tsx (94%) rename src/app/[lang]/dashboard/components/server/{revenue-chart => }/revenue-chart.tsx (93%) rename src/app/[lang]/dashboard/components/server/{skeletons => }/skeletons.tsx (100%) rename src/app/[lang]/dashboard/{components/server/card => controller}/card.controller.ts (70%) rename src/app/[lang]/dashboard/{components/server/cards => controller}/cards.controller.ts (61%) create mode 100644 src/app/[lang]/dashboard/controller/create-invoice.controller.ts rename src/app/[lang]/dashboard/{components/server/latest-invoices => controller}/latest-invoices.controller.ts (62%) rename src/app/[lang]/dashboard/{components/server/revenue-chart => controller}/revenue-chart.controller.ts (82%) create mode 100644 src/bootstrap/i18n/store-lang-action.ts diff --git a/src/app/[lang]/dashboard/components/server/card/card.tsx b/src/app/[lang]/dashboard/components/server/card.tsx similarity index 86% rename from src/app/[lang]/dashboard/components/server/card/card.tsx rename to src/app/[lang]/dashboard/components/server/card.tsx index 9cf258b..3df00e2 100644 --- a/src/app/[lang]/dashboard/components/server/card/card.tsx +++ b/src/app/[lang]/dashboard/components/server/card.tsx @@ -1,4 +1,4 @@ -import cardController from "@/app/[lang]/dashboard/components/server/card/card.controller"; +import cardController from "@/app/[lang]/dashboard/controller/card.controller"; export function Card({ title, diff --git a/src/app/[lang]/dashboard/components/server/cards/cards.tsx b/src/app/[lang]/dashboard/components/server/cards.tsx similarity index 83% rename from src/app/[lang]/dashboard/components/server/cards/cards.tsx rename to src/app/[lang]/dashboard/components/server/cards.tsx index 438c297..d506061 100644 --- a/src/app/[lang]/dashboard/components/server/cards/cards.tsx +++ b/src/app/[lang]/dashboard/components/server/cards.tsx @@ -1,5 +1,5 @@ -import { Card } from "@/app/[lang]/dashboard/components/server/card/card"; -import cardsController from "@/app/[lang]/dashboard/components/server/cards/cards.controller"; +import { Card } from "@/app/[lang]/dashboard/components/server/card"; +import cardsController from "@/app/[lang]/dashboard/controller/cards.controller"; export default async function CardWrapper() { const { customersNumber, invoicesNumber, invoicesSummary } = diff --git a/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.tsx b/src/app/[lang]/dashboard/components/server/latest-invoices.tsx similarity index 94% rename from src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.tsx rename to src/app/[lang]/dashboard/components/server/latest-invoices.tsx index 8afeae2..4d54d2b 100644 --- a/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.tsx +++ b/src/app/[lang]/dashboard/components/server/latest-invoices.tsx @@ -1,5 +1,5 @@ import CreateRandomInvoiceContainer from "@/app/[lang]/dashboard/components/client/create-random-invoice/create-random-invoice"; -import latestInvoicesController from "@/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.controller"; +import latestInvoicesController from "@/app/[lang]/dashboard/controller/latest-invoices.controller"; import { ArrowPathIcon } from "@heroicons/react/24/outline"; import clsx from "clsx"; import { isLeft } from "fp-ts/lib/Either"; diff --git a/src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.tsx b/src/app/[lang]/dashboard/components/server/revenue-chart.tsx similarity index 93% rename from src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.tsx rename to src/app/[lang]/dashboard/components/server/revenue-chart.tsx index 2583c44..6e6381b 100644 --- a/src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.tsx +++ b/src/app/[lang]/dashboard/components/server/revenue-chart.tsx @@ -1,4 +1,4 @@ -import revenueChartController from "@/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.controller"; +import revenueChartController from "@/app/[lang]/dashboard/controller/revenue-chart.controller"; import { CalendarIcon } from "@heroicons/react/24/outline"; export default async function RevenueChart() { diff --git a/src/app/[lang]/dashboard/components/server/skeletons/skeletons.tsx b/src/app/[lang]/dashboard/components/server/skeletons.tsx similarity index 100% rename from src/app/[lang]/dashboard/components/server/skeletons/skeletons.tsx rename to src/app/[lang]/dashboard/components/server/skeletons.tsx diff --git a/src/app/[lang]/dashboard/components/server/card/card.controller.ts b/src/app/[lang]/dashboard/controller/card.controller.ts similarity index 70% rename from src/app/[lang]/dashboard/components/server/card/card.controller.ts rename to src/app/[lang]/dashboard/controller/card.controller.ts index ddab125..5db4b72 100644 --- a/src/app/[lang]/dashboard/components/server/card/card.controller.ts +++ b/src/app/[lang]/dashboard/controller/card.controller.ts @@ -7,6 +7,9 @@ import { /** * Controllers are bridge between feature layer and application layer. + * They decide, feature layer will be cached or not, where to run in client or server + * Or connect multiple usecases and run them, handle their failure, hydrate and store data in + * client state managements. */ export default function cardController(props: { type: "invoices" | "customers" | "pending" | "collected"; diff --git a/src/app/[lang]/dashboard/components/server/cards/cards.controller.ts b/src/app/[lang]/dashboard/controller/cards.controller.ts similarity index 61% rename from src/app/[lang]/dashboard/components/server/cards/cards.controller.ts rename to src/app/[lang]/dashboard/controller/cards.controller.ts index a439eb8..93de870 100644 --- a/src/app/[lang]/dashboard/components/server/cards/cards.controller.ts +++ b/src/app/[lang]/dashboard/controller/cards.controller.ts @@ -3,6 +3,9 @@ import { connection } from "next/server"; /** * Controllers are bridge between feature layer and application layer. + * They decide, feature layer will be cached or not, where to run in client or server + * Or connect multiple usecases and run them, handle their failure, hydrate and store data in + * client state managements. */ export default function cardsController() { connection(); diff --git a/src/app/[lang]/dashboard/controller/create-invoice.controller.ts b/src/app/[lang]/dashboard/controller/create-invoice.controller.ts new file mode 100644 index 0000000..185261a --- /dev/null +++ b/src/app/[lang]/dashboard/controller/create-invoice.controller.ts @@ -0,0 +1,19 @@ +"use server"; + +import { ApiEither } from "@/feature/common/data/api-task"; +import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice.param"; +import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-invoice.usecase"; +import { connection } from "next/server"; + +/** + * Controllers are bridge between feature layer and application layer. + * They decide, feature layer will be cached or not, where to run in client or server + * Or connect multiple usecases and run them, handle their failure, hydrate and store data in + * client state managements. + */ +export default async function createInvoiceController( + params: InvoiceParam, +): Promise> { + connection(); + return createInvoiceUsecase(params); +} diff --git a/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.controller.ts b/src/app/[lang]/dashboard/controller/latest-invoices.controller.ts similarity index 62% rename from src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.controller.ts rename to src/app/[lang]/dashboard/controller/latest-invoices.controller.ts index b9b6a05..aece969 100644 --- a/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.controller.ts +++ b/src/app/[lang]/dashboard/controller/latest-invoices.controller.ts @@ -3,6 +3,9 @@ import { connection } from "next/server"; /** * Controllers are bridge between feature layer and application layer. + * They decide, feature layer will be cached or not, where to run in client or server + * Or connect multiple usecases and run them, handle their failure, hydrate and store data in + * client state managements. */ export default function latestInvoicesController() { connection(); diff --git a/src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.controller.ts b/src/app/[lang]/dashboard/controller/revenue-chart.controller.ts similarity index 82% rename from src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.controller.ts rename to src/app/[lang]/dashboard/controller/revenue-chart.controller.ts index 2b811a1..1986288 100644 --- a/src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.controller.ts +++ b/src/app/[lang]/dashboard/controller/revenue-chart.controller.ts @@ -3,6 +3,9 @@ import fetchRevenuesUsecase from "@/feature/core/revenue/domain/usecase/fetch-re /** * Controllers are bridge between feature layer and application layer. + * They decide, feature layer will be cached or not, where to run in client or server + * Or connect multiple usecases and run them, handle their failure, hydrate and store data in + * client state managements. */ export default async function revenueChartController() { const revenue = await fetchRevenuesUsecase(); diff --git a/src/app/[lang]/dashboard/loading.tsx b/src/app/[lang]/dashboard/loading.tsx index 0002d3a..d8aec02 100644 --- a/src/app/[lang]/dashboard/loading.tsx +++ b/src/app/[lang]/dashboard/loading.tsx @@ -1,4 +1,4 @@ -import DashboardSkeleton from "@/app/[lang]/dashboard/components/server/skeletons/skeletons"; +import DashboardSkeleton from "@/app/[lang]/dashboard/components/server/skeletons"; export default function Loading() { return ; diff --git a/src/app/[lang]/dashboard/module/dashboard.app-module.ts b/src/app/[lang]/dashboard/module/dashboard.app-module.ts index 0f7e5e0..e4344ab 100644 --- a/src/app/[lang]/dashboard/module/dashboard.app-module.ts +++ b/src/app/[lang]/dashboard/module/dashboard.app-module.ts @@ -1,6 +1,6 @@ import CreateRandomInvoiceButtonVM from "@/app/[lang]/dashboard/vm/create-random-invoice-button-vm"; import di from "@/bootstrap/di/init-di"; -import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-invoice.usecase"; +// 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 @@ -8,9 +8,9 @@ import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-i export default function dashboardAppModule() { const dashboardDi = di.createChildContainer(); - dashboardDi.register(createInvoiceUsecase.name, { - useValue: createInvoiceUsecase, - }); + // dashboardDi.register(createInvoiceUsecase.name, { + // useValue: createInvoiceUsecase, + // }); dashboardDi.register( CreateRandomInvoiceButtonVM, CreateRandomInvoiceButtonVM, diff --git a/src/app/[lang]/dashboard/page.tsx b/src/app/[lang]/dashboard/page.tsx index ea09ada..ee88963 100644 --- a/src/app/[lang]/dashboard/page.tsx +++ b/src/app/[lang]/dashboard/page.tsx @@ -1,13 +1,13 @@ import { LatestInvoicesSkeleton, RevenueChartSkeleton, -} from "@/app/[lang]/dashboard/components/server/skeletons/skeletons"; -import CardWrapper from "@/app/[lang]/dashboard/components/server/cards/cards"; -import LatestInvoices from "@/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices"; -import RevenueChart from "@/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart"; +} from "@/app/[lang]/dashboard/components/server/skeletons"; +import CardWrapper from "@/app/[lang]/dashboard/components/server/cards"; +import RevenueChart from "@/app/[lang]/dashboard/components/server/revenue-chart"; import { Suspense } from "react"; import { getServerTranslation, LANGS } from "@/bootstrap/i18n/i18n"; import langKey from "@/bootstrap/i18n/dictionaries/lang-key"; +import LatestInvoices from "@/app/[lang]/dashboard/components/server/latest-invoices"; export default async function Dashboard(props: { params: Promise<{ lang: LANGS }>; diff --git a/src/app/[lang]/dashboard/vm/create-random-invoice-button-vm.ts b/src/app/[lang]/dashboard/vm/create-random-invoice-button-vm.ts index 3ee3c1f..92e0c25 100644 --- a/src/app/[lang]/dashboard/vm/create-random-invoice-button-vm.ts +++ b/src/app/[lang]/dashboard/vm/create-random-invoice-button-vm.ts @@ -1,3 +1,4 @@ +import createInvoiceController from "@/app/[lang]/dashboard/controller/create-invoice.controller"; import ButtonVm from "@/app/components/button/button.i-vm"; import { useServerAction } from "@/bootstrap/helpers/hooks/use-server-action"; import useThrottle from "@/bootstrap/helpers/hooks/use-throttle"; @@ -19,7 +20,7 @@ export default class CreateRandomInvoiceButtonVM extends BaseVM { constructor() { super(); - this.createInvoice = this.di.resolve(createInvoiceUsecase.name); + this.createInvoice = createInvoiceController; } useVM(): ButtonVm { diff --git a/src/app/[lang]/layout.tsx b/src/app/[lang]/layout.tsx index fd59033..2703929 100644 --- a/src/app/[lang]/layout.tsx +++ b/src/app/[lang]/layout.tsx @@ -20,7 +20,7 @@ export default async function layout( ) { const { params, children } = props; const { lang } = await params; - const { resources } = await getI18n({ lng: lang }); + await getI18n({ lng: lang }); return ( - - {children} - + {children} diff --git a/src/bootstrap/i18n/i18n-provider.tsx b/src/bootstrap/i18n/i18n-provider.tsx index 8b3ab16..f3258f3 100644 --- a/src/bootstrap/i18n/i18n-provider.tsx +++ b/src/bootstrap/i18n/i18n-provider.tsx @@ -1,17 +1,24 @@ "use client"; import { I18nextProvider } from "react-i18next"; -import { i18nInstance, getI18n, LANGS } from "@/bootstrap/i18n/i18n"; -import { Resource } from "i18next"; -import { PropsWithChildren } from "react"; +import { getI18n, LANGS } from "@/bootstrap/i18n/i18n"; +import { PropsWithChildren, useEffect, useState } from "react"; +import { i18n } from "i18next"; +import storeLang from "@/bootstrap/i18n/store-lang-action"; export default function TranslationsProvider({ children, lng, - resources, -}: PropsWithChildren & { lng: LANGS; resources: Resource }) { - if (!resources) return children; - getI18n({ lng, resources }); +}: PropsWithChildren & { lng: LANGS }) { + const [i18n, setI18n] = useState(); - return {children}; + useEffect(() => { + (async () => { + storeLang(lng); + setI18n((await getI18n({ lng })).i18n); + })(); + }, [lng]); + + if (!i18n) return null; + return {children}; } diff --git a/src/bootstrap/i18n/store-lang-action.ts b/src/bootstrap/i18n/store-lang-action.ts new file mode 100644 index 0000000..2ef60ce --- /dev/null +++ b/src/bootstrap/i18n/store-lang-action.ts @@ -0,0 +1,9 @@ +"use server"; + +import { LANGS } from "@/bootstrap/i18n/i18n"; +import { cookieName } from "@/bootstrap/i18n/settings"; +import { cookies } from "next/headers"; + +export default async function storeLang(lng: LANGS) { + (await cookies()).set(cookieName, lng); +} diff --git a/src/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices.usecase.ts b/src/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices.usecase.ts index 710e291..d863476 100644 --- a/src/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices.usecase.ts +++ b/src/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices.usecase.ts @@ -1,4 +1,3 @@ -import "server-only"; import { ApiEither } from "@/feature/common/data/api-task"; import serverDi from "@/feature/common/server.di"; import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice.entity"; diff --git a/src/feature/core/customer/domain/usecase/fetch-customers-amount-usecase.ts b/src/feature/core/customer/domain/usecase/fetch-customers-amount-usecase.ts index 0660119..ff5fdc7 100644 --- a/src/feature/core/customer/domain/usecase/fetch-customers-amount-usecase.ts +++ b/src/feature/core/customer/domain/usecase/fetch-customers-amount-usecase.ts @@ -1,4 +1,3 @@ -import "server-only"; import serverDi from "@/feature/common/server.di"; import { customerKey } from "@/feature/core/customer/customer-key"; import CustomerRepo, { diff --git a/src/feature/core/customer/domain/usecase/fetch-customers-usecase.ts b/src/feature/core/customer/domain/usecase/fetch-customers-usecase.ts index cb3b240..dfca5fe 100644 --- a/src/feature/core/customer/domain/usecase/fetch-customers-usecase.ts +++ b/src/feature/core/customer/domain/usecase/fetch-customers-usecase.ts @@ -1,4 +1,3 @@ -import "server-only"; import { ApiEither } from "@/feature/common/data/api-task"; import serverDi from "@/feature/common/server.di"; import { customerKey } from "@/feature/core/customer/customer-key"; diff --git a/src/feature/core/invoice/data/repo/invoice-db.repo.ts b/src/feature/core/invoice/data/repo/invoice-db.repo.ts index e381f9a..f8b8582 100644 --- a/src/feature/core/invoice/data/repo/invoice-db.repo.ts +++ b/src/feature/core/invoice/data/repo/invoice-db.repo.ts @@ -1,3 +1,4 @@ +import "server-only"; import { sql } from "@/bootstrap/boundaries/db/db"; import ApiTask from "@/feature/common/data/api-task"; import { failureOr } from "@/feature/common/failures/failure-helpers"; diff --git a/src/feature/core/invoice/domain/usecase/create-invoice.usecase.ts b/src/feature/core/invoice/domain/usecase/create-invoice.usecase.ts index b190856..da93b8d 100644 --- a/src/feature/core/invoice/domain/usecase/create-invoice.usecase.ts +++ b/src/feature/core/invoice/domain/usecase/create-invoice.usecase.ts @@ -1,5 +1,3 @@ -"use server"; - import { ApiEither } from "@/feature/common/data/api-task"; import ParamsFailure from "@/feature/common/failures/params.failure"; import serverDi from "@/feature/common/server.di"; diff --git a/src/feature/core/invoice/domain/usecase/fetch-all-invoices-amount.usecase.ts b/src/feature/core/invoice/domain/usecase/fetch-all-invoices-amount.usecase.ts index 67dfd8d..32ab554 100644 --- a/src/feature/core/invoice/domain/usecase/fetch-all-invoices-amount.usecase.ts +++ b/src/feature/core/invoice/domain/usecase/fetch-all-invoices-amount.usecase.ts @@ -1,4 +1,3 @@ -import "server-only"; import serverDi from "@/feature/common/server.di"; import InvoiceRepo, { invoiceRepoKey, diff --git a/src/feature/core/invoice/domain/usecase/fetch-invoices-status-summary.usecase.ts b/src/feature/core/invoice/domain/usecase/fetch-invoices-status-summary.usecase.ts index 7407635..91ba865 100644 --- a/src/feature/core/invoice/domain/usecase/fetch-invoices-status-summary.usecase.ts +++ b/src/feature/core/invoice/domain/usecase/fetch-invoices-status-summary.usecase.ts @@ -1,4 +1,3 @@ -import "server-only"; import serverDi from "@/feature/common/server.di"; import InvoiceRepo, { invoiceRepoKey, diff --git a/src/feature/core/revenue/domain/usecase/fetch-revenues.usecase.ts b/src/feature/core/revenue/domain/usecase/fetch-revenues.usecase.ts index e1a00f3..f8ec678 100644 --- a/src/feature/core/revenue/domain/usecase/fetch-revenues.usecase.ts +++ b/src/feature/core/revenue/domain/usecase/fetch-revenues.usecase.ts @@ -1,4 +1,3 @@ -import "server-only"; import serverDi from "@/feature/common/server.di"; import Revenue from "@/feature/core/revenue/domain/entity/revenue.entity"; import RevenueRepo, { diff --git a/src/feature/core/summary-info/domain/usecase/fetch-summary-info.usecase.ts b/src/feature/core/summary-info/domain/usecase/fetch-summary-info.usecase.ts index 5c2a945..8849e0b 100644 --- a/src/feature/core/summary-info/domain/usecase/fetch-summary-info.usecase.ts +++ b/src/feature/core/summary-info/domain/usecase/fetch-summary-info.usecase.ts @@ -1,4 +1,3 @@ -import "server-only"; import serverDi from "@/feature/common/server.di"; import fetchCustomersAmountUsecase from "@/feature/core/customer/domain/usecase/fetch-customers-amount-usecase"; import fetchAllInvoicesAmountUsecase from "@/feature/core/invoice/domain/usecase/fetch-all-invoices-amount.usecase";