fix: ♿️ Improve inputs responsivity
This commit is contained in:
@ -1,10 +1,7 @@
|
|||||||
import { Box, Button, Fade, Flex, IconButton, Stack } from '@chakra-ui/react'
|
import { Box, Button, Fade, Flex, IconButton, Stack } from '@chakra-ui/react'
|
||||||
import { TrashIcon, PlusIcon } from 'assets/icons'
|
import { TrashIcon, PlusIcon } from 'assets/icons'
|
||||||
import cuid from 'cuid'
|
import cuid from 'cuid'
|
||||||
import { dequal } from 'dequal'
|
import React, { useState } from 'react'
|
||||||
import { Draft } from 'immer'
|
|
||||||
import React, { useEffect, useState } from 'react'
|
|
||||||
import { useImmer } from 'use-immer'
|
|
||||||
|
|
||||||
type ItemWithId<T> = T & { id: string }
|
type ItemWithId<T> = T & { id: string }
|
||||||
|
|
||||||
@ -31,32 +28,28 @@ export const TableList = <T,>({
|
|||||||
Item,
|
Item,
|
||||||
ComponentBetweenItems = () => <></>,
|
ComponentBetweenItems = () => <></>,
|
||||||
}: Props<T>) => {
|
}: Props<T>) => {
|
||||||
const [items, setItems] = useImmer(initialItems)
|
const [items, setItems] = useState(initialItems)
|
||||||
const [showDeleteIndex, setShowDeleteIndex] = useState<number | null>(null)
|
const [showDeleteIndex, setShowDeleteIndex] = useState<number | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (dequal(items, initialItems)) return
|
|
||||||
onItemsChange(items)
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [items])
|
|
||||||
|
|
||||||
const createItem = () => {
|
const createItem = () => {
|
||||||
setItems((items) => {
|
const id = cuid()
|
||||||
const id = cuid()
|
const newItem = { id } as ItemWithId<T>
|
||||||
const newItem = { id } as Draft<ItemWithId<T>>
|
setItems([...items, newItem])
|
||||||
items.push(newItem)
|
onItemsChange([...items, newItem])
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateItem = (itemIndex: number, updates: Partial<T>) =>
|
const updateItem = (itemIndex: number, updates: Partial<T>) => {
|
||||||
setItems((items) => {
|
const newItems = items.map((item, idx) =>
|
||||||
items[itemIndex] = { ...items[itemIndex], ...updates }
|
idx === itemIndex ? { ...item, ...updates } : item
|
||||||
})
|
)
|
||||||
|
setItems(newItems)
|
||||||
|
onItemsChange(newItems)
|
||||||
|
}
|
||||||
|
|
||||||
const deleteItem = (itemIndex: number) => () => {
|
const deleteItem = (itemIndex: number) => () => {
|
||||||
setItems((items) => {
|
items.splice(itemIndex, 1)
|
||||||
items.splice(itemIndex, 1)
|
setItems([...items])
|
||||||
})
|
onItemsChange([...items])
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMouseEnter = (itemIndex: number) => () =>
|
const handleMouseEnter = (itemIndex: number) => () =>
|
||||||
|
@ -15,7 +15,7 @@ import { useTypebot } from 'contexts/TypebotContext'
|
|||||||
import cuid from 'cuid'
|
import cuid from 'cuid'
|
||||||
import { Variable } from 'models'
|
import { Variable } from 'models'
|
||||||
import React, { useState, useRef, ChangeEvent, useEffect } from 'react'
|
import React, { useState, useRef, ChangeEvent, useEffect } from 'react'
|
||||||
import { useDebounce } from 'use-debounce'
|
import { useDebouncedCallback } from 'use-debounce'
|
||||||
import { byId, isNotDefined } from 'utils'
|
import { byId, isNotDefined } from 'utils'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -40,8 +40,11 @@ export const VariableSearchInput = ({
|
|||||||
const [inputValue, setInputValue] = useState(
|
const [inputValue, setInputValue] = useState(
|
||||||
variables.find(byId(initialVariableId))?.name ?? ''
|
variables.find(byId(initialVariableId))?.name ?? ''
|
||||||
)
|
)
|
||||||
const [debouncedInputValue] = useDebounce(
|
const debounced = useDebouncedCallback(
|
||||||
inputValue,
|
(value) => {
|
||||||
|
const variable = variables.find((v) => v.name === value)
|
||||||
|
if (variable) onSelectVariable(variable)
|
||||||
|
},
|
||||||
process.env.NEXT_PUBLIC_E2E_TEST ? 0 : debounceTimeout
|
process.env.NEXT_PUBLIC_E2E_TEST ? 0 : debounceTimeout
|
||||||
)
|
)
|
||||||
const [filteredItems, setFilteredItems] = useState<Variable[]>(
|
const [filteredItems, setFilteredItems] = useState<Variable[]>(
|
||||||
@ -60,14 +63,16 @@ export const VariableSearchInput = ({
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(
|
||||||
const variable = variables.find((v) => v.name === debouncedInputValue)
|
() => () => {
|
||||||
if (variable) onSelectVariable(variable)
|
debounced.flush()
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
},
|
||||||
}, [debouncedInputValue])
|
[debounced]
|
||||||
|
)
|
||||||
|
|
||||||
const onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
const onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
setInputValue(e.target.value)
|
setInputValue(e.target.value)
|
||||||
|
debounced(e.target.value)
|
||||||
onOpen()
|
onOpen()
|
||||||
if (e.target.value === '') {
|
if (e.target.value === '') {
|
||||||
setFilteredItems([...variables.slice(0, 50)])
|
setFilteredItems([...variables.slice(0, 50)])
|
||||||
@ -84,6 +89,7 @@ export const VariableSearchInput = ({
|
|||||||
|
|
||||||
const handleVariableNameClick = (variable: Variable) => () => {
|
const handleVariableNameClick = (variable: Variable) => () => {
|
||||||
setInputValue(variable.name)
|
setInputValue(variable.name)
|
||||||
|
onSelectVariable(variable)
|
||||||
onClose()
|
onClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +106,10 @@ export const VariableSearchInput = ({
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
deleteVariable(variable.id)
|
deleteVariable(variable.id)
|
||||||
setFilteredItems(filteredItems.filter((item) => item.id !== variable.id))
|
setFilteredItems(filteredItems.filter((item) => item.id !== variable.id))
|
||||||
if (variable.name === inputValue) setInputValue('')
|
if (variable.name === inputValue) {
|
||||||
|
setInputValue('')
|
||||||
|
debounced('')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
import { CreateTypebotMoreButton } from 'components/templates/ImportFileMenuItem'
|
import { CreateTypebotMoreButton } from 'components/templates/ImportFileMenuItem'
|
||||||
import { TemplateButton } from 'components/templates/TemplateButton'
|
import { TemplateButton } from 'components/templates/TemplateButton'
|
||||||
import { useUser } from 'contexts/UserContext'
|
import { useUser } from 'contexts/UserContext'
|
||||||
import { Typebot } from 'models'
|
import { defaultTheme, Typebot } from 'models'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { createTypebot, importTypebot } from 'services/typebots/typebots'
|
import { createTypebot, importTypebot } from 'services/typebots/typebots'
|
||||||
@ -40,6 +40,13 @@ export const TemplatesContent = () => {
|
|||||||
...typebot,
|
...typebot,
|
||||||
ownerId: user.id,
|
ownerId: user.id,
|
||||||
folderId,
|
folderId,
|
||||||
|
theme: {
|
||||||
|
...defaultTheme,
|
||||||
|
chat: {
|
||||||
|
...defaultTheme.chat,
|
||||||
|
hostAvatar: { isEnabled: true, url: user.image ?? undefined },
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
: await createTypebot({
|
: await createTypebot({
|
||||||
folderId,
|
folderId,
|
||||||
|
@ -59,6 +59,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
? data
|
? data
|
||||||
: (parseNewTypebot({
|
: (parseNewTypebot({
|
||||||
ownerId: user.id,
|
ownerId: user.id,
|
||||||
|
ownerAvatarUrl: user.image,
|
||||||
...data,
|
...data,
|
||||||
}) as Prisma.TypebotUncheckedCreateInput),
|
}) as Prisma.TypebotUncheckedCreateInput),
|
||||||
})
|
})
|
||||||
|
@ -324,10 +324,12 @@ export const parseNewTypebot = ({
|
|||||||
ownerId,
|
ownerId,
|
||||||
folderId,
|
folderId,
|
||||||
name,
|
name,
|
||||||
|
ownerAvatarUrl,
|
||||||
}: {
|
}: {
|
||||||
ownerId: string
|
ownerId: string
|
||||||
folderId: string | null
|
folderId: string | null
|
||||||
name: string
|
name: string
|
||||||
|
ownerAvatarUrl?: string
|
||||||
}): Omit<
|
}): Omit<
|
||||||
Typebot,
|
Typebot,
|
||||||
| 'createdAt'
|
| 'createdAt'
|
||||||
@ -358,7 +360,13 @@ export const parseNewTypebot = ({
|
|||||||
blocks: [startBlock],
|
blocks: [startBlock],
|
||||||
edges: [],
|
edges: [],
|
||||||
variables: [],
|
variables: [],
|
||||||
theme: defaultTheme,
|
theme: {
|
||||||
|
...defaultTheme,
|
||||||
|
chat: {
|
||||||
|
...defaultTheme.chat,
|
||||||
|
hostAvatar: { isEnabled: true, url: ownerAvatarUrl },
|
||||||
|
},
|
||||||
|
},
|
||||||
settings: defaultSettings,
|
settings: defaultSettings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user