diff --git a/apps/builder/src/components/TableList.tsx b/apps/builder/src/components/TableList.tsx index a35abc7c0..478f6e657 100644 --- a/apps/builder/src/components/TableList.tsx +++ b/apps/builder/src/components/TableList.tsx @@ -9,7 +9,7 @@ import { } from '@chakra-ui/react' import { TrashIcon, PlusIcon } from '@/components/icons' import { createId } from '@paralleldrive/cuid2' -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' type ItemWithId = T & { id: string } @@ -40,6 +40,10 @@ export const TableList = ({ const [items, setItems] = useState(initialItems) const [showDeleteIndex, setShowDeleteIndex] = useState(null) + useEffect(() => { + if (items.length && initialItems.length === 0) setItems(initialItems) + }, [initialItems, items.length]) + const createItem = () => { const id = createId() const newItem = { id, ...newItemDefaultProps } as ItemWithId diff --git a/apps/builder/src/features/billing/billing.spec.ts b/apps/builder/src/features/billing/billing.spec.ts index 744d9b375..60adcd8de 100644 --- a/apps/builder/src/features/billing/billing.spec.ts +++ b/apps/builder/src/features/billing/billing.spec.ts @@ -225,8 +225,10 @@ test('should display invoices', async ({ page }) => { await page.click('text=Settings & Members') await page.click('text=Billing & Usage') await expect(page.locator('text="Invoices"')).toBeVisible() - await expect(page.locator('tr')).toHaveCount(2) + await expect(page.locator('tr')).toHaveCount(3) await expect(page.locator('text="$39.00"')).toBeVisible() + await expect(page.locator('text="$34.00"')).toBeVisible() + await expect(page.locator('text="$174.00"')).toBeVisible() }) test('custom plans should work', async ({ page }) => { diff --git a/apps/builder/src/features/blocks/integrations/pixel/components/PixelLogo.tsx b/apps/builder/src/features/blocks/integrations/pixel/components/PixelLogo.tsx new file mode 100644 index 000000000..2f6e7f1af --- /dev/null +++ b/apps/builder/src/features/blocks/integrations/pixel/components/PixelLogo.tsx @@ -0,0 +1,44 @@ +import { IconProps, Icon } from '@chakra-ui/react' + +export const PixelLogo = (props: IconProps) => ( + + + + + + + + + + + + + + + + + +) diff --git a/apps/builder/src/features/blocks/integrations/pixel/components/PixelNodeBody.tsx b/apps/builder/src/features/blocks/integrations/pixel/components/PixelNodeBody.tsx new file mode 100644 index 000000000..1b2ad8ec7 --- /dev/null +++ b/apps/builder/src/features/blocks/integrations/pixel/components/PixelNodeBody.tsx @@ -0,0 +1,20 @@ +import React from 'react' +import { Text } from '@chakra-ui/react' +import { PixelBlock } from '@typebot.io/schemas' + +type Props = { + options: PixelBlock['options'] +} + +export const PixelNodeBody = ({ options }: Props) => ( + + {options.eventType + ? `Track "${options.eventType}"` + : options.pixelId + ? 'Init Pixel' + : 'Configure...'} + +) diff --git a/apps/builder/src/features/blocks/integrations/pixel/components/PixelSettings.tsx b/apps/builder/src/features/blocks/integrations/pixel/components/PixelSettings.tsx new file mode 100644 index 000000000..40535a135 --- /dev/null +++ b/apps/builder/src/features/blocks/integrations/pixel/components/PixelSettings.tsx @@ -0,0 +1,185 @@ +import { DropdownList } from '@/components/DropdownList' +import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSettings' +import { TableList, TableListItemProps } from '@/components/TableList' +import { TextLink } from '@/components/TextLink' +import { TextInput } from '@/components/inputs' +import { CodeEditor } from '@/components/inputs/CodeEditor' +import { Select } from '@/components/inputs/Select' +import { Stack, Text } from '@chakra-ui/react' +import { isDefined, isEmpty } from '@typebot.io/lib' +import { + PixelBlock, + pixelEventTypes, + pixelObjectProperties, +} from '@typebot.io/schemas' +import React, { useMemo } from 'react' + +const pixelReferenceUrl = + 'https://developers.facebook.com/docs/meta-pixel/reference#standard-events' + +type Props = { + options?: PixelBlock['options'] + onOptionsChange: (options: PixelBlock['options']) => void +} + +type Item = NonNullable[number] + +export const PixelSettings = ({ options, onOptionsChange }: Props) => { + const updatePixelId = (pixelId: string) => + onOptionsChange({ + ...options, + pixelId: isEmpty(pixelId) ? undefined : pixelId, + }) + + const updateIsTrackingEventEnabled = (isChecked: boolean) => + onOptionsChange({ + ...options, + params: isChecked && !options?.params ? [] : undefined, + }) + + const updateEventType = ( + _: string | undefined, + eventType?: (typeof pixelEventTypes)[number] | 'Custom' + ) => + onOptionsChange({ + ...options, + params: [], + eventType, + }) + + const updateParams = (params: PixelBlock['options']['params']) => + onOptionsChange({ + ...options, + params, + }) + + const updateEventName = (name: string) => { + if (options?.eventType !== 'Custom') return + onOptionsChange({ + ...options, + name: isEmpty(name) ? undefined : name, + }) + } + + const Item = useMemo( + () => + function Component(props: TableListItemProps) { + return + }, + [options?.eventType] + ) + + return ( + + + + + Read the{' '} + + reference + {' '} + to better understand the available options. + +