2
0

🚸 (editor) Add graph gesture notification

This commit is contained in:
Baptiste Arnaud
2024-01-24 10:15:40 +01:00
parent d85a03f621
commit bf6c258edc
17 changed files with 154 additions and 59 deletions

View File

@ -0,0 +1,33 @@
import { colors } from '@/lib/theme'
import { useColorMode, useColorModeValue } from '@chakra-ui/react'
import { Toaster as SonnerToaster } from 'sonner'
export const Toaster = () => {
const { colorMode } = useColorMode()
const theme = useColorModeValue(
{
bg: undefined,
actionBg: colors.blue[500],
actionColor: undefined,
},
{
bg: colors.gray[900],
actionBg: colors.blue[400],
actionColor: 'white',
}
)
return (
<SonnerToaster
theme={colorMode}
toastOptions={{
actionButtonStyle: {
backgroundColor: theme.actionBg,
color: theme.actionColor,
},
style: {
backgroundColor: theme.bg,
},
}}
/>
)
}

View File

@ -643,3 +643,11 @@ export const XCircleIcon = (props: IconProps) => (
<path d="m9 9 6 6" />
</Icon>
)
export const LightBulbIcon = (props: IconProps) => (
<Icon viewBox="0 0 24 24" {...featherIconsBaseProps} {...props}>
<path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5" />
<path d="M9 18h6" />
<path d="M10 22h4" />
</Icon>
)

View File

@ -2,7 +2,7 @@ import { signOut, useSession } from 'next-auth/react'
import { useRouter } from 'next/router'
import { createContext, ReactNode, useEffect, useState } from 'react'
import { isDefined, isNotDefined } from '@typebot.io/lib'
import { User } from '@typebot.io/prisma'
import { User } from '@typebot.io/schemas'
import { setUser as setSentryUser } from '@sentry/nextjs'
import { useToast } from '@/hooks/useToast'
import { updateUserQuery } from './queries/updateUserQuery'

View File

