Skip to content

Commit d122112

Browse files
feat(security-questionnaire): add action to answer a single question (#1826)
Co-authored-by: Tofik Hasanov <[email protected]>
1 parent 96882fe commit d122112

File tree

8 files changed

+339
-331
lines changed

8 files changed

+339
-331
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use server';
2+
3+
import { authActionClient } from '@/actions/safe-action';
4+
import { answerQuestion } from '@/jobs/tasks/vendors/answer-question';
5+
import { z } from 'zod';
6+
import { headers } from 'next/headers';
7+
import { revalidatePath } from 'next/cache';
8+
9+
const inputSchema = z.object({
10+
question: z.string(),
11+
questionIndex: z.number(),
12+
totalQuestions: z.number(),
13+
});
14+
15+
export const answerSingleQuestionAction = authActionClient
16+
.inputSchema(inputSchema)
17+
.metadata({
18+
name: 'answer-single-question',
19+
track: {
20+
event: 'answer-single-question',
21+
channel: 'server',
22+
},
23+
})
24+
.action(async ({ parsedInput, ctx }) => {
25+
const { question, questionIndex, totalQuestions } = parsedInput;
26+
const { session } = ctx;
27+
28+
if (!session?.activeOrganizationId) {
29+
throw new Error('No active organization');
30+
}
31+
32+
const organizationId = session.activeOrganizationId;
33+
34+
try {
35+
// Call answerQuestion function directly
36+
const result = await answerQuestion(
37+
{
38+
question,
39+
organizationId,
40+
questionIndex,
41+
totalQuestions,
42+
},
43+
{
44+
useMetadata: false,
45+
},
46+
);
47+
48+
// Revalidate the page to show updated answer
49+
const headersList = await headers();
50+
let path = headersList.get('x-pathname') || headersList.get('referer') || '';
51+
path = path.replace(/\/[a-z]{2}\//, '/');
52+
revalidatePath(path);
53+
54+
return {
55+
success: result.success,
56+
data: {
57+
questionIndex: result.questionIndex,
58+
question: result.question,
59+
answer: result.answer,
60+
sources: result.sources,
61+
error: result.error,
62+
},
63+
};
64+
} catch (error) {
65+
return {
66+
success: false,
67+
error: error instanceof Error ? error.message : 'Failed to answer question',
68+
};
69+
}
70+
});
71+

apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireDetail/useQuestionnaireDetail.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ export function useQuestionnaireDetail({
9494

9595
// Single answer hook
9696
const singleAnswer = useQuestionnaireSingleAnswer({
97-
singleAnswerToken: state.singleAnswerToken,
9897
results: state.results.map((r) => ({
9998
question: r.question,
10099
answer: r.answer,

apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireDetail/useQuestionnaireDetailState.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,23 +100,17 @@ export function useQuestionnaireDetailState({
100100

101101
const deleteAnswerAction = useAction(deleteQuestionnaireAnswer);
102102

103-
// Create trigger tokens
103+
// Create trigger token for auto-answer (single question answers now use server action)
104104
useEffect(() => {
105-
const fetchTokens = async () => {
106-
const [autoTokenResult, singleTokenResult] = await Promise.all([
107-
createTriggerToken('vendor-questionnaire-orchestrator'),
108-
createTriggerToken('answer-question'),
109-
]);
105+
const fetchToken = async () => {
106+
const autoTokenResult = await createTriggerToken('vendor-questionnaire-orchestrator');
110107

111108
if (autoTokenResult.success && autoTokenResult.token) {
112109
setAutoAnswerToken(autoTokenResult.token);
113110
}
114-
if (singleTokenResult.success && singleTokenResult.token) {
115-
setSingleAnswerToken(singleTokenResult.token);
116-
}
117111
};
118112

119-
fetchTokens();
113+
fetchToken();
120114
}, []);
121115

122116
// Sync queue ref with state

apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireParse.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ interface UseQuestionnaireParseProps {
1616
parseToken: string | null;
1717
autoAnswerToken: string | null;
1818
setAutoAnswerToken: (token: string | null) => void;
19-
singleAnswerToken: string | null;
20-
setSingleAnswerToken: (token: string | null) => void;
2119
setIsParseProcessStarted: (started: boolean) => void;
2220
setParseTaskId: (id: string | null) => void;
2321
setParseToken: (token: string | null) => void;
@@ -36,8 +34,6 @@ export function useQuestionnaireParse({
3634
parseToken,
3735
autoAnswerToken,
3836
setAutoAnswerToken,
39-
singleAnswerToken,
40-
setSingleAnswerToken,
4137
setIsParseProcessStarted,
4238
setParseTaskId,
4339
setParseToken,
@@ -62,18 +58,6 @@ export function useQuestionnaireParse({
6258
}
6359
}, [autoAnswerToken, setAutoAnswerToken]);
6460

65-
// Get trigger token for single answer (can trigger and read)
66-
useEffect(() => {
67-
async function getSingleAnswerToken() {
68-
const result = await createTriggerToken('answer-question');
69-
if (result.success && result.token) {
70-
setSingleAnswerToken(result.token);
71-
}
72-
}
73-
if (!singleAnswerToken) {
74-
getSingleAnswerToken();
75-
}
76-
}, [singleAnswerToken, setSingleAnswerToken]);
7761

7862
// Track parse task with realtime hook
7963
const { run: parseRun, error: parseError } = useRealtimeRun<typeof parseQuestionnaireTask>(

apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireParser.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ export function useQuestionnaireParser() {
1515
parseToken: state.parseToken,
1616
autoAnswerToken: state.autoAnswerToken,
1717
setAutoAnswerToken: state.setAutoAnswerToken,
18-
singleAnswerToken: state.singleAnswerToken,
19-
setSingleAnswerToken: state.setSingleAnswerToken,
2018
setIsParseProcessStarted: state.setIsParseProcessStarted,
2119
setParseTaskId: state.setParseTaskId,
2220
setParseToken: state.setParseToken,
@@ -44,7 +42,6 @@ export function useQuestionnaireParser() {
4442
});
4543

4644
const singleAnswer = useQuestionnaireSingleAnswer({
47-
singleAnswerToken: state.singleAnswerToken,
4845
results: state.results,
4946
answeringQuestionIndex: state.answeringQuestionIndex,
5047
setResults: state.setResults,

0 commit comments

Comments
 (0)