Skip to content

Commit

Permalink
馃搱 Send onboarding replies to PostHog
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed Feb 2, 2024
1 parent ce79e89 commit fd4867f
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 36 deletions.
6 changes: 3 additions & 3 deletions apps/builder/src/features/account/UserProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ export const UserProvider = ({ children }: { children: ReactNode }) => {
if (isNotDefined(user)) return
const newUser = { ...user, ...updates }
setUser(newUser)
saveUser(newUser)
saveUser(updates)
}

const saveUser = useDebouncedCallback(
async (newUser?: Partial<User>) => {
async (updates: Partial<User>) => {
if (isNotDefined(user)) return
const { error } = await updateUserQuery(user.id, { ...user, ...newUser })
const { error } = await updateUserQuery(user.id, updates)
if (error) showToast({ title: error.name, description: error.message })
await refreshUser()
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
Stack,
Heading,
useColorMode,
Menu,
MenuButton,
MenuList,
Expand Down Expand Up @@ -34,7 +33,6 @@ export const UserPreferencesForm = () => {
const { getLanguage } = useTolgee()
const router = useRouter()
const { t } = useTranslate()
const { colorMode } = useColorMode()
const { user, updateUser } = useUser()

useEffect(() => {
Expand Down Expand Up @@ -117,7 +115,7 @@ export const UserPreferencesForm = () => {
defaultValue={
user?.preferredAppAppearance
? user.preferredAppAppearance
: colorMode
: 'system'
}
onChange={changeAppearance}
/>
Expand Down
6 changes: 3 additions & 3 deletions apps/builder/src/features/account/queries/updateUserQuery.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { User } from '@typebot.io/prisma'
import { sendRequest } from '@typebot.io/lib'
import { User } from '@typebot.io/schemas'

export const updateUserQuery = async (id: string, user: User) =>
export const updateUserQuery = async (id: string, user: Partial<User>) =>
sendRequest({
url: `/api/users/${id}`,
method: 'PUT',
method: 'PATCH',
body: user,
})
65 changes: 46 additions & 19 deletions apps/builder/src/features/auth/components/OnboardingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ export const OnboardingPage = () => {
const confettiCanon = useRef<confetti.CreateTypes>()
const { user, updateUser } = useUser()
const [currentStep, setCurrentStep] = useState<number>(user?.name ? 2 : 1)
const [onboardingReplies, setOnboardingReplies] = useState<{
name?: string
company?: string
onboardingCategories?: string[]
referral?: string
}>({})

const isNewUser =
user &&
Expand All @@ -49,30 +55,58 @@ export const OnboardingPage = () => {
})
}

const updateUserInfo = async (answer: {
const setOnboardingAnswer = async (answer: {
message: string
blockId: string
}) => {
const isOtherItem = [
'cl126pv7n001o2e6dajltc4qz',
'saw904bfzgspmt0l24achtiy',
].includes(answer.blockId)
if (isOtherItem) return
const isName = answer.blockId === 'cl126820m000g2e6dfleq78bt'
const isCompany = answer.blockId === 'cl126jioz000v2e6dwrk1f2cb'
const isCategories = answer.blockId === 'cl126lb8v00142e6duv5qe08l'
if (isName) updateUser({ name: answer.message })
const isOtherCategory = answer.blockId === 'cl126pv7n001o2e6dajltc4qz'
const isReferral = answer.blockId === 'phcb0s1e9qgp0f8l2amcu7xr'
const isOtherReferral = answer.blockId === 'saw904bfzgspmt0l24achtiy'
if (isName)
setOnboardingReplies((prev) => ({ ...prev, name: answer.message }))
if (isCategories) {
const onboardingCategories = answer.message.split(', ')
updateUser({ onboardingCategories })
setOnboardingReplies((prev) => ({
...prev,
onboardingCategories,
}))
}
if (isOtherCategory)
setOnboardingReplies((prev) => ({
...prev,
categories: prev.onboardingCategories
? [...prev.onboardingCategories, answer.message]
: [answer.message],
}))
if (isCompany) {
updateUser({ company: answer.message })
setOnboardingReplies((prev) => ({ ...prev, company: answer.message }))
if (confettiCanon.current) shootConfettis(confettiCanon.current)
}
if (isReferral)
setOnboardingReplies((prev) => ({ ...prev, referral: answer.message }))
if (isOtherReferral)
setOnboardingReplies((prev) => ({ ...prev, referral: answer.message }))
setCurrentStep((prev) => prev + 1)
}

const skipOnboarding = () => {
updateUser(onboardingReplies)
replace({ pathname: '/typebots', query })
}

const updateUserAndProceedToTypebotCreation = () => {
updateUser(onboardingReplies)
setTimeout(() => {
replace({
pathname: '/typebots',
query: { ...query, isFirstBot: true },
})
}, 2000)
}

if (!isNewUser) return null
return (
<VStack h="100vh" flexDir="column" justifyContent="center" spacing="10">
Expand All @@ -83,7 +117,7 @@ export const OnboardingPage = () => {
right="5"
variant="ghost"
size="sm"
onClick={() => replace({ pathname: '/typebots', query })}
onClick={skipOnboarding}
>
{t('skip')}
</Button>
Expand All @@ -93,15 +127,8 @@ export const OnboardingPage = () => {
typebot={env.NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID}
style={{ borderRadius: '1rem' }}
prefilledVariables={{ Name: user?.name, Email: user?.email }}
onEnd={() => {
setTimeout(() => {
replace({
pathname: '/typebots',
query: { ...query, isFirstBot: true },
})
}, 2000)
}}
onAnswer={updateUserInfo}
onEnd={updateUserAndProceedToTypebotCreation}
onAnswer={setOnboardingAnswer}
/>
</Flex>
<chakra.canvas
Expand Down
21 changes: 18 additions & 3 deletions apps/builder/src/pages/api/users/[userId].ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ 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 { Prisma, User } from '@typebot.io/prisma'
import { User } from '@typebot.io/schemas'
import { trackEvents } from '@typebot.io/lib/telemetry/trackEvents'
import { Prisma } from '@typebot.io/prisma'

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req, res)
if (!user) return notAuthenticated(res)

const id = req.query.userId as string
if (req.method === 'PUT') {
if (req.method === 'PATCH') {
const data = (
typeof req.body === 'string' ? JSON.parse(req.body) : req.body
) as User
) as Partial<User>
const typebots = await prisma.user.update({
where: { id },
data: {
Expand All @@ -22,6 +24,19 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
data.displayedInAppNotifications ?? Prisma.DbNull,
},
})
if (data.onboardingCategories || data.referral || data.company || data.name)
await trackEvents([
{
name: 'User updated',
userId: user.id,
data: {
name: data.name ?? undefined,
onboardingCategories: data.onboardingCategories ?? undefined,
referral: data.referral ?? undefined,
company: data.company ?? undefined,
},
},
])
return res.send({ typebots })
}
return methodNotAllowed(res)
Expand Down
8 changes: 4 additions & 4 deletions apps/docs/self-hosting/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,9 @@ The related environment variables are listed here but you are probably not inter

<Accordion title="PostHog">

| Parameter | Default | Description |
| ---------------------------- | ----------------------- | ---------------- |
| NEXT_PUBLIC_POSTHOG_API_KEY | | PostHog API Key |
| NEXT_PUBLIC_POSTHOG_API_HOST | https://app.posthog.com | PostHog API Host |
| Parameter | Default | Description |
| ------------------------ | ----------------------- | ---------------- |
| NEXT_PUBLIC_POSTHOG_KEY | | PostHog API Key |
| NEXT_PUBLIC_POSTHOG_HOST | https://app.posthog.com | PostHog API Host |

</Accordion>
7 changes: 6 additions & 1 deletion packages/lib/telemetry/trackEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ export const trackEvents = async (events: TelemetryEvent[]) => {
client.capture({
distinctId: event.userId,
event: event.name,
properties: 'data' in event ? event.data : undefined,
properties:
event.name === 'User updated'
? { $set: event.data }
: 'data' in event
? event.data
: undefined,
groups,
})
})
Expand Down
1 change: 1 addition & 0 deletions packages/prisma/mysql/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ model User {
image String? @db.VarChar(1000)
company String?
onboardingCategories Json
referral String?
graphNavigation GraphNavigation?
preferredAppAppearance String?
accounts Account[]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "User" ADD COLUMN "referral" TEXT;
1 change: 1 addition & 0 deletions packages/prisma/postgresql/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ model User {
image String?
company String?
onboardingCategories Json
referral String?
graphNavigation GraphNavigation?
preferredAppAppearance String?
accounts Account[]
Expand Down
13 changes: 13 additions & 0 deletions packages/schemas/features/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ const userCreatedEventSchema = userEvent.merge(
})
)

const userUpdatedEventSchema = userEvent.merge(
z.object({
name: z.literal('User updated'),
data: z.object({
name: z.string().optional(),
onboardingCategories: z.array(z.string()).optional(),
referral: z.string().optional(),
company: z.string().optional(),
}),
})
)

const typebotCreatedEventSchema = typebotEvent.merge(
z.object({
name: z.literal('Typebot created'),
Expand Down Expand Up @@ -129,6 +141,7 @@ export const eventSchema = z.discriminatedUnion('name', [
subscriptionAutoUpdatedEventSchema,
workspacePastDueEventSchema,
workspaceNotPastDueEventSchema,
userUpdatedEventSchema,
])

export type TelemetryEvent = z.infer<typeof eventSchema>
1 change: 1 addition & 0 deletions packages/schemas/features/user/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const userSchema = z.object({
image: z.string().nullable(),
company: z.string().nullable(),
onboardingCategories: z.array(z.string()),
referral: z.string().nullable(),
graphNavigation: z.nativeEnum(GraphNavigation),
preferredAppAppearance: z.string().nullable(),
displayedInAppNotifications: displayedInAppNotificationsSchema.nullable(),
Expand Down

0 comments on commit fd4867f

Please sign in to comment.