@ -17,25 +17,17 @@ import {
SettingsIcon,
} from '@/components/icons'
import { useTypebot } from '../providers/TypebotProvider'
import { useUser } from '@/features/account/hooks/useUser'
import { useRouter } from 'next/router'
import React, { useEffect, useState } from 'react'
import React, { useState } from 'react'
import { EditorSettingsModal } from './EditorSettingsModal'
import { parseDefaultPublicId } from '@/features/publish/helpers/parseDefaultPublicId'
import { useTranslate } from '@tolgee/react'
export const BoardMenuButton = (props: FlexProps) => {
const { query } = useRouter()
const { typebot } = useTypebot()
const { user } = useUser()
const [isDownloading, setIsDownloading] = useState(false)
const { isOpen, onOpen, onClose } = useDisclosure()
const { t } = useTranslate()
useEffect(() => {
if (user && !user.graphNavigation && !query.isFirstBot) onOpen()
}, [onOpen, query.isFirstBot, user, user?.graphNavigation])
const downloadFlow = () => {
assert(typebot)
setIsDownloading(true)
@ -54,7 +46,7 @@ export const BoardMenuButton = (props: FlexProps) => {
}
const redirectToDocumentation = () =>
window.open('https://docs.typebot.io/get-started/overview', '_blank')
window.open('https://docs.typebot.io/editor/graph', '_blank')
return (
<Flex

View File

@ -29,6 +29,10 @@ import { useGroupsStore } from '../hooks/useGroupsStore'
import { useShallow } from 'zustand/react/shallow'
import { projectMouse } from '../helpers/projectMouse'
import { useKeyboardShortcuts } from '@/hooks/useKeyboardShortcuts'
import { useUser } from '@/features/account/hooks/useUser'
import { graphGestureNotficationKey } from '@typebot.io/schemas/features/user/constants'
import { toast } from 'sonner'
import { LightBulbIcon } from '@/components/icons'
const maxScale = 2
const minScale = 0.3
@ -55,6 +59,7 @@ export const Graph = ({
setDraggedItem,
} = useBlockDnd()
const { pasteGroups, createGroup } = useTypebot()
const { user, updateUser } = useUser()
const {
isReadOnly,
setGraphPosition: setGlobalGraphPosition,
@ -184,6 +189,26 @@ export const Graph = ({
setLastMouseClickPosition(
projectMouse({ x: e.clientX, y: e.clientY }, graphPosition)
)
} else if (
user &&
!user?.displayedInAppNotifications?.[graphGestureNotficationKey]
) {
toast.info('To move the graph using your mouse, hold the Space bar', {
action: {
label: 'More info',
onClick: () => {
window.open('https://docs.typebot.io/editor/graph', '_blank')
},
},
duration: 30000,
icon: <LightBulbIcon w="20px" h="20px" />,
})
updateUser({
displayedInAppNotifications: {
...user.displayedInAppNotifications,
[graphGestureNotficationKey]: true,
},
})
}
setSelectBoxCoordinates(undefined)
setOpenedBlockId(undefined)

View File

@ -22,7 +22,7 @@ import { isCloudProdInstance } from '@/helpers/isCloudProdInstance'
import { initPostHogIfEnabled } from '@/features/telemetry/posthog'
import { TolgeeProvider, useTolgeeSSR } from '@tolgee/react'
import { tolgee } from '@/lib/tolgee'
import { Toaster } from 'sonner'
import { Toaster } from '@/components/Toaster'
initPostHogIfEnabled()
@ -63,8 +63,8 @@ const App = ({ Component, pageProps }: AppProps) => {
return (
<TolgeeProvider tolgee={ssrTolgee}>
<ToastContainer />
<Toaster />
<ChakraProvider theme={customTheme}>
<Toaster />
<SessionProvider session={pageProps.session}>
<UserProvider>
<TypebotProvider typebotId={typebotId}>

View File

@ -2,7 +2,7 @@ import prisma from '@typebot.io/lib/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
import { getAuthenticatedUser } from '@/features/auth/helpers/getAuthenticatedUser'
import { methodNotAllowed, notAuthenticated } from '@typebot.io/lib/api'
import { User } from '@typebot.io/prisma'
import { Prisma, User } from '@typebot.io/prisma'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req, res)
@ -18,6 +18,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
data: {
...data,
onboardingCategories: data.onboardingCategories ?? [],
displayedInAppNotifications:
data.displayedInAppNotifications ?? Prisma.DbNull,
},
})
return res.send({ typebots })

View File

@ -64,15 +64,6 @@
"group": "Get Started",
"pages": ["get-started/introduction", "get-started/overview"]
},
{
"group": "Workspace",
"pages": [
"workspace",
"workspace/add-members-and-guests",
"workspace/subscription",
"workspace/preferences"
]
},
{
"group": "Flow",
"pages": [
@ -191,6 +182,15 @@
"group": "Results",
"pages": ["results/overview", "results/analytics"]
},
{
"group": "Workspace",
"pages": [
"workspace",
"workspace/add-members-and-guests",
"workspace/subscription",
"workspace/preferences"
]
},
{
"group": "Guides",
"pages": [

View File

@ -1,4 +1,5 @@
import { User } from '@typebot.io/prisma'
import { graphGestureNotficationKey } from '@typebot.io/schemas/features/user/constants'
export const mockedUser: User = {
id: 'userId',
@ -13,4 +14,7 @@ export const mockedUser: User = {
lastActivityAt: new Date('2022-01-01'),
onboardingCategories: [],
updatedAt: new Date('2022-01-01'),
displayedInAppNotifications: {
[graphGestureNotficationKey]: true,
},
}

View File

@ -144,6 +144,8 @@ export const updateUser = (data: Partial<User>) =>
data: {
...data,
onboardingCategories: data.onboardingCategories ?? [],
displayedInAppNotifications:
data.displayedInAppNotifications ?? Prisma.DbNull,
},
where: {
id: userId,

View File

@ -59,6 +59,7 @@ model User {
workspaces MemberInWorkspace[]
sessions Session[]
bannedIps BannedIp[]
displayedInAppNotifications Json?
}
model ApiToken {

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "User" ADD COLUMN "displayedInAppNotifications" JSONB;

View File

@ -55,6 +55,7 @@ model User {
workspaces MemberInWorkspace[]
sessions Session[]
bannedIps BannedIp[]
displayedInAppNotifications Json?
}
model ApiToken {

View File

@ -0,0 +1 @@
export const graphGestureNotficationKey = 'graphGestureNotification'

View File

@ -0,0 +1,22 @@
import { GraphNavigation, User as PrismaUser } from '@typebot.io/prisma'
import { z } from '../../zod'
const displayedInAppNotificationsSchema = z.record(z.boolean())
export const userSchema = z.object({
id: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
lastActivityAt: z.date(),
name: z.string().nullable(),
email: z.string().nullable(),
emailVerified: z.date().nullable(),
image: z.string().nullable(),
company: z.string().nullable(),
onboardingCategories: z.array(z.string()),
graphNavigation: z.nativeEnum(GraphNavigation),
preferredAppAppearance: z.string().nullable(),
displayedInAppNotifications: displayedInAppNotificationsSchema.nullable(),
}) satisfies z.ZodType<PrismaUser>
export type User = z.infer<typeof userSchema>

View File

@ -13,3 +13,4 @@ export * from './features/workspace'
export * from './features/items'
export * from './features/analytics'
export * from './features/events'
export * from './features/user/schema'

View File

@ -18,6 +18,7 @@ const inspectUser = async () => {
},
select: {
name: true,
createdAt: true,
lastActivityAt: true,
company: true,
onboardingCategories: true,