feature/research-di #1

Merged
behnam merged 37 commits from feature/research-di into develop 2024-11-21 15:50:19 +00:00
17 changed files with 64 additions and 52 deletions
Showing only changes of commit 43a622851d - Show all commits

2
.gitignore vendored
View File

@ -9,7 +9,7 @@
!.yarn/plugins !.yarn/plugins
!.yarn/releases !.yarn/releases
!.yarn/versions !.yarn/versions
.vscode
# testing # testing
/coverage /coverage

View File

@ -1,10 +1,10 @@
import fetchSummaryInfoUsecase from '@/feature/core/summary-info/domain/usecase/fetch-summary-info-usecase';
import { import {
BanknotesIcon, BanknotesIcon,
ClockIcon, ClockIcon,
UserGroupIcon, UserGroupIcon,
InboxIcon, InboxIcon,
} from '@heroicons/react/24/outline'; } from '@heroicons/react/24/outline';
import { fetchCardData } from '@/app/lib/data';
const iconMap = { const iconMap = {
collected: BanknotesIcon, collected: BanknotesIcon,
@ -14,21 +14,16 @@ const iconMap = {
}; };
export default async function CardWrapper() { export default async function CardWrapper() {
const { const {customersNumber, invoicesNumber, invoicesSummary } = await fetchSummaryInfoUsecase();
numberOfInvoices,
numberOfCustomers,
totalPaidInvoices,
totalPendingInvoices,
} = await fetchCardData();
return ( return (
<> <>
<Card title="Collected" value={totalPaidInvoices} type="collected" /> <Card title="Collected" value={invoicesSummary.paid} type="collected" />
<Card title="Pending" value={totalPendingInvoices} type="pending" /> <Card title="Pending" value={invoicesSummary.pending} type="pending" />
<Card title="Total Invoices" value={numberOfInvoices} type="invoices" /> <Card title="Total Invoices" value={invoicesNumber} type="invoices" />
<Card <Card
title="Total Customers" title="Total Customers"
value={numberOfCustomers} value={customersNumber}
type="customers" type="customers"
/> />
</> </>

View File

@ -1,9 +1,9 @@
import fetchCustomerInvoicesUsecase from '@/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices-usecase';
import { ArrowPathIcon } from '@heroicons/react/24/outline'; import { ArrowPathIcon } from '@heroicons/react/24/outline';
import clsx from 'clsx'; import clsx from 'clsx';
import Image from 'next/image'; import Image from 'next/image';
import { fetchLatestInvoices } from '@/app/lib/data';
export default async function LatestInvoices() { export default async function LatestInvoices() {
const latestInvoices = await fetchLatestInvoices(); const latestInvoices = await fetchCustomerInvoicesUsecase();
return ( return (
<div className="flex w-full flex-col md:col-span-4"> <div className="flex w-full flex-col md:col-span-4">
@ -26,25 +26,25 @@ export default async function LatestInvoices() {
> >
<div className="flex items-center"> <div className="flex items-center">
<Image <Image
src={invoice.image_url} src={invoice.customerImageUrl}
alt={`${invoice.name}'s profile picture`} alt={`${invoice.customerName}'s profile picture`}
className="mr-4 rounded-full" className="mr-4 rounded-full"
width={32} width={32}
height={32} height={32}
/> />
<div className="min-w-0"> <div className="min-w-0">
<p className="truncate text-sm font-semibold md:text-base"> <p className="truncate text-sm font-semibold md:text-base">
{invoice.name} {invoice.customerName}
</p> </p>
<p className="hidden text-sm text-gray-500 sm:block"> <p className="hidden text-sm text-gray-500 sm:block">
{invoice.email} {invoice.customerEmail}
</p> </p>
</div> </div>
</div> </div>
<p <p
className="truncate text-sm font-medium md:text-base" className="truncate text-sm font-medium md:text-base"
> >
{invoice.amount} {invoice.invoicesAmount}
</p> </p>
</div> </div>
); );

View File

@ -1,9 +1,9 @@
import { generateYAxis } from '@/app/lib/utils'; import { generateYAxis } from '@/app/lib/utils';
import fetchRevenuesUsecase from '@/feature/core/revenue/domain/usecase/fetch-revenues-usecase';
import { CalendarIcon } from '@heroicons/react/24/outline'; import { CalendarIcon } from '@heroicons/react/24/outline';
import { fetchRevenue } from '@/app/lib/data';
export default async function RevenueChart() { export default async function RevenueChart() {
const revenue = await fetchRevenue(); const revenue = await fetchRevenuesUsecase();
const chartHeight = 350; const chartHeight = 350;

View File

@ -0,0 +1,27 @@
import di from "@/bootstrap/di/init-di"
import fetchCustomerInvoicesUsecase from "@/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices-usecase";
import fetchCustomersUsecase from "@/feature/core/customer/domain/usecase/fetch-customers-usecase";
import fetchAllInvoicesAmountUsecase from "@/feature/core/invoice/domain/usecase/fetch-all-invoices-amount-usecase";
import fetchRevenuesUsecase from "@/feature/core/revenue/domain/usecase/fetch-revenues-usecase";
export default function dashboardAppModule() {
const dashboardDi = di.createChildContainer()
dashboardDi.register(fetchCustomersUsecase.name, {
useValue: fetchCustomersUsecase
})
dashboardDi.register(fetchAllInvoicesAmountUsecase.name, {
useValue: fetchAllInvoicesAmountUsecase
})
dashboardDi.register(fetchAllInvoicesAmountUsecase.name, {
useValue: fetchAllInvoicesAmountUsecase
})
dashboardDi.register(fetchCustomerInvoicesUsecase.name, {
useValue: fetchCustomerInvoicesUsecase
})
dashboardDi.register(fetchRevenuesUsecase.name, {
useValue: fetchRevenuesUsecase
})
return dashboardDi
}

View File

@ -12,7 +12,10 @@ import getSummaryInfoDi from "@/feature/core/summary-info/data/module/summary-in
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> = {}
export default function serverDi(module: string): DependencyContainer { export default function serverDi(module: string): DependencyContainer {
if (memoizedDis[module]) return memoizedDis[module]
const getDi = { const getDi = {
[testModuleKey]: getTestModule, [testModuleKey]: getTestModule,
[customerKey]: getCustomerDi, [customerKey]: getCustomerDi,
@ -24,5 +27,7 @@ export default function serverDi(module: string): DependencyContainer {
if (!getDi) throw new Error("Server Di didn't found for module: " + module) if (!getDi) throw new Error("Server Di didn't found for module: " + module)
return getDi() const di = getDi()
memoizedDis[module] = di
return di
} }

View File

@ -1,16 +1,11 @@
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 { 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 fetchCustomerInvoicesUsecase from "@/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices-usecase";
import CustomerDbRepo from "@/feature/core/customer/data/repo/customer-db-repo";
import { DependencyContainer } from "tsyringe"; import { DependencyContainer } from "tsyringe";
export default function getCustomerInvoiceDi(): DependencyContainer { export default function getCustomerInvoiceDi(): DependencyContainer {
const customerInvoiceDi = di.createChildContainer() const customerInvoiceDi = di.createChildContainer()
customerInvoiceDi.register(fetchCustomerInvoicesUsecase.name, { customerInvoiceDi.register(customerInvoiceRepoKey, CustomerInvoiceDbRepo)
useValue: fetchCustomerInvoicesUsecase
})
customerInvoiceDi.register(customerInvoiceRepoKey, CustomerDbRepo)
return customerInvoiceDi return customerInvoiceDi
} }

View File

@ -2,7 +2,6 @@ import { formatCurrency } from "@/app/lib/utils";
import { sql } from "@/bootstrap/db/db"; import { sql } from "@/bootstrap/db/db";
import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice"; 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 { connection } from "next/server";
import postgres from "postgres"; import postgres from "postgres";
type customerInvoiceDbResponse = { type customerInvoiceDbResponse = {
@ -13,11 +12,8 @@ type customerInvoiceDbResponse = {
amount: string; amount: string;
} }
export default class CustomerDbRepo implements CustomerInvoiceRepo { export default class CustomerInvoiceDbRepo implements CustomerInvoiceRepo {
async fetchList(): Promise<CustomerInvoice[]> { async fetchList(): Promise<CustomerInvoice[]> {
// This is equivalent to in fetch(..., {cache: 'no-store'}).
connection()
try { try {
const data = await sql` const data = await sql`
SELECT invoices.amount, customers.name, customers.image_url, customers.email, invoices.id SELECT invoices.amount, customers.name, customers.image_url, customers.email, invoices.id

View File

@ -3,9 +3,10 @@ import serverDi from "@/feature/common/server-di";
import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice"; import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice";
import CustomerInvoiceRepo, { customerInvoiceRepoKey } from "@/feature/core/customer-invoice/domain/i-repo/customer-invoice-repo"; import CustomerInvoiceRepo, { customerInvoiceRepoKey } 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";
import { connection } from "next/server";
export default function fetchCustomerInvoicesUsecase(): Promise<CustomerInvoice[]> { export default async function fetchCustomerInvoicesUsecase(): Promise<CustomerInvoice[]> {
connection()
const repo = serverDi(customerInvoiceModuleKey).resolve<CustomerInvoiceRepo>(customerInvoiceRepoKey) const repo = serverDi(customerInvoiceModuleKey).resolve<CustomerInvoiceRepo>(customerInvoiceRepoKey)
return repo.fetchList() return repo.fetchList()
} }

View File

@ -1,16 +1,11 @@
import di from "@/bootstrap/di/init-di"; import di from "@/bootstrap/di/init-di";
import CustomerDbRepo from "@/feature/core/customer/data/repo/customer-db-repo"; import CustomerDbRepo from "@/feature/core/customer/data/repo/customer-db-repo";
import { customerRepoKey } from "@/feature/core/customer/domain/i-repo/customer-repo"; import { customerRepoKey } from "@/feature/core/customer/domain/i-repo/customer-repo";
import fetchCustomersUsecase from "@/feature/core/customer/domain/usecase/fetch-customers-usecase";
import { DependencyContainer } from "tsyringe"; import { DependencyContainer } from "tsyringe";
export default function getCustomerDi(): DependencyContainer { export default function getCustomerDi(): DependencyContainer {
const customerDi = di.createChildContainer() const customerDi = di.createChildContainer()
customerDi.register(fetchCustomersUsecase.name, {
useValue: fetchCustomersUsecase
})
customerDi.register(customerRepoKey, CustomerDbRepo) customerDi.register(customerRepoKey, CustomerDbRepo)
return customerDi return customerDi
} }

View File

@ -2,7 +2,7 @@ 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, { customerRepoKey } from "@/feature/core/customer/domain/i-repo/customer-repo"; import CustomerRepo, { customerRepoKey } from "@/feature/core/customer/domain/i-repo/customer-repo";
export default function fetchCustomersAmountUsecase(): Promise<number> { export default async function fetchCustomersAmountUsecase(): Promise<number> {
const repo = serverDi(customerKey).resolve<CustomerRepo>(customerRepoKey) const repo = serverDi(customerKey).resolve<CustomerRepo>(customerRepoKey)
return repo.fetchCustomersAmount() return repo.fetchCustomersAmount()
} }

View File

@ -5,7 +5,7 @@ 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, { customerRepoKey } from "@/feature/core/customer/domain/i-repo/customer-repo"; import CustomerRepo, { customerRepoKey } from "@/feature/core/customer/domain/i-repo/customer-repo";
export default function fetchCustomersUsecase(query: string): Promise<Customer[]> { export default async function fetchCustomersUsecase(query: string): Promise<Customer[]> {
const repo = serverDi(customerKey).resolve<CustomerRepo>(customerRepoKey) const repo = serverDi(customerKey).resolve<CustomerRepo>(customerRepoKey)
return repo.fetchList(query) return repo.fetchList(query)

View File

@ -3,7 +3,7 @@ import serverDi from "@/feature/common/server-di";
import InvoiceRepo, { invoiceRepoKey } from "@/feature/core/invoice/domain/i-repo/invoice-repo"; import InvoiceRepo, { invoiceRepoKey } 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 async function fetchAllInvoicesAmountUsecase(): Promise<number> {
const repo = serverDi(invoiceModuleKey).resolve<InvoiceRepo>(invoiceRepoKey) const repo = serverDi(invoiceModuleKey).resolve<InvoiceRepo>(invoiceRepoKey)
return repo.fetchAllInvoicesAmount() return repo.fetchAllInvoicesAmount()

View File

@ -3,7 +3,7 @@ import InvoiceRepo, { invoiceRepoKey } from "@/feature/core/invoice/domain/i-rep
import InvoiceStatusSummary from "@/feature/core/invoice/domain/value-object/invoice-status"; 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 async function fetchInvoicesStatusSummary(): Promise<InvoiceStatusSummary> {
const repo = serverDi(invoiceModuleKey).resolve<InvoiceRepo>(invoiceRepoKey) const repo = serverDi(invoiceModuleKey).resolve<InvoiceRepo>(invoiceRepoKey)
return repo.fetchInvoicesStatusSummary() return repo.fetchInvoicesStatusSummary()
} }

View File

@ -11,7 +11,6 @@ export type RevenueDbResponse = {
export default class RevenueDbRepo implements RevenueRepo { export default class RevenueDbRepo implements RevenueRepo {
async fetchRevenues(): Promise<Revenue[]> { async fetchRevenues(): Promise<Revenue[]> {
// This is equivalent to in fetch(..., {cache: 'no-store'}). // This is equivalent to in fetch(..., {cache: 'no-store'}).
connection()
try { try {
// Artificially delay a response for demo purposes. // Artificially delay a response for demo purposes.
// Don't do this in production :) // Don't do this in production :)

View File

@ -1,9 +1,9 @@
import serverDi from "@/feature/common/server-di"; import serverDi from "@/feature/common/server-di";
import Revenue from "@/feature/core/revenue/domain/entity/revenue"; import Revenue from "@/feature/core/revenue/domain/entity/revenue";
import RevenueRepo from "@/feature/core/revenue/domain/i-repo/revenue-repo"; import RevenueRepo, { revenueRepoKey } 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 async function fetchRevenuesUsecase(): Promise<Revenue[]> {
const repo = serverDi(revenueModuleKey).resolve<RevenueRepo>(revenueModuleKey) const repo = serverDi(revenueModuleKey).resolve<RevenueRepo>(revenueRepoKey)
return repo.fetchRevenues() return repo.fetchRevenues()
} }

View File

@ -2,7 +2,6 @@ import di from "@/bootstrap/di/init-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" import fetchInvoicesStatusSummary from "@/feature/core/invoice/domain/usecase/fetch-invoices-status-summary"
import fetchSummaryInfoUsecase from "@/feature/core/summary-info/domain/usecase/fetch-summary-info-usecase"
export default function getSummaryInfoDi() { export default function getSummaryInfoDi() {
const summaryInfoDi = di.createChildContainer() const summaryInfoDi = di.createChildContainer()
@ -14,7 +13,7 @@ export default function getSummaryInfoDi() {
useValue: fetchCustomersAmountUsecase useValue: fetchCustomersAmountUsecase
}) })
summaryInfoDi.register(fetchInvoicesStatusSummary.name, { summaryInfoDi.register(fetchInvoicesStatusSummary.name, {
useValue: fetchSummaryInfoUsecase useValue: fetchInvoicesStatusSummary
}) })
return summaryInfoDi return summaryInfoDi
} }