Skip to content

Commit

Permalink
✨ (editor) Add unpublish and close typebot options
Browse files Browse the repository at this point in the history
Introducing more menu items on the "Publised" button in the editor. You can now unpublish a typebot and close it to new
responses
  • Loading branch information
baptisteArno committed Oct 6, 2022
1 parent 7ca97d4 commit bfed599
Show file tree
Hide file tree
Showing 80 changed files with 1,111 additions and 960 deletions.
7 changes: 7 additions & 0 deletions apps/builder/assets/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -489,3 +489,10 @@ export const AlertIcon = (props: IconProps) => (
<line x1="12" y1="17" x2="12.01" y2="17"></line>
</Icon>
)

export const CloudOffIcon = (props: IconProps) => (
<Icon viewBox="0 0 24 24" {...featherIconsBaseProps} {...props}>
<path d="M22.61 16.95A5 5 0 0 0 18 10h-1.26a8 8 0 0 0-7.05-6M5 5a8 8 0 0 0 4 15h9a5 5 0 0 0 1.7-.3"></path>
<line x1="1" y1="1" x2="23" y2="23"></line>
</Icon>
)
55 changes: 46 additions & 9 deletions apps/builder/components/shared/buttons/PublishButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ import {
useDisclosure,
ButtonProps,
} from '@chakra-ui/react'
import { ChevronLeftIcon } from 'assets/icons'
import {
ChevronLeftIcon,
CloudOffIcon,
LockedIcon,
UnlockedIcon,
} from 'assets/icons'
import { useTypebot } from 'contexts/TypebotContext/TypebotContext'
import { useWorkspace } from 'contexts/WorkspaceContext'
import { InputBlockType } from 'models'
Expand All @@ -34,6 +39,9 @@ export const PublishButton = (props: ButtonProps) => {
restorePublishedTypebot,
typebot,
isSavingLoading,
updateTypebot,
unpublishTypebot,
save,
} = useTypebot()

const hasInputFile = typebot?.groups
Expand All @@ -46,6 +54,16 @@ export const PublishButton = (props: ButtonProps) => {
if (!publishedTypebot) push(`/typebots/${query.typebotId}/share`)
}

const closeTypebot = async () => {
updateTypebot({ isClosed: true })
await save()
}

const openTypebot = async () => {
updateTypebot({ isClosed: false })
await save()
}

