task-l.3.1

This commit is contained in:
phaichayon
2026-06-22 14:18:26 +07:00
parent 42f403a7ed
commit 1b901efc51
21 changed files with 1320 additions and 102 deletions

View File

@@ -2,6 +2,7 @@ import { auth } from '@/auth';
import { HydrationBoundary, dehydrate } from '@tanstack/react-query';
import PageContainer from '@/components/layout/page-container';
import { ApprovalDetail } from '@/features/foundation/approval/components/approval-detail';
import { getApprovalRequest } from '@/features/foundation/approval/server/service';
import { approvalByIdOptions } from '@/features/foundation/approval/queries';
import { PERMISSIONS } from '@/lib/auth/rbac';
import { getQueryClient } from '@/lib/query-client';
@@ -40,9 +41,30 @@ export default async function ApprovalDetailRoute({ params }: PageProps) {
session.user.activePermissions.includes(PERMISSIONS.crmApprovalSubmit)));
const isOrgAdmin =
session?.user?.systemRole === 'super_admin' || session?.user?.activeMembershipRole === 'admin';
const accessContext =
session?.user?.activeOrganizationId && session?.user?.id
? {
organizationId: session.user.activeOrganizationId,
userId: session.user.id,
membershipRole: session.user.activeMembershipRole ?? 'user',
businessRole: session.user.activeBusinessRole ?? 'sales_support',
permissions: session.user.activePermissions ?? [],
branchScopeIds: session.user.activeBranchScopeIds ?? [],
productTypeScopeIds: session.user.activeProductTypeScopeIds ?? [],
ownershipScope: session.user.activeOwnershipScope ?? 'organization',
branchScopeMode: 'all',
productScopeMode: 'all'
}
: null;
const resolvedCanRead =
canRead && accessContext
? await getApprovalRequest(id, session.user.activeOrganizationId!, accessContext)
.then(() => true)
.catch(() => false)
: false;
const queryClient = getQueryClient();
if (canRead) {
if (resolvedCanRead) {
void queryClient.prefetchQuery(approvalByIdOptions(id));
}
@@ -50,14 +72,14 @@ export default async function ApprovalDetailRoute({ params }: PageProps) {
<PageContainer
pageTitle='รายละเอียดการอนุมัติเอกสาร'
pageDescription='ลำดับขั้น ผู้อนุมัติปัจจุบัน และไทม์ไลน์ของคำขออนุมัติเอกสาร'
access={canRead}
access={resolvedCanRead}
accessFallback={
<div className='text-muted-foreground rounded-lg border border-dashed p-8 text-center'>
You do not have access to this approval request.
</div>
}
>
{canRead && session?.user ? (
{resolvedCanRead && session?.user ? (
<HydrationBoundary state={dehydrate(queryClient)}>
<ApprovalDetail
approvalId={id}

View File

@@ -3,7 +3,10 @@ import { HydrationBoundary, dehydrate } from '@tanstack/react-query';
import PageContainer from '@/components/layout/page-container';
import { CustomerDetail } from '@/features/crm/customers/components/customer-detail';
import { customerByIdOptions, customerContactsOptions } from '@/features/crm/customers/api/queries';
import { getCustomerReferenceData } from '@/features/crm/customers/server/service';
import {
getCustomerDetail,
getCustomerReferenceData
} from '@/features/crm/customers/server/service';
import { listCustomerEnquiryRelations } from '@/features/crm/enquiries/server/service';
import { listCustomerQuotationRelations } from '@/features/crm/quotations/server/service';
import { PERMISSIONS } from '@/lib/auth/rbac';
@@ -46,34 +49,55 @@ export default async function CustomerDetailRoute({ params }: PageProps) {
(!!session?.user?.activeOrganizationId &&
(session.user.activeMembershipRole === 'admin' ||
session.user.activePermissions.includes(PERMISSIONS.crmContactDelete)));
const accessContext =
session?.user?.activeOrganizationId && session?.user?.id
? {
organizationId: session.user.activeOrganizationId,
userId: session.user.id,
membershipRole: session.user.activeMembershipRole ?? 'user',
businessRole: session.user.activeBusinessRole ?? 'sales_support',
permissions: session.user.activePermissions ?? [],
branchScopeIds: session.user.activeBranchScopeIds ?? [],
productTypeScopeIds: session.user.activeProductTypeScopeIds ?? [],
ownershipScope: session.user.activeOwnershipScope ?? 'organization',
branchScopeMode: 'all',
productScopeMode: 'all'
}
: null;
const resolvedCanRead =
canRead && accessContext
? await getCustomerDetail(id, session.user.activeOrganizationId!, accessContext)
.then(() => true)
.catch(() => false)
: false;
const queryClient = getQueryClient();
if (canRead) {
if (resolvedCanRead) {
void queryClient.prefetchQuery(customerByIdOptions(id));
}
if (canContactRead) {
if (resolvedCanRead && canContactRead) {
void queryClient.prefetchQuery(customerContactsOptions(id));
}
const referenceData =
canRead && session?.user?.activeOrganizationId
resolvedCanRead && session?.user?.activeOrganizationId
? await getCustomerReferenceData(session.user.activeOrganizationId)
: null;
const relatedEnquiries =
canRead && session?.user?.activeOrganizationId
? await listCustomerEnquiryRelations(id, session.user.activeOrganizationId)
resolvedCanRead && session?.user?.activeOrganizationId && accessContext
? await listCustomerEnquiryRelations(id, session.user.activeOrganizationId, accessContext)
: [];
const relatedQuotations =
canRead && session?.user?.activeOrganizationId
? await listCustomerQuotationRelations(id, session.user.activeOrganizationId)
resolvedCanRead && session?.user?.activeOrganizationId && accessContext
? await listCustomerQuotationRelations(id, session.user.activeOrganizationId, accessContext)
: [];
return (
<PageContainer
pageTitle='Customer Detail'
pageDescription='Customer profile, contacts, audit timeline, and future CRM document handoff.'
access={canRead}
access={resolvedCanRead}
accessFallback={
<div className='text-muted-foreground rounded-lg border border-dashed p-8 text-center'>
You do not have access to this customer record.