2
0

fix: ️ Improve inputs responsivity

This commit is contained in:
Baptiste Arnaud
2022-03-22 15:32:48 +01:00
parent bd702f2eba
commit 03aadab409
5 changed files with 52 additions and 34 deletions

View File

@ -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) => () =>

View File

@ -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 (

View File

@ -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,

View File

@ -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),
}) })

View File

@ -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,
} }
} }