2
0

feat: Add collaboration

This commit is contained in:
Baptiste Arnaud
2022-02-24 11:13:19 +01:00
parent dd671a5d2c
commit b9dafa611e
63 changed files with 1932 additions and 148 deletions

View File

@ -0,0 +1,27 @@
import { createTransport } from 'nodemailer'
export const sendEmailNotification = ({
to,
subject,
content,
}: {
to: string
subject: string
content: string
}) => {
const transporter = createTransport({
host: process.env.AUTH_EMAIL_SERVER_HOST,
port: Number(process.env.AUTH_EMAIL_SERVER_PORT),
auth: {
user: process.env.AUTH_EMAIL_SERVER_USER,
pass: process.env.AUTH_EMAIL_SERVER_PASSWORD,
},
})
return transporter.sendMail({
from: `"${process.env.AUTH_EMAIL_FROM_NAME}" <${process.env.AUTH_EMAIL_FROM_EMAIL}>`,
to,
subject,
html: content,
})
}

View File

@ -0,0 +1,10 @@
import { User } from 'db'
import { NextApiRequest } from 'next'
import { getSession } from 'next-auth/react'
export const getAuthenticatedUser = async (
req: NextApiRequest
): Promise<User | undefined> => {
const session = await getSession({ req })
return session?.user as User | undefined
}

View File

