Ship enterprise CRM frontend with real API wiring and thin app routes.
Connect all CRM pages to the BFF and CRM service, add module docs, and mark CRM available in the SuperApp catalog. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
065c053c16
commit
e140908034
125
frontend/.eslintrc.json
Normal file
125
frontend/.eslintrc.json
Normal file
@ -0,0 +1,125 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals",
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["app/accounting/**/*", "components/accounting/**/*"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"@/components/beauty/**",
|
||||
"@/components/healthcare/**",
|
||||
"@/modules/beauty/**",
|
||||
"@/modules/healthcare/**"
|
||||
],
|
||||
"message": "Accounting must not import beauty or healthcare modules."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["app/beauty/**/*", "modules/beauty/**/*"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"@/components/accounting/**",
|
||||
"@/components/healthcare/**",
|
||||
"@/modules/accounting/**",
|
||||
"@/modules/healthcare/**"
|
||||
],
|
||||
"message": "Beauty must not import accounting or healthcare modules."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["app/healthcare/**/*", "src/modules/healthcare/**/*"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"@/components/accounting/**",
|
||||
"@/components/beauty/**",
|
||||
"@/modules/beauty/**",
|
||||
"@/modules/accounting/**",
|
||||
"@/src/modules/beauty/**"
|
||||
],
|
||||
"message": "Healthcare must not import accounting or beauty modules."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["app/crm/**/*", "modules/crm/**/*"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"@/components/accounting/**",
|
||||
"@/components/beauty/**",
|
||||
"@/components/healthcare/**",
|
||||
"@/modules/beauty/**",
|
||||
"@/modules/healthcare/**",
|
||||
"@/modules/accounting/**"
|
||||
],
|
||||
"message": "CRM must not import accounting, beauty, or healthcare modules."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"components/ds/**/*",
|
||||
"shared/**/*",
|
||||
"components/providers/**/*",
|
||||
"components/AuthGuard.tsx",
|
||||
"components/AdminAuthGuard.tsx",
|
||||
"components/ThemeProvider.tsx",
|
||||
"components/SiteHeader.tsx",
|
||||
"hooks/**/*"
|
||||
],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"@/components/accounting/**",
|
||||
"@/components/beauty/**",
|
||||
"@/components/healthcare/**",
|
||||
"@/modules/beauty/**",
|
||||
"@/modules/healthcare/**",
|
||||
"@/modules/accounting/**",
|
||||
"@/modules/crm/**"
|
||||
],
|
||||
"message": "Shared/platform code must not import business module code."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
96
frontend/app/api/crm/[...path]/route.ts
Normal file
96
frontend/app/api/crm/[...path]/route.ts
Normal file
@ -0,0 +1,96 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
/**
|
||||
* Same-origin BFF proxy → CRM service.
|
||||
* Browser calls /api/crm/* so TLS/CORS/DNS issues
|
||||
* do not block CRUD from the SuperApp origin.
|
||||
*/
|
||||
const UPSTREAM =
|
||||
process.env.CRM_SERVICE_URL ||
|
||||
process.env.NEXT_PUBLIC_CRM_API_URL ||
|
||||
"http://localhost:8003";
|
||||
|
||||
async function proxy(req: NextRequest, pathSegments: string[]) {
|
||||
const path = pathSegments.join("/");
|
||||
const url = new URL(req.url);
|
||||
const target = `${UPSTREAM.replace(/\/$/, "")}/${path}${url.search}`;
|
||||
|
||||
const headers = new Headers();
|
||||
const pass = ["authorization", "content-type", "x-tenant-id", "accept"];
|
||||
for (const h of pass) {
|
||||
const v = req.headers.get(h);
|
||||
if (v) headers.set(h, v);
|
||||
}
|
||||
|
||||
let body: ArrayBuffer | undefined;
|
||||
if (req.method !== "GET" && req.method !== "HEAD") {
|
||||
body = await req.arrayBuffer();
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(target, {
|
||||
method: req.method,
|
||||
headers,
|
||||
body,
|
||||
cache: "no-store",
|
||||
});
|
||||
const outHeaders = new Headers();
|
||||
const ct = res.headers.get("content-type");
|
||||
if (ct) outHeaders.set("content-type", ct);
|
||||
return new NextResponse(await res.arrayBuffer(), {
|
||||
status: res.status,
|
||||
headers: outHeaders,
|
||||
});
|
||||
} catch (err) {
|
||||
const detail = err instanceof Error ? err.message : "upstream_unreachable";
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: {
|
||||
code: "crm_proxy_error",
|
||||
message: `پروکسی CRM به ${UPSTREAM} وصل نشد — ${detail}`,
|
||||
},
|
||||
},
|
||||
{ status: 502 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(
|
||||
req: NextRequest,
|
||||
ctx: { params: Promise<{ path: string[] }> }
|
||||
) {
|
||||
const { path } = await ctx.params;
|
||||
return proxy(req, path);
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
req: NextRequest,
|
||||
ctx: { params: Promise<{ path: string[] }> }
|
||||
) {
|
||||
const { path } = await ctx.params;
|
||||
return proxy(req, path);
|
||||
}
|
||||
|
||||
export async function PATCH(
|
||||
req: NextRequest,
|
||||
ctx: { params: Promise<{ path: string[] }> }
|
||||
) {
|
||||
const { path } = await ctx.params;
|
||||
return proxy(req, path);
|
||||
}
|
||||
|
||||
export async function PUT(
|
||||
req: NextRequest,
|
||||
ctx: { params: Promise<{ path: string[] }> }
|
||||
) {
|
||||
const { path } = await ctx.params;
|
||||
return proxy(req, path);
|
||||
}
|
||||
|
||||
export async function DELETE(
|
||||
req: NextRequest,
|
||||
ctx: { params: Promise<{ path: string[] }> }
|
||||
) {
|
||||
const { path } = await ctx.params;
|
||||
return proxy(req, path);
|
||||
}
|
||||
7
frontend/app/crm/hub/error.tsx
Normal file
7
frontend/app/crm/hub/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/hub/loading.tsx
Normal file
5
frontend/app/crm/hub/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/hub/page.tsx
Normal file
3
frontend/app/crm/hub/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { CrmHub as default } from "@/modules/crm/pages/hub";
|
||||
4
frontend/app/crm/layout.tsx
Normal file
4
frontend/app/crm/layout.tsx
Normal file
@ -0,0 +1,4 @@
|
||||
/** CRM root — sub-routes supply portal shells. */
|
||||
export default function CrmRootLayout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
13
frontend/app/crm/not-found.tsx
Normal file
13
frontend/app/crm/not-found.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import Link from "next/link";
|
||||
import { Button, EmptyState } from "@/components/ds";
|
||||
|
||||
export default function CrmNotFound() {
|
||||
return (
|
||||
<div className="flex min-h-[50vh] items-center justify-center p-6">
|
||||
<EmptyState
|
||||
title="صفحه CRM یافت نشد"
|
||||
action={<Link href="/crm/hub"><Button>بازگشت به CRM</Button></Link>}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
7
frontend/app/crm/sales/activities/error.tsx
Normal file
7
frontend/app/crm/sales/activities/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/activities/loading.tsx
Normal file
5
frontend/app/crm/sales/activities/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/activities/page.tsx
Normal file
3
frontend/app/crm/sales/activities/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/activities";
|
||||
7
frontend/app/crm/sales/analytics/error.tsx
Normal file
7
frontend/app/crm/sales/analytics/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/analytics/loading.tsx
Normal file
5
frontend/app/crm/sales/analytics/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/analytics/page.tsx
Normal file
3
frontend/app/crm/sales/analytics/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/analytics";
|
||||
7
frontend/app/crm/sales/api-keys/error.tsx
Normal file
7
frontend/app/crm/sales/api-keys/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/api-keys/loading.tsx
Normal file
5
frontend/app/crm/sales/api-keys/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/api-keys/page.tsx
Normal file
3
frontend/app/crm/sales/api-keys/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { ApiKeysPage as default } from "@/modules/crm/features/sales/scoped";
|
||||
7
frontend/app/crm/sales/audit-logs/error.tsx
Normal file
7
frontend/app/crm/sales/audit-logs/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/audit-logs/loading.tsx
Normal file
5
frontend/app/crm/sales/audit-logs/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/audit-logs/page.tsx
Normal file
3
frontend/app/crm/sales/audit-logs/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { AuditLogsPage as default } from "@/modules/crm/features/sales/admin";
|
||||
7
frontend/app/crm/sales/automation/error.tsx
Normal file
7
frontend/app/crm/sales/automation/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/automation/loading.tsx
Normal file
5
frontend/app/crm/sales/automation/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/automation/page.tsx
Normal file
3
frontend/app/crm/sales/automation/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { AutomationPage as default } from "@/modules/crm/features/sales/scoped";
|
||||
7
frontend/app/crm/sales/calls/error.tsx
Normal file
7
frontend/app/crm/sales/calls/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/calls/loading.tsx
Normal file
5
frontend/app/crm/sales/calls/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/calls/page.tsx
Normal file
3
frontend/app/crm/sales/calls/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/calls";
|
||||
7
frontend/app/crm/sales/campaigns/error.tsx
Normal file
7
frontend/app/crm/sales/campaigns/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/campaigns/loading.tsx
Normal file
5
frontend/app/crm/sales/campaigns/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/campaigns/page.tsx
Normal file
3
frontend/app/crm/sales/campaigns/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { CampaignsPage as default } from "@/modules/crm/features/sales/scoped";
|
||||
7
frontend/app/crm/sales/capabilities/error.tsx
Normal file
7
frontend/app/crm/sales/capabilities/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/capabilities/loading.tsx
Normal file
5
frontend/app/crm/sales/capabilities/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/capabilities/page.tsx
Normal file
3
frontend/app/crm/sales/capabilities/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { CapabilitiesPage as default } from "@/modules/crm/features/sales/admin";
|
||||
7
frontend/app/crm/sales/companies/error.tsx
Normal file
7
frontend/app/crm/sales/companies/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/companies/loading.tsx
Normal file
5
frontend/app/crm/sales/companies/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/companies/page.tsx
Normal file
3
frontend/app/crm/sales/companies/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/companies";
|
||||
7
frontend/app/crm/sales/contacts/error.tsx
Normal file
7
frontend/app/crm/sales/contacts/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/contacts/loading.tsx
Normal file
5
frontend/app/crm/sales/contacts/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/contacts/page.tsx
Normal file
3
frontend/app/crm/sales/contacts/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/contacts";
|
||||
7
frontend/app/crm/sales/custom-fields/error.tsx
Normal file
7
frontend/app/crm/sales/custom-fields/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/custom-fields/loading.tsx
Normal file
5
frontend/app/crm/sales/custom-fields/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/custom-fields/page.tsx
Normal file
3
frontend/app/crm/sales/custom-fields/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/custom-fields";
|
||||
7
frontend/app/crm/sales/customers/error.tsx
Normal file
7
frontend/app/crm/sales/customers/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/customers/loading.tsx
Normal file
5
frontend/app/crm/sales/customers/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/customers/page.tsx
Normal file
3
frontend/app/crm/sales/customers/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/customers";
|
||||
7
frontend/app/crm/sales/dashboard/activities/error.tsx
Normal file
7
frontend/app/crm/sales/dashboard/activities/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/dashboard/activities/loading.tsx
Normal file
5
frontend/app/crm/sales/dashboard/activities/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/dashboard/activities/page.tsx
Normal file
3
frontend/app/crm/sales/dashboard/activities/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { ActivityDashboard as default } from "@/modules/crm/features/sales/dashboards";
|
||||
7
frontend/app/crm/sales/dashboard/calendar/error.tsx
Normal file
7
frontend/app/crm/sales/dashboard/calendar/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/dashboard/calendar/loading.tsx
Normal file
5
frontend/app/crm/sales/dashboard/calendar/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/dashboard/calendar/page.tsx
Normal file
3
frontend/app/crm/sales/dashboard/calendar/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { CalendarDashboard as default } from "@/modules/crm/features/sales/dashboards";
|
||||
7
frontend/app/crm/sales/dashboard/leads/error.tsx
Normal file
7
frontend/app/crm/sales/dashboard/leads/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/dashboard/leads/loading.tsx
Normal file
5
frontend/app/crm/sales/dashboard/leads/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/dashboard/leads/page.tsx
Normal file
3
frontend/app/crm/sales/dashboard/leads/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { LeadDashboard as default } from "@/modules/crm/features/sales/dashboards";
|
||||
7
frontend/app/crm/sales/dashboard/overview/error.tsx
Normal file
7
frontend/app/crm/sales/dashboard/overview/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/dashboard/overview/loading.tsx
Normal file
5
frontend/app/crm/sales/dashboard/overview/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/dashboard/overview/page.tsx
Normal file
3
frontend/app/crm/sales/dashboard/overview/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { OverviewDashboard as default } from "@/modules/crm/features/sales/dashboards";
|
||||
7
frontend/app/crm/sales/dashboard/pipeline/error.tsx
Normal file
7
frontend/app/crm/sales/dashboard/pipeline/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/dashboard/pipeline/loading.tsx
Normal file
5
frontend/app/crm/sales/dashboard/pipeline/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/dashboard/pipeline/page.tsx
Normal file
3
frontend/app/crm/sales/dashboard/pipeline/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { PipelineDashboard as default } from "@/modules/crm/features/sales/dashboards";
|
||||
7
frontend/app/crm/sales/dashboard/sales/error.tsx
Normal file
7
frontend/app/crm/sales/dashboard/sales/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/dashboard/sales/loading.tsx
Normal file
5
frontend/app/crm/sales/dashboard/sales/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/dashboard/sales/page.tsx
Normal file
3
frontend/app/crm/sales/dashboard/sales/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { SalesDashboard as default } from "@/modules/crm/features/sales/dashboards";
|
||||
7
frontend/app/crm/sales/deals/error.tsx
Normal file
7
frontend/app/crm/sales/deals/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/deals/loading.tsx
Normal file
5
frontend/app/crm/sales/deals/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/deals/page.tsx
Normal file
3
frontend/app/crm/sales/deals/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/deals";
|
||||
7
frontend/app/crm/sales/documents/error.tsx
Normal file
7
frontend/app/crm/sales/documents/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/documents/loading.tsx
Normal file
5
frontend/app/crm/sales/documents/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/documents/page.tsx
Normal file
3
frontend/app/crm/sales/documents/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/documents";
|
||||
7
frontend/app/crm/sales/emails/error.tsx
Normal file
7
frontend/app/crm/sales/emails/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/emails/loading.tsx
Normal file
5
frontend/app/crm/sales/emails/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/emails/page.tsx
Normal file
3
frontend/app/crm/sales/emails/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/emails";
|
||||
7
frontend/app/crm/sales/export/error.tsx
Normal file
7
frontend/app/crm/sales/export/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/export/loading.tsx
Normal file
5
frontend/app/crm/sales/export/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/export/page.tsx
Normal file
3
frontend/app/crm/sales/export/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/export";
|
||||
7
frontend/app/crm/sales/health/error.tsx
Normal file
7
frontend/app/crm/sales/health/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/health/loading.tsx
Normal file
5
frontend/app/crm/sales/health/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/health/page.tsx
Normal file
3
frontend/app/crm/sales/health/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { HealthPage as default } from "@/modules/crm/features/sales/admin";
|
||||
7
frontend/app/crm/sales/import/error.tsx
Normal file
7
frontend/app/crm/sales/import/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/import/loading.tsx
Normal file
5
frontend/app/crm/sales/import/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/import/page.tsx
Normal file
3
frontend/app/crm/sales/import/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { ImportPage as default } from "@/modules/crm/features/sales/scoped";
|
||||
7
frontend/app/crm/sales/integrations/error.tsx
Normal file
7
frontend/app/crm/sales/integrations/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/integrations/loading.tsx
Normal file
5
frontend/app/crm/sales/integrations/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/integrations/page.tsx
Normal file
3
frontend/app/crm/sales/integrations/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { IntegrationsPage as default } from "@/modules/crm/features/sales/scoped";
|
||||
7
frontend/app/crm/sales/kanban/error.tsx
Normal file
7
frontend/app/crm/sales/kanban/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/kanban/loading.tsx
Normal file
5
frontend/app/crm/sales/kanban/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/kanban/page.tsx
Normal file
3
frontend/app/crm/sales/kanban/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/kanban";
|
||||
5
frontend/app/crm/sales/layout.tsx
Normal file
5
frontend/app/crm/sales/layout.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { createPortalLayout } from "@/modules/crm/components/createPortalLayout";
|
||||
|
||||
export default createPortalLayout("sales");
|
||||
7
frontend/app/crm/sales/leads/error.tsx
Normal file
7
frontend/app/crm/sales/leads/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/leads/loading.tsx
Normal file
5
frontend/app/crm/sales/leads/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/leads/page.tsx
Normal file
3
frontend/app/crm/sales/leads/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/leads";
|
||||
7
frontend/app/crm/sales/meetings/error.tsx
Normal file
7
frontend/app/crm/sales/meetings/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/meetings/loading.tsx
Normal file
5
frontend/app/crm/sales/meetings/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/meetings/page.tsx
Normal file
3
frontend/app/crm/sales/meetings/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/meetings";
|
||||
7
frontend/app/crm/sales/notes/error.tsx
Normal file
7
frontend/app/crm/sales/notes/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/notes/loading.tsx
Normal file
5
frontend/app/crm/sales/notes/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/notes/page.tsx
Normal file
3
frontend/app/crm/sales/notes/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { default } from "@/modules/crm/features/sales/notes";
|
||||
7
frontend/app/crm/sales/notifications/error.tsx
Normal file
7
frontend/app/crm/sales/notifications/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/notifications/loading.tsx
Normal file
5
frontend/app/crm/sales/notifications/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
3
frontend/app/crm/sales/notifications/page.tsx
Normal file
3
frontend/app/crm/sales/notifications/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
"use client";
|
||||
|
||||
export { NotificationsPage as default } from "@/modules/crm/features/sales/admin";
|
||||
7
frontend/app/crm/sales/permissions/error.tsx
Normal file
7
frontend/app/crm/sales/permissions/error.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ErrorState } from "@/components/ds";
|
||||
|
||||
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
|
||||
return <ErrorState message={error.message} onRetry={reset} />;
|
||||
}
|
||||
5
frontend/app/crm/sales/permissions/loading.tsx
Normal file
5
frontend/app/crm/sales/permissions/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { LoadingState } from "@/components/ds";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoadingState label="در حال بارگذاری CRM…" />;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user