build: add pnpm
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
import { FlexProps, Flex, Box, Divider, Text } from '@chakra-ui/react'
|
||||
import { useColorModeValue } from '@chakra-ui/system'
|
||||
import {
|
||||
FlexProps,
|
||||
Flex,
|
||||
Box,
|
||||
Divider,
|
||||
Text,
|
||||
useColorModeValue,
|
||||
} from '@chakra-ui/react'
|
||||
import React from 'react'
|
||||
|
||||
export const DividerWithText = (props: FlexProps) => {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useUser } from 'contexts/UserContext'
|
||||
import { Answer, Typebot } from 'models'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { parseTypebotToPublicTypebot } from 'services/publicTypebot'
|
||||
import { sendRequest } from 'utils'
|
||||
import { getViewerUrl, sendRequest } from 'utils'
|
||||
import confetti from 'canvas-confetti'
|
||||
import { useToast } from 'components/shared/hooks/useToast'
|
||||
|
||||
@@ -119,6 +119,7 @@ export const OnboardingModal = ({ totalTypebots }: Props) => {
|
||||
<ModalBody>
|
||||
{typebot && (
|
||||
<TypebotViewer
|
||||
apiHost={getViewerUrl({ isBuilder: true })}
|
||||
typebot={parseTypebotToPublicTypebot(typebot)}
|
||||
predefinedVariables={{
|
||||
Name: user?.name?.split(' ')[0] ?? undefined,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Flex, HStack, StackProps } from '@chakra-ui/layout'
|
||||
import { CloseButton } from '@chakra-ui/react'
|
||||
import { CloseButton, Flex, HStack, StackProps } from '@chakra-ui/react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
type VerifyEmailBannerProps = { id: string } & StackProps
|
||||
|
||||
@@ -18,6 +18,7 @@ import { useTypebot } from 'contexts/TypebotContext/TypebotContext'
|
||||
import { Log } from 'db'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { parseTypebotToPublicTypebot } from 'services/publicTypebot'
|
||||
import { getViewerUrl } from 'utils'
|
||||
|
||||
export const PreviewDrawer = () => {
|
||||
const { typebot } = useTypebot()
|
||||
@@ -100,6 +101,7 @@ export const PreviewDrawer = () => {
|
||||
pointerEvents={isResizing ? 'none' : 'auto'}
|
||||
>
|
||||
<TypebotViewer
|
||||
apiHost={getViewerUrl({ isBuilder: true })}
|
||||
typebot={publicTypebot}
|
||||
onNewGroupVisible={setPreviewingEdge}
|
||||
onNewLog={handleNewLog}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { chakra, Fade, Button } from '@chakra-ui/react'
|
||||
import { Cell as CellProps } from '@tanstack/react-table'
|
||||
import { Cell as CellProps, flexRender } from '@tanstack/react-table'
|
||||
import { ExpandIcon } from 'assets/icons'
|
||||
import { memo } from 'react'
|
||||
import { TableData } from 'services/typebots/results'
|
||||
|
||||
type Props = {
|
||||
cell: CellProps<any>
|
||||
cell: CellProps<TableData, unknown>
|
||||
size: number
|
||||
isExpandButtonVisible: boolean
|
||||
cellIndex: number
|
||||
@@ -34,7 +35,7 @@ const Cell = ({
|
||||
maxWidth: size,
|
||||
}}
|
||||
>
|
||||
{cell.renderCell()}
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
<chakra.span
|
||||
pos="absolute"
|
||||
top="0"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Box, BoxProps, chakra } from '@chakra-ui/react'
|
||||
import { HeaderGroup } from '@tanstack/react-table'
|
||||
import { flexRender, HeaderGroup } from '@tanstack/react-table'
|
||||
import React from 'react'
|
||||
import { TableData } from 'services/typebots/results'
|
||||
|
||||
type Props = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
headerGroup: HeaderGroup<any>
|
||||
headerGroup: HeaderGroup<TableData>
|
||||
}
|
||||
|
||||
export const HeaderRow = ({ headerGroup }: Props) => {
|
||||
@@ -28,7 +28,9 @@ export const HeaderRow = ({ headerGroup }: Props) => {
|
||||
maxWidth: header.getSize(),
|
||||
}}
|
||||
>
|
||||
{header.isPlaceholder ? null : header.renderHeader()}
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(header.column.columnDef.header, header.getContext())}
|
||||
{header.column.getCanResize() && (
|
||||
<ResizeHandle
|
||||
onMouseDown={header.getResizeHandler()}
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
convertResultsToTableData,
|
||||
getAllResults,
|
||||
deleteResults as deleteFetchResults,
|
||||
} from 'services/typebots'
|
||||
} from 'services/typebots/results'
|
||||
|
||||
type ResultsActionButtonsProps = {
|
||||
selectedResultsId: string[]
|
||||
@@ -93,7 +93,9 @@ export const ResultsActionButtons = ({
|
||||
|
||||
const dataToUnparse = isSelectAll
|
||||
? await getAllTableData()
|
||||
: tableData.filter((data) => selectedResultsId.includes(data.id))
|
||||
: tableData.filter((data) =>
|
||||
selectedResultsId.includes(data.id.plainText)
|
||||
)
|
||||
const csvData = new Blob(
|
||||
[
|
||||
unparse({
|
||||
|
||||
@@ -13,10 +13,10 @@ import { ResultHeaderCell, ResultsTablePreferences } from 'models'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { LoadingRows } from './LoadingRows'
|
||||
import {
|
||||
createTable,
|
||||
useTableInstance,
|
||||
useReactTable,
|
||||
getCoreRowModel,
|
||||
ColumnOrderState,
|
||||
ColumnDef,
|
||||
} from '@tanstack/react-table'
|
||||
import { BlockIcon } from 'components/editor/BlocksSideBar/BlockIcon'
|
||||
import { ColumnSettingsButton } from './ColumnsSettingsButton'
|
||||
@@ -25,21 +25,11 @@ import { useDebounce } from 'use-debounce'
|
||||
import { ResultsActionButtons } from './ResultsActionButtons'
|
||||
import { Row } from './Row'
|
||||
import { HeaderRow } from './HeaderRow'
|
||||
|
||||
type RowType = {
|
||||
id: string
|
||||
[key: string]:
|
||||
| {
|
||||
plainText: string
|
||||
element?: JSX.Element | undefined
|
||||
}
|
||||
| string
|
||||
}
|
||||
const table = createTable().setRowType<RowType>()
|
||||
import { CellValueType, TableData } from 'services/typebots/results'
|
||||
|
||||
type ResultsTableProps = {
|
||||
resultHeader: ResultHeaderCell[]
|
||||
data: RowType[]
|
||||
data: TableData[]
|
||||
hasMore?: boolean
|
||||
preferences?: ResultsTablePreferences
|
||||
onScrollToBottom: () => void
|
||||
@@ -92,18 +82,18 @@ export const ResultsTable = ({
|
||||
const bottomElement = useRef<HTMLDivElement | null>(null)
|
||||
const tableWrapper = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
const columns = React.useMemo(
|
||||
const columns = React.useMemo<ColumnDef<TableData>[]>(
|
||||
() => [
|
||||
table.createDisplayColumn({
|
||||
{
|
||||
id: 'select',
|
||||
enableResizing: false,
|
||||
maxSize: 40,
|
||||
header: ({ instance }) => (
|
||||
header: ({ table }) => (
|
||||
<IndeterminateCheckbox
|
||||
{...{
|
||||
checked: instance.getIsAllRowsSelected(),
|
||||
indeterminate: instance.getIsSomeRowsSelected(),
|
||||
onChange: instance.getToggleAllRowsSelectedHandler(),
|
||||
checked: table.getIsAllRowsSelected(),
|
||||
indeterminate: table.getIsSomeRowsSelected(),
|
||||
onChange: table.getToggleAllRowsSelectedHandler(),
|
||||
}}
|
||||
/>
|
||||
),
|
||||
@@ -118,26 +108,24 @@ export const ResultsTable = ({
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
...resultHeader.map((header) =>
|
||||
table.createDataColumn(header.label, {
|
||||
id: header.id,
|
||||
size: header.isLong ? 400 : 200,
|
||||
cell: (info) => {
|
||||
const value = info.getValue()
|
||||
if (!value) return
|
||||
if (typeof value === 'string') return ''
|
||||
return value.element || value.plainText || ''
|
||||
},
|
||||
header: () => (
|
||||
<HStack overflow="hidden" data-testid={`${header.label} header`}>
|
||||
<HeaderIcon header={header} />
|
||||
<Text>{header.label}</Text>
|
||||
</HStack>
|
||||
),
|
||||
})
|
||||
),
|
||||
table.createDisplayColumn({
|
||||
},
|
||||
...resultHeader.map<ColumnDef<TableData>>((header) => ({
|
||||
id: header.id,
|
||||
accessorKey: header.label,
|
||||
size: header.isLong ? 400 : 200,
|
||||
header: () => (
|
||||
<HStack overflow="hidden" data-testid={`${header.label} header`}>
|
||||
<HeaderIcon header={header} />
|
||||
<Text>{header.label}</Text>
|
||||
</HStack>
|
||||
),
|
||||
cell: (info) => {
|
||||
const value = info.getValue() as CellValueType | undefined
|
||||
if (!value) return
|
||||
return value.element || value.plainText || ''
|
||||
},
|
||||
})),
|
||||
{
|
||||
id: 'logs',
|
||||
enableResizing: false,
|
||||
maxSize: 110,
|
||||
@@ -152,13 +140,13 @@ export const ResultsTable = ({
|
||||
See logs
|
||||
</Button>
|
||||
),
|
||||
}),
|
||||
},
|
||||
],
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[resultHeader]
|
||||
)
|
||||
|
||||
const instance = useTableInstance(table, {
|
||||
const instance = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
state: {
|
||||
@@ -167,7 +155,7 @@ export const ResultsTable = ({
|
||||
columnOrder: columnsOrder,
|
||||
columnSizing: columnsWidth,
|
||||
},
|
||||
getRowId: (row) => row.id,
|
||||
getRowId: (row) => row.id.plainText,
|
||||
columnResizeMode: 'onChange',
|
||||
onRowSelectionChange: setRowSelection,
|
||||
onColumnVisibilityChange: setColumnsVisibility,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Row as RowProps } from '@tanstack/react-table'
|
||||
import Cell from './Cell'
|
||||
import { TableData } from 'services/typebots/results'
|
||||
|
||||
type Props = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
row: RowProps<any>
|
||||
row: RowProps<TableData>
|
||||
isSelected: boolean
|
||||
bottomElement?: React.MutableRefObject<HTMLDivElement | null>
|
||||
onExpandButtonClick: () => void
|
||||
|
||||
@@ -16,11 +16,10 @@ import { useWorkspace } from 'contexts/WorkspaceContext'
|
||||
import React from 'react'
|
||||
import { parseDefaultPublicId } from 'services/typebots'
|
||||
import { isFreePlan } from 'services/workspace'
|
||||
import { isDefined, isNotDefined } from 'utils'
|
||||
import { getViewerUrl, isDefined, isNotDefined } from 'utils'
|
||||
import { CustomDomainsDropdown } from './customDomain/CustomDomainsDropdown'
|
||||
import { EditableUrl } from './EditableUrl'
|
||||
import { integrationsList } from './integrations/EmbedButton'
|
||||
import { env } from 'utils'
|
||||
|
||||
export const ShareContent = () => {
|
||||
const { workspace } = useWorkspace()
|
||||
@@ -59,7 +58,9 @@ export const ShareContent = () => {
|
||||
</Heading>
|
||||
{typebot && (
|
||||
<EditableUrl
|
||||
hostname={env('VIEWER_URL') ?? 'https://typebot.io'}
|
||||
hostname={
|
||||
getViewerUrl({ isBuilder: true }) ?? 'https://typebot.io'
|
||||
}
|
||||
pathname={publicId}
|
||||
onPathnameChange={handlePublicIdChange}
|
||||
/>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { FlexProps } from '@chakra-ui/layout'
|
||||
import prettier from 'prettier/standalone'
|
||||
import parserHtml from 'prettier/parser-html'
|
||||
import { BubbleParams } from 'typebot-js'
|
||||
import { parseInitBubbleCode, typebotJsHtml } from '../params'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { env, getViewerUrl } from 'utils'
|
||||
import { FlexProps } from '@chakra-ui/react'
|
||||
|
||||
type ChatEmbedCodeProps = {
|
||||
withStarterVariables?: boolean
|
||||
@@ -21,9 +21,7 @@ export const ChatEmbedCode = ({
|
||||
const snippet = prettier.format(
|
||||
createSnippet({
|
||||
url: `${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ?? getViewerUrl({ isBuilder: true })
|
||||
}/${typebot?.publicId}`,
|
||||
button,
|
||||
proactiveMessage,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { parseInitContainerCode, typebotJsHtml } from '../params'
|
||||
import { IframeParams } from 'typebot-js'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { env, getViewerUrl } from 'utils'
|
||||
|
||||
type ContainerEmbedCodeProps = {
|
||||
widthLabel: string
|
||||
@@ -23,9 +23,7 @@ export const ContainerEmbedCode = ({
|
||||
const snippet = prettier.format(
|
||||
parseSnippet({
|
||||
url: `${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ?? getViewerUrl({ isBuilder: true })
|
||||
}/${typebot?.publicId}`,
|
||||
heightLabel,
|
||||
widthLabel,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FlexProps } from '@chakra-ui/react'
|
||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { env, getViewerUrl } from 'utils'
|
||||
|
||||
type Props = {
|
||||
widthLabel: string
|
||||
@@ -14,9 +14,7 @@ export const IframeEmbedCode = ({
|
||||
}: Props & FlexProps) => {
|
||||
const { typebot } = useTypebot()
|
||||
const src = `${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ?? getViewerUrl({ isBuilder: true })
|
||||
}/${typebot?.publicId}`
|
||||
const code = `<iframe src="${src}" width="${widthLabel}" height="${heightLabel}" />`
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { FlexProps } from '@chakra-ui/layout'
|
||||
import { FlexProps } from '@chakra-ui/react'
|
||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import parserHtml from 'prettier/parser-html'
|
||||
import prettier from 'prettier/standalone'
|
||||
import { PopupParams } from 'typebot-js'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { env, getViewerUrl } from 'utils'
|
||||
import { parseInitPopupCode, typebotJsHtml } from '../params'
|
||||
|
||||
type PopupEmbedCodeProps = {
|
||||
@@ -18,9 +18,7 @@ export const PopupEmbedCode = ({ delay }: PopupEmbedCodeProps & FlexProps) => {
|
||||
const snippet = prettier.format(
|
||||
createSnippet({
|
||||
url: `${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ?? getViewerUrl({ isBuilder: true })
|
||||
}/${typebot?.publicId}`,
|
||||
delay,
|
||||
}),
|
||||
|
||||
@@ -10,7 +10,7 @@ import parserBabel from 'prettier/parser-babel'
|
||||
import prettier from 'prettier/standalone'
|
||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { env, getViewerUrl } from 'utils'
|
||||
|
||||
type StandardReactDivProps = { widthLabel: string; heightLabel: string }
|
||||
export const StandardReactDiv = ({
|
||||
@@ -21,9 +21,7 @@ export const StandardReactDiv = ({
|
||||
const snippet = prettier.format(
|
||||
parseContainerSnippet({
|
||||
url: `${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ?? getViewerUrl({ isBuilder: true })
|
||||
}/${typebot?.publicId}`,
|
||||
heightLabel,
|
||||
widthLabel,
|
||||
@@ -73,9 +71,7 @@ export const PopupReactCode = ({ delay }: PopupEmbedCodeProps & FlexProps) => {
|
||||
const snippet = prettier.format(
|
||||
parsePopupSnippet({
|
||||
url: `${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ?? getViewerUrl({ isBuilder: true })
|
||||
}/${typebot?.publicId}`,
|
||||
delay,
|
||||
}),
|
||||
@@ -124,9 +120,7 @@ export const ChatReactCode = ({
|
||||
const snippet = prettier.format(
|
||||
parseBubbleSnippet({
|
||||
url: `${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ?? getViewerUrl({ isBuilder: true })
|
||||
}/${typebot?.publicId}`,
|
||||
button,
|
||||
proactiveMessage,
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
import { useToast } from 'components/shared/hooks/useToast'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { createCustomDomain } from 'services/user'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { env, getViewerUrl } from 'utils'
|
||||
|
||||
const hostnameRegex =
|
||||
/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/
|
||||
@@ -118,9 +118,8 @@ export const CustomDomainModal = ({
|
||||
<Stack>
|
||||
<Text fontWeight="bold">Value</Text>
|
||||
<Text>
|
||||
{isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')}
|
||||
{env('VIEWER_INTERNAL_URL') ??
|
||||
getViewerUrl({ isBuilder: true })}
|
||||
</Text>
|
||||
</Stack>
|
||||
</HStack>
|
||||
|
||||
@@ -11,7 +11,7 @@ import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSet
|
||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||
import { useState } from 'react'
|
||||
import { BubbleParams } from 'typebot-js'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { env, getViewerUrl } from 'utils'
|
||||
import { ModalProps } from '../../EmbedButton'
|
||||
|
||||
type GtmInstructionsProps = {
|
||||
@@ -41,9 +41,7 @@ const StandardInstructions = ({ publicId }: Pick<ModalProps, 'publicId'>) => {
|
||||
|
||||
const jsCode = parseInitContainerCode({
|
||||
url: `${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ?? getViewerUrl({ isBuilder: true })
|
||||
}/${publicId}`,
|
||||
})
|
||||
const headCode = `${typebotJsHtml}
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from '@chakra-ui/react'
|
||||
import { CopyButton } from 'components/shared/buttons/CopyButton'
|
||||
import { PublishFirstInfo } from 'components/shared/Info'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { env, getViewerUrl } from 'utils'
|
||||
import { ModalProps } from '../EmbedButton'
|
||||
|
||||
export const NotionModal = ({
|
||||
@@ -46,17 +46,15 @@ export const NotionModal = ({
|
||||
pr="4.5rem"
|
||||
type={'text'}
|
||||
defaultValue={`${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ??
|
||||
getViewerUrl({ isBuilder: true })
|
||||
}/${publicId}`}
|
||||
/>
|
||||
<InputRightElement width="4.5rem">
|
||||
<CopyButton
|
||||
textToCopy={`${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ??
|
||||
getViewerUrl({ isBuilder: true })
|
||||
}/${publicId}`}
|
||||
/>
|
||||
</InputRightElement>
|
||||
|
||||
@@ -14,7 +14,7 @@ import { BubbleParams } from 'typebot-js'
|
||||
import { ModalProps } from '../../EmbedButton'
|
||||
import parserHtml from 'prettier/parser-html'
|
||||
import prettier from 'prettier/standalone'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { env, getViewerUrl } from 'utils'
|
||||
|
||||
type ShopifyInstructionsProps = {
|
||||
type: 'standard' | 'popup' | 'bubble'
|
||||
@@ -46,9 +46,7 @@ const StandardInstructions = ({ publicId }: Pick<ModalProps, 'publicId'>) => {
|
||||
|
||||
const jsCode = parseInitContainerCode({
|
||||
url: `${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ?? getViewerUrl({ isBuilder: true })
|
||||
}/${publicId}`,
|
||||
})
|
||||
const headCode = prettier.format(
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import { ExternalLinkIcon } from 'assets/icons'
|
||||
import { CopyButton } from 'components/shared/buttons/CopyButton'
|
||||
import { PublishFirstInfo } from 'components/shared/Info'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { env, getViewerUrl } from 'utils'
|
||||
import { ModalProps } from '../EmbedButton'
|
||||
|
||||
export const WordpressModal = ({
|
||||
@@ -55,17 +55,15 @@ export const WordpressModal = ({
|
||||
pr="4.5rem"
|
||||
type={'text'}
|
||||
defaultValue={`${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ??
|
||||
getViewerUrl({ isBuilder: true })
|
||||
}/${publicId}`}
|
||||
/>
|
||||
<InputRightElement width="4.5rem">
|
||||
<CopyButton
|
||||
textToCopy={`${
|
||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
||||
? env('VIEWER_URL')
|
||||
: env('VIEWER_INTERNAL_URL')
|
||||
env('VIEWER_INTERNAL_URL') ??
|
||||
getViewerUrl({ isBuilder: true })
|
||||
}/${publicId}`}
|
||||
/>
|
||||
</InputRightElement>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Box, BoxProps, HStack } from '@chakra-ui/react'
|
||||
import { EditorState, EditorView, basicSetup } from '@codemirror/basic-setup'
|
||||
import { EditorView, basicSetup } from 'codemirror'
|
||||
import { EditorState } from '@codemirror/state'
|
||||
import { json, jsonParseLinter } from '@codemirror/lang-json'
|
||||
import { css } from '@codemirror/lang-css'
|
||||
import { javascript } from '@codemirror/lang-javascript'
|
||||
@@ -43,7 +44,7 @@ export const CodeEditor = ({
|
||||
setPlainTextValue(value)
|
||||
onChange && onChange(value)
|
||||
},
|
||||
env('E2E_TEST') === 'enabled' ? 0 : debounceTimeout
|
||||
env('E2E_TEST') === 'true' ? 0 : debounceTimeout
|
||||
)
|
||||
|
||||
useEffect(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEventListener } from '@chakra-ui/hooks'
|
||||
import { useEventListener } from '@chakra-ui/react'
|
||||
import assert from 'assert'
|
||||
import {
|
||||
useGraph,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { chakra } from '@chakra-ui/system'
|
||||
import { chakra } from '@chakra-ui/react'
|
||||
import { colors } from 'libs/theme'
|
||||
import { Edge as EdgeProps } from 'models'
|
||||
import React from 'react'
|
||||
|
||||
@@ -3,7 +3,6 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import {
|
||||
Plate,
|
||||
selectEditor,
|
||||
serializeHtml,
|
||||
TEditor,
|
||||
TElement,
|
||||
Value,
|
||||
@@ -16,6 +15,7 @@ import { parseHtmlStringToPlainText } from 'services/utils'
|
||||
import { defaultTextBubbleContent, TextBubbleContent, Variable } from 'models'
|
||||
import { VariableSearchInput } from 'components/shared/VariableSearchInput'
|
||||
import { ReactEditor } from 'slate-react'
|
||||
import { serializeHtml } from '@udecode/plate-serializer-html'
|
||||
|
||||
type Props = {
|
||||
initialValue: TElement[]
|
||||
@@ -98,7 +98,7 @@ export const TextBubbleEditor = ({ initialValue, onClose }: Props) => {
|
||||
setValue(val)
|
||||
setIsVariableDropdownOpen(false)
|
||||
}
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (e.shiftKey) return
|
||||
if (e.key === 'Enter') closeEditor()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { StackProps, HStack, Button } from '@chakra-ui/react'
|
||||
import { StackProps, HStack, Button, IconButton } from '@chakra-ui/react'
|
||||
import {
|
||||
MARK_BOLD,
|
||||
MARK_ITALIC,
|
||||
@@ -7,7 +7,13 @@ import {
|
||||
import { getPluginType, PlateEditor, Value } from '@udecode/plate-core'
|
||||
import { LinkToolbarButton } from '@udecode/plate-ui-link'
|
||||
import { MarkToolbarButton } from '@udecode/plate-ui-toolbar'
|
||||
import { BoldIcon, ItalicIcon, UnderlineIcon, LinkIcon } from 'assets/icons'
|
||||
import {
|
||||
BoldIcon,
|
||||
ItalicIcon,
|
||||
UnderlineIcon,
|
||||
LinkIcon,
|
||||
UserIcon,
|
||||
} from 'assets/icons'
|
||||
|
||||
type Props = {
|
||||
editor: PlateEditor<Value>
|
||||
@@ -33,9 +39,12 @@ export const ToolBar = ({
|
||||
borderBottomWidth={1}
|
||||
{...props}
|
||||
>
|
||||
<Button size="sm" onMouseDown={handleVariablesButtonMouseDown}>
|
||||
Variables
|
||||
</Button>
|
||||
<IconButton
|
||||
aria-label="Insert variable"
|
||||
size="sm"
|
||||
onMouseDown={handleVariablesButtonMouseDown}
|
||||
icon={<UserIcon />}
|
||||
/>
|
||||
<span data-testid="bold-button">
|
||||
<MarkToolbarButton
|
||||
type={getPluginType(editor, MARK_BOLD)}
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
import { ChangeEvent, useState } from 'react'
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
HStack,
|
||||
Stack,
|
||||
Text,
|
||||
Input as ClassicInput,
|
||||
SimpleGrid,
|
||||
GridItem,
|
||||
} from '@chakra-ui/react'
|
||||
import { useState } from 'react'
|
||||
import { Button, Flex, HStack, Stack, Text } from '@chakra-ui/react'
|
||||
import { SearchContextManager } from '@giphy/react-components'
|
||||
import { UploadButton } from '../buttons/UploadButton'
|
||||
import { GiphySearch } from './GiphySearch'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { BaseEmoji, emojiIndex } from 'emoji-mart'
|
||||
import { emojis } from './emojis'
|
||||
import { Input } from '../Textbox/Input'
|
||||
import { env, isEmpty } from 'utils'
|
||||
import { EmojiSearchableList } from './emoji/EmojiSearchableList'
|
||||
|
||||
type Props = {
|
||||
url?: string
|
||||
@@ -101,7 +91,7 @@ const BodyContent = ({
|
||||
case 'giphy':
|
||||
return <GiphyContent onNewUrl={onSubmit} />
|
||||
case 'emoji':
|
||||
return <EmojiContent onEmojiSelected={onSubmit} />
|
||||
return <EmojiSearchableList onEmojiSelected={onSubmit} />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,55 +123,6 @@ const EmbedLinkContent = ({ initialUrl, onNewUrl }: ContentProps) => (
|
||||
</Stack>
|
||||
)
|
||||
|
||||
const EmojiContent = ({
|
||||
onEmojiSelected,
|
||||
}: {
|
||||
onEmojiSelected: (emoji: string) => void
|
||||
}) => {
|
||||
const [searchValue, setSearchValue] = useState('')
|
||||
const [filteredEmojis, setFilteredEmojis] = useState<string[]>(emojis)
|
||||
|
||||
const handleEmojiClick = (emoji: string) => () => onEmojiSelected(emoji)
|
||||
|
||||
const handleSearchChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setSearchValue(e.target.value)
|
||||
setFilteredEmojis(
|
||||
emojiIndex.search(e.target.value)?.map((o) => (o as BaseEmoji).native) ??
|
||||
emojis
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<ClassicInput
|
||||
placeholder="Search..."
|
||||
value={searchValue}
|
||||
onChange={handleSearchChange}
|
||||
/>
|
||||
<SimpleGrid
|
||||
maxH="350px"
|
||||
overflowY="scroll"
|
||||
overflowX="hidden"
|
||||
spacing={0}
|
||||
columns={7}
|
||||
>
|
||||
{filteredEmojis.map((emoji) => (
|
||||
<GridItem key={emoji}>
|
||||
<Button
|
||||
onClick={handleEmojiClick(emoji)}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
fontSize="xl"
|
||||
>
|
||||
{emoji}
|
||||
</Button>
|
||||
</GridItem>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
const GiphyContent = ({ onNewUrl }: ContentProps) => {
|
||||
if (isEmpty(env('GIPHY_API_KEY')))
|
||||
return <Text>NEXT_PUBLIC_GIPHY_API_KEY is missing in environment</Text>
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
import emojis from './emojiList.json'
|
||||
import emojiTagsData from 'emojilib'
|
||||
import {
|
||||
Stack,
|
||||
SimpleGrid,
|
||||
GridItem,
|
||||
Button,
|
||||
Input as ClassicInput,
|
||||
Text,
|
||||
} from '@chakra-ui/react'
|
||||
import { useState, ChangeEvent, useEffect, useRef } from 'react'
|
||||
|
||||
const emojiTags = emojiTagsData as Record<string, string[]>
|
||||
|
||||
const people = emojis['Smileys & Emotion'].concat(emojis['People & Body'])
|
||||
const nature = emojis['Animals & Nature']
|
||||
const food = emojis['Food & Drink']
|
||||
const activities = emojis['Activities']
|
||||
const travel = emojis['Travel & Places']
|
||||
const objects = emojis['Objects']
|
||||
const symbols = emojis['Symbols']
|
||||
const flags = emojis['Flags']
|
||||
|
||||
export const EmojiSearchableList = ({
|
||||
onEmojiSelected,
|
||||
}: {
|
||||
onEmojiSelected: (emoji: string) => void
|
||||
}) => {
|
||||
const scrollContainer = useRef<HTMLDivElement>(null)
|
||||
const bottomElement = useRef<HTMLDivElement>(null)
|
||||
const [isSearching, setIsSearching] = useState(false)
|
||||
const [filteredPeople, setFilteredPeople] = useState(people)
|
||||
const [filteredAnimals, setFilteredAnimals] = useState(nature)
|
||||
const [filteredFood, setFilteredFood] = useState(food)
|
||||
const [filteredTravel, setFilteredTravel] = useState(travel)
|
||||
const [filteredActivities, setFilteredActivities] = useState(activities)
|
||||
const [filteredObjects, setFilteredObjects] = useState(objects)
|
||||
const [filteredSymbols, setFilteredSymbols] = useState(symbols)
|
||||
const [filteredFlags, setFilteredFlags] = useState(flags)
|
||||
const [totalDisplayedCategories, setTotalDisplayedCategories] = useState(1)
|
||||
|
||||
useEffect(() => {
|
||||
if (!bottomElement.current) return
|
||||
const observer = new IntersectionObserver(handleObserver, {
|
||||
root: scrollContainer.current,
|
||||
})
|
||||
if (bottomElement.current) observer.observe(bottomElement.current)
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [bottomElement.current])
|
||||
|
||||
const handleObserver = (entities: IntersectionObserverEntry[]) => {
|
||||
const target = entities[0]
|
||||
if (target.isIntersecting) setTotalDisplayedCategories((c) => c + 1)
|
||||
}
|
||||
|
||||
const handleSearchChange = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const searchValue = e.target.value
|
||||
if (searchValue.length <= 2 && isSearching) return resetEmojiList()
|
||||
setIsSearching(true)
|
||||
setTotalDisplayedCategories(8)
|
||||
const byTag = (emoji: string) =>
|
||||
emojiTags[emoji].find((tag) => tag.includes(searchValue))
|
||||
setFilteredPeople(people.filter(byTag))
|
||||
setFilteredAnimals(nature.filter(byTag))
|
||||
setFilteredFood(food.filter(byTag))
|
||||
setFilteredTravel(travel.filter(byTag))
|
||||
setFilteredActivities(activities.filter(byTag))
|
||||
setFilteredObjects(objects.filter(byTag))
|
||||
setFilteredSymbols(symbols.filter(byTag))
|
||||
setFilteredFlags(flags.filter(byTag))
|
||||
}
|
||||
|
||||
const resetEmojiList = () => {
|
||||
setTotalDisplayedCategories(1)
|
||||
setIsSearching(false)
|
||||
setFilteredPeople(people)
|
||||
setFilteredAnimals(nature)
|
||||
setFilteredFood(food)
|
||||
setFilteredTravel(travel)
|
||||
setFilteredActivities(activities)
|
||||
setFilteredObjects(objects)
|
||||
setFilteredSymbols(symbols)
|
||||
setFilteredFlags(flags)
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<ClassicInput placeholder="Search..." onChange={handleSearchChange} />
|
||||
<Stack ref={scrollContainer} overflow="scroll" maxH="350px" spacing={4}>
|
||||
{filteredPeople.length > 0 && (
|
||||
<Stack>
|
||||
<Text fontSize="sm" pl="2">
|
||||
People
|
||||
</Text>
|
||||
<EmojiGrid emojis={filteredPeople} onEmojiClick={onEmojiSelected} />
|
||||
</Stack>
|
||||
)}
|
||||
{filteredAnimals.length > 0 && totalDisplayedCategories >= 2 && (
|
||||
<Stack>
|
||||
<Text fontSize="sm" pl="2">
|
||||
Animals & Nature
|
||||
</Text>
|
||||
<EmojiGrid
|
||||
emojis={filteredAnimals}
|
||||
onEmojiClick={onEmojiSelected}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
{filteredFood.length > 0 && totalDisplayedCategories >= 3 && (
|
||||
<Stack>
|
||||
<Text fontSize="sm" pl="2">
|
||||
Food & Drink
|
||||
</Text>
|
||||
<EmojiGrid emojis={filteredFood} onEmojiClick={onEmojiSelected} />
|
||||
</Stack>
|
||||
)}
|
||||
{filteredTravel.length > 0 && totalDisplayedCategories >= 4 && (
|
||||
<Stack>
|
||||
<Text fontSize="sm" pl="2">
|
||||
Travel & Places
|
||||
</Text>
|
||||
<EmojiGrid emojis={filteredTravel} onEmojiClick={onEmojiSelected} />
|
||||
</Stack>
|
||||
)}
|
||||
{filteredActivities.length > 0 && totalDisplayedCategories >= 5 && (
|
||||
<Stack>
|
||||
<Text fontSize="sm" pl="2">
|
||||
Activities
|
||||
</Text>
|
||||
<EmojiGrid
|
||||
emojis={filteredActivities}
|
||||
onEmojiClick={onEmojiSelected}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
{filteredObjects.length > 0 && totalDisplayedCategories >= 6 && (
|
||||
<Stack>
|
||||
<Text fontSize="sm" pl="2">
|
||||
Objects
|
||||
</Text>
|
||||
<EmojiGrid
|
||||
emojis={filteredObjects}
|
||||
onEmojiClick={onEmojiSelected}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
{filteredSymbols.length > 0 && totalDisplayedCategories >= 7 && (
|
||||
<Stack>
|
||||
<Text fontSize="sm" pl="2">
|
||||
Symbols
|
||||
</Text>
|
||||
<EmojiGrid
|
||||
emojis={filteredSymbols}
|
||||
onEmojiClick={onEmojiSelected}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
{filteredFlags.length > 0 && totalDisplayedCategories >= 8 && (
|
||||
<Stack>
|
||||
<Text fontSize="sm" pl="2">
|
||||
Flags
|
||||
</Text>
|
||||
<EmojiGrid emojis={filteredFlags} onEmojiClick={onEmojiSelected} />
|
||||
</Stack>
|
||||
)}
|
||||
<div ref={bottomElement} />
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
const EmojiGrid = ({
|
||||
emojis,
|
||||
onEmojiClick,
|
||||
}: {
|
||||
emojis: string[]
|
||||
onEmojiClick: (emoji: string) => void
|
||||
}) => {
|
||||
const handleClick = (emoji: string) => () => onEmojiClick(emoji)
|
||||
return (
|
||||
<SimpleGrid spacing={0} columns={7}>
|
||||
{emojis.map((emoji) => (
|
||||
<GridItem
|
||||
as={Button}
|
||||
onClick={handleClick(emoji)}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
fontSize="xl"
|
||||
key={emoji}
|
||||
>
|
||||
{emoji}
|
||||
</GridItem>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
)
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@ export const SearchableDropdown = ({
|
||||
const debounced = useDebouncedCallback(
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
onValueChange ? onValueChange : () => {},
|
||||
env('E2E_TEST') === 'enabled' ? 0 : debounceTimeout
|
||||
env('E2E_TEST') === 'true' ? 0 : debounceTimeout
|
||||
)
|
||||
const [filteredItems, setFilteredItems] = useState([
|
||||
...items
|
||||
|
||||
@@ -23,7 +23,7 @@ export const SmartNumberInput = ({
|
||||
const [currentValue, setCurrentValue] = useState(value?.toString() ?? '')
|
||||
const debounced = useDebouncedCallback(
|
||||
onValueChange,
|
||||
env('E2E_TEST') === 'enabled' ? 0 : debounceTimeout
|
||||
env('E2E_TEST') === 'true' ? 0 : debounceTimeout
|
||||
)
|
||||
|
||||
useEffect(
|
||||
|
||||
@@ -36,7 +36,7 @@ export const TextBox = ({
|
||||
(value) => {
|
||||
onChange(value)
|
||||
},
|
||||
env('E2E_TEST') === 'enabled' ? 0 : debounceTimeout
|
||||
env('E2E_TEST') === 'true' ? 0 : debounceTimeout
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { Editable, EditablePreview, EditableInput } from '@chakra-ui/editable'
|
||||
import { Tooltip } from '@chakra-ui/tooltip'
|
||||
import {
|
||||
Editable,
|
||||
EditablePreview,
|
||||
EditableInput,
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
type EditableProps = {
|
||||
|
||||
@@ -47,7 +47,7 @@ export const VariableSearchInput = ({
|
||||
const variable = variables.find((v) => v.name === value)
|
||||
if (variable) onSelectVariable(variable)
|
||||
},
|
||||
env('E2E_TEST') === 'enabled' ? 0 : debounceTimeout
|
||||
env('E2E_TEST') === 'true' ? 0 : debounceTimeout
|
||||
)
|
||||
const [filteredItems, setFilteredItems] = useState<Variable[]>(
|
||||
variables ?? []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useToast as useChakraToast, UseToastOptions } from '@chakra-ui/toast'
|
||||
import { useToast as useChakraToast, UseToastOptions } from '@chakra-ui/react'
|
||||
|
||||
export const useToast = () => {
|
||||
const toast = useChakraToast()
|
||||
|
||||
@@ -17,7 +17,7 @@ import { useToast } from 'components/shared/hooks/useToast'
|
||||
import { Typebot } from 'models'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { parseTypebotToPublicTypebot } from 'services/publicTypebot'
|
||||
import { sendRequest } from 'utils'
|
||||
import { getViewerUrl, sendRequest } from 'utils'
|
||||
import { TemplateProps, templates } from './data'
|
||||
|
||||
type Props = {
|
||||
@@ -71,6 +71,7 @@ export const TemplatesModal = ({ isOpen, onClose, onTypebotChoose }: Props) => {
|
||||
</Heading>
|
||||
{typebot && (
|
||||
<TypebotViewer
|
||||
apiHost={getViewerUrl({ isBuilder: true })}
|
||||
typebot={parseTypebotToPublicTypebot(typebot)}
|
||||
key={typebot.id}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user