Skip to content

Commit 76ba04d

Browse files
[dev] [Marfuen] mariano/fix-vendor-risks-links (#1832)
* refactor(risk): update getRisks and getAssignees functions to accept orgId * chore(policy-editor): gate policy ai assistant behind feature flag --------- Co-authored-by: Mariano Fuentes <[email protected]>
1 parent 1b8dd00 commit 76ba04d

File tree

8 files changed

+67
-63
lines changed

8 files changed

+67
-63
lines changed

apps/app/src/app/(app)/[orgId]/policies/[policyId]/editor/components/PolicyDetails.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type { JSONContent } from '@tiptap/react';
1313
import { structuredPatch } from 'diff';
1414
import { CheckCircle, Loader2, Sparkles, X } from 'lucide-react';
1515
import { useAction } from 'next-safe-action/hooks';
16+
import { useFeatureFlagEnabled } from 'posthog-js/react';
1617
import { useMemo, useState } from 'react';
1718
import { toast } from 'sonner';
1819
import { switchPolicyDisplayFormatAction } from '../../actions/switch-policy-display-format';
@@ -47,6 +48,7 @@ export function PolicyContentManager({
4748

4849
const [proposedPolicyMarkdown, setProposedPolicyMarkdown] = useState<string | null>(null);
4950
const [isApplying, setIsApplying] = useState(false);
51+
const isAiPolicyAssistantEnabled = useFeatureFlagEnabled('is-ai-policy-assistant-enabled');
5052

5153
const switchFormat = useAction(switchPolicyDisplayFormatAction, {
5254
onError: () => toast.error('Failed to switch view.'),
@@ -103,17 +105,19 @@ export function PolicyContentManager({
103105
PDF View
104106
</TabsTrigger>
105107
</TabsList>
106-
{!isPendingApproval && displayFormat === 'EDITOR' && (
107-
<Button
108-
variant={showAiAssistant ? 'default' : 'outline'}
109-
size="sm"
110-
onClick={() => setShowAiAssistant((prev) => !prev)}
111-
className="gap-2"
112-
>
113-
<Sparkles className="h-4 w-4" />
114-
AI Assistant
115-
</Button>
116-
)}
108+
{!isPendingApproval &&
109+
displayFormat === 'EDITOR' &&
110+
isAiPolicyAssistantEnabled && (
111+
<Button
112+
variant={showAiAssistant ? 'default' : 'outline'}
113+
size="sm"
114+
onClick={() => setShowAiAssistant((prev) => !prev)}
115+
className="gap-2"
116+
>
117+
<Sparkles className="h-4 w-4" />
118+
AI Assistant
119+
</Button>
120+
)}
117121
</div>
118122
<TabsContent value="EDITOR" className="mt-4">
119123
<PolicyEditorWrapper
@@ -134,7 +138,7 @@ export function PolicyContentManager({
134138
</Tabs>
135139
</div>
136140

137-
{showAiAssistant && (
141+
{showAiAssistant && isAiPolicyAssistantEnabled && (
138142
<div className="w-80 shrink-0 min-h-[400px] self-stretch flex flex-col">
139143
<PolicyAiAssistant
140144
policyId={policyId}

apps/app/src/app/(app)/[orgId]/risk/(overview)/RisksTable.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { DataTableToolbar } from '@/components/data-table/data-table-toolbar';
55
import { CreateRiskSheet } from '@/components/sheets/create-risk-sheet';
66
import { useDataTable } from '@/hooks/use-data-table';
77
import { getFiltersStateParser, getSortingStateParser } from '@/lib/parsers';
8-
import { useSession } from '@/utils/auth-client';
98
import type { Member, Risk, User } from '@db';
109
import { Risk as RiskType } from '@db';
1110
import { ColumnDef } from '@tanstack/react-table';
@@ -42,15 +41,15 @@ export const RisksTable = ({
4241
pageCount: initialPageCount,
4342
onboardingRunId,
4443
searchParams: initialSearchParams,
44+
orgId,
4545
}: {
4646
risks: RiskRow[];
4747
assignees: (Member & { user: User })[];
4848
pageCount: number;
4949
onboardingRunId?: string | null;
5050
searchParams: GetRiskSchema;
51+
orgId: string;
5152
}) => {
52-
const session = useSession();
53-
const orgId = session?.data?.session?.activeOrganizationId;
5453
const [_, setOpenSheet] = useQueryState('create-risk-sheet');
5554

5655
const { itemStatuses, progress, itemsInfo, isActive, isLoading } = useOnboardingStatus(
@@ -99,8 +98,9 @@ export const RisksTable = ({
9998

10099
// Fetcher function for SWR
101100
const fetcher = useCallback(async () => {
102-
return await getRisksAction(currentSearchParams);
103-
}, [currentSearchParams]);
101+
if (!orgId) return { data: [], pageCount: 0 };
102+
return await getRisksAction({ orgId, searchParams: currentSearchParams });
103+
}, [orgId, currentSearchParams]);
104104

105105
// Use SWR to fetch risks with polling when onboarding is active
106106
const { data: risksData } = useSWR(swrKey, fetcher, {
@@ -202,7 +202,7 @@ export const RisksTable = ({
202202
residualImpact: 'insignificant' as const,
203203
treatmentStrategy: 'accept' as const,
204204
treatmentStrategyDescription: null,
205-
organizationId: orgId || '',
205+
organizationId: orgId,
206206
assigneeId: null,
207207
assignee: null,
208208
createdAt: new Date(),
@@ -229,7 +229,7 @@ export const RisksTable = ({
229229
residualImpact: 'insignificant' as const,
230230
treatmentStrategy: 'accept' as const,
231231
treatmentStrategyDescription: null,
232-
organizationId: orgId || '',
232+
organizationId: orgId,
233233
assigneeId: null,
234234
assignee: null,
235235
createdAt: new Date(),
@@ -241,7 +241,7 @@ export const RisksTable = ({
241241
return [...risksWithStatus, ...pendingRisks, ...tempRisks];
242242
}, [risks, itemsInfo, itemStatuses, orgId, isActive, onboardingRunId]);
243243

244-
const columns = useMemo<ColumnDef<RiskRow>[]>(() => getColumns(orgId ?? ''), [orgId]);
244+
const columns = useMemo<ColumnDef<RiskRow>[]>(() => getColumns(orgId), [orgId]);
245245

246246
const { table } = useDataTable({
247247
data: mergedRisks,

apps/app/src/app/(app)/[orgId]/risk/(overview)/actions/get-risks-action.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
import { getRisks } from '../data/getRisks';
44
import type { GetRiskSchema } from '../data/validations';
55

6-
export async function getRisksAction(input: GetRiskSchema) {
7-
return await getRisks(input);
6+
type GetRisksActionInput = {
7+
orgId: string;
8+
searchParams: GetRiskSchema;
9+
};
10+
11+
export async function getRisksAction({ orgId, searchParams }: GetRisksActionInput) {
12+
return await getRisks({ orgId, searchParams });
813
}

apps/app/src/app/(app)/[orgId]/risk/(overview)/data/getRisks.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import 'server-only';
22

3-
import { auth } from '@/utils/auth';
43
import { db, Prisma, type User } from '@db';
5-
import { headers } from 'next/headers';
64
import type { GetRiskSchema } from './validations';
75

8-
export async function getRisks(input: GetRiskSchema): Promise<{
6+
export type GetRisksInput = {
7+
orgId: string;
8+
searchParams: GetRiskSchema;
9+
};
10+
11+
export async function getRisks({ orgId, searchParams }: GetRisksInput): Promise<{
912
data: (Omit<
1013
Prisma.RiskGetPayload<{
1114
include: { assignee: { include: { user: true } } };
@@ -14,16 +17,11 @@ export async function getRisks(input: GetRiskSchema): Promise<{
1417
> & { assignee: User | null })[];
1518
pageCount: number;
1619
}> {
17-
const session = await auth.api.getSession({
18-
headers: await headers(),
19-
});
20-
21-
if (!session?.session.activeOrganizationId) {
22-
// In case of unauthorized or missing org, return empty data and 0 pageCount
20+
if (!orgId) {
2321
return { data: [], pageCount: 0 };
2422
}
2523

26-
const { title, page, perPage, sort, filters, joinOperator } = input;
24+
const { title, page, perPage, sort, filters, joinOperator } = searchParams;
2725

2826
const orderBy = sort.map((s) => ({
2927
[s.id]: s.desc ? 'desc' : 'asc',
@@ -37,7 +35,7 @@ export async function getRisks(input: GetRiskSchema): Promise<{
3735
});
3836

3937
const where: Prisma.RiskWhereInput = {
40-
organizationId: session.session.activeOrganizationId,
38+
organizationId: orgId,
4139
...(title && {
4240
title: {
4341
contains: title,

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

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ import { AppOnboarding } from '@/components/app-onboarding';
22
import PageWithBreadcrumb from '@/components/pages/PageWithBreadcrumb';
33
import { CreateRiskSheet } from '@/components/sheets/create-risk-sheet';
44
import { getValidFilters } from '@/lib/data-table';
5-
import { auth } from '@/utils/auth';
65
import { db } from '@db';
76
import type { Metadata } from 'next';
8-
import { headers } from 'next/headers';
97
import { cache } from 'react';
108
import { RisksTable } from './RisksTable';
119
import { getRisks } from './data/getRisks';
@@ -35,8 +33,8 @@ export default async function RiskRegisterPage(props: {
3533
};
3634

3735
const [risksResult, assignees, onboarding] = await Promise.all([
38-
getRisks(searchParamsForTable),
39-
getAssignees(),
36+
getRisks({ orgId, searchParams: searchParamsForTable }),
37+
getAssignees(orgId),
4038
db.onboarding.findFirst({
4139
where: { organizationId: orgId },
4240
select: { triggerJobId: true },
@@ -92,6 +90,7 @@ export default async function RiskRegisterPage(props: {
9290
assignees={assignees}
9391
onboardingRunId={onboarding?.triggerJobId ?? null}
9492
searchParams={searchParamsForTable}
93+
orgId={orgId}
9594
/>
9695
</PageWithBreadcrumb>
9796
);
@@ -103,18 +102,14 @@ export async function generateMetadata(): Promise<Metadata> {
103102
};
104103
}
105104

106-
const getAssignees = cache(async () => {
107-
const session = await auth.api.getSession({
108-
headers: await headers(),
109-
});
110-
111-
if (!session || !session.session.activeOrganizationId) {
105+
const getAssignees = cache(async (orgId: string) => {
106+
if (!orgId) {
112107
return [];
113108
}
114109

115110
return await db.member.findMany({
116111
where: {
117-
organizationId: session.session.activeOrganizationId,
112+
organizationId: orgId,
118113
isActive: true,
119114
deactivated: false,
120115
role: {
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
'use server';
22

3-
import { auth } from '@/utils/auth';
4-
import { headers } from 'next/headers';
53
import { getVendors } from '../data/queries';
64
import type { GetVendorsSchema } from '../data/validations';
75

8-
export async function getVendorsAction(input: GetVendorsSchema) {
9-
const session = await auth.api.getSession({
10-
headers: await headers(),
11-
});
6+
export type GetVendorsActionInput = {
7+
orgId: string;
8+
searchParams: GetVendorsSchema;
9+
};
1210

13-
if (!session?.session.activeOrganizationId) {
11+
export async function getVendorsAction({ orgId, searchParams }: GetVendorsActionInput) {
12+
if (!orgId) {
1413
return { data: [], pageCount: 0 };
1514
}
1615

17-
return await getVendors(session.session.activeOrganizationId, input);
16+
return await getVendors(orgId, searchParams);
1817
}
19-

apps/app/src/app/(app)/[orgId]/vendors/(overview)/components/VendorsTable.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@ import { DataTableToolbar } from '@/components/data-table/data-table-toolbar';
55
import { OnboardingLoadingAnimation } from '@/components/onboarding-loading-animation';
66
import { useDataTable } from '@/hooks/use-data-table';
77
import { getFiltersStateParser, getSortingStateParser } from '@/lib/parsers';
8-
import { useSession } from '@/utils/auth-client';
98
import { Departments, Vendor } from '@db';
109
import { ColumnDef } from '@tanstack/react-table';
1110
import { Loader2 } from 'lucide-react';
1211
import { parseAsInteger, parseAsString, parseAsStringEnum, useQueryState } from 'nuqs';
1312
import { useCallback, useMemo } from 'react';
1413
import useSWR from 'swr';
1514
import { CreateVendorSheet } from '../../components/create-vendor-sheet';
16-
import { getVendorsAction } from '../actions/get-vendors-action';
15+
import { getVendorsAction, type GetVendorsActionInput } from '../actions/get-vendors-action';
1716
import type { GetAssigneesResult, GetVendorsResult } from '../data/queries';
1817
import type { GetVendorsSchema } from '../data/validations';
1918
import { useOnboardingStatus } from '../hooks/use-onboarding-status';
@@ -25,6 +24,10 @@ export type VendorRow = GetVendorsResult['data'][number] & {
2524
isAssessing?: boolean;
2625
};
2726

27+
const callGetVendorsAction = getVendorsAction as unknown as (
28+
input: GetVendorsActionInput,
29+
) => Promise<GetVendorsResult>;
30+
2831
const ACTIVE_STATUSES: Array<'pending' | 'processing' | 'created' | 'assessing'> = [
2932
'pending',
3033
'processing',
@@ -38,6 +41,7 @@ interface VendorsTableProps {
3841
assignees: GetAssigneesResult;
3942
onboardingRunId?: string | null;
4043
searchParams: GetVendorsSchema;
44+
orgId: string;
4145
}
4246

4347
export function VendorsTable({
@@ -46,10 +50,8 @@ export function VendorsTable({
4650
assignees,
4751
onboardingRunId,
4852
searchParams: initialSearchParams,
53+
orgId,
4954
}: VendorsTableProps) {
50-
const session = useSession();
51-
const orgId = session?.data?.session?.activeOrganizationId;
52-
5355
const { itemStatuses, progress, itemsInfo, isActive, isLoading } = useOnboardingStatus(
5456
onboardingRunId,
5557
'vendors',
@@ -103,8 +105,9 @@ export function VendorsTable({
103105

104106
// Fetcher function for SWR
105107
const fetcher = useCallback(async () => {
106-
return await getVendorsAction(currentSearchParams);
107-
}, [currentSearchParams]);
108+
if (!orgId) return { data: [], pageCount: 0 };
109+
return await callGetVendorsAction({ orgId, searchParams: currentSearchParams });
110+
}, [orgId, currentSearchParams]);
108111

109112
// Use SWR to fetch vendors with polling when onboarding is active
110113
const { data: vendorsData } = useSWR(swrKey, fetcher, {
@@ -203,7 +206,7 @@ export function VendorsTable({
203206
residualProbability: 'very_unlikely' as const,
204207
residualImpact: 'insignificant' as const,
205208
website: null,
206-
organizationId: orgId || '',
209+
organizationId: orgId,
207210
assigneeId: null,
208211
assignee: null,
209212
createdAt: new Date(),
@@ -228,7 +231,7 @@ export function VendorsTable({
228231
residualProbability: 'very_unlikely' as const,
229232
residualImpact: 'insignificant' as const,
230233
website: null,
231-
organizationId: orgId || '',
234+
organizationId: orgId,
232235
assigneeId: null,
233236
assignee: null,
234237
createdAt: new Date(),
@@ -240,7 +243,7 @@ export function VendorsTable({
240243
return [...vendorsWithStatus, ...pendingVendors, ...tempVendors];
241244
}, [vendors, itemsInfo, itemStatuses, orgId, isActive, onboardingRunId]);
242245

243-
const columns = useMemo<ColumnDef<VendorRow>[]>(() => getColumns(orgId ?? ''), [orgId]);
246+
const columns = useMemo<ColumnDef<VendorRow>[]>(() => getColumns(orgId), [orgId]);
244247

245248
const { table } = useDataTable({
246249
data: mergedVendors,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export default async function Page({
9090
assignees={assignees}
9191
onboardingRunId={onboarding?.triggerJobId ?? null}
9292
searchParams={parsedSearchParams}
93+
orgId={orgId}
9394
/>
9495
</PageWithBreadcrumb>
9596
);

0 commit comments

Comments
 (0)