@ -15,7 +15,7 @@ export const useFolders = ({
const { data, error, mutate } = useSWR<{ folders: DashboardFolder[] }, Error>(
`/api/folders?${params}`,
fetcher,
{ dedupingInterval: 0 }
{ dedupingInterval: process.env.NEXT_PUBLIC_E2E_TEST ? 0 : undefined }
)
if (error) onError(error)
return {

View File

@ -0,0 +1,48 @@
import { CollaboratorsOnTypebots } from 'db'
import { fetcher } from 'services/utils'
import useSWR from 'swr'
import { sendRequest } from 'utils'
export type Collaborator = CollaboratorsOnTypebots & {
user: {
name: string | null
image: string | null
email: string | null
}
}
export const useCollaborators = ({
typebotId,
onError,
}: {
typebotId?: string
onError: (error: Error) => void
}) => {
const { data, error, mutate } = useSWR<
{ collaborators: Collaborator[] },
Error
>(typebotId ? `/api/typebots/${typebotId}/collaborators` : null, fetcher)
if (error) onError(error)
return {
collaborators: data?.collaborators,
isLoading: !error && !data,
mutate,
}
}
export const updateCollaborator = (
typebotId: string,
userId: string,
updates: Partial<CollaboratorsOnTypebots>
) =>
sendRequest({
method: 'PUT',
url: `/api/typebots/${typebotId}/collaborators/${userId}`,
body: updates,
})
export const deleteCollaborator = (typebotId: string, userId: string) =>
sendRequest({
method: 'DELETE',
url: `/api/typebots/${typebotId}/collaborators/${userId}`,
})

View File

@ -0,0 +1,2 @@
export * from './results'
export * from './typebots'

View File

@ -0,0 +1,51 @@
import { CollaborationType, Invitation } from 'db'
import { fetcher } from 'services/utils'
import useSWR from 'swr'
import { sendRequest } from 'utils'
export const useInvitations = ({
typebotId,
onError,
}: {
typebotId?: string
onError: (error: Error) => void
}) => {
const { data, error, mutate } = useSWR<{ invitations: Invitation[] }, Error>(
typebotId ? `/api/typebots/${typebotId}/invitations` : null,
fetcher,
{ dedupingInterval: process.env.NEXT_PUBLIC_E2E_TEST ? 0 : undefined }
)
if (error) onError(error)
return {
invitations: data?.invitations,
isLoading: !error && !data,
mutate,
}
}
export const sendInvitation = (
typebotId: string,
{ email, type }: { email: string; type: CollaborationType }
) =>
sendRequest({
method: 'POST',
url: `/api/typebots/${typebotId}/invitations`,
body: { email, type },
})
export const updateInvitation = (
typebotId: string,
userId: string,
updates: Partial<Invitation>
) =>
sendRequest({
method: 'PUT',
url: `/api/typebots/${typebotId}/invitations/${userId}`,
body: updates,
})
export const deleteInvitation = (typebotId: string, userId: string) =>
sendRequest({
method: 'DELETE',
url: `/api/typebots/${typebotId}/invitations/${userId}`,
})

View File

@ -1,9 +1,9 @@
import { ResultWithAnswers, VariableWithValue } from 'models'
import useSWRInfinite from 'swr/infinite'
import { fetcher } from './utils'
import { stringify } from 'qs'
import { Answer } from 'db'
import { isDefined, sendRequest } from 'utils'
import { fetcher } from 'services/utils'
const paginationLimit = 50

View File

@ -39,7 +39,7 @@ import {
import shortId, { generate } from 'short-uuid'
import { Typebot } from 'models'
import useSWR from 'swr'
import { fetcher, omit, toKebabCase } from './utils'
import { fetcher, omit, toKebabCase } from '../utils'
import {
isBubbleStepType,
stepTypeHasItems,
@ -49,7 +49,7 @@ import {
import { deepEqual } from 'fast-equals'
import { stringify } from 'qs'
import { isChoiceInput, isConditionStep, sendRequest } from 'utils'
import { parseBlocksToPublicBlocks } from './publicTypebot'
import { parseBlocksToPublicBlocks } from '../publicTypebot'
export type TypebotInDashboard = Pick<
Typebot,
@ -66,7 +66,9 @@ export const useTypebots = ({
const { data, error, mutate } = useSWR<
{ typebots: TypebotInDashboard[] },
Error
>(`/api/typebots?${params}`, fetcher, { dedupingInterval: 0 })
>(`/api/typebots?${params}`, fetcher, {
dedupingInterval: process.env.NEXT_PUBLIC_E2E_TEST ? 0 : undefined,
})
if (error) onError(error)
return {
typebots: data?.typebots,
@ -109,7 +111,6 @@ export const duplicateTypebot = async (typebotId: string) => {
},
'id'
)
console.log(duplicatedTypebot)
return sendRequest<Typebot>({
url: `/api/typebots`,
method: 'POST',

View File

@ -1,7 +1,7 @@
import { Credentials } from 'models'
import useSWR from 'swr'
import { sendRequest } from 'utils'
import { fetcher } from './utils'
import { fetcher } from '../utils'
export const useCredentials = ({
userId,

View File

@ -2,7 +2,7 @@ import { CustomDomain } from 'db'
import { Credentials } from 'models'
import useSWR from 'swr'
import { sendRequest } from 'utils'
import { fetcher } from './utils'
import { fetcher } from '../utils'
export const useCustomDomains = ({
userId,

View File

@ -0,0 +1,3 @@
export * from './user'
export * from './customDomains'
export * from './credentials'

View File

@ -0,0 +1,42 @@
import { Typebot } from 'models'
import { fetcher } from 'services/utils'
import useSWR from 'swr'
import { isNotDefined } from 'utils'
export const useSharedTypebotsCount = ({
userId,
onError,
}: {
userId?: string
onError: (error: Error) => void
}) => {
const { data, error, mutate } = useSWR<{ count: number }, Error>(
userId ? `/api/users/${userId}/sharedTypebots?count=true` : null,
fetcher
)
if (error) onError(error)
return {
totalSharedTypebots: data?.count ?? 0,
isLoading: !error && isNotDefined(data?.count),
mutate,
}
}
export const useSharedTypebots = ({
userId,
onError,
}: {
userId?: string
onError: (error: Error) => void
}) => {
const { data, error, mutate } = useSWR<
{ sharedTypebots: Pick<Typebot, 'name' | 'id' | 'publishedTypebotId'>[] },
Error
>(userId ? `/api/users/${userId}/sharedTypebots` : null, fetcher)
if (error) onError(error)
return {
sharedTypebots: data?.sharedTypebots,
isLoading: !error && isNotDefined(data),
mutate,
}
}