Skip to content

Commit

Permalink
♻️ (editor) Improve webhook creation
Browse files Browse the repository at this point in the history
Remove terrible useEffects
  • Loading branch information
baptisteArno committed Feb 15, 2023
1 parent 6e066c4 commit ac464ea
Show file tree
Hide file tree
Showing 23 changed files with 481 additions and 528 deletions.
9 changes: 0 additions & 9 deletions apps/builder/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@ const nextConfig = withTM({
experimental: {
outputFileTracingRoot: path.join(__dirname, '../../'),
},
async redirects() {
return [
{
source: '/typebots/:typebotId',
destination: '/typebots/:typebotId/edit',
permanent: true,
},
]
},
headers: async () => {
return [
{
Expand Down
4 changes: 2 additions & 2 deletions apps/builder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"dependencies": {
"@chakra-ui/anatomy": "^2.1.1",
"@chakra-ui/css-reset": "2.0.11",
"@chakra-ui/react": "2.4.9",
"@chakra-ui/react": "2.5.0",
"@chakra-ui/theme-tools": "^2.0.16",
"@codemirror/lang-css": "6.0.1",
"@codemirror/lang-html": "6.4.1",
Expand Down Expand Up @@ -63,7 +63,7 @@
"emails": "workspace:*",
"emojilib": "3.0.8",
"focus-visible": "5.2.0",
"framer-motion": "8.5.4",
"framer-motion": "9.0.2",
"google-auth-library": "8.7.0",
"google-spreadsheet": "3.3.0",
"got": "12.5.3",
Expand Down
15 changes: 8 additions & 7 deletions apps/builder/src/components/inputs/TextBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,16 @@ export const TextBox = ({
debounceTimeout = 1000,
label,
moreInfoTooltip,
defaultValue,
isRequired,
...props
}: TextBoxProps) => {
const textBoxRef = useRef<(HTMLInputElement & HTMLTextAreaElement) | null>(
null
)
const [value, setValue] = useState<string>(props.defaultValue ?? '')
const [value, setValue] = useState<string>(defaultValue ?? '')
const [carretPosition, setCarretPosition] = useState<number>(
props.defaultValue?.length ?? 0
defaultValue?.length ?? 0
)
const [isTouched, setIsTouched] = useState(false)
const debounced = useDebouncedCallback(
Expand All @@ -50,10 +52,9 @@ export const TextBox = ({
)

useEffect(() => {
if (props.defaultValue !== value && value === '' && !isTouched)
setValue(props.defaultValue ?? '')
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.defaultValue])
if (isTouched || defaultValue === value) return
setValue(defaultValue ?? '')
}, [defaultValue, isTouched, value])

useEffect(
() => () => {
Expand Down Expand Up @@ -111,7 +112,7 @@ export const TextBox = ({
)

return (
<FormControl isRequired={props.isRequired}>
<FormControl isRequired={isRequired}>
{label && (
<FormLabel>
{label}{' '}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,16 @@ import {
VariableForTest,
ResponseVariableMapping,
WebhookBlock,
defaultWebhookAttributes,
Webhook,
MakeComBlock,
PabblyConnectBlock,
Webhook,
} from 'models'
import { DropdownList } from '@/components/DropdownList'
import { CodeEditor } from '@/components/CodeEditor'
import { HeadersInputs, QueryParamsInputs } from './KeyValueInputs'
import { VariableForTestInputs } from './VariableForTestInputs'
import { DataVariableInputs } from './ResponseMappingInputs'
import { byId } from 'utils'
import { byId, env } from 'utils'
import { ExternalLinkIcon } from '@/components/icons'
import { useToast } from '@/hooks/useToast'
import { SwitchWithLabel } from '@/components/SwitchWithLabel'
Expand All @@ -41,11 +40,15 @@ import { executeWebhook } from '../../queries/executeWebhookQuery'
import { getDeepKeys } from '../../utils/getDeepKeys'
import { Input } from '@/components/inputs'
import { convertVariablesForTestToVariables } from '../../utils/convertVariablesForTestToVariables'
import { useDebouncedCallback } from 'use-debounce'

const debounceWebhookTimeout = 2000

type Provider = {
name: 'Make.com' | 'Pabbly Connect'
name: 'Pabbly Connect'
url: string
}

type Props = {
block: WebhookBlock | MakeComBlock | PabblyConnectBlock
onOptionsChange: (options: WebhookOptions) => void
Expand All @@ -61,39 +64,28 @@ export const WebhookSettings = ({
const [isTestResponseLoading, setIsTestResponseLoading] = useState(false)
const [testResponse, setTestResponse] = useState<string>()
const [responseKeys, setResponseKeys] = useState<string[]>([])

const { showToast } = useToast()
const [localWebhook, setLocalWebhook] = useState(
const [localWebhook, _setLocalWebhook] = useState(
webhooks.find(byId(webhookId))
)
const updateWebhookDebounced = useDebouncedCallback(
async (newLocalWebhook) => {
await updateWebhook(newLocalWebhook.id, newLocalWebhook)
},
env('E2E_TEST') === 'true' ? 0 : debounceWebhookTimeout
)

useEffect(() => {
if (localWebhook) return
const incomingWebhook = webhooks.find(byId(webhookId))
setLocalWebhook(incomingWebhook)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [webhooks])

useEffect(() => {
if (!typebot) return
if (!localWebhook) {
const newWebhook = {
id: webhookId,
...defaultWebhookAttributes,
typebotId: typebot.id,
} as Webhook
updateWebhook(webhookId, newWebhook)
}
const setLocalWebhook = (newLocalWebhook: Webhook) => {
_setLocalWebhook(newLocalWebhook)
updateWebhookDebounced(newLocalWebhook)
}

return () => {
setLocalWebhook((localWebhook) => {
if (!localWebhook) return
updateWebhook(webhookId, localWebhook).then()
return localWebhook
})
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
useEffect(
() => () => {
updateWebhookDebounced.flush()
},
[updateWebhookDebounced]
)

const handleUrlChange = (url?: string) =>
localWebhook && setLocalWebhook({ ...localWebhook, url: url ?? null })
Expand Down Expand Up @@ -126,8 +118,7 @@ export const WebhookSettings = ({
const handleTestRequestClick = async () => {
if (!typebot || !localWebhook) return
setIsTestResponseLoading(true)
await updateWebhook(localWebhook.id, localWebhook)
await save()
await Promise.all([updateWebhook(localWebhook.id, localWebhook), save()])
const { data, error } = await executeWebhook(
typebot.id,
convertVariablesForTestToVariables(
Expand All @@ -152,6 +143,7 @@ export const WebhookSettings = ({
)

if (!localWebhook) return <Spinner />

return (
<Stack spacing={4}>
{provider && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { duplicateWebhookQueries } from './queries/duplicateWebhookQuery'
export { duplicateWebhookQuery } from './queries/duplicateWebhookQuery'
export { WebhookSettings } from './components/WebhookSettings'
export { WebhookContent } from './components/WebhookContent'
export { WebhookIcon } from './components/WebhookIcon'
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Webhook } from 'models'
import { sendRequest } from 'utils'

type Props = {
typebotId: string
data: Partial<Omit<Webhook, 'typebotId'>>
}

export const createWebhookQuery = ({ typebotId, data }: Props) =>
sendRequest<{ webhook: Webhook }>({
method: 'POST',
url: `/api/typebots/${typebotId}/webhooks`,
body: { data },
})
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import { Webhook } from 'models'
import { sendRequest } from 'utils'
import { saveWebhookQuery } from './saveWebhookQuery'
import { createWebhookQuery } from './createWebhookQuery'

export const duplicateWebhookQueries = async (
typebotId: string,
existingWebhookId: string,
newWebhookId: string
): Promise<Webhook | undefined> => {
type Props = {
existingIds: { typebotId: string; webhookId: string }
newIds: { typebotId: string; webhookId: string }
}
export const duplicateWebhookQuery = async ({
existingIds,
newIds,
}: Props): Promise<Webhook | undefined> => {
const { data } = await sendRequest<{ webhook: Webhook }>(
`/api/webhooks/${existingWebhookId}`
`/api/typebots/${existingIds.typebotId}/webhooks/${existingIds.webhookId}`
)
if (!data) return
const newWebhook = { ...data.webhook, id: newWebhookId, typebotId }
await saveWebhookQuery(newWebhook.id, newWebhook)
const newWebhook = {
...data.webhook,
id: newIds.webhookId,
typebotId: newIds.typebotId,
}
await createWebhookQuery({
typebotId: newIds.typebotId,
data: { ...data.webhook, id: newIds.webhookId },
})
return newWebhook
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Webhook } from 'models'
import { sendRequest } from 'utils'

type Props = {
typebotId: string
webhookId: string
data: Partial<Omit<Webhook, 'id' | 'typebotId'>>
}

export const updateWebhookQuery = ({ typebotId, webhookId, data }: Props) =>
sendRequest<{ webhook: Webhook }>({
method: 'PATCH',
url: `/api/typebots/${typebotId}/webhooks/${webhookId}`,
body: { data },
})
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { duplicateWebhookQueries } from '@/features/blocks/integrations/webhook'
import { duplicateWebhookQuery } from '@/features/blocks/integrations/webhook'
import { createId } from '@paralleldrive/cuid2'
import { Plan, Prisma } from 'db'
import {
Expand All @@ -25,11 +25,13 @@ export const importTypebotQuery = async (typebot: Typebot, userPlan: Plan) => {
.filter(isWebhookBlock)
await Promise.all(
webhookBlocks.map((s) =>
duplicateWebhookQueries(
newTypebot.id,
s.webhookId,
webhookIdsMapping.get(s.webhookId) as string
)
duplicateWebhookQuery({
existingIds: { typebotId: typebot.id, webhookId: s.webhookId },
newIds: {
typebotId: newTypebot.id,
webhookId: webhookIdsMapping.get(s.webhookId) as string,
},
})
)
)
return { data, error }
Expand Down
Loading

4 comments on commit ac464ea

@vercel
Copy link

@vercel vercel bot commented on ac464ea Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on ac464ea Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

viewer-v2 – ./apps/viewer

app.yvon.earth
ar.nigerias.io
bot.enreso.org
bot.rslabs.pro
bots.bridge.ai
chat.hayuri.id
chicken.cr8.ai
gollum.riku.ai
gsbulletin.com
panther.cr7.ai
panther.cr8.ai
penguin.cr8.ai
talk.gocare.io
test.bot.gives
ticketfute.com
unicorn.cr8.ai
apo.nigerias.io
apr.nigerias.io
aso.nigerias.io
bot.ageenda.com
bot.artiweb.app
bot.devitus.com
bot.jesopizz.it
bot.reeplai.com
bot.scayver.com
bot.tc-mail.com
chat.lalmon.com
chat.sureb4.com
eventhub.com.au
fitness.riku.ai
games.klujo.com
help.taxtree.io
sakuranembro.it
typebot.aloe.do
bot.contakit.com
bot.piccinato.co
bot.sv-energy.it
botc.ceox.com.br
clo.closeer.work
cockroach.cr8.ai
faqs.nigerias.io
feedback.ofx.one
form.syncwin.com
haymanevents.com
kw.wpwakanda.com
myrentalhost.com
bots.baptiste-arnaud.fr
help.comebackreward.com
link.venturasuceder.com
mainmenu.diddancing.com
manualhandlingcourse.ie
register.kandabrand.com
signup.hypemarketing.in
subfooter.wpwakanda.com
survey.hypemarketing.in
testbot.afterorigin.com
typebot.influencer.love
91181264.your-access.one
liveconvert.kandalearn.com
mainmenu1one.wpwakanda.com
tarian.theiofoundation.org
ted.meujalecobrasil.com.br
type.dericsoncalari.com.br
bot.pinpointinteractive.com
bot.polychromes-project.com
bot.seidinembroseanchetu.it
chatbot.berbelanjabiz.trade
designguide.techyscouts.com
liveconvert2.kandalearn.com
presente.empresarias.com.mx
sell.sellthemotorhome.co.uk
anamnese.odontopavani.com.br
austin.channelautomation.com
bot.marketingplusmindset.com
bot.seidibergamoseanchetu.it
desabafe.sergiolimajr.com.br
download.venturemarketing.in
piazzatorre.barrettamario.it
type.cookieacademyonline.com
bot.brigadeirosemdrama.com.br
forms.escoladeautomacao.com.br
onboarding.libertydreamcare.ie
type.talitasouzamarques.com.br
agendamento.sergiolimajr.com.br
anamnese.clinicamegasjdr.com.br
bookings.littlepartymonkeys.com
bot.comercializadoraomicron.com
elevateyourmind.groovepages.com
viewer-v2-typebot-io.vercel.app
yourfeedback.comebackreward.com
gerador.verificadordehospedes.com
personal-trainer.barrettamario.it
preagendamento.sergiolimajr.com.br
studiotecnicoimmobiliaremerelli.it
download.thailandmicespecialist.com
register.thailandmicespecialist.com
bot.studiotecnicoimmobiliaremerelli.it
pesquisa.escolamodacomproposito.com.br
anamnese.clinicaramosodontologia.com.br
viewer-v2-git-main-typebot-io.vercel.app

@vercel
Copy link

@vercel vercel bot commented on ac464ea Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./apps/docs

docs-typebot-io.vercel.app
docs-git-main-typebot-io.vercel.app
docs.typebot.io

@vercel
Copy link

@vercel vercel bot commented on ac464ea Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

builder-v2 – ./apps/builder

builder-v2-git-main-typebot-io.vercel.app
app.typebot.io
builder-v2-typebot-io.vercel.app

Please sign in to comment.