11import { env } from '@/env.mjs' ;
22import { auth } from '@/utils/auth' ;
33import { db } from '@db' ;
4- import { PageHeader , PageLayout } from '@trycompai/design-system' ;
4+ import { Button , PageHeader , PageLayout } from '@trycompai/design-system' ;
5+ import { Launch } from '@trycompai/design-system/icons' ;
56import { Prisma } from '@prisma/client' ;
67import type { Metadata } from 'next' ;
78import { headers } from 'next/headers' ;
9+ import Link from 'next/link' ;
810import { TrustPortalSwitch } from './portal-settings/components/TrustPortalSwitch' ;
911
1012export default async function TrustPage ( { params } : { params : Promise < { orgId : string } > } ) {
1113 const { orgId } = await params ;
1214
13- // Fetch portal settings data
14- await ensureFriendlyUrlIfEnabled ( orgId ) ;
15+ // Ensure Trust record exists with default friendlyUrl
16+ await ensureTrustRecord ( orgId ) ;
1517 const trustPortal = await getTrustPortal ( orgId ) ;
1618 const certificateFiles = await fetchComplianceCertificates ( orgId ) ;
1719 const faqs = await fetchOrganizationFaqs ( orgId ) ;
@@ -21,13 +23,28 @@ export default async function TrustPage({ params }: { params: Promise<{ orgId: s
2123 orderBy : { createdAt : 'desc' } ,
2224 } ) ;
2325
26+ // Build the public trust portal URL
27+ const portalUrl =
28+ trustPortal ?. domainVerified && trustPortal . domain
29+ ? `https://${ trustPortal . domain } `
30+ : `https://trust.inc/${ trustPortal ?. friendlyUrl ?? orgId } ` ;
31+
2432 return (
25- < PageLayout header = { < PageHeader title = "Portal Settings" /> } >
33+ < PageLayout
34+ header = {
35+ < PageHeader
36+ title = "Trust Portal"
37+ actions = {
38+ < Button iconRight = { < Launch /> } >
39+ < Link href = { portalUrl } target = "_blank" rel = "noopener noreferrer" >
40+ Visit Trust Portal
41+ </ Link >
42+ </ Button >
43+ }
44+ />
45+ }
46+ >
2647 < TrustPortalSwitch
27- enabled = { trustPortal ?. enabled ?? false }
28- slug = { trustPortal ?. friendlyUrl ?? orgId }
29- domain = { trustPortal ?. domain ?? '' }
30- domainVerified = { trustPortal ?. domainVerified ?? false }
3148 orgId = { orgId }
3249 soc2type1 = { trustPortal ?. soc2type1 ?? false }
3350 soc2type2 = { trustPortal ?. soc2type2 ?? false }
@@ -85,7 +102,6 @@ const getTrustPortal = async (orgId: string) => {
85102 } ) ;
86103
87104 return {
88- enabled : trustPortal ?. status === 'published' ,
89105 domain : trustPortal ?. domain ,
90106 domainVerified : trustPortal ?. domainVerified ,
91107 soc2type1 : trustPortal ?. soc2type1 ,
@@ -114,66 +130,32 @@ const getTrustPortal = async (orgId: string) => {
114130} ;
115131
116132/**
117- * Create a URL-friendly slug from organization name
118- */
119- const slugifyOrganizationName = ( name : string ) : string => {
120- const cleaned = name
121- . trim ( )
122- . toLowerCase ( )
123- . replace ( / & / g, 'and' )
124- . replace ( / [ ^ a - z 0 - 9 ] + / g, '-' )
125- . replace ( / - + / g, '-' )
126- . replace ( / ^ - | - $ / g, '' ) ;
127-
128- return cleaned . slice ( 0 , 60 ) ;
129- } ;
130-
131- /**
132- * Ensure friendlyUrl exists for enabled trust portals
133- * This auto-heals cases where portal was enabled before friendlyUrl was required
133+ * Ensure Trust record exists with friendlyUrl defaulting to organizationId
134134 */
135- const ensureFriendlyUrlIfEnabled = async ( organizationId : string ) : Promise < void > => {
135+ const ensureTrustRecord = async ( organizationId : string ) : Promise < void > => {
136136 const trust = await db . trust . findUnique ( {
137137 where : { organizationId } ,
138- select : { status : true , friendlyUrl : true } ,
138+ select : { friendlyUrl : true } ,
139139 } ) ;
140140
141- // Only sync if portal is enabled and friendlyUrl is missing
142- if ( ! trust || trust . status !== 'published' || trust . friendlyUrl ) {
141+ // If trust record exists with friendlyUrl, nothing to do
142+ if ( trust ? .friendlyUrl ) {
143143 return ;
144144 }
145145
146- const org = await db . organization . findUnique ( {
147- where : { id : organizationId } ,
148- select : { name : true } ,
149- } ) ;
150-
151- if ( ! org ) return ;
152-
153- const baseCandidate = slugifyOrganizationName ( org . name ) || `org-${ organizationId . slice ( - 8 ) } ` ;
154-
155- for ( let i = 0 ; i < 25 ; i += 1 ) {
156- const candidate = i === 0 ? baseCandidate : `${ baseCandidate } -${ i + 1 } ` ;
157-
158- const taken = await db . trust . findUnique ( {
159- where : { friendlyUrl : candidate } ,
160- select : { organizationId : true } ,
146+ // Create or update trust record with organizationId as default friendlyUrl
147+ try {
148+ await db . trust . upsert ( {
149+ where : { organizationId } ,
150+ update : { friendlyUrl : organizationId } ,
151+ create : { organizationId, friendlyUrl : organizationId , status : 'published' } ,
161152 } ) ;
162-
163- if ( taken && taken . organizationId !== organizationId ) continue ;
164-
165- try {
166- await db . trust . update ( {
167- where : { organizationId } ,
168- data : { friendlyUrl : candidate } ,
169- } ) ;
153+ } catch ( error : unknown ) {
154+ if ( error instanceof Prisma . PrismaClientKnownRequestError && error . code === 'P2002' ) {
155+ // Conflict on unique constraint - record already exists
170156 return ;
171- } catch ( error : unknown ) {
172- if ( error instanceof Prisma . PrismaClientKnownRequestError && error . code === 'P2002' ) {
173- continue ;
174- }
175- throw error ;
176157 }
158+ throw error ;
177159 }
178160} ;
179161
0 commit comments