Add WhatsApp integration beta test (#722)

Related to #401
This commit is contained in:
Baptiste Arnaud
2023-08-29 10:01:28 +02:00
parent 036b407a11
commit b852b4af0b
136 changed files with 6694 additions and 5383 deletions

View File

@@ -8,6 +8,9 @@ import { smtpCredentialsSchema } from '@typebot.io/schemas/features/blocks/integ
import { encrypt } from '@typebot.io/lib/api/encryption'
import { z } from 'zod'
import { isWriteWorkspaceForbidden } from '@/features/workspace/helpers/isWriteWorkspaceForbidden copy'
import { whatsAppCredentialsSchema } from '@typebot.io/schemas/features/whatsapp'
import { Credentials } from '@typebot.io/schemas'
import { isDefined } from '@typebot.io/lib/utils'
const inputShape = {
data: true,
@@ -33,6 +36,7 @@ export const createCredentials = authenticatedProcedure
smtpCredentialsSchema.pick(inputShape),
googleSheetsCredentialsSchema.pick(inputShape),
openAICredentialsSchema.pick(inputShape),
whatsAppCredentialsSchema.pick(inputShape),
]),
})
)
@@ -42,6 +46,11 @@ export const createCredentials = authenticatedProcedure
})
)
.mutation(async ({ input: { credentials }, ctx: { user } }) => {
if (await isNotAvailable(credentials.name, credentials.type))
throw new TRPCError({
code: 'CONFLICT',
message: 'Credentials already exist.',
})
const workspace = await prisma.workspace.findFirst({
where: {
id: credentials.workspaceId,
@@ -64,3 +73,14 @@ export const createCredentials = authenticatedProcedure
})
return { credentialsId: createdCredentials.id }
})
const isNotAvailable = async (name: string, type: Credentials['type']) => {
if (type !== 'whatsApp') return
const existingCredentials = await prisma.credentials.findFirst({
where: {
type,
name,
},
})
return isDefined(existingCredentials)
}

View File

@@ -30,6 +30,9 @@ export const deleteCredentials = authenticatedProcedure
const workspace = await prisma.workspace.findFirst({
where: {
id: workspaceId,
members: {
some: { userId: user.id, role: { in: ['ADMIN', 'MEMBER'] } },
},
},
select: { id: true, members: true },
})

View File

@@ -7,6 +7,7 @@ import { openAICredentialsSchema } from '@typebot.io/schemas/features/blocks/int
import { smtpCredentialsSchema } from '@typebot.io/schemas/features/blocks/integrations/sendEmail'
import { z } from 'zod'
import { isReadWorkspaceFobidden } from '@/features/workspace/helpers/isReadWorkspaceFobidden'
import { whatsAppCredentialsSchema } from '@typebot.io/schemas/features/whatsapp'
export const listCredentials = authenticatedProcedure
.meta({
@@ -24,7 +25,8 @@ export const listCredentials = authenticatedProcedure
type: stripeCredentialsSchema.shape.type
.or(smtpCredentialsSchema.shape.type)
.or(googleSheetsCredentialsSchema.shape.type)
.or(openAICredentialsSchema.shape.type),
.or(openAICredentialsSchema.shape.type)
.or(whatsAppCredentialsSchema.shape.type),
})
)
.output(

View File

@@ -1,9 +1,9 @@
import {
Button,
ButtonProps,
IconButton,
Menu,
MenuButton,
MenuButtonProps,
MenuItem,
MenuList,
Stack,
@@ -16,13 +16,14 @@ import { useToast } from '../../../hooks/useToast'
import { Credentials } from '@typebot.io/schemas'
import { trpc } from '@/lib/trpc'
type Props = Omit<MenuButtonProps, 'type'> & {
type Props = Omit<ButtonProps, 'type'> & {
type: Credentials['type']
workspaceId: string
currentCredentialsId?: string
onCredentialsSelect: (credentialId?: string) => void
onCreateNewClick: () => void
defaultCredentialLabel?: string
credentialsName: string
}
export const CredentialsDropdown = ({
@@ -32,6 +33,7 @@ export const CredentialsDropdown = ({
onCredentialsSelect,
onCreateNewClick,
defaultCredentialLabel,
credentialsName,
...props
}: Props) => {
const router = useRouter()
@@ -59,7 +61,8 @@ export const CredentialsDropdown = ({
},
})
const defaultCredentialsLabel = defaultCredentialLabel ?? `Select an account`
const defaultCredentialsLabel =
defaultCredentialLabel ?? `Select ${credentialsName}`
const currentCredential = data?.credentials.find(
(c) => c.id === currentCredentialsId
@@ -97,6 +100,19 @@ export const CredentialsDropdown = ({
mutate({ workspaceId, credentialsId })
}
if (data?.credentials.length === 0 && !defaultCredentialLabel) {
return (
<Button
colorScheme="gray"
textAlign="left"
leftIcon={<PlusIcon />}
onClick={onCreateNewClick}
{...props}
>
Add {credentialsName}
</Button>
)
}
return (
<Menu isLazy>
<MenuButton
@@ -107,7 +123,11 @@ export const CredentialsDropdown = ({
textAlign="left"
{...props}
>
<Text noOfLines={1} overflowY="visible" h="20px">
<Text
noOfLines={1}
overflowY="visible"
h={props.size === 'sm' ? '18px' : '20px'}
>
{currentCredential ? currentCredential.name : defaultCredentialsLabel}
</Text>
</MenuButton>