Skip to content

Commit 3a8fccc

Browse files
[dev] [tofikwest] tofik/trust-portal-fix-subprocessor (#2109)
* refactor(trust-portal): remove isSubProcessor references from vendor logic * refactor(trust-portal): improve code readability and handle button loading state --------- Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
1 parent d106e26 commit 3a8fccc

6 files changed

Lines changed: 44 additions & 40 deletions

File tree

apps/api/src/trust-portal/trust-access.service.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2463,7 +2463,6 @@ export class TrustAccessService {
24632463
const vendors = await db.vendor.findMany({
24642464
where: {
24652465
organizationId: trust.organizationId,
2466-
isSubProcessor: true,
24672466
showOnTrustPortal: true,
24682467
},
24692468
orderBy: [{ trustPortalOrder: 'asc' }, { name: 'asc' }],

apps/app/src/app/(app)/[orgId]/trust/page.tsx

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1+
import { APP_AWS_ORG_ASSETS_BUCKET, s3Client } from '@/app/s3';
12
import { env } from '@/env.mjs';
23
import { auth } from '@/utils/auth';
4+
import { GetObjectCommand } from '@aws-sdk/client-s3';
5+
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
36
import { db } from '@db';
7+
import { Prisma } from '@prisma/client';
48
import { Button, PageHeader, PageLayout } from '@trycompai/design-system';
59
import { Launch } from '@trycompai/design-system/icons';
6-
import { Prisma } from '@prisma/client';
710
import type { Metadata } from 'next';
811
import { headers } from 'next/headers';
912
import Link from 'next/link';
1013
import { TrustPortalSwitch } from './portal-settings/components/TrustPortalSwitch';
11-
import { APP_AWS_ORG_ASSETS_BUCKET, s3Client } from '@/app/s3';
12-
import { GetObjectCommand } from '@aws-sdk/client-s3';
13-
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
1414

1515
/**
1616
* Valid compliance badge types for trust portal
@@ -51,7 +51,11 @@ function mapCertificationToBadgeType(certType: string): ComplianceBadgeType | nu
5151
if (normalized.includes('hipaa')) {
5252
return 'hipaa';
5353
}
54-
if (normalized.includes('pcidss') || normalized.includes('pci dss') || normalized.includes('pci_dss')) {
54+
if (
55+
normalized.includes('pcidss') ||
56+
normalized.includes('pci dss') ||
57+
normalized.includes('pci_dss')
58+
) {
5559
return 'pci_dss';
5660
}
5761
if (normalized.includes('nen7510') || normalized.includes('nen 7510')) {
@@ -118,14 +122,12 @@ function generateLogoUrl(website: string | null): string | null {
118122
* Sync vendor trust portal data from GlobalVendors risk assessment
119123
* Updates compliance badges and logo URL if they can be derived from existing data
120124
*/
121-
async function syncVendorTrustData(
122-
vendor: {
123-
id: string;
124-
website: string | null;
125-
complianceBadges: Prisma.JsonValue | null;
126-
logoUrl: string | null;
127-
}
128-
): Promise<{ complianceBadges: ComplianceBadge[] | null; logoUrl: string | null } | null> {
125+
async function syncVendorTrustData(vendor: {
126+
id: string;
127+
website: string | null;
128+
complianceBadges: Prisma.JsonValue | null;
129+
logoUrl: string | null;
130+
}): Promise<{ complianceBadges: ComplianceBadge[] | null; logoUrl: string | null } | null> {
129131
const updates: Prisma.VendorUpdateInput = {};
130132
let hasUpdates = false;
131133

@@ -141,12 +143,12 @@ async function syncVendorTrustData(
141143
if (extractedBadges && extractedBadges.length > 0) {
142144
// Only update if current badges are empty or different
143145
const currentBadges = vendor.complianceBadges as ComplianceBadge[] | null;
144-
const currentTypes = new Set(currentBadges?.map(b => b.type) ?? []);
145-
const extractedTypes = new Set(extractedBadges.map(b => b.type));
146-
147-
const isDifferent =
146+
const currentTypes = new Set(currentBadges?.map((b) => b.type) ?? []);
147+
const extractedTypes = new Set(extractedBadges.map((b) => b.type));
148+
149+
const isDifferent =
148150
currentTypes.size !== extractedTypes.size ||
149-
[...extractedTypes].some(t => !currentTypes.has(t));
151+
[...extractedTypes].some((t) => !currentTypes.has(t));
150152

151153
if (isDifferent) {
152154
updates.complianceBadges = extractedBadges as unknown as Prisma.InputJsonValue;
@@ -218,9 +220,9 @@ export default async function TrustPage({ params }: { params: Promise<{ orgId: s
218220
orderBy: { order: 'asc' },
219221
});
220222

221-
// Fetch vendors/subprocessors with risk assessment data for syncing
223+
// Fetch vendors with risk assessment data for syncing
222224
const vendorsRaw = await db.vendor.findMany({
223-
where: { organizationId: orgId, isSubProcessor: true },
225+
where: { organizationId: orgId },
224226
orderBy: [{ trustPortalOrder: 'asc' }, { name: 'asc' }],
225227
});
226228

apps/app/src/app/(app)/[orgId]/trust/portal-settings/components/TrustPortalCustomLinks.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ export function TrustPortalCustomLinks({
199199
};
200200

201201
const handleSave = () => {
202+
if (createLink.status === 'executing' || updateLink.status === 'executing') {
203+
return;
204+
}
205+
202206
if (!title.trim() || !url.trim()) {
203207
toast.error('Title and URL are required');
204208
return;
@@ -245,10 +249,8 @@ export function TrustPortalCustomLinks({
245249
};
246250

247251
const handleDelete = (linkId: string) => {
248-
if (confirm('Are you sure you want to delete this link?')) {
249-
setLinks((prev) => prev.filter((l) => l.id !== linkId));
250-
deleteLink.execute({ linkId });
251-
}
252+
setLinks((prev) => prev.filter((l) => l.id !== linkId));
253+
deleteLink.execute({ linkId });
252254
};
253255

254256
const handleDragEnd = (event: DragEndEvent) => {
@@ -370,7 +372,11 @@ export function TrustPortalCustomLinks({
370372

371373
<div className="flex gap-2">
372374
<div className="flex-1">
373-
<Button onClick={handleSave} width="full">
375+
<Button
376+
onClick={handleSave}
377+
width="full"
378+
loading={createLink.status === 'executing' || updateLink.status === 'executing'}
379+
>
374380
{editingLink ? 'Update' : 'Create'}
375381
</Button>
376382
</div>

apps/app/src/app/(app)/[orgId]/trust/portal-settings/components/TrustPortalSwitch.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ type TrustVendor = {
117117
name: string;
118118
description: string;
119119
website: string | null;
120-
isSubProcessor: boolean;
121120
showOnTrustPortal: boolean;
122121
logoUrl: string | null;
123122
complianceBadges: ComplianceBadge[] | null;

apps/app/src/app/(app)/[orgId]/trust/portal-settings/components/TrustPortalVendors.tsx

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ interface Vendor {
2727
name: string;
2828
description: string;
2929
website: string | null;
30-
isSubProcessor: boolean;
3130
showOnTrustPortal: boolean;
3231
logoUrl: string | null;
3332
complianceBadges: ComplianceBadge[] | null;
@@ -178,15 +177,13 @@ export function TrustPortalVendors({
178177
});
179178
};
180179

181-
const subprocessorVendors = vendors.filter((v) => v.isSubProcessor);
182-
183180
// Pagination logic
184-
const totalPages = Math.max(1, Math.ceil(subprocessorVendors.length / ITEMS_PER_PAGE));
181+
const totalPages = Math.max(1, Math.ceil(vendors.length / ITEMS_PER_PAGE));
185182
const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
186183
const endIndex = startIndex + ITEMS_PER_PAGE;
187184
const paginatedVendors = useMemo(
188-
() => subprocessorVendors.slice(startIndex, endIndex),
189-
[subprocessorVendors, startIndex, endIndex],
185+
() => vendors.slice(startIndex, endIndex),
186+
[vendors, startIndex, endIndex],
190187
);
191188

192189
const handlePageChange = (page: number) => {
@@ -197,17 +194,16 @@ export function TrustPortalVendors({
197194
return (
198195
<div className="space-y-6">
199196
<div className="space-y-1">
200-
<h3 className="text-lg font-medium">Vendors & Subprocessors</h3>
197+
<h3 className="text-lg font-medium">Vendors</h3>
201198
<p className="text-sm text-muted-foreground">
202-
Configure which vendors marked as subprocessors appear on your public trust portal
199+
Configure which vendors appear on your public trust portal
203200
</p>
204201
</div>
205202

206-
{subprocessorVendors.length === 0 ? (
203+
{vendors.length === 0 ? (
207204
<div className="rounded-md border border-dashed border-border p-8 text-center">
208205
<p className="text-sm text-muted-foreground">
209-
No vendors marked as subprocessors. Go to the Vendors page to mark vendors as
210-
subprocessors.
206+
No vendors found. Go to the Vendors page to add vendors.
211207
</p>
212208
</div>
213209
) : (
@@ -264,8 +260,8 @@ export function TrustPortalVendors({
264260
{totalPages > 1 && (
265261
<div className="flex items-center justify-between pt-4">
266262
<p className="text-sm text-muted-foreground">
267-
Showing {startIndex + 1}-{Math.min(endIndex, subprocessorVendors.length)} of{' '}
268-
{subprocessorVendors.length} vendors
263+
Showing {startIndex + 1}-{Math.min(endIndex, vendors.length)} of{' '}
264+
{vendors.length} vendors
269265
</p>
270266
<div className="flex items-center gap-2">
271267
<Button

packages/docs/openapi.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7024,6 +7024,7 @@
70247024
"enum": [
70257025
"todo",
70267026
"in_progress",
7027+
"in_review",
70277028
"done",
70287029
"not_relevant",
70297030
"failed"
@@ -7332,6 +7333,7 @@
73327333
"enum": [
73337334
"todo",
73347335
"in_progress",
7336+
"in_review",
73357337
"done",
73367338
"not_relevant",
73377339
"failed"

0 commit comments

Comments
 (0)