import { Button, HStack, IconButton, Stack, Tooltip, Text, Menu, MenuButton, MenuList, MenuItem, useDisclosure, ButtonProps, useColorModeValue, } from '@chakra-ui/react' import { ChevronLeftIcon, CloudOffIcon, LockedIcon, UnlockedIcon, } from '@/components/icons' import { useTypebot } from '@/features/editor/providers/TypebotProvider' import { useWorkspace } from '@/features/workspace/WorkspaceProvider' import { InputBlockType } from '@typebot.io/schemas' import { useRouter } from 'next/router' import { isNotDefined } from '@typebot.io/lib' import { ChangePlanModal } from '@/features/billing/components/ChangePlanModal' import { isFreePlan } from '@/features/billing/helpers/isFreePlan' import { parseTimeSince } from '@/helpers/parseTimeSince' import { useI18n } from '@/locales' import { trpc } from '@/lib/trpc' import { useToast } from '@/hooks/useToast' import { parseDefaultPublicId } from '../helpers/parseDefaultPublicId' export const PublishButton = (props: ButtonProps) => { const t = useI18n() const warningTextColor = useColorModeValue('red.300', 'red.600') const { workspace } = useWorkspace() const { push, query } = useRouter() const { isOpen, onOpen, onClose } = useDisclosure() const { isPublished, publishedTypebot, restorePublishedTypebot, typebot, isSavingLoading, updateTypebot, save, } = useTypebot() const { showToast } = useToast() const { typebot: { getPublishedTypebot: { refetch: refetchPublishedTypebot }, }, } = trpc.useContext() const { mutate: publishTypebotMutate, isLoading: isPublishing } = trpc.typebot.publishTypebot.useMutation({ onError: (error) => showToast({ title: 'Error while publishing typebot', description: error.message, }), onSuccess: () => { if (!publishedTypebot) push(`/typebots/${query.typebotId}/share`) refetchPublishedTypebot() }, }) const { mutate: unpublishTypebotMutate, isLoading: isUnpublishing } = trpc.typebot.unpublishTypebot.useMutation({ onError: (error) => showToast({ title: 'Error while unpublishing typebot', description: error.message, }), onSuccess: () => { if (!publishedTypebot) push(`/typebots/${query.typebotId}/share`) refetchPublishedTypebot() }, }) const hasInputFile = typebot?.groups .flatMap((g) => g.blocks) .some((b) => b.type === InputBlockType.FILE) const handlePublishClick = async () => { if (!typebot?.id) return if (isFreePlan(workspace) && hasInputFile) return onOpen() if (!typebot.publicId) { await updateTypebot({ updates: { publicId: parseDefaultPublicId(typebot.name, typebot.id), }, save: true, }) } else await save() publishTypebotMutate({ typebotId: typebot.id, }) } const unpublishTypebot = async () => { if (!typebot?.id) return if (typebot.isClosed) await updateTypebot({ updates: { isClosed: false }, save: true }) unpublishTypebotMutate({ typebotId: typebot?.id, }) } const closeTypebot = async () => { await updateTypebot({ updates: { isClosed: true }, save: true }) } const openTypebot = async () => { await updateTypebot({ updates: { isClosed: false }, save: true }) } return ( {!publishedTypebot?.version ? ( This will deploy your bot with an updated engine. Make sure to test it properly in preview mode before publishing. ) : ( There are non published changes. )} Published version from{' '} {publishedTypebot && parseTimeSince(publishedTypebot.updatedAt.toString())}{' '} ago } isDisabled={isNotDefined(publishedTypebot) || isPublished} > {publishedTypebot && ( } aria-label="Show published typebot menu" size="sm" isDisabled={isPublishing || isSavingLoading} /> {!isPublished && ( Restore published version )} {!typebot?.isClosed ? ( }> Close typebot to new responses ) : ( }> Reopen typebot to new responses )} }> Unpublish typebot )} ) }