♻️ (builder) Change to features-centric folder structure
This commit is contained in:
committed by
Baptiste Arnaud
parent
3686465a85
commit
643571fe7d
@ -0,0 +1,7 @@
|
||||
import { FilterIcon } from '@/components/icons'
|
||||
import { IconProps } from '@chakra-ui/react'
|
||||
import React from 'react'
|
||||
|
||||
export const ConditionIcon = (props: IconProps) => (
|
||||
<FilterIcon color="purple.500" {...props} />
|
||||
)
|
@ -0,0 +1,73 @@
|
||||
import { Stack, Tag, Text, Flex, Wrap } from '@chakra-ui/react'
|
||||
import { useTypebot } from '@/features/editor'
|
||||
import { Comparison, ConditionItem, ComparisonOperators } from 'models'
|
||||
import React from 'react'
|
||||
import { byId, isNotDefined } from 'utils'
|
||||
|
||||
type Props = {
|
||||
item: ConditionItem
|
||||
}
|
||||
|
||||
export const ConditionNodeContent = ({ item }: Props) => {
|
||||
const { typebot } = useTypebot()
|
||||
return (
|
||||
<Flex px={2} py={2}>
|
||||
{item.content.comparisons.length === 0 ||
|
||||
comparisonIsEmpty(item.content.comparisons[0]) ? (
|
||||
<Text color={'gray.500'}>Configure...</Text>
|
||||
) : (
|
||||
<Stack maxW="170px">
|
||||
{item.content.comparisons.map((comparison, idx) => {
|
||||
const variable = typebot?.variables.find(
|
||||
byId(comparison.variableId)
|
||||
)
|
||||
return (
|
||||
<Wrap key={comparison.id} spacing={1} noOfLines={1}>
|
||||
{idx > 0 && <Text>{item.content.logicalOperator ?? ''}</Text>}
|
||||
{variable?.name && (
|
||||
<Tag bgColor="orange.400" color="white">
|
||||
{variable.name}
|
||||
</Tag>
|
||||
)}
|
||||
{comparison.comparisonOperator && (
|
||||
<Text>
|
||||
{parseComparisonOperatorSymbol(
|
||||
comparison.comparisonOperator
|
||||
)}
|
||||
</Text>
|
||||
)}
|
||||
{comparison?.value && (
|
||||
<Tag bgColor={'gray.200'}>
|
||||
<Text noOfLines={1}>{comparison.value}</Text>
|
||||
</Tag>
|
||||
)}
|
||||
</Wrap>
|
||||
)
|
||||
})}
|
||||
</Stack>
|
||||
)}
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
const comparisonIsEmpty = (comparison: Comparison) =>
|
||||
isNotDefined(comparison.comparisonOperator) &&
|
||||
isNotDefined(comparison.value) &&
|
||||
isNotDefined(comparison.variableId)
|
||||
|
||||
const parseComparisonOperatorSymbol = (operator: ComparisonOperators) => {
|
||||
switch (operator) {
|
||||
case ComparisonOperators.CONTAINS:
|
||||
return 'contains'
|
||||
case ComparisonOperators.EQUAL:
|
||||
return '='
|
||||
case ComparisonOperators.GREATER:
|
||||
return '>'
|
||||
case ComparisonOperators.IS_SET:
|
||||
return 'is set'
|
||||
case ComparisonOperators.LESS:
|
||||
return '<'
|
||||
case ComparisonOperators.NOT_EQUAL:
|
||||
return '!='
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
import { Stack } from '@chakra-ui/react'
|
||||
import { DropdownList } from '@/components/DropdownList'
|
||||
import { Comparison, Variable, ComparisonOperators } from 'models'
|
||||
import { TableListItemProps } from '@/components/TableList'
|
||||
import { VariableSearchInput } from '@/components/VariableSearchInput'
|
||||
import { Input } from '@/components/inputs'
|
||||
|
||||
export const ComparisonItem = ({
|
||||
item,
|
||||
onItemChange,
|
||||
}: TableListItemProps<Comparison>) => {
|
||||
const handleSelectVariable = (variable?: Variable) => {
|
||||
if (variable?.id === item.variableId) return
|
||||
onItemChange({ ...item, variableId: variable?.id })
|
||||
}
|
||||
|
||||
const handleSelectComparisonOperator = (
|
||||
comparisonOperator: ComparisonOperators
|
||||
) => {
|
||||
if (comparisonOperator === item.comparisonOperator) return
|
||||
onItemChange({ ...item, comparisonOperator })
|
||||
}
|
||||
const handleChangeValue = (value: string) => {
|
||||
if (value === item.value) return
|
||||
onItemChange({ ...item, value })
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack p="4" rounded="md" flex="1" borderWidth="1px">
|
||||
<VariableSearchInput
|
||||
initialVariableId={item.variableId}
|
||||
onSelectVariable={handleSelectVariable}
|
||||
placeholder="Search for a variable"
|
||||
/>
|
||||
<DropdownList<ComparisonOperators>
|
||||
currentItem={item.comparisonOperator}
|
||||
onItemSelect={handleSelectComparisonOperator}
|
||||
items={Object.values(ComparisonOperators)}
|
||||
placeholder="Select an operator"
|
||||
/>
|
||||
{item.comparisonOperator !== ComparisonOperators.IS_SET && (
|
||||
<Input
|
||||
defaultValue={item.value ?? ''}
|
||||
onChange={handleChangeValue}
|
||||
placeholder="Type a value..."
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
)
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import { Flex } from '@chakra-ui/react'
|
||||
import { DropdownList } from '@/components/DropdownList'
|
||||
import {
|
||||
Comparison,
|
||||
ConditionItem,
|
||||
ConditionBlock,
|
||||
LogicalOperator,
|
||||
} from 'models'
|
||||
import React from 'react'
|
||||
import { ComparisonItem } from './ComparisonsItem'
|
||||
import { TableList } from '@/components/TableList'
|
||||
|
||||
type ConditionSettingsBodyProps = {
|
||||
block: ConditionBlock
|
||||
onItemChange: (updates: Partial<ConditionItem>) => void
|
||||
}
|
||||
|
||||
export const ConditionSettingsBody = ({
|
||||
block,
|
||||
onItemChange,
|
||||
}: ConditionSettingsBodyProps) => {
|
||||
const itemContent = block.items[0].content
|
||||
|
||||
const handleComparisonsChange = (comparisons: Comparison[]) =>
|
||||
onItemChange({ content: { ...itemContent, comparisons } })
|
||||
const handleLogicalOperatorChange = (logicalOperator: LogicalOperator) =>
|
||||
onItemChange({ content: { ...itemContent, logicalOperator } })
|
||||
|
||||
return (
|
||||
<TableList<Comparison>
|
||||
initialItems={itemContent.comparisons}
|
||||
onItemsChange={handleComparisonsChange}
|
||||
Item={ComparisonItem}
|
||||
ComponentBetweenItems={() => (
|
||||
<Flex justify="center">
|
||||
<DropdownList<LogicalOperator>
|
||||
currentItem={itemContent.logicalOperator}
|
||||
onItemSelect={handleLogicalOperatorChange}
|
||||
items={Object.values(LogicalOperator)}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
addLabel="Add a comparison"
|
||||
/>
|
||||
)
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { ConditionSettingsBody } from './ConditonSettingsBody'
|
@ -0,0 +1,80 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
|
||||
import cuid from 'cuid'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
|
||||
const typebotId = cuid()
|
||||
|
||||
test.describe('Condition block', () => {
|
||||
test('its configuration should work', async ({ page }) => {
|
||||
await importTypebotInDatabase(
|
||||
getTestAsset('typebots/logic/condition.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.click('text=Configure... >> nth=0', { force: true })
|
||||
await page.fill(
|
||||
'input[placeholder="Search for a variable"] >> nth=-1',
|
||||
'Age'
|
||||
)
|
||||
await page.click('button:has-text("Age")')
|
||||
await page.click('button:has-text("Select an operator")')
|
||||
await page.click('button:has-text("Greater than")', { force: true })
|
||||
await page.fill('input[placeholder="Type a value..."]', '80')
|
||||
|
||||
await page.click('button:has-text("Add a comparison")')
|
||||
|
||||
await page.fill(
|
||||
':nth-match(input[placeholder="Search for a variable"], 2)',
|
||||
'Age'
|
||||
)
|
||||
await page.click('button:has-text("Age")')
|
||||
await page.click('button:has-text("Select an operator")')
|
||||
await page.click('button:has-text("Less than")', { force: true })
|
||||
await page.fill(
|
||||
':nth-match(input[placeholder="Type a value..."], 2)',
|
||||
'100'
|
||||
)
|
||||
|
||||
await page.click('text=Configure...', { force: true })
|
||||
await page.fill(
|
||||
'input[placeholder="Search for a variable"] >> nth=-1',
|
||||
'Age'
|
||||
)
|
||||
await page.click('button:has-text("Age")')
|
||||
await page.click('button:has-text("Select an operator")')
|
||||
await page.click('button:has-text("Greater than")', { force: true })
|
||||
await page.fill('input[placeholder="Type a value..."]', '20')
|
||||
|
||||
await page.click('text=Preview')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type a number..."]')
|
||||
.fill('15')
|
||||
await typebotViewer(page).locator('text=Send').click()
|
||||
await expect(
|
||||
typebotViewer(page).locator('text=You are younger than 20')
|
||||
).toBeVisible()
|
||||
|
||||
await page.click('text=Restart')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type a number..."]')
|
||||
.fill('45')
|
||||
await typebotViewer(page).locator('text=Send').click()
|
||||
await expect(
|
||||
typebotViewer(page).locator('text=You are older than 20')
|
||||
).toBeVisible()
|
||||
|
||||
await page.click('text=Restart')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type a number..."]')
|
||||
.fill('90')
|
||||
await typebotViewer(page).locator('text=Send').click()
|
||||
await expect(
|
||||
typebotViewer(page).locator('text=You are older than 80')
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
@ -0,0 +1,3 @@
|
||||
export { ConditionSettingsBody } from './components/ConditionSettingsBody'
|
||||
export { ConditionNodeContent } from './components/ConditionNodeContent'
|
||||
export { ConditionIcon } from './components/ConditionIcon'
|
Reference in New Issue
Block a user