Compare commits
No commits in common. "5a29c54a6ac9a014c814a5663503332cb2247308" and "1675d84caee45c51460ef63de46a5d902d0deb2e" have entirely different histories.
5a29c54a6a
...
1675d84cae
@ -5,9 +5,6 @@ import CreateRandomInvoiceButtonVM from "@/app/[lang]/dashboard/vm/create-random
|
|||||||
import { useDI } from "@/bootstrap/di/di-context";
|
import { useDI } from "@/bootstrap/di/di-context";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
|
||||||
/**
|
|
||||||
* From a parent component Vm and view will be connected together.
|
|
||||||
*/
|
|
||||||
export default function CreateRandomInvoiceContainer() {
|
export default function CreateRandomInvoiceContainer() {
|
||||||
const di = useDI();
|
const di = useDI();
|
||||||
const vm = useRef(di.resolve(CreateRandomInvoiceButtonVM));
|
const vm = useRef(di.resolve(CreateRandomInvoiceButtonVM));
|
||||||
|
@ -2,26 +2,17 @@ import { DocumentIcon } from "@/app/components/icons/document";
|
|||||||
import HomeIcon from "@/app/components/icons/home";
|
import HomeIcon from "@/app/components/icons/home";
|
||||||
import { UserIcon } from "@/app/components/icons/user";
|
import { UserIcon } from "@/app/components/icons/user";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { useRef } from "react";
|
|
||||||
|
|
||||||
type LinkItem = {
|
type LinkItem = {
|
||||||
name: string;
|
name: string;
|
||||||
href: string;
|
href: string;
|
||||||
icon: (props: { className?: string }) => JSX.Element;
|
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() {
|
export default function navLinkPersonalVM() {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
// Map of links to display in the side navigation.
|
// Map of links to display in the side navigation.
|
||||||
// Depending on the size of the application, this would be stored in a database.
|
// Depending on the size of the application, this would be stored in a database.
|
||||||
const links = useRef<LinkItem[]>([
|
const links: LinkItem[] = [
|
||||||
{ name: "Home", href: "/dashboard", icon: HomeIcon },
|
{ name: "Home", href: "/dashboard", icon: HomeIcon },
|
||||||
{
|
{
|
||||||
name: "Invoices",
|
name: "Invoices",
|
||||||
@ -29,7 +20,7 @@ export default function navLinkPersonalVM() {
|
|||||||
icon: DocumentIcon,
|
icon: DocumentIcon,
|
||||||
},
|
},
|
||||||
{ name: "Customers", href: "/dashboard/customers", icon: UserIcon },
|
{ name: "Customers", href: "/dashboard/customers", icon: UserIcon },
|
||||||
]).current;
|
];
|
||||||
return {
|
return {
|
||||||
links,
|
links,
|
||||||
isLinkActive: (link: LinkItem) => pathname === link.href,
|
isLinkActive: (link: LinkItem) => pathname === link.href,
|
@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import navLinkPersonalVM from "@/app/[lang]/dashboard/components/client/nav-links/nav-link.personal-vm";
|
import navLinkPersonalVM from "@/app/[lang]/dashboard/components/client/nav-links/nav-link-vm";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
/* eslint-disable react/jsx-props-no-spreading */
|
"use client"
|
||||||
|
|
||||||
"use client";
|
import * as React from "react"
|
||||||
|
import { ThemeProvider as NextThemesProvider } from "next-themes"
|
||||||
import * as React from "react";
|
|
||||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
|
||||||
|
|
||||||
export function ThemeProvider({
|
export function ThemeProvider({
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof NextThemesProvider>) {
|
}: React.ComponentProps<typeof NextThemesProvider>) {
|
||||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,6 @@ import {
|
|||||||
InboxIcon,
|
InboxIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
|
|
||||||
/**
|
|
||||||
* 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: {
|
export default function cardController(props: {
|
||||||
type: "invoices" | "customers" | "pending" | "collected";
|
type: "invoices" | "customers" | "pending" | "collected";
|
||||||
}) {
|
}) {
|
@ -1,4 +1,4 @@
|
|||||||
import cardController from "@/app/[lang]/dashboard/controller/card.controller";
|
import cardController from "@/app/[lang]/dashboard/components/server/card/card-controller";
|
||||||
|
|
||||||
export function Card({
|
export function Card({
|
||||||
title,
|
title,
|
@ -0,0 +1,7 @@
|
|||||||
|
import fetchSummaryInfoUsecase from "@/feature/core/summary-info/domain/usecase/fetch-summary-info-usecase";
|
||||||
|
import { connection } from "next/server";
|
||||||
|
|
||||||
|
export default function cardsController() {
|
||||||
|
connection();
|
||||||
|
return fetchSummaryInfoUsecase();
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { Card } from "@/app/[lang]/dashboard/components/server/card";
|
import { Card } from "@/app/[lang]/dashboard/components/server/card/card";
|
||||||
import cardsController from "@/app/[lang]/dashboard/controller/cards.controller";
|
import cardsController from "@/app/[lang]/dashboard/components/server/cards/cards-controller";
|
||||||
|
|
||||||
export default async function CardWrapper() {
|
export default async function CardWrapper() {
|
||||||
const { customersNumber, invoicesNumber, invoicesSummary } =
|
const { customersNumber, invoicesNumber, invoicesSummary } =
|
@ -0,0 +1,7 @@
|
|||||||
|
import fetchCustomerInvoicesUsecase from "@/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices-usecase";
|
||||||
|
import { connection } from "next/server";
|
||||||
|
|
||||||
|
export default function latestInvoicesController() {
|
||||||
|
connection();
|
||||||
|
return fetchCustomerInvoicesUsecase();
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import CreateRandomInvoiceContainer from "@/app/[lang]/dashboard/components/client/create-random-invoice/create-random-invoice";
|
import CreateRandomInvoiceContainer from "@/app/[lang]/dashboard/components/client/create-random-invoice/create-random-invoice";
|
||||||
import latestInvoicesController from "@/app/[lang]/dashboard/controller/latest-invoices.controller";
|
import latestInvoicesController from "@/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices-controller";
|
||||||
import { ArrowPathIcon } from "@heroicons/react/24/outline";
|
import { ArrowPathIcon } from "@heroicons/react/24/outline";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { isLeft } from "fp-ts/lib/Either";
|
import { isLeft } from "fp-ts/lib/Either";
|
@ -1,12 +1,6 @@
|
|||||||
import Revenue from "@/feature/core/revenue/domain/entity/revenue.entity";
|
import Revenue from "@/feature/core/revenue/domain/entity/revenue";
|
||||||
import fetchRevenuesUsecase from "@/feature/core/revenue/domain/usecase/fetch-revenues.usecase";
|
import fetchRevenuesUsecase from "@/feature/core/revenue/domain/usecase/fetch-revenues-usecase";
|
||||||
|
|
||||||
/**
|
|
||||||
* 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() {
|
export default async function revenueChartController() {
|
||||||
const revenue = await fetchRevenuesUsecase();
|
const revenue = await fetchRevenuesUsecase();
|
||||||
const chartHeight = 350;
|
const chartHeight = 350;
|
@ -1,4 +1,4 @@
|
|||||||
import revenueChartController from "@/app/[lang]/dashboard/controller/revenue-chart.controller";
|
import revenueChartController from "@/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart-controller";
|
||||||
import { CalendarIcon } from "@heroicons/react/24/outline";
|
import { CalendarIcon } from "@heroicons/react/24/outline";
|
||||||
|
|
||||||
export default async function RevenueChart() {
|
export default async function RevenueChart() {
|
@ -1,13 +0,0 @@
|
|||||||
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.
|
|
||||||
* 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();
|
|
||||||
return fetchSummaryInfoUsecase();
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
"use server";
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<ApiEither<string>> {
|
|
||||||
connection();
|
|
||||||
const usecase = serverDi(invoiceModuleKey).resolve<CreateInvoiceUsecase>(
|
|
||||||
createInvoiceUsecaseKey,
|
|
||||||
);
|
|
||||||
return usecase(params);
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
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.
|
|
||||||
* 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();
|
|
||||||
return fetchCustomerInvoicesUsecase();
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import SideNav from "@/app/[lang]/dashboard/components/server/sidenav";
|
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 { DiContext } from "@/bootstrap/di/di-context";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import DashboardSkeleton from "@/app/[lang]/dashboard/components/server/skeletons";
|
import DashboardSkeleton from "@/app/[lang]/dashboard/components/server/skeletons/skeletons";
|
||||||
|
|
||||||
export default function Loading() {
|
export default function Loading() {
|
||||||
return <DashboardSkeleton />;
|
return <DashboardSkeleton />;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
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
|
|
||||||
*/
|
|
||||||
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,
|
@ -1,13 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
LatestInvoicesSkeleton,
|
LatestInvoicesSkeleton,
|
||||||
RevenueChartSkeleton,
|
RevenueChartSkeleton,
|
||||||
} from "@/app/[lang]/dashboard/components/server/skeletons";
|
} from "@/app/[lang]/dashboard/components/server/skeletons/skeletons";
|
||||||
import CardWrapper from "@/app/[lang]/dashboard/components/server/cards";
|
import CardWrapper from "@/app/[lang]/dashboard/components/server/cards/cards";
|
||||||
import RevenueChart from "@/app/[lang]/dashboard/components/server/revenue-chart";
|
import LatestInvoices from "@/app/[lang]/dashboard/components/server/latest-invoices/latest-invoices";
|
||||||
|
import RevenueChart from "@/app/[lang]/dashboard/components/server/revenue-chart/revenue-chart";
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import { getServerTranslation, LANGS } from "@/bootstrap/i18n/i18n";
|
import { getServerTranslation, LANGS } from "@/bootstrap/i18n/i18n";
|
||||||
import langKey from "@/bootstrap/i18n/dictionaries/lang-key";
|
import langKey from "@/bootstrap/i18n/dictionaries/lang-key";
|
||||||
import LatestInvoices from "@/app/[lang]/dashboard/components/server/latest-invoices";
|
|
||||||
|
|
||||||
export default async function Dashboard(props: {
|
export default async function Dashboard(props: {
|
||||||
params: Promise<{ lang: LANGS }>;
|
params: Promise<{ lang: LANGS }>;
|
||||||
|
@ -1,26 +1,20 @@
|
|||||||
import createInvoiceController from "@/app/[lang]/dashboard/controller/create-invoice.controller";
|
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 { useServerAction } from "@/bootstrap/helpers/hooks/use-server-action";
|
||||||
import useThrottle from "@/bootstrap/helpers/hooks/use-throttle";
|
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/create-invoice.usecase";
|
import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/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";
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<ButtonVm> {
|
export default class CreateRandomInvoiceButtonVM extends BaseVM<ButtonVm> {
|
||||||
private createInvoice: CreateInvoiceUsecase;
|
private createInvoice: typeof createInvoiceUsecase;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.createInvoice = createInvoiceController;
|
this.createInvoice = this.di.resolve(createInvoiceUsecase.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
useVM(): ButtonVm {
|
useVM(): ButtonVm {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ThemeProvider } from "@/app/[lang]/dashboard/components/client/theme-provider/theme-provider";
|
import { ThemeProvider } from "@/app/[lang]/dashboard/components/client/theme-provider/theme-provider";
|
||||||
import { getI18n, LANGS } from "@/bootstrap/i18n/i18n";
|
import { initI18next, LANGS } from "@/bootstrap/i18n/i18n";
|
||||||
import TranslationsProvider from "@/bootstrap/i18n/i18n-provider";
|
import TranslationsProvider from "@/bootstrap/i18n/i18n-provider";
|
||||||
import localFont from "next/font/local";
|
import localFont from "next/font/local";
|
||||||
import { PropsWithChildren } from "react";
|
import { PropsWithChildren } from "react";
|
||||||
@ -20,7 +20,7 @@ export default async function layout(
|
|||||||
) {
|
) {
|
||||||
const { params, children } = props;
|
const { params, children } = props;
|
||||||
const { lang } = await params;
|
const { lang } = await params;
|
||||||
await getI18n({ lng: lang });
|
const { resources } = await initI18next({ lng: lang });
|
||||||
return (
|
return (
|
||||||
<html lang={lang} suppressHydrationWarning>
|
<html lang={lang} suppressHydrationWarning>
|
||||||
<body
|
<body
|
||||||
@ -32,7 +32,9 @@ export default async function layout(
|
|||||||
enableSystem
|
enableSystem
|
||||||
disableTransitionOnChange
|
disableTransitionOnChange
|
||||||
>
|
>
|
||||||
<TranslationsProvider lng={lang}>{children}</TranslationsProvider>
|
<TranslationsProvider lng={lang} resources={resources}>
|
||||||
|
{children}
|
||||||
|
</TranslationsProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
7
src/app/components/button/button-vm.ts
Normal file
7
src/app/components/button/button-vm.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export default interface ButtonVm {
|
||||||
|
props: {
|
||||||
|
title: string;
|
||||||
|
isDisable: boolean;
|
||||||
|
};
|
||||||
|
onClick(): void;
|
||||||
|
}
|
@ -1,11 +0,0 @@
|
|||||||
/**
|
|
||||||
* Interface for viewmodel of button. this is bridge between view and viewmodel.
|
|
||||||
* With this interface, view is adapter and vms will be implementations in bridge pattern
|
|
||||||
*/
|
|
||||||
export default interface ButtonVm {
|
|
||||||
props: {
|
|
||||||
title: string;
|
|
||||||
isDisable: boolean;
|
|
||||||
};
|
|
||||||
onClick(): void;
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import BaseView, { BuildProps } from "@/bootstrap/helpers/view/base-view";
|
import BaseView, { BuildProps } from "@/bootstrap/helpers/view/base-view";
|
||||||
import ButtonVm from "@/app/components/button/button.i-vm";
|
import ButtonVm from "@/app/components/button/button-vm";
|
||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Slot } from "@radix-ui/react-slot";
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
|
@ -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 { createInvoiceUsecaseKey } from "@/feature/core/invoice/domain/usecase/create-invoice/create-invoice.usecase";
|
import createInvoiceUsecase from "@/feature/core/invoice/domain/usecase/create-invoice-usecase";
|
||||||
import type { Meta } from "@storybook/react";
|
import type { Meta } from "@storybook/react";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
|
||||||
@ -36,32 +36,30 @@ export const Primary: Story = {
|
|||||||
export const WithVM: Story = {
|
export const WithVM: Story = {
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story) => {
|
(Story) => {
|
||||||
const di = useRef(
|
const di = mockedModuleDi([
|
||||||
mockedModuleDi([
|
|
||||||
{
|
{
|
||||||
token: CreateRandomInvoiceButtonVM,
|
token: CreateRandomInvoiceButtonVM,
|
||||||
provider: CreateRandomInvoiceButtonVM,
|
provider: CreateRandomInvoiceButtonVM,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
token: createInvoiceUsecaseKey,
|
token: createInvoiceUsecase.name,
|
||||||
// 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: () => {
|
render: (_, globalProps) => {
|
||||||
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 <Child />;
|
return (
|
||||||
|
<DiContext.Provider value={globalProps.di}>
|
||||||
|
<Child />
|
||||||
|
</DiContext.Provider>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -2,9 +2,6 @@ import { constructor } from "tsyringe/dist/typings/types";
|
|||||||
|
|
||||||
export const isServer = typeof window === "undefined";
|
export const isServer = typeof window === "undefined";
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the given value is a class
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export function isClass(fn: any): fn is constructor<unknown> {
|
export function isClass(fn: any): fn is constructor<unknown> {
|
||||||
return typeof fn === "function" && /^(class|function [A-Z])/.test(fn);
|
return typeof fn === "function" && /^(class|function [A-Z])/.test(fn);
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
import { clsx, type ClassValue } from "clsx";
|
import { clsx, type ClassValue } from "clsx";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
/**
|
|
||||||
* To connect tailwind classes.
|
|
||||||
* @param inputs Tailwind classes
|
|
||||||
*/
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs));
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
@ -66,11 +66,6 @@ export type BuildProps<
|
|||||||
children?: ReactNode;
|
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<
|
export default abstract class BaseView<
|
||||||
IVM extends IVMParent,
|
IVM extends IVMParent,
|
||||||
PROPS extends IPropParent = undefined,
|
PROPS extends IPropParent = undefined,
|
||||||
|
@ -1,12 +1,5 @@
|
|||||||
import IBaseVM from "@/bootstrap/helpers/vm/i-base-vm";
|
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 <Button vm={vm} memoizedByVM={false} />;
|
|
||||||
*/
|
|
||||||
const getArgVM = <IVM>(vmObj: IVM) => {
|
const getArgVM = <IVM>(vmObj: IVM) => {
|
||||||
class VM implements IBaseVM<IVM> {
|
class VM implements IBaseVM<IVM> {
|
||||||
useVM(): IVM {
|
useVM(): IVM {
|
||||||
|
@ -5,12 +5,6 @@ import { NoOverride } from "@/bootstrap/helpers/type-helper";
|
|||||||
import IBaseVM from "@/bootstrap/helpers/vm/i-base-vm";
|
import IBaseVM from "@/bootstrap/helpers/vm/i-base-vm";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for all viewmodels. It provides
|
|
||||||
* - dependency injection: To get closes di which serves from di provider
|
|
||||||
* - rerender method: to rerender your component manually
|
|
||||||
* - produce method: to produce your vm dynamically by passing and attaching dependencies to it
|
|
||||||
*/
|
|
||||||
export default abstract class BaseVM<
|
export default abstract class BaseVM<
|
||||||
IVM,
|
IVM,
|
||||||
DEP extends object | undefined = undefined,
|
DEP extends object | undefined = undefined,
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
/**
|
|
||||||
* All viewmodels should implement this interface.
|
|
||||||
*/
|
|
||||||
export default interface IBaseVM<VM> {
|
export default interface IBaseVM<VM> {
|
||||||
useVM(): VM;
|
useVM(): VM;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,3 @@
|
|||||||
/**
|
|
||||||
* main language keys which will be used for translation to avoid using strings directly and be
|
|
||||||
* a single source of truth in all changes between all languages dictionaries.
|
|
||||||
* All languages dictionaries should have the same keys by having this object type.
|
|
||||||
*/
|
|
||||||
const langKey = {
|
const langKey = {
|
||||||
global: {
|
global: {
|
||||||
home: "global.home",
|
home: "global.home",
|
||||||
|
@ -1,24 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { I18nextProvider } from "react-i18next";
|
import { I18nextProvider } from "react-i18next";
|
||||||
import { getI18n, LANGS } from "@/bootstrap/i18n/i18n";
|
import { i18nInstance, initI18next, LANGS } from "@/bootstrap/i18n/i18n";
|
||||||
import { PropsWithChildren, useEffect, useState } from "react";
|
import { Resource } from "i18next";
|
||||||
import { i18n } from "i18next";
|
import { PropsWithChildren } from "react";
|
||||||
import storeLang from "@/bootstrap/i18n/store-lang-action";
|
|
||||||
|
|
||||||
export default function TranslationsProvider({
|
export default function TranslationsProvider({
|
||||||
children,
|
children,
|
||||||
lng,
|
lng,
|
||||||
}: PropsWithChildren & { lng: LANGS }) {
|
resources,
|
||||||
const [i18n, setI18n] = useState<i18n>();
|
}: PropsWithChildren & { lng: LANGS; resources: Resource }) {
|
||||||
|
if (!resources) return children;
|
||||||
|
initI18next({ lng, resources });
|
||||||
|
|
||||||
useEffect(() => {
|
return <I18nextProvider i18n={i18nInstance}>{children}</I18nextProvider>;
|
||||||
(async () => {
|
|
||||||
storeLang(lng);
|
|
||||||
setI18n((await getI18n({ lng })).i18n);
|
|
||||||
})();
|
|
||||||
}, [lng]);
|
|
||||||
|
|
||||||
if (!i18n) return null;
|
|
||||||
return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ export enum LANGS {
|
|||||||
RU = "ru",
|
RU = "ru",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getI18n = async (params: {
|
export const initI18next = async (params: {
|
||||||
lng: LANGS;
|
lng: LANGS;
|
||||||
resources?: Resource;
|
resources?: Resource;
|
||||||
ns?: string;
|
ns?: string;
|
||||||
@ -43,9 +43,13 @@ export async function getServerTranslation(
|
|||||||
ns?: string,
|
ns?: string,
|
||||||
options: { keyPrefix?: string } = {},
|
options: { keyPrefix?: string } = {},
|
||||||
) {
|
) {
|
||||||
const { i18n } = await getI18n({ lng });
|
await initI18next({ lng });
|
||||||
return {
|
return {
|
||||||
t: i18n.getFixedT(lng, Array.isArray(ns) ? ns[0] : ns, options?.keyPrefix),
|
t: i18nInstance.getFixedT(
|
||||||
|
lng,
|
||||||
|
Array.isArray(ns) ? ns[0] : ns,
|
||||||
|
options?.keyPrefix,
|
||||||
|
),
|
||||||
i18n: i18nInstance,
|
i18n: i18nInstance,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
"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);
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
import { Either } from "fp-ts/lib/Either";
|
import { Either } from "fp-ts/lib/Either";
|
||||||
import { TaskEither } from "fp-ts/lib/TaskEither";
|
import { TaskEither } from "fp-ts/lib/TaskEither";
|
||||||
import BaseFailure from "@/feature/common/failures/base.failure";
|
import BaseFailure from "@/feature/common/failures/base-failure";
|
||||||
|
|
||||||
type ApiTask<ResponseType> = TaskEither<BaseFailure<unknown>, ResponseType>;
|
type ApiTask<ResponseType> = TaskEither<BaseFailure<unknown>, ResponseType>;
|
||||||
export type ApiEither<ResponseType> = Either<
|
export type ApiEither<ResponseType> = Either<
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
import { makeFailureMessage } from "@/feature/common/failures/failure-helpers";
|
import { makeFailureMessage } from "@/feature/common/failures/failure-helpers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class can be used as a base class for creating custom failure classes.
|
* This is a class called BaseFailure that extends the Error class. It is
|
||||||
* With this class you can set message and metadata, with messages and extending
|
* used as a base class for creating custom failure classes.
|
||||||
* you can create your failure messages hierarchy and automatically by syncing langKey
|
|
||||||
* with the hirerarchy of failure messages.
|
|
||||||
* For example if you pass a key of `user` to the constructor of `UserCreationFailure`
|
|
||||||
* so in langKey you can have failure message `faiure.user` so automatically,
|
|
||||||
* you can show translated error message everywhere in the app.
|
|
||||||
* Also you can use this failure message to have grained control over failures.
|
|
||||||
*/
|
*/
|
||||||
export default abstract class BaseFailure<META_DATA> {
|
export default abstract class BaseFailure<META_DATA> {
|
||||||
/* ------------------------------- Attributes ------------------------------- */
|
/* ------------------------------- Attributes ------------------------------- */
|
@ -1,4 +1,4 @@
|
|||||||
import BaseDevFailure from "@/feature/common/failures/dev/base-dev.failure";
|
import BaseDevFailure from "@/feature/common/failures/dev/base-dev-failure";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Failure for needed arguments in a method but sent wrong one
|
* Failure for needed arguments in a method but sent wrong one
|
5
src/feature/common/failures/dev/base-dev-failure.ts
Normal file
5
src/feature/common/failures/dev/base-dev-failure.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import BaseFailure from "@/feature/common/failures/base-failure";
|
||||||
|
|
||||||
|
export default abstract class BaseDevFailure<
|
||||||
|
META_DATA,
|
||||||
|
> extends BaseFailure<META_DATA> {}
|
@ -1,10 +0,0 @@
|
|||||||
import BaseFailure from "@/feature/common/failures/base.failure";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a base class for development failures. All dev failures means we as a developer
|
|
||||||
* made a mistake in the process and we should fix it and can be used in monitoring and
|
|
||||||
* should be handled in hotfix ASAP.
|
|
||||||
*/
|
|
||||||
export default abstract class BaseDevFailure<
|
|
||||||
META_DATA,
|
|
||||||
> extends BaseFailure<META_DATA> {}
|
|
@ -1,7 +1,7 @@
|
|||||||
import BaseDevFailure from "@/feature/common/failures/dev/base-dev.failure";
|
import BaseDevFailure from "@/feature/common/failures/dev/base-dev-failure";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a failure when we didn't provice specific dependency.
|
* This is a failure of not having specific dependency
|
||||||
*/
|
*/
|
||||||
export default class DependencyFailure<
|
export default class DependencyFailure<
|
||||||
META_DATA,
|
META_DATA,
|
@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import BaseFailure from "@/feature/common/failures/base.failure";
|
import BaseFailure from "@/feature/common/failures/base-failure";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is supposed to save previous failure of TaskEither
|
* This method is supposed to save previous failure of TaskEither
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import BaseFailure from "./base.failure";
|
import BaseFailure from "./base-failure";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Failure for HTTP response when response dosn't have base structure
|
* Failure for HTTP response when response dosn't have base structure
|
@ -1,7 +1,7 @@
|
|||||||
import BaseFailure from "./base.failure";
|
import BaseFailure from "./base-failure";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Failure for params failure. which means some params are missing or not valid
|
* Failure for params failure
|
||||||
*/
|
*/
|
||||||
export default class ParamsFailure<META_DATA> extends BaseFailure<META_DATA> {
|
export default class ParamsFailure<META_DATA> extends BaseFailure<META_DATA> {
|
||||||
/* ------------------------------- Constructor ------------------------------ */
|
/* ------------------------------- Constructor ------------------------------ */
|
@ -1,14 +1,14 @@
|
|||||||
import getCustomerInvoiceDi from "@/feature/core/customer-invoice/data/module/customer-invoice.di";
|
import getCustomerInvoiceDi from "@/feature/core/customer-invoice/data/module/customer-invoice-di";
|
||||||
import { customerInvoiceModuleKey } from "@/feature/core/customer-invoice/invoice.module-key";
|
import { customerInvoiceModuleKey } from "@/feature/core/customer-invoice/invoice-module-key";
|
||||||
import { customerKey } from "@/feature/core/customer/customer-key";
|
import { customerKey } from "@/feature/core/customer/customer-key";
|
||||||
import getCustomerDi from "@/feature/core/customer/data/module/customer-di";
|
import getCustomerDi from "@/feature/core/customer/data/module/customer-di";
|
||||||
import getInvoiceDi from "@/feature/core/invoice/data/module/invoice.di";
|
import getInvoiceDi from "@/feature/core/invoice/data/module/invoice-di";
|
||||||
import { invoiceModuleKey } from "@/feature/core/invoice/invoice.module-key";
|
import { invoiceModuleKey } from "@/feature/core/invoice/invoice-module-key";
|
||||||
import { DependencyContainer } from "tsyringe";
|
import { DependencyContainer } from "tsyringe";
|
||||||
import { summaryInfoModuleKey } from "@/feature/core/summary-info/domain/summary-info.module-key";
|
import { summaryInfoModuleKey } from "@/feature/core/summary-info/domain/summary-info-module-key";
|
||||||
import getSummaryInfoDi from "@/feature/core/summary-info/data/module/summary-info.di";
|
import getSummaryInfoDi from "@/feature/core/summary-info/data/module/summary-info-di";
|
||||||
import { revenueModuleKey } from "@/feature/core/revenue/domain/revenue.module-key";
|
import { revenueModuleKey } from "@/feature/core/revenue/domain/revenue-module-key";
|
||||||
import getRevenueDi from "@/feature/core/revenue/data/module/revenue.di";
|
import getRevenueDi from "@/feature/core/revenue/data/module/revenue-di";
|
||||||
|
|
||||||
const memoizedDis: Record<string, DependencyContainer> = {};
|
const memoizedDis: Record<string, DependencyContainer> = {};
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
import di from "@/bootstrap/di/init-di";
|
import di from "@/bootstrap/di/init-di";
|
||||||
import CustomerInvoiceDbRepo from "@/feature/core/customer-invoice/data/repo/customer-invoice-db.repo";
|
import CustomerInvoiceDbRepo from "@/feature/core/customer-invoice/data/repo/customer-invoice-db-repo";
|
||||||
import { customerInvoiceRepoKey } from "@/feature/core/customer-invoice/domain/i-repo/customer-invoice.repo";
|
import { customerInvoiceRepoKey } from "@/feature/core/customer-invoice/domain/i-repo/customer-invoice-repo";
|
||||||
import { DependencyContainer } from "tsyringe";
|
import { DependencyContainer } from "tsyringe";
|
||||||
|
|
||||||
export default function getCustomerInvoiceDi(): DependencyContainer {
|
export default function getCustomerInvoiceDi(): DependencyContainer {
|
@ -1,10 +1,10 @@
|
|||||||
import { sql } from "@/bootstrap/boundaries/db/db";
|
import { sql } from "@/bootstrap/boundaries/db/db";
|
||||||
import ApiTask from "@/feature/common/data/api-task";
|
import ApiTask from "@/feature/common/data/api-task";
|
||||||
import { failureOr } from "@/feature/common/failures/failure-helpers";
|
import { failureOr } from "@/feature/common/failures/failure-helpers";
|
||||||
import NetworkFailure from "@/feature/common/failures/network.failure";
|
import NetworkFailure from "@/feature/common/failures/network-failure";
|
||||||
import { formatCurrency } from "@/feature/common/feature-helpers";
|
import { formatCurrency } from "@/feature/common/feature-helpers";
|
||||||
import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice.entity";
|
import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice";
|
||||||
import CustomerInvoiceRepo from "@/feature/core/customer-invoice/domain/i-repo/customer-invoice.repo";
|
import CustomerInvoiceRepo from "@/feature/core/customer-invoice/domain/i-repo/customer-invoice-repo";
|
||||||
import { pipe } from "fp-ts/lib/function";
|
import { pipe } from "fp-ts/lib/function";
|
||||||
import { tryCatch } from "fp-ts/lib/TaskEither";
|
import { tryCatch } from "fp-ts/lib/TaskEither";
|
||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
@ -1,5 +1,5 @@
|
|||||||
import ApiTask from "@/feature/common/data/api-task";
|
import ApiTask from "@/feature/common/data/api-task";
|
||||||
import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice.entity";
|
import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice";
|
||||||
|
|
||||||
export default interface CustomerInvoiceRepo {
|
export default interface CustomerInvoiceRepo {
|
||||||
fetchList(): ApiTask<CustomerInvoice[]>;
|
fetchList(): ApiTask<CustomerInvoice[]>;
|
@ -1,10 +1,11 @@
|
|||||||
|
import "server-only";
|
||||||
import { ApiEither } from "@/feature/common/data/api-task";
|
import { ApiEither } from "@/feature/common/data/api-task";
|
||||||
import serverDi from "@/feature/common/server.di";
|
import serverDi from "@/feature/common/server-di";
|
||||||
import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice.entity";
|
import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice";
|
||||||
import CustomerInvoiceRepo, {
|
import CustomerInvoiceRepo, {
|
||||||
customerInvoiceRepoKey,
|
customerInvoiceRepoKey,
|
||||||
} from "@/feature/core/customer-invoice/domain/i-repo/customer-invoice.repo";
|
} from "@/feature/core/customer-invoice/domain/i-repo/customer-invoice-repo";
|
||||||
import { customerInvoiceModuleKey } from "@/feature/core/customer-invoice/invoice.module-key";
|
import { customerInvoiceModuleKey } from "@/feature/core/customer-invoice/invoice-module-key";
|
||||||
|
|
||||||
export default function fetchCustomerInvoicesUsecase(): Promise<
|
export default function fetchCustomerInvoicesUsecase(): Promise<
|
||||||
ApiEither<CustomerInvoice[]>
|
ApiEither<CustomerInvoice[]>
|
@ -1,7 +1,7 @@
|
|||||||
import { sql } from "@/bootstrap/boundaries/db/db";
|
import { sql } from "@/bootstrap/boundaries/db/db";
|
||||||
import ApiTask from "@/feature/common/data/api-task";
|
import ApiTask from "@/feature/common/data/api-task";
|
||||||
import { failureOr } from "@/feature/common/failures/failure-helpers";
|
import { failureOr } from "@/feature/common/failures/failure-helpers";
|
||||||
import NetworkFailure from "@/feature/common/failures/network.failure";
|
import NetworkFailure from "@/feature/common/failures/network-failure";
|
||||||
import { formatCurrency } from "@/feature/common/feature-helpers";
|
import { formatCurrency } from "@/feature/common/feature-helpers";
|
||||||
import Customer from "@/feature/core/customer/domain/entity/customer";
|
import Customer from "@/feature/core/customer/domain/entity/customer";
|
||||||
import CustomerRepo from "@/feature/core/customer/domain/i-repo/customer-repo";
|
import CustomerRepo from "@/feature/core/customer/domain/i-repo/customer-repo";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import serverDi from "@/feature/common/server.di";
|
import "server-only";
|
||||||
|
import serverDi from "@/feature/common/server-di";
|
||||||
import { customerKey } from "@/feature/core/customer/customer-key";
|
import { customerKey } from "@/feature/core/customer/customer-key";
|
||||||
import CustomerRepo, {
|
import CustomerRepo, {
|
||||||
customerRepoKey,
|
customerRepoKey,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
import "server-only";
|
||||||
import { ApiEither } from "@/feature/common/data/api-task";
|
import { ApiEither } from "@/feature/common/data/api-task";
|
||||||
import serverDi from "@/feature/common/server.di";
|
import serverDi from "@/feature/common/server-di";
|
||||||
import { customerKey } from "@/feature/core/customer/customer-key";
|
import { customerKey } from "@/feature/core/customer/customer-key";
|
||||||
import Customer from "@/feature/core/customer/domain/entity/customer";
|
import Customer from "@/feature/core/customer/domain/entity/customer";
|
||||||
import CustomerRepo, {
|
import CustomerRepo, {
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
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-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;
|
||||||
}
|
}
|
@ -1,12 +1,11 @@
|
|||||||
import "server-only";
|
|
||||||
import { sql } from "@/bootstrap/boundaries/db/db";
|
import { sql } from "@/bootstrap/boundaries/db/db";
|
||||||
import ApiTask from "@/feature/common/data/api-task";
|
import ApiTask from "@/feature/common/data/api-task";
|
||||||
import { failureOr } from "@/feature/common/failures/failure-helpers";
|
import { failureOr } from "@/feature/common/failures/failure-helpers";
|
||||||
import NetworkFailure from "@/feature/common/failures/network.failure";
|
import NetworkFailure from "@/feature/common/failures/network-failure";
|
||||||
import { formatCurrency } from "@/feature/common/feature-helpers";
|
import { formatCurrency } from "@/feature/common/feature-helpers";
|
||||||
import InvoiceRepo from "@/feature/core/invoice/domain/i-repo/invoice.i-repo";
|
import InvoiceRepo from "@/feature/core/invoice/domain/i-repo/invoice-repo";
|
||||||
import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice.param";
|
import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice-param";
|
||||||
import InvoiceStatusSummary from "@/feature/core/invoice/domain/value-object/invoice-status.value-object";
|
import InvoiceStatusSummary from "@/feature/core/invoice/domain/value-object/invoice-status";
|
||||||
import { pipe } from "fp-ts/lib/function";
|
import { pipe } from "fp-ts/lib/function";
|
||||||
import { tryCatch } from "fp-ts/lib/TaskEither";
|
import { tryCatch } from "fp-ts/lib/TaskEither";
|
||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
@ -1,6 +1,6 @@
|
|||||||
import ApiTask from "@/feature/common/data/api-task";
|
import ApiTask from "@/feature/common/data/api-task";
|
||||||
import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice.param";
|
import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice-param";
|
||||||
import InvoiceStatusSummary from "@/feature/core/invoice/domain/value-object/invoice-status.value-object";
|
import InvoiceStatusSummary from "@/feature/core/invoice/domain/value-object/invoice-status";
|
||||||
|
|
||||||
export default interface InvoiceRepo {
|
export default interface InvoiceRepo {
|
||||||
fetchAllInvoicesAmount(): Promise<number>;
|
fetchAllInvoicesAmount(): Promise<number>;
|
@ -1,21 +1,22 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
import { ApiEither } from "@/feature/common/data/api-task";
|
import { ApiEither } from "@/feature/common/data/api-task";
|
||||||
import ParamsFailure from "@/feature/common/failures/params.failure";
|
import ParamsFailure from "@/feature/common/failures/params-failure";
|
||||||
import serverDi from "@/feature/common/server.di";
|
import serverDi from "@/feature/common/server-di";
|
||||||
import InvoiceRepo, {
|
import InvoiceRepo, {
|
||||||
invoiceRepoKey,
|
invoiceRepoKey,
|
||||||
} from "@/feature/core/invoice/domain/i-repo/invoice.i-repo";
|
} from "@/feature/core/invoice/domain/i-repo/invoice-repo";
|
||||||
import {
|
import {
|
||||||
InvoiceParam,
|
InvoiceParam,
|
||||||
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";
|
||||||
|
|
||||||
const createInvoiceUsecase: CreateInvoiceUsecase = async (
|
export default async function createInvoiceUsecase(
|
||||||
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(
|
||||||
@ -28,6 +29,4 @@ const createInvoiceUsecase: CreateInvoiceUsecase = async (
|
|||||||
}),
|
}),
|
||||||
chain((params) => repo.createInvoice(params)),
|
chain((params) => repo.createInvoice(params)),
|
||||||
)();
|
)();
|
||||||
};
|
}
|
||||||
|
|
||||||
export default createInvoiceUsecase;
|
|
@ -1,8 +0,0 @@
|
|||||||
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";
|
|
@ -1,8 +1,9 @@
|
|||||||
import serverDi from "@/feature/common/server.di";
|
import "server-only";
|
||||||
|
import serverDi from "@/feature/common/server-di";
|
||||||
import InvoiceRepo, {
|
import InvoiceRepo, {
|
||||||
invoiceRepoKey,
|
invoiceRepoKey,
|
||||||
} from "@/feature/core/invoice/domain/i-repo/invoice.i-repo";
|
} from "@/feature/core/invoice/domain/i-repo/invoice-repo";
|
||||||
import { invoiceModuleKey } from "@/feature/core/invoice/invoice.module-key";
|
import { invoiceModuleKey } from "@/feature/core/invoice/invoice-module-key";
|
||||||
|
|
||||||
export default function fetchAllInvoicesAmountUsecase(): Promise<number> {
|
export default function fetchAllInvoicesAmountUsecase(): Promise<number> {
|
||||||
const repo = serverDi(invoiceModuleKey).resolve<InvoiceRepo>(invoiceRepoKey);
|
const repo = serverDi(invoiceModuleKey).resolve<InvoiceRepo>(invoiceRepoKey);
|
@ -1,9 +1,10 @@
|
|||||||
import serverDi from "@/feature/common/server.di";
|
import "server-only";
|
||||||
|
import serverDi from "@/feature/common/server-di";
|
||||||
import InvoiceRepo, {
|
import InvoiceRepo, {
|
||||||
invoiceRepoKey,
|
invoiceRepoKey,
|
||||||
} from "@/feature/core/invoice/domain/i-repo/invoice.i-repo";
|
} from "@/feature/core/invoice/domain/i-repo/invoice-repo";
|
||||||
import InvoiceStatusSummary from "@/feature/core/invoice/domain/value-object/invoice-status.value-object";
|
import InvoiceStatusSummary from "@/feature/core/invoice/domain/value-object/invoice-status";
|
||||||
import { invoiceModuleKey } from "@/feature/core/invoice/invoice.module-key";
|
import { invoiceModuleKey } from "@/feature/core/invoice/invoice-module-key";
|
||||||
|
|
||||||
export default function fetchInvoicesStatusSummary(): Promise<InvoiceStatusSummary> {
|
export default function fetchInvoicesStatusSummary(): Promise<InvoiceStatusSummary> {
|
||||||
const repo = serverDi(invoiceModuleKey).resolve<InvoiceRepo>(invoiceRepoKey);
|
const repo = serverDi(invoiceModuleKey).resolve<InvoiceRepo>(invoiceRepoKey);
|
@ -1,6 +1,6 @@
|
|||||||
import di from "@/bootstrap/di/init-di";
|
import di from "@/bootstrap/di/init-di";
|
||||||
import RevenueDbRepo from "@/feature/core/revenue/data/repo/revenue-db.repo";
|
import RevenueDbRepo from "@/feature/core/revenue/data/repo/revenue-db-repo";
|
||||||
import { revenueRepoKey } from "@/feature/core/revenue/domain/i-repo/revenue.i-repo";
|
import { revenueRepoKey } from "@/feature/core/revenue/domain/i-repo/revenue-repo";
|
||||||
|
|
||||||
export default function getRevenueDi() {
|
export default function getRevenueDi() {
|
||||||
const revenueDi = di.createChildContainer();
|
const revenueDi = di.createChildContainer();
|
@ -1,6 +1,6 @@
|
|||||||
import { sql } from "@/bootstrap/boundaries/db/db";
|
import { sql } from "@/bootstrap/boundaries/db/db";
|
||||||
import Revenue from "@/feature/core/revenue/domain/entity/revenue.entity";
|
import Revenue from "@/feature/core/revenue/domain/entity/revenue";
|
||||||
import RevenueRepo from "@/feature/core/revenue/domain/i-repo/revenue.i-repo";
|
import RevenueRepo from "@/feature/core/revenue/domain/i-repo/revenue-repo";
|
||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
||||||
|
|
||||||
export type RevenueDbResponse = {
|
export type RevenueDbResponse = {
|
@ -1,4 +1,4 @@
|
|||||||
import Revenue from "@/feature/core/revenue/domain/entity/revenue.entity";
|
import Revenue from "@/feature/core/revenue/domain/entity/revenue";
|
||||||
|
|
||||||
export default interface RevenueRepo {
|
export default interface RevenueRepo {
|
||||||
fetchRevenues(): Promise<Revenue[]>;
|
fetchRevenues(): Promise<Revenue[]>;
|
@ -1,9 +1,10 @@
|
|||||||
import serverDi from "@/feature/common/server.di";
|
import "server-only";
|
||||||
import Revenue from "@/feature/core/revenue/domain/entity/revenue.entity";
|
import serverDi from "@/feature/common/server-di";
|
||||||
|
import Revenue from "@/feature/core/revenue/domain/entity/revenue";
|
||||||
import RevenueRepo, {
|
import RevenueRepo, {
|
||||||
revenueRepoKey,
|
revenueRepoKey,
|
||||||
} from "@/feature/core/revenue/domain/i-repo/revenue.i-repo";
|
} from "@/feature/core/revenue/domain/i-repo/revenue-repo";
|
||||||
import { revenueModuleKey } from "@/feature/core/revenue/domain/revenue.module-key";
|
import { revenueModuleKey } from "@/feature/core/revenue/domain/revenue-module-key";
|
||||||
|
|
||||||
export default function fetchRevenuesUsecase(): Promise<Revenue[]> {
|
export default function fetchRevenuesUsecase(): Promise<Revenue[]> {
|
||||||
const repo = serverDi(revenueModuleKey).resolve<RevenueRepo>(revenueRepoKey);
|
const repo = serverDi(revenueModuleKey).resolve<RevenueRepo>(revenueRepoKey);
|
@ -1,6 +1,6 @@
|
|||||||
import fetchCustomersAmountUsecase from "@/feature/core/customer/domain/usecase/fetch-customers-amount-usecase";
|
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";
|
import fetchAllInvoicesAmountUsecase from "@/feature/core/invoice/domain/usecase/fetch-all-invoices-amount-usecase";
|
||||||
import fetchInvoicesStatusSummary from "@/feature/core/invoice/domain/usecase/fetch-invoices-status-summary.usecase";
|
import fetchInvoicesStatusSummary from "@/feature/core/invoice/domain/usecase/fetch-invoices-status-summary";
|
||||||
import di from "@/bootstrap/di/init-di";
|
import di from "@/bootstrap/di/init-di";
|
||||||
|
|
||||||
export default function getSummaryInfoDi() {
|
export default function getSummaryInfoDi() {
|
@ -1,9 +1,10 @@
|
|||||||
import serverDi from "@/feature/common/server.di";
|
import "server-only";
|
||||||
|
import serverDi from "@/feature/common/server-di";
|
||||||
import fetchCustomersAmountUsecase from "@/feature/core/customer/domain/usecase/fetch-customers-amount-usecase";
|
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";
|
import fetchAllInvoicesAmountUsecase from "@/feature/core/invoice/domain/usecase/fetch-all-invoices-amount-usecase";
|
||||||
import fetchInvoicesStatusSummary from "@/feature/core/invoice/domain/usecase/fetch-invoices-status-summary.usecase";
|
import fetchInvoicesStatusSummary from "@/feature/core/invoice/domain/usecase/fetch-invoices-status-summary";
|
||||||
import { summaryInfoModuleKey } from "@/feature/core/summary-info/domain/summary-info.module-key";
|
import { summaryInfoModuleKey } from "@/feature/core/summary-info/domain/summary-info-module-key";
|
||||||
import SummaryInfo from "@/feature/core/summary-info/domain/value-object/summary-info.value-object";
|
import SummaryInfo from "@/feature/core/summary-info/domain/value-object/summary-info";
|
||||||
|
|
||||||
export default async function fetchSummaryInfoUsecase(): Promise<SummaryInfo> {
|
export default async function fetchSummaryInfoUsecase(): Promise<SummaryInfo> {
|
||||||
try {
|
try {
|
@ -1,4 +1,4 @@
|
|||||||
import InvoiceStatusSummary from "@/feature/core/invoice/domain/value-object/invoice-status.value-object";
|
import InvoiceStatusSummary from "@/feature/core/invoice/domain/value-object/invoice-status";
|
||||||
|
|
||||||
export default class SummaryInfo {
|
export default class SummaryInfo {
|
||||||
customersNumber: number;
|
customersNumber: number;
|
@ -1,9 +1,6 @@
|
|||||||
import di from "@/bootstrap/di/init-di";
|
import di from "@/bootstrap/di/init-di";
|
||||||
import * as serverDi from "@/feature/common/server.di";
|
import * as serverDi from "@/feature/common/server-di";
|
||||||
|
|
||||||
/**
|
|
||||||
* To mock and get server di
|
|
||||||
*/
|
|
||||||
export default function mockDi() {
|
export default function mockDi() {
|
||||||
vi.spyOn(serverDi, "default").mockReturnValue(di);
|
vi.spyOn(serverDi, "default").mockReturnValue(di);
|
||||||
return di;
|
return di;
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
import { Mock } from "moq.ts";
|
import { Mock } from "moq.ts";
|
||||||
|
|
||||||
/**
|
|
||||||
* To get mock object to mock objects and classes
|
|
||||||
*/
|
|
||||||
export function getMock<T>() {
|
export function getMock<T>() {
|
||||||
return new Mock<T>();
|
return new Mock<T>();
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import CustomerRepo, {
|
|||||||
import { getMock } from "@/test/common/mock/mock-factory";
|
import { getMock } from "@/test/common/mock/mock-factory";
|
||||||
import { describe } from "vitest";
|
import { describe } from "vitest";
|
||||||
import { faker } from "@faker-js/faker";
|
import { faker } from "@faker-js/faker";
|
||||||
import CustomerFakeFactory from "@/test/common/fake-factory/customer/customer.fake-factory";
|
import CustomerFakeFactory from "@/test/common/fake-factory/customer/customer-fake-factory";
|
||||||
import fetchCustomersUsecase from "@/feature/core/customer/domain/usecase/fetch-customers-usecase";
|
import fetchCustomersUsecase from "@/feature/core/customer/domain/usecase/fetch-customers-usecase";
|
||||||
import mockDi from "@/test/common/mock/mock-di";
|
import mockDi from "@/test/common/mock/mock-di";
|
||||||
import { right } from "fp-ts/lib/TaskEither";
|
import { right } from "fp-ts/lib/TaskEither";
|
Loading…
x
Reference in New Issue
Block a user