diff --git a/src/app/[lang]/dashboard/components/client/create-random-invoice/create-random-invoice.tsx b/src/app/[lang]/dashboard/components/client/create-random-invoice/create-random-invoice.tsx index 68742c2..8db5bf3 100644 --- a/src/app/[lang]/dashboard/components/client/create-random-invoice/create-random-invoice.tsx +++ b/src/app/[lang]/dashboard/components/client/create-random-invoice/create-random-invoice.tsx @@ -5,6 +5,9 @@ import CreateRandomInvoiceButtonVM from "@/app/[lang]/dashboard/vm/create-random import { useDI } from "@/bootstrap/di/di-context"; import { useRef } from "react"; +/** + * From a parent component Vm and view will be connected together. + */ export default function CreateRandomInvoiceContainer() { const di = useDI(); const vm = useRef(di.resolve(CreateRandomInvoiceButtonVM)); diff --git a/src/app/[lang]/dashboard/components/client/nav-links/nav-link-vm.ts b/src/app/[lang]/dashboard/components/client/nav-links/nav-link.personal-vm.ts similarity index 65% rename from src/app/[lang]/dashboard/components/client/nav-links/nav-link-vm.ts rename to src/app/[lang]/dashboard/components/client/nav-links/nav-link.personal-vm.ts index bdf58b2..9ddf695 100644 --- a/src/app/[lang]/dashboard/components/client/nav-links/nav-link-vm.ts +++ b/src/app/[lang]/dashboard/components/client/nav-links/nav-link.personal-vm.ts @@ -2,17 +2,26 @@ import { DocumentIcon } from "@/app/components/icons/document"; import HomeIcon from "@/app/components/icons/home"; import { UserIcon } from "@/app/components/icons/user"; import { usePathname } from "next/navigation"; +import { useRef } from "react"; type LinkItem = { name: string; href: string; icon: (props: { className?: string }) => JSX.Element; }; + +/** + * Beside of reusable vm each View can have it's own personal vm to handle it's ownlogics. + * Difference between personal vm and other vms which extends BaseVM, is that + * personal vm directly will be called inside of view and instinctly connected to the view, + * so they come together always and there is no need to be connected with interface for reusable + * vms. + */ export default function navLinkPersonalVM() { const pathname = usePathname(); // Map of links to display in the side navigation. // Depending on the size of the application, this would be stored in a database. - const links: LinkItem[] = [ + const links = useRef([ { name: "Home", href: "/dashboard", icon: HomeIcon }, { name: "Invoices", @@ -20,7 +29,7 @@ export default function navLinkPersonalVM() { icon: DocumentIcon, }, { name: "Customers", href: "/dashboard/customers", icon: UserIcon }, - ]; + ]).current; return { links, isLinkActive: (link: LinkItem) => pathname === link.href, diff --git a/src/app/[lang]/dashboard/components/client/nav-links/nav-links.tsx b/src/app/[lang]/dashboard/components/client/nav-links/nav-links.tsx index edb724c..8c2f587 100644 --- a/src/app/[lang]/dashboard/components/client/nav-links/nav-links.tsx +++ b/src/app/[lang]/dashboard/components/client/nav-links/nav-links.tsx @@ -1,6 +1,6 @@ "use client"; -import navLinkPersonalVM from "@/app/[lang]/dashboard/components/client/nav-links/nav-link-vm"; +import navLinkPersonalVM from "@/app/[lang]/dashboard/components/client/nav-links/nav-link.personal-vm"; import clsx from "clsx"; import Link from "next/link"; diff --git a/src/app/[lang]/dashboard/components/client/theme-provider/theme-provider.tsx b/src/app/[lang]/dashboard/components/client/theme-provider/theme-provider.tsx index 6a1ffe4..65b6bf4 100644 --- a/src/app/[lang]/dashboard/components/client/theme-provider/theme-provider.tsx +++ b/src/app/[lang]/dashboard/components/client/theme-provider/theme-provider.tsx @@ -1,11 +1,13 @@ -"use client" +/* eslint-disable react/jsx-props-no-spreading */ -import * as React from "react" -import { ThemeProvider as NextThemesProvider } from "next-themes" +"use client"; + +import * as React from "react"; +import { ThemeProvider as NextThemesProvider } from "next-themes"; export function ThemeProvider({ children, ...props }: React.ComponentProps) { - return {children} + return {children}; } diff --git a/src/app/[lang]/dashboard/components/server/card/card-controller.ts b/src/app/[lang]/dashboard/components/server/card/card.controller.ts similarity index 84% rename from src/app/[lang]/dashboard/components/server/card/card-controller.ts rename to src/app/[lang]/dashboard/components/server/card/card.controller.ts index 5f28e88..ddab125 100644 --- a/src/app/[lang]/dashboard/components/server/card/card-controller.ts +++ b/src/app/[lang]/dashboard/components/server/card/card.controller.ts @@ -5,6 +5,9 @@ import { InboxIcon, } from "@heroicons/react/24/outline"; +/** + * Controllers are bridge between feature layer and application layer. + */ export default function cardController(props: { type: "invoices" | "customers" | "pending" | "collected"; }) { diff --git a/src/app/[lang]/dashboard/components/server/card/card.tsx b/src/app/[lang]/dashboard/components/server/card/card.tsx index 0bb192a..9cf258b 100644 --- a/src/app/[lang]/dashboard/components/server/card/card.tsx +++ b/src/app/[lang]/dashboard/components/server/card/card.tsx @@ -1,4 +1,4 @@ -import cardController from "@/app/[lang]/dashboard/components/server/card/card-controller"; +import cardController from "@/app/[lang]/dashboard/components/server/card/card.controller"; export function Card({ title, diff --git a/src/app/[lang]/dashboard/components/server/cards/cards-controller.ts b/src/app/[lang]/dashboard/components/server/cards/cards.controller.ts similarity index 62% rename from src/app/[lang]/dashboard/components/server/cards/cards-controller.ts rename to src/app/[lang]/dashboard/components/server/cards/cards.controller.ts index 9d38e29..a439eb8 100644 --- a/src/app/[lang]/dashboard/components/server/cards/cards-controller.ts +++ b/src/app/[lang]/dashboard/components/server/cards/cards.controller.ts @@ -1,6 +1,9 @@ -import fetchSummaryInfoUsecase from "@/feature/core/summary-info/domain/usecase/fetch-summary-info-usecase"; +import fetchSummaryInfoUsecase from "@/feature/core/summary-info/domain/usecase/fetch-summary-info.usecase"; import { connection } from "next/server"; +/** + * Controllers are bridge between feature layer and application layer. + */ export default function cardsController() { connection(); return fetchSummaryInfoUsecase(); diff --git a/src/app/[lang]/dashboard/components/server/cards/cards.tsx b/src/app/[lang]/dashboard/components/server/cards/cards.tsx index 91c641d..438c297 100644 --- a/src/app/[lang]/dashboard/components/server/cards/cards.tsx +++ b/src/app/[lang]/dashboard/components/server/cards/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 cardsController from "@/app/[lang]/dashboard/components/server/cards/cards.controller"; export default async function CardWrapper() { const { customersNumber, invoicesNumber, invoicesSummary } = diff --git a/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices-controller.ts b/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.controller.ts similarity index 61% rename from src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices-controller.ts rename to src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.controller.ts index 2b7df56..b9b6a05 100644 --- a/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices-controller.ts +++ b/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.controller.ts @@ -1,6 +1,9 @@ -import fetchCustomerInvoicesUsecase from "@/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices-usecase"; +import fetchCustomerInvoicesUsecase from "@/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices.usecase"; import { connection } from "next/server"; +/** + * Controllers are bridge between feature layer and application layer. + */ export default function latestInvoicesController() { connection(); return fetchCustomerInvoicesUsecase(); diff --git a/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.tsx b/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.tsx index e55a6e1..8afeae2 100644 --- a/src/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices.tsx +++ b/src/app/[lang]/dashboard/components/server/latest-invoices/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/components/server/latest-invoices/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-controller.ts b/src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.controller.ts similarity index 87% rename from src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart-controller.ts rename to src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.controller.ts index 55c0797..2b811a1 100644 --- a/src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart-controller.ts +++ b/src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.controller.ts @@ -1,6 +1,9 @@ -import Revenue from "@/feature/core/revenue/domain/entity/revenue"; -import fetchRevenuesUsecase from "@/feature/core/revenue/domain/usecase/fetch-revenues-usecase"; +import Revenue from "@/feature/core/revenue/domain/entity/revenue.entity"; +import fetchRevenuesUsecase from "@/feature/core/revenue/domain/usecase/fetch-revenues.usecase"; +/** + * Controllers are bridge between feature layer and application layer. + */ export default async function revenueChartController() { const revenue = await fetchRevenuesUsecase(); const chartHeight = 350; diff --git a/src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.tsx b/src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.tsx index e6bc5a0..2583c44 100644 --- a/src/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart.tsx +++ b/src/app/[lang]/dashboard/components/server/revenue-chart/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/components/server/revenue-chart/revenue-chart.controller"; import { CalendarIcon } from "@heroicons/react/24/outline"; export default async function RevenueChart() { diff --git a/src/app/[lang]/dashboard/layout.tsx b/src/app/[lang]/dashboard/layout.tsx index 308e2a7..41a0efc 100644 --- a/src/app/[lang]/dashboard/layout.tsx +++ b/src/app/[lang]/dashboard/layout.tsx @@ -1,7 +1,7 @@ "use client"; import SideNav from "@/app/[lang]/dashboard/components/server/sidenav"; -import dashboardAppModule from "@/app/[lang]/dashboard/module/dashboard-app-module"; +import dashboardAppModule from "@/app/[lang]/dashboard/module/dashboard.app-module"; import { DiContext } from "@/bootstrap/di/di-context"; import { useRef } from "react"; diff --git a/src/app/[lang]/dashboard/module/dashboard-app-module.ts b/src/app/[lang]/dashboard/module/dashboard.app-module.ts similarity index 81% rename from src/app/[lang]/dashboard/module/dashboard-app-module.ts rename to src/app/[lang]/dashboard/module/dashboard.app-module.ts index 323a2f2..0f7e5e0 100644 --- a/src/app/[lang]/dashboard/module/dashboard-app-module.ts +++ b/src/app/[lang]/dashboard/module/dashboard.app-module.ts @@ -1,7 +1,10 @@ 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 + */ export default function dashboardAppModule() { const dashboardDi = di.createChildContainer(); 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 44abdcb..3ee3c1f 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,14 +1,19 @@ -import ButtonVm from "@/app/components/button/button-vm"; +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"; import BaseVM from "@/bootstrap/helpers/vm/base-vm"; import langKey from "@/bootstrap/i18n/dictionaries/lang-key"; -import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice-param"; -import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-invoice-usecase"; +import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice.param"; +import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-invoice.usecase"; import { faker } from "@faker-js/faker"; import { useRouter } from "next/navigation"; import { useTranslation } from "react-i18next"; +/** + * Viewmodel for the button view to connect to business logics and all UI logics + * For UI logics, all translations, states, sideeffects and events will be handled + * in this layer. + */ export default class CreateRandomInvoiceButtonVM extends BaseVM { private createInvoice: typeof createInvoiceUsecase; diff --git a/src/app/[lang]/layout.tsx b/src/app/[lang]/layout.tsx index 89037c1..fd59033 100644 --- a/src/app/[lang]/layout.tsx +++ b/src/app/[lang]/layout.tsx @@ -1,5 +1,5 @@ import { ThemeProvider } from "@/app/[lang]/dashboard/components/client/theme-provider/theme-provider"; -import { initI18next, LANGS } from "@/bootstrap/i18n/i18n"; +import { getI18n, LANGS } from "@/bootstrap/i18n/i18n"; import TranslationsProvider from "@/bootstrap/i18n/i18n-provider"; import localFont from "next/font/local"; import { PropsWithChildren } from "react"; @@ -20,7 +20,7 @@ export default async function layout( ) { const { params, children } = props; const { lang } = await params; - const { resources } = await initI18next({ lng: lang }); + const { resources } = await getI18n({ lng: lang }); return ( { return typeof fn === "function" && /^(class|function [A-Z])/.test(fn); diff --git a/src/bootstrap/helpers/lib/ui-utils.ts b/src/bootstrap/helpers/lib/ui-utils.ts index a5ef193..f8373a9 100644 --- a/src/bootstrap/helpers/lib/ui-utils.ts +++ b/src/bootstrap/helpers/lib/ui-utils.ts @@ -1,6 +1,10 @@ import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; +/** + * To connect tailwind classes. + * @param inputs Tailwind classes + */ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } diff --git a/src/bootstrap/helpers/view/base-view.tsx b/src/bootstrap/helpers/view/base-view.tsx index b0d4f57..914c9fc 100644 --- a/src/bootstrap/helpers/view/base-view.tsx +++ b/src/bootstrap/helpers/view/base-view.tsx @@ -66,6 +66,11 @@ export type BuildProps< children?: ReactNode; }; +/** + * Base view is base component for all views in mvvm architecture which gets + * vm as props and connect it to the view and memoize the component by default + * to just render just on changes of its vm. + */ export default abstract class BaseView< IVM extends IVMParent, PROPS extends IPropParent = undefined, diff --git a/src/bootstrap/helpers/view/storybook-with-arg-vm.ts b/src/bootstrap/helpers/view/storybook-with-arg-vm.ts index 210e173..7a3387c 100644 --- a/src/bootstrap/helpers/view/storybook-with-arg-vm.ts +++ b/src/bootstrap/helpers/view/storybook-with-arg-vm.ts @@ -1,5 +1,12 @@ import IBaseVM from "@/bootstrap/helpers/vm/i-base-vm"; +/** + * To use with mvvm library to make a vm based on props so you can pass the result to the view + * @param vmObj All properties which view needs to get from vm. + * @returns Vm which is suitable to be passed to the view + * @example const vm = getArgVM(globalData.parsedProps.vm); + return