return (
<HStack spacing="1px">
<ChangePlanModal
Expand All @@ -68,33 +86,52 @@ export const PublishButton = (props: ButtonProps) => {
</Text>
</Stack>
}
isDisabled={isNotDefined(publishedTypebot)}
isDisabled={isNotDefined(publishedTypebot) || isPublished}
>
<Button
colorScheme="blue"
isLoading={isPublishing || isSavingLoading}
isDisabled={isPublished}
onClick={handlePublishClick}
borderRightRadius={publishedTypebot && !isPublished ? 0 : undefined}
borderRightRadius={publishedTypebot ? 0 : undefined}
{...props}
>
{isPublished ? 'Published' : 'Publish'}
{isPublished
? typebot?.isClosed
? 'Closed'
: 'Published'
: 'Publish'}
</Button>
</Tooltip>

{publishedTypebot && !isPublished && (
{publishedTypebot && (
<Menu>
<MenuButton
as={IconButton}
colorScheme="blue"
colorScheme={'blue'}
borderLeftRadius={0}
icon={<ChevronLeftIcon transform="rotate(-90deg)" />}
aria-label="Show published version"
aria-label="Show published typebot menu"
size="sm"
isDisabled={isPublishing || isSavingLoading}
/>
<MenuList>
<MenuItem onClick={restorePublishedTypebot}>
Restore published version
{!isPublished && (
<MenuItem onClick={restorePublishedTypebot}>
Restore published version
</MenuItem>
)}
{!typebot?.isClosed ? (
<MenuItem onClick={closeTypebot} icon={<LockedIcon />}>
Close typebot to new responses
</MenuItem>
) : (
<MenuItem onClick={openTypebot} icon={<UnlockedIcon />}>
Reopen typebot to new responses
</MenuItem>
)}
<MenuItem onClick={unpublishTypebot} icon={<CloudOffIcon />}>
Unpublish typebot
</MenuItem>
</MenuList>
</Menu>
Expand Down
19 changes: 19 additions & 0 deletions apps/builder/contexts/TypebotContext/TypebotContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { saveWebhook } from 'services/webhook'
import { stringify } from 'qs'
import cuid from 'cuid'
import { useToast } from 'components/shared/hooks/useToast'
import { deletePublishedTypebotQuery } from 'services/typebots/deletePublishedTypebotQuery'
const autoSaveTimeout = 10000

type UpdateTypebotPayload = Partial<{
Expand All @@ -55,6 +56,7 @@ type UpdateTypebotPayload = Partial<{
icon: string
customDomain: string
resultsTablePreferences: ResultsTablePreferences
isClosed: boolean
}>

export type SetTypebot = (
Expand All @@ -81,6 +83,7 @@ const typebotContext = createContext<
) => Promise<void>
updateTypebot: (updates: UpdateTypebotPayload) => void
publishTypebot: () => void
unpublishTypebot: () => void
restorePublishedTypebot: () => void
} & GroupsActions &
BlocksActions &
Expand Down Expand Up @@ -314,6 +317,21 @@ export const TypebotContext = ({
}
}

const unpublishTypebot = async () => {
if (!publishedTypebot || !localTypebot) return
setIsPublishing(true)
const { error } = await deletePublishedTypebotQuery({
publishedTypebotId: publishedTypebot.id,
typebotId: localTypebot.id,
})
setIsPublishing(false)
if (error) showToast({ description: error.message })
mutate({
typebot: localTypebot,
webhooks: webhooks ?? [],
})
}

const restorePublishedTypebot = () => {
if (!publishedTypebot || !localTypebot) return
setLocalTypebot(parsePublicTypebotToTypebot(publishedTypebot, localTypebot))
Expand Down Expand Up @@ -351,6 +369,7 @@ export const TypebotContext = ({
canUndo,
canRedo,
publishTypebot,
unpublishTypebot,
isPublishing,
isPublished,
updateTypebot: updateLocalTypebot,
Expand Down
14 changes: 13 additions & 1 deletion apps/builder/pages/api/publicTypebots/[id].ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
import prisma from 'libs/prisma'
import { InputBlockType, PublicTypebot } from 'models'
import { NextApiRequest, NextApiResponse } from 'next'
import { canPublishFileInput } from 'services/api/dbRules'
import { canPublishFileInput, canWriteTypebot } from 'services/api/dbRules'
import { getAuthenticatedUser } from 'services/api/utils'
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'

Expand Down Expand Up @@ -32,6 +32,18 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
})
return res.send({ typebots })
}
if (req.method === 'DELETE') {
const publishedTypebotId = req.query.id as string
const typebotId = req.query.typebotId as string | undefined
if (!typebotId) return badRequest(res, 'typebotId is required')
await prisma.publicTypebot.deleteMany({
where: {
id: publishedTypebotId,
typebot: canWriteTypebot(typebotId, user),
},
})
return res.send({ success: true })
}
return methodNotAllowed(res)
}

Expand Down
11 changes: 7 additions & 4 deletions apps/builder/pages/api/typebots/[typebotId].ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,18 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}

if (req.method === 'DELETE') {
const typebots = await prisma.typebot.updateMany({
where: canWriteTypebot(typebotId, user),
data: { isArchived: true },
})
await archiveResults(res)({
typebotId,
user,
resultsFilter: { typebotId },
})
await prisma.publicTypebot.deleteMany({
where: { typebot: canWriteTypebot(typebotId, user) },
})
const typebots = await prisma.typebot.updateMany({
where: canWriteTypebot(typebotId, user),
data: { isArchived: true },
})
return res.send({ typebots })
}
if (req.method === 'PUT') {
Expand Down
2 changes: 1 addition & 1 deletion apps/builder/playwright/global-setup.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FullConfig } from '@playwright/test'
import { setupDatabase, teardownDatabase } from './services/database'
import { setupDatabase, teardownDatabase } from 'utils/playwright/databaseSetup'

// eslint-disable-next-line @typescript-eslint/no-var-requires
require('dotenv').config({ path: '.env' })
Expand Down
13 changes: 0 additions & 13 deletions apps/builder/playwright/services/browser.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
import { Page } from '@playwright/test'

export const refreshUser = async () => {
await fetch('/api/auth/session?update')
const event = new Event('visibilitychange')
document.dispatchEvent(event)
}

export const mockSessionResponsesToOtherUser = async (page: Page) =>
page.route('/api/auth/session', (route) => {
if (route.request().method() === 'GET') {
return route.fulfill({
status: 200,
body: '{"user":{"id":"otherUserId","name":"James Doe","email":"other-user@email.com","emailVerified":null,"image":"https://avatars.githubusercontent.com/u/16015833?v=4","stripeId":null,"graphNavigation": "TRACKPAD"}}',
})
}
return route.continue()
})
Loading

5 comments on commit bfed599

@vercel
Copy link

@vercel vercel bot commented on bfed599 Oct 6, 2022

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-alpha – ./apps/viewer

finplex.be
bot.aws.bj
biiapp.com
247987.com
ns8.vn
8jours.top
yobot.me
sat.cr8.ai
bot.aipr.kr
minipost.uk
bt.id8rs.com
vhpage.cr8.ai
bot.krdfy.com
bot.lalmon.com
ticketfute.com
bot.enreso.org
an.nigerias.io
apo.nigerias.io
ar.nigerias.io
am.nigerias.io
apr.nigerias.io
aso.nigerias.io
bot.ageenda.com
bot.artiweb.app
eventhub.com.au
games.klujo.com
bot.tc-mail.com
sakuranembro.it
chat.sureb4.com
typebot.aloe.do
bot.piccinato.co
bot.upfunnel.art
botc.ceox.com.br
clo.closeer.work
faqs.nigerias.io
feedback.ofx.one
kw.wpwakanda.com
form.syncwin.com
myrentalhost.com
stan.vselise.com
voicehelp.cr8.ai
app.chatforms.net
typebot.aloe.bot
bot.agfunnel.tech
bot.phuonghub.com
bot.hostnation.de
bot.maitempah.com
fmm.wpwakanda.com
bot.reviewzer.com
cares.urlabout.me
gentleman-shop.fr
k1.kandabrand.com
lb.ticketfute.com
ov1.wpwakanda.com
1988.bouclidom.com
bot.neferlopez.com
bot.megafox.com.br
ov3.wpwakanda.com
andreimayer.com.br
ov2.wpwakanda.com
bots.robomotion.io
dicanatural.online
cadu.uninta.edu.br
goalsettingbot.com
positivobra.com.br
bot.eventhub.com.au
demo.botscientis.us
this-is-a-test.com
survey.digienge.io
zap.techadviser.in
bot.digitalbled.com
carsalesenquiry.com
kbsub.wpwakanda.com
forms.webisharp.com
live.botscientis.us
nutrisamirbayde.com
mentoria.omelhor.vc
quest.wpwakanda.com
test.botscientis.us
order.maitempah.com
typebot.stillio.com
bium.gratirabbit.com
bot.ansuraniphone.my
bot.cotemeuplano.com
chatbee.agfunnel.com
chat.hayurihijab.com
click.sevenoways.com
get.freebotoffer.xyz
connect.growthguy.in
offer.botscientis.us
kuiz.sistemniaga.com
tenorioadvogados.com
uppity.wpwakanda.com
talkbot.agfunnel.com
aidigitalmarketing.kr
abutton.wpwakanda.com
bbutton.wpwakanda.com
bot.meuesocial.com.br
bot.incusservices.com
bot.ramonmatos.com.br

@vercel
Copy link

@vercel vercel bot commented on bfed599 Oct 6, 2022

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-typebot-io.vercel.app
builder-v2-git-main-typebot-io.vercel.app
app.typebot.io

@vercel
Copy link

@vercel vercel bot commented on bfed599 Oct 6, 2022

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 bfed599 Oct 6, 2022

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 bfed599 Oct 6, 2022

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-git-main-typebot-io.vercel.app
docs.typebot.io
docs-typebot-io.vercel.app

Please sign in to comment.