Skip to content

Commit 5919452

Browse files
committed
chore: refactor, add suggestions
1 parent 7143088 commit 5919452

File tree

5 files changed

+122
-60
lines changed

5 files changed

+122
-60
lines changed

packages/frontend/src/components/AiBuilder/components/AIFormModalContent.tsx

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useForm } from 'react-hook-form'
22
import { FaWandMagicSparkles } from 'react-icons/fa6'
33
import { Form } from 'react-router-dom'
44
import {
5+
Button,
56
Flex,
67
FormControl,
78
FormErrorMessage,
@@ -12,44 +13,13 @@ import {
1213
Textarea,
1314
} from '@chakra-ui/react'
1415
import { zodResolver } from '@hookform/resolvers/zod'
15-
import { Button, FormLabel } from '@opengovsg/design-system-react'
16-
import { z } from 'zod'
16+
import { FormLabel } from '@opengovsg/design-system-react'
1717

1818
import pairLogo from '@/assets/pair-logo.svg'
1919
import { ImageBox } from '@/components/FlowStepConfigurationModal/ChooseAndAddConnection/ConfigureExcelConnection'
2020

21-
const AI_FORM_SCHEMA = z.object({
22-
flowName: z.string().trim().min(1, 'Flow name is required'),
23-
trigger: z
24-
.string()
25-
.trim()
26-
.min(15, 'Trigger description must be at least 15 characters')
27-
.max(250, 'Trigger description must not exceed 250 characters'),
28-
actions: z
29-
.string()
30-
.trim()
31-
.min(30, 'Actions description must be at least 30 characters')
32-
.max(1000, 'Actions description must not exceed 1000 characters'),
33-
})
34-
35-
const AI_FORM_FIELDS = [
36-
{
37-
key: 'trigger' as const,
38-
label: 'How does your workflow start?',
39-
placeholder: 'When a new joiner submits a form with their details',
40-
resize: 'none' as const,
41-
},
42-
{
43-
key: 'actions' as const,
44-
label: 'Describe what happens next step-by-step',
45-
placeholder:
46-
'Add this new joiner to the database\nSend the new joiner a welcome email\nInform respective team that there is a new joiner',
47-
resize: 'vertical' as const,
48-
maxH: '200px',
49-
},
50-
]
51-
52-
export type AiFormData = z.infer<typeof AI_FORM_SCHEMA>
21+
import { AI_FORM_FIELDS, AI_FORM_IDEAS } from '../constants'
22+
import { AI_FORM_SCHEMA, AiFormData } from '../schema'
5323

5424
export const AIFormModalContent = ({
5525
flowName,
@@ -70,18 +40,22 @@ export const AIFormModalContent = ({
7040
register,
7141
handleSubmit,
7242
formState: { errors, isValid },
43+
setValue,
7344
} = useForm<AiFormData>({
7445
resolver: zodResolver(AI_FORM_SCHEMA),
7546
mode: 'onChange',
7647
defaultValues: {
7748
flowName: flowName || 'Name your Pipe',
78-
trigger: trigger || 'When a new joiner submits a form with their details',
79-
actions:
80-
actions ||
81-
'Add this new joiner to the database\nSend the new joiner a welcome email\nInform respective team that there is a new joiner',
49+
trigger: trigger || undefined,
50+
actions: actions || undefined,
8251
},
8352
})
8453

54+
const handleIdeaClick = (idea: (typeof AI_FORM_IDEAS)[number]) => {
55+
setValue('trigger', idea.trigger, { shouldValidate: true })
56+
setValue('actions', idea.actions, { shouldValidate: true })
57+
}
58+
8559
return (
8660
<>
8761
<Form onSubmit={handleSubmit(onSubmit)}>
@@ -110,6 +84,29 @@ export const AIFormModalContent = ({
11084
)}
11185
</FormControl>
11286
))}
87+
<Flex flexDir="column">
88+
<FormLabel isRequired>
89+
{/* arbitrary isRequired to hide optional text */}
90+
Need inspiration? Try one of these:
91+
</FormLabel>
92+
<Flex flexDir="row" gap={2} justifyContent="space-between">
93+
{AI_FORM_IDEAS.map((idea) => (
94+
<Button
95+
key={idea.label}
96+
size="xs"
97+
bgColor="interaction.muted.main.active"
98+
color="primary.500"
99+
variant="clear"
100+
_hover={{
101+
bgColor: 'primary.200',
102+
}}
103+
onClick={() => handleIdeaClick(idea)}
104+
>
105+
<Text textStyle="caption-1">{idea.label}</Text>
106+
</Button>
107+
))}
108+
</Flex>
109+
</Flex>
113110
</Flex>
114111
</ModalBody>
115112
<ModalFooter>

packages/frontend/src/components/AiBuilder/components/StepsPreview.tsx

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ import PrimarySpinner from '@/components/PrimarySpinner'
2121
import { GENERATE_AI_STEPS } from '@/graphql/mutations/generate-ai-steps'
2222
import { TOOLBOX_ACTIONS } from '@/helpers/toolbox'
2323

24+
import { AiFormData } from '../schema'
25+
2426
import { useAiBuilderContext } from './AiBuilderContext'
25-
import { AiFormData, AIFormModalContent } from './AIFormModalContent'
27+
import { AIFormModalContent } from './AIFormModalContent'
2628
import BranchStep from './BranchStep'
2729
import GroupedStepContainer from './GroupedStepContainer'
2830
import Step from './Step'
@@ -219,30 +221,36 @@ export default function StepsPreview() {
219221
) : stepGroupType === TOOLBOX_ACTIONS.ForEach ? (
220222
<Box w="100%">
221223
<Flex flexDir="column" w="100%" px={4} py={3}>
222-
{forEachSteps.map((step) => (
224+
{forEachSteps.map((step, index) => (
223225
<Step
224226
key={String(step.position)}
225227
allApps={allApps}
226228
step={step}
227229
isNested={true}
230+
isLastStep={
231+
forEachSteps.length - 1 === index &&
232+
ifThenSteps.length === 0
233+
}
228234
/>
229235
))}
230-
<GroupedStepContainer
231-
stepGroupType={TOOLBOX_ACTIONS.IfThen}
232-
stepGroupCaption="If-then"
233-
isNested={true}
234-
>
235-
<Flex flexDir="column" w="100%" px={2} gap={4} mt={2}>
236-
{ifThenSteps.map((branchSteps) => (
237-
<BranchStep
238-
key={String(branchSteps[0].position)}
239-
allApps={allApps}
240-
branchSteps={branchSteps}
241-
isMobile={isMobile}
242-
/>
243-
))}
244-
</Flex>
245-
</GroupedStepContainer>
236+
{ifThenSteps.length > 0 && (
237+
<GroupedStepContainer
238+
stepGroupType={TOOLBOX_ACTIONS.IfThen}
239+
stepGroupCaption="If-then"
240+
isNested={true}
241+
>
242+
<Flex flexDir="column" w="100%" px={2} gap={4} mt={2}>
243+
{ifThenSteps.map((branchSteps) => (
244+
<BranchStep
245+
key={String(branchSteps[0].position)}
246+
allApps={allApps}
247+
branchSteps={branchSteps}
248+
isMobile={isMobile}
249+
/>
250+
))}
251+
</Flex>
252+
</GroupedStepContainer>
253+
)}
246254
</Flex>
247255
</Box>
248256
) : (
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
export const AI_FORM_FIELDS = [
2+
{
3+
key: 'trigger' as const,
4+
label: 'How does your workflow start?',
5+
placeholder: 'When a new joiner submits a form with their details',
6+
resize: 'none' as const,
7+
},
8+
{
9+
key: 'actions' as const,
10+
label: 'Describe what happens next step-by-step',
11+
placeholder:
12+
'Add this new joiner to the database\nSend the new joiner a welcome email\nInform respective team that there is a new joiner',
13+
resize: 'vertical' as const,
14+
maxH: '200px',
15+
},
16+
]
17+
18+
export const AI_FORM_IDEAS = [
19+
{
20+
label: 'Route support enquiries',
21+
trigger: 'When a new support enquiry is submitted',
22+
actions:
23+
'If the query is related to IT, route to the IT department.\nIf the query is related to HR, route to the HR department.\nIf the query is related to Finance, route to the Finance department.',
24+
},
25+
{
26+
label: 'Schedule reminders',
27+
trigger: 'Every day at 09:00 AM',
28+
actions:
29+
'Find rows in Tiles where the RSVPed column is Yes and the Reminder sent column is empty.\nFor each row, send a reminder email to the attendee.\nMark the row as Reminder sent.',
30+
},
31+
{
32+
label: 'Attendance taking',
33+
trigger: 'When a new event attendance is received',
34+
actions:
35+
"Find the attendee in Tiles\nIf the attendee is found, update the Attended? column to Yes\nIf the attendee is not found, create a new row in Tiles with the attendee's details.",
36+
},
37+
{
38+
label: 'Send follow ups',
39+
trigger: 'When a new form submission is received',
40+
actions: 'Send a follow up email to the customer.',
41+
},
42+
]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import z from 'zod'
2+
3+
export const AI_FORM_SCHEMA = z.object({
4+
flowName: z.string().trim().min(1, 'Flow name is required'),
5+
trigger: z
6+
.string()
7+
.trim()
8+
.min(15, 'Trigger description must be at least 15 characters')
9+
.max(250, 'Trigger description must not exceed 250 characters'),
10+
actions: z
11+
.string()
12+
.trim()
13+
.min(30, 'Actions description must be at least 30 characters')
14+
.max(1000, 'Actions description must not exceed 1000 characters'),
15+
})
16+
17+
export type AiFormData = z.infer<typeof AI_FORM_SCHEMA>

packages/frontend/src/pages/Flows/components/CreateFlowModal.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,8 @@ import * as URLS from '@/config/urls'
2828
import { LaunchDarklyContext } from '@/contexts/LaunchDarkly'
2929
import { CREATE_FLOW } from '@/graphql/mutations/create-flow'
3030

31-
import {
32-
AiFormData,
33-
AIFormModalContent,
34-
} from '../../../components/AiBuilder/components/AIFormModalContent'
31+
import { AIFormModalContent } from '../../../components/AiBuilder/components/AIFormModalContent'
32+
import { AiFormData } from '../../../components/AiBuilder/schema'
3533

3634
interface CreateFlowModalProps {
3735
onClose: () => void

0 commit comments

Comments
 (0)