@greatapps/common 1.1.650 → 1.1.652

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { useEffect, useRef } from "react";
2
+ import { useEffect, useRef, useState } from "react";
3
3
  import { useAuth } from "../../providers/auth.provider";
4
4
  import { useIsDefaultWhitelabel, useWhitelabel } from "../../providers/whitelabel.provider";
5
5
  import { useActiveSubscription } from "../../modules/subscriptions/hooks/find-active-subscription.hook";
@@ -39,8 +39,9 @@ function hideCrisp() {
39
39
  function showCrisp() {
40
40
  crispDo("chat:show");
41
41
  }
42
- const FREE_PLAN_WELCOME_PENDING_KEY = "crisp:free-plan-welcome:pending";
42
+ const FREE_PLAN_ID = 5;
43
43
  const FREE_PLAN_WELCOME_SHOWN_KEY = "crisp:free-plan-welcome:shown";
44
+ const FREE_PLAN_WELCOME_QUERY_FLAG = "createNew";
44
45
  const FREE_PLAN_WELCOME_MESSAGE = `Oi! Tenho uma novidade exclusiva para voc\xEA \u{1F389}
45
46
 
46
47
  Criamos o Plano Iniciante pensando exatamente em voc\xEA: R$ 14,90/m\xEAs para quem j\xE1 deu o primeiro passo e quer ir al\xE9m.
@@ -48,13 +49,6 @@ Criamos o Plano Iniciante pensando exatamente em voc\xEA: R$ 14,90/m\xEAs para q
48
49
  Com ele voc\xEA conecta seu pr\xF3prio dom\xEDnio, publica at\xE9 3 p\xE1ginas e libera recursos como scripts, API Meta, exporta\xE7\xE3o de leads e possibilidade de contratar GreatAI.
49
50
 
50
51
  Acesse o menu "Assinaturas" e assine agora!`;
51
- function markFreePlanWelcomePending(userId) {
52
- try {
53
- if (typeof window === "undefined") return;
54
- window.localStorage.setItem(FREE_PLAN_WELCOME_PENDING_KEY, String(userId));
55
- } catch {
56
- }
57
- }
58
52
  function sendCrispMessage(text) {
59
53
  safeCrispPush(["do", "message:show", ["text", text]]);
60
54
  }
@@ -138,17 +132,22 @@ function CrispEmbed() {
138
132
  } catch {
139
133
  }
140
134
  }, [user, account, isV4, shouldLoadCrisp, subscription?.plan_name]);
135
+ const [isFreshSignup, setIsFreshSignup] = useState(false);
141
136
  useEffect(() => {
142
- if (!user || !shouldLoadCrisp) return;
143
137
  try {
144
- const userId = String(user.id);
145
- const pending = window.localStorage.getItem(FREE_PLAN_WELCOME_PENDING_KEY);
146
- if (pending !== userId) return;
147
- const shownKey = `${FREE_PLAN_WELCOME_SHOWN_KEY}:${userId}`;
148
- if (window.localStorage.getItem(shownKey)) {
149
- window.localStorage.removeItem(FREE_PLAN_WELCOME_PENDING_KEY);
150
- return;
138
+ const params = new URLSearchParams(window.location.search);
139
+ if (params.get(FREE_PLAN_WELCOME_QUERY_FLAG) === "true") {
140
+ setIsFreshSignup(true);
151
141
  }
142
+ } catch {
143
+ }
144
+ }, []);
145
+ useEffect(() => {
146
+ if (!user || !shouldLoadCrisp || !isFreshSignup) return;
147
+ if (subscription?.id_plan !== FREE_PLAN_ID) return;
148
+ try {
149
+ const shownKey = `${FREE_PLAN_WELCOME_SHOWN_KEY}:${user.id}`;
150
+ if (window.localStorage.getItem(shownKey)) return;
152
151
  safeCrispPush([
153
152
  "on",
154
153
  "session:loaded",
@@ -158,16 +157,14 @@ function CrispEmbed() {
158
157
  }
159
158
  ]);
160
159
  window.localStorage.setItem(shownKey, "1");
161
- window.localStorage.removeItem(FREE_PLAN_WELCOME_PENDING_KEY);
162
160
  } catch {
163
161
  }
164
- }, [user, shouldLoadCrisp]);
162
+ }, [user, shouldLoadCrisp, isFreshSignup, subscription?.id_plan]);
165
163
  return null;
166
164
  }
167
165
  export {
168
166
  CrispEmbed,
169
167
  hideCrisp,
170
- markFreePlanWelcomePending,
171
168
  openCrispChat,
172
169
  openCrispHelpdesk,
173
170
  sendCrispMessage,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/embeds/CrispEmbed.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef } from 'react';\nimport { useAuth } from '../../providers/auth.provider';\nimport { useIsDefaultWhitelabel, useWhitelabel } from '../../providers/whitelabel.provider';\nimport { useActiveSubscription } from '../../modules/subscriptions/hooks/find-active-subscription.hook';\n\nconst V4_WHITELABEL_ID = 367568;\n\nconst PROFILE_LABELS: Record<string, string> = {\n owner: 'Proprietário',\n admin: 'Administrador',\n editor: 'Colaborador',\n viewer: 'Visualizador',\n};\n\nconst CRISP_WEBSITE_ID = '3339a3ec-b4c6-4aac-8b86-45668fb7655c';\nconst CRISP_SCRIPT_URL = 'https://client.crisp.chat/l.js';\nconst CRISP_LOAD_DELAY = 800;\n\n// ── Crisp helpers ──────────────────────────────────────────────\n\nfunction safeCrispPush(args: unknown[]) {\n try {\n const win = window as any;\n if (!win.$crisp) win.$crisp = [];\n win.$crisp.push(args);\n } catch {}\n}\n\nfunction crispDo(action: string) {\n safeCrispPush(['do', action]);\n}\n\nfunction crispSegment(segment: string) {\n safeCrispPush(['set', 'session:segments', [[segment]]]);\n}\n\nfunction crispSessionData(key: string, value: string) {\n safeCrispPush(['set', 'session:data', [[[key, value]]]]);\n}\n\n// ── Public API ─────────────────────────────────────────────────\n\nexport function openCrispHelpdesk() {\n crispDo('helpdesk:search');\n}\n\nexport function hideCrisp() {\n crispDo('chat:hide');\n}\n\nexport function showCrisp() {\n crispDo('chat:show');\n}\n\nconst FREE_PLAN_WELCOME_PENDING_KEY = 'crisp:free-plan-welcome:pending';\nconst FREE_PLAN_WELCOME_SHOWN_KEY = 'crisp:free-plan-welcome:shown';\nconst FREE_PLAN_WELCOME_MESSAGE = `Oi! Tenho uma novidade exclusiva para você 🎉\n\nCriamos o Plano Iniciante pensando exatamente em você: R$ 14,90/mês para quem já deu o primeiro passo e quer ir além.\n\nCom ele você conecta seu próprio domínio, publica até 3 páginas e libera recursos como scripts, API Meta, exportação de leads e possibilidade de contratar GreatAI.\n\nAcesse o menu \"Assinaturas\" e assine agora!`;\n\nexport function markFreePlanWelcomePending(userId: number | string) {\n try {\n if (typeof window === 'undefined') return;\n window.localStorage.setItem(FREE_PLAN_WELCOME_PENDING_KEY, String(userId));\n } catch {}\n}\n\nexport function sendCrispMessage(text: string) {\n safeCrispPush(['do', 'message:show', ['text', text]]);\n}\n\nexport function openCrispChat() {\n crispDo('chat:open');\n}\n\nexport function updateCrispUser(data: {\n email?: string;\n name?: string;\n lastName?: string;\n company?: string;\n ddi?: string;\n phone?: string;\n photo?: string;\n}) {\n try {\n if (data.email) safeCrispPush(['set', 'user:email', data.email]);\n\n const fullName = `${data.name ?? ''} ${data.lastName ?? ''}`.trim();\n if (fullName) safeCrispPush(['set', 'user:nickname', fullName]);\n\n if (data.company) safeCrispPush(['set', 'user:company', data.company]);\n\n const phone = `${data.ddi ?? ''}${data.phone ?? ''}`.trim();\n if (phone) safeCrispPush(['set', 'user:phone', phone]);\n\n if (data.photo?.startsWith('http')) {\n safeCrispPush(['set', 'user:avatar', data.photo]);\n }\n } catch {}\n}\n\n// ── Component ──────────────────────────────────────────────────\n\nexport function CrispEmbed() {\n const { user, account } = useAuth();\n const { whitelabel } = useWhitelabel();\n const { data: subscriptionData } = useActiveSubscription();\n const scriptLoadedRef = useRef(false);\n\n const isGreat = useIsDefaultWhitelabel();\n const subscription = subscriptionData?.data?.[0] ?? null;\n const isV4 = whitelabel?.id === V4_WHITELABEL_ID;\n const shouldLoadCrisp = isV4 || isGreat;\n\n // Load Crisp script (once, with 800ms delay)\n useEffect(() => {\n if (!user || !shouldLoadCrisp || scriptLoadedRef.current) return;\n\n try {\n const win = window as any;\n\n if (!win.$crisp) {\n win.$crisp = [];\n win.CRISP_WEBSITE_ID = CRISP_WEBSITE_ID;\n win.$crisp.push(['config', 'container:index', [100]]);\n }\n\n if (document.querySelector(`script[src=\"${CRISP_SCRIPT_URL}\"]`)) {\n scriptLoadedRef.current = true;\n return;\n }\n\n const timeout = setTimeout(() => {\n try {\n if (document.querySelector(`script[src=\"${CRISP_SCRIPT_URL}\"]`)) return;\n const s = document.createElement('script');\n s.src = CRISP_SCRIPT_URL;\n s.async = true;\n document.head.appendChild(s);\n scriptLoadedRef.current = true;\n } catch {}\n }, CRISP_LOAD_DELAY);\n\n return () => clearTimeout(timeout);\n } catch {}\n }, [user, shouldLoadCrisp]);\n\n // Identify user\n useEffect(() => {\n try {\n if (!user || !shouldLoadCrisp || !(window as any)?.$crisp) return;\n\n updateCrispUser({\n email: user.email,\n name: user.name,\n lastName: user.last_name,\n company: account?.name,\n ddi: user.ddi,\n phone: user.phone,\n photo: user.photo ?? undefined,\n });\n\n if (isV4) {\n crispSegment('company_v4');\n crispSessionData('Company', 'V4');\n } else {\n const planName = subscription?.plan_name ?? '';\n const profileLabel = PROFILE_LABELS[user.profile ?? ''] ?? user.profile ?? '';\n if (planName) crispSegment(`plano_${planName}`);\n if (profileLabel) crispSegment(`usuario_${profileLabel}`);\n if (planName) crispSessionData('Plano', planName);\n if (profileLabel) crispSessionData('Usuario', profileLabel);\n }\n } catch {}\n }, [user, account, isV4, shouldLoadCrisp, subscription?.plan_name]);\n\n // Mostra mensagem de boas-vindas no Crisp para quem acabou de se cadastrar no plano free.\n useEffect(() => {\n if (!user || !shouldLoadCrisp) return;\n try {\n const userId = String(user.id);\n const pending = window.localStorage.getItem(FREE_PLAN_WELCOME_PENDING_KEY);\n if (pending !== userId) return;\n\n const shownKey = `${FREE_PLAN_WELCOME_SHOWN_KEY}:${userId}`;\n if (window.localStorage.getItem(shownKey)) {\n window.localStorage.removeItem(FREE_PLAN_WELCOME_PENDING_KEY);\n return;\n }\n\n // Defer to session:loaded para garantir que a Crisp está pronta antes\n // de exibir a mensagem. Sem isso, comandos enfileirados pré-load podem\n // ser descartados silenciosamente.\n safeCrispPush([\n 'on',\n 'session:loaded',\n () => {\n sendCrispMessage(FREE_PLAN_WELCOME_MESSAGE);\n openCrispChat();\n },\n ]);\n window.localStorage.setItem(shownKey, '1');\n window.localStorage.removeItem(FREE_PLAN_WELCOME_PENDING_KEY);\n } catch {}\n }, [user, shouldLoadCrisp]);\n\n return null;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/embeds/CrispEmbed.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { useAuth } from '../../providers/auth.provider';\nimport { useIsDefaultWhitelabel, useWhitelabel } from '../../providers/whitelabel.provider';\nimport { useActiveSubscription } from '../../modules/subscriptions/hooks/find-active-subscription.hook';\n\nconst V4_WHITELABEL_ID = 367568;\n\nconst PROFILE_LABELS: Record<string, string> = {\n owner: 'Proprietário',\n admin: 'Administrador',\n editor: 'Colaborador',\n viewer: 'Visualizador',\n};\n\nconst CRISP_WEBSITE_ID = '3339a3ec-b4c6-4aac-8b86-45668fb7655c';\nconst CRISP_SCRIPT_URL = 'https://client.crisp.chat/l.js';\nconst CRISP_LOAD_DELAY = 800;\n\n// ── Crisp helpers ──────────────────────────────────────────────\n\nfunction safeCrispPush(args: unknown[]) {\n try {\n const win = window as any;\n if (!win.$crisp) win.$crisp = [];\n win.$crisp.push(args);\n } catch {}\n}\n\nfunction crispDo(action: string) {\n safeCrispPush(['do', action]);\n}\n\nfunction crispSegment(segment: string) {\n safeCrispPush(['set', 'session:segments', [[segment]]]);\n}\n\nfunction crispSessionData(key: string, value: string) {\n safeCrispPush(['set', 'session:data', [[[key, value]]]]);\n}\n\n// ── Public API ─────────────────────────────────────────────────\n\nexport function openCrispHelpdesk() {\n crispDo('helpdesk:search');\n}\n\nexport function hideCrisp() {\n crispDo('chat:hide');\n}\n\nexport function showCrisp() {\n crispDo('chat:show');\n}\n\nconst FREE_PLAN_ID = 5;\nconst FREE_PLAN_WELCOME_SHOWN_KEY = 'crisp:free-plan-welcome:shown';\nconst FREE_PLAN_WELCOME_QUERY_FLAG = 'createNew';\nconst FREE_PLAN_WELCOME_MESSAGE = `Oi! Tenho uma novidade exclusiva para você 🎉\n\nCriamos o Plano Iniciante pensando exatamente em você: R$ 14,90/mês para quem já deu o primeiro passo e quer ir além.\n\nCom ele você conecta seu próprio domínio, publica até 3 páginas e libera recursos como scripts, API Meta, exportação de leads e possibilidade de contratar GreatAI.\n\nAcesse o menu \"Assinaturas\" e assine agora!`;\n\nexport function sendCrispMessage(text: string) {\n safeCrispPush(['do', 'message:show', ['text', text]]);\n}\n\nexport function openCrispChat() {\n crispDo('chat:open');\n}\n\nexport function updateCrispUser(data: {\n email?: string;\n name?: string;\n lastName?: string;\n company?: string;\n ddi?: string;\n phone?: string;\n photo?: string;\n}) {\n try {\n if (data.email) safeCrispPush(['set', 'user:email', data.email]);\n\n const fullName = `${data.name ?? ''} ${data.lastName ?? ''}`.trim();\n if (fullName) safeCrispPush(['set', 'user:nickname', fullName]);\n\n if (data.company) safeCrispPush(['set', 'user:company', data.company]);\n\n const phone = `${data.ddi ?? ''}${data.phone ?? ''}`.trim();\n if (phone) safeCrispPush(['set', 'user:phone', phone]);\n\n if (data.photo?.startsWith('http')) {\n safeCrispPush(['set', 'user:avatar', data.photo]);\n }\n } catch {}\n}\n\n// ── Component ──────────────────────────────────────────────────\n\nexport function CrispEmbed() {\n const { user, account } = useAuth();\n const { whitelabel } = useWhitelabel();\n const { data: subscriptionData } = useActiveSubscription();\n const scriptLoadedRef = useRef(false);\n\n const isGreat = useIsDefaultWhitelabel();\n const subscription = subscriptionData?.data?.[0] ?? null;\n const isV4 = whitelabel?.id === V4_WHITELABEL_ID;\n const shouldLoadCrisp = isV4 || isGreat;\n\n // Load Crisp script (once, with 800ms delay)\n useEffect(() => {\n if (!user || !shouldLoadCrisp || scriptLoadedRef.current) return;\n\n try {\n const win = window as any;\n\n if (!win.$crisp) {\n win.$crisp = [];\n win.CRISP_WEBSITE_ID = CRISP_WEBSITE_ID;\n win.$crisp.push(['config', 'container:index', [100]]);\n }\n\n if (document.querySelector(`script[src=\"${CRISP_SCRIPT_URL}\"]`)) {\n scriptLoadedRef.current = true;\n return;\n }\n\n const timeout = setTimeout(() => {\n try {\n if (document.querySelector(`script[src=\"${CRISP_SCRIPT_URL}\"]`)) return;\n const s = document.createElement('script');\n s.src = CRISP_SCRIPT_URL;\n s.async = true;\n document.head.appendChild(s);\n scriptLoadedRef.current = true;\n } catch {}\n }, CRISP_LOAD_DELAY);\n\n return () => clearTimeout(timeout);\n } catch {}\n }, [user, shouldLoadCrisp]);\n\n // Identify user\n useEffect(() => {\n try {\n if (!user || !shouldLoadCrisp || !(window as any)?.$crisp) return;\n\n updateCrispUser({\n email: user.email,\n name: user.name,\n lastName: user.last_name,\n company: account?.name,\n ddi: user.ddi,\n phone: user.phone,\n photo: user.photo ?? undefined,\n });\n\n if (isV4) {\n crispSegment('company_v4');\n crispSessionData('Company', 'V4');\n } else {\n const planName = subscription?.plan_name ?? '';\n const profileLabel = PROFILE_LABELS[user.profile ?? ''] ?? user.profile ?? '';\n if (planName) crispSegment(`plano_${planName}`);\n if (profileLabel) crispSegment(`usuario_${profileLabel}`);\n if (planName) crispSessionData('Plano', planName);\n if (profileLabel) crispSessionData('Usuario', profileLabel);\n }\n } catch {}\n }, [user, account, isV4, shouldLoadCrisp, subscription?.plan_name]);\n\n // Captura `?createNew=true` da URL inicial. O register do gapps redireciona\n // para pages com esse flag, e localStorage não cruza origens — então o\n // sinal de \"acabou de se cadastrar\" vem via query string.\n const [isFreshSignup, setIsFreshSignup] = useState(false);\n useEffect(() => {\n try {\n const params = new URLSearchParams(window.location.search);\n if (params.get(FREE_PLAN_WELCOME_QUERY_FLAG) === 'true') {\n setIsFreshSignup(true);\n }\n } catch {}\n }, []);\n\n // Mostra mensagem de boas-vindas no Crisp para quem acabou de se cadastrar no plano free.\n useEffect(() => {\n if (!user || !shouldLoadCrisp || !isFreshSignup) return;\n if (subscription?.id_plan !== FREE_PLAN_ID) return;\n try {\n const shownKey = `${FREE_PLAN_WELCOME_SHOWN_KEY}:${user.id}`;\n if (window.localStorage.getItem(shownKey)) return;\n\n // Defer to session:loaded para garantir que a Crisp está pronta antes\n // de exibir a mensagem. Sem isso, comandos enfileirados pré-load podem\n // ser descartados silenciosamente.\n safeCrispPush([\n 'on',\n 'session:loaded',\n () => {\n sendCrispMessage(FREE_PLAN_WELCOME_MESSAGE);\n openCrispChat();\n },\n ]);\n window.localStorage.setItem(shownKey, '1');\n } catch {}\n }, [user, shouldLoadCrisp, isFreshSignup, subscription?.id_plan]);\n\n return null;\n}\n"],"mappings":"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","names":[]}
@@ -17,7 +17,6 @@ import { useRegister } from "../modules/auth/hooks/register.hook";
17
17
  import { useLogout } from "../modules/auth/hooks/logout.hook";
18
18
  import { useSocialGoogleLogin } from "../modules/auth/hooks/social-google-login.hook";
19
19
  import { useSocialGoogleOnboarding } from "../modules/auth/hooks/social-google-onboarding.hook";
20
- import { markFreePlanWelcomePending } from "../components/embeds/CrispEmbed";
21
20
  import {
22
21
  useCurrentAccount,
23
22
  ACCOUNT_QUERY_KEY
@@ -62,13 +61,11 @@ function AuthProvider({ children }) {
62
61
  );
63
62
  const register = useCallback(
64
63
  async (data) => {
65
- const isFreePlan = data.idPlan == null || data.idPlan === "" || Number(data.idPlan) === -1;
66
64
  await registerMutate(data, {
67
- onSuccess: (response) => {
65
+ onSuccess: (data2) => {
68
66
  queryClient.clear();
69
- setUserData(response.user);
70
- queryClient.setQueryData(accountKey, response.account);
71
- if (isFreePlan) markFreePlanWelcomePending(response.user.id);
67
+ setUserData(data2.user);
68
+ queryClient.setQueryData(accountKey, data2.account);
72
69
  }
73
70
  });
74
71
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/auth.provider.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n ReactNode,\n useCallback,\n useContext,\n useMemo,\n} from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport {\n useUserQuery,\n useSetUserData,\n useUserValidateSession,\n} from \"../modules/auth/hooks/useUserQuery\";\nimport { useLogin } from \"../modules/auth/hooks/login.hook\";\nimport { useRegister } from \"../modules/auth/hooks/register.hook\";\nimport { useLogout } from \"../modules/auth/hooks/logout.hook\";\nimport { useSocialGoogleLogin } from \"../modules/auth/hooks/social-google-login.hook\";\nimport { useSocialGoogleOnboarding } from \"../modules/auth/hooks/social-google-onboarding.hook\";\nimport {\n AuthState,\n LoginRequest,\n RegisterRequest,\n SocialGooglePartial,\n SocialOnboardingRequest,\n} from \"../modules/auth/schema\";\nimport { markFreePlanWelcomePending } from \"../components/embeds/CrispEmbed\";\n\nexport type LoginResult =\n | { result: \"success\" }\n | { result: \"two_factor_required\"; cookie: string; twoFactorMode: \"verify\" | \"setup\" }\n | { result: \"error\"; message: string };\n\nexport type GoogleLoginResult =\n | { result: \"success\" }\n | { result: \"two_factor_required\"; cookie: string; twoFactorMode: \"verify\" | \"setup\" }\n | { result: \"needs_onboarding\"; onboardingToken: string; partial: SocialGooglePartial }\n | { result: \"link_requires_password\"; message: string }\n | { result: \"error\"; message: string };\nimport {\n useCurrentAccount,\n ACCOUNT_QUERY_KEY,\n} from \"../modules/accounts/hooks/current-account.hook\";\nimport { useWhitelabelUrls } from \"./whitelabel.provider\";\nimport { useWlQueryKey } from \"../hooks/useAuthQueryKey\";\n\ninterface AuthContextProps extends AuthState {\n login: (credentials: LoginRequest) => Promise<LoginResult>;\n register: (data: RegisterRequest) => Promise<void>;\n logout: () => Promise<void>;\n loginWithGoogle: (code: string) => Promise<GoogleLoginResult>;\n completeGoogleOnboarding: (data: SocialOnboardingRequest) => Promise<void>;\n}\n\nexport const AuthContext = createContext<AuthContextProps | undefined>(\n undefined,\n);\n\ninterface AuthProviderProps {\n children: ReactNode;\n}\n\nexport function AuthProvider({ children }: AuthProviderProps) {\n const { data: user, isLoading: isQueryLoading } = useUserQuery();\n const { data: account, isLoading: isAccountLoading } = useCurrentAccount();\n const { isLoading: isSessionLoading } = useUserValidateSession();\n\n const queryClient = useQueryClient();\n const setUserData = useSetUserData();\n const { accountsUrl, pagesUrl } = useWhitelabelUrls();\n const accountKey = useWlQueryKey([...ACCOUNT_QUERY_KEY]);\n\n const { mutateAsync: loginMutate, isPending: isLogging } = useLogin();\n const { mutateAsync: registerMutate, isPending: isRegistering } =\n useRegister();\n const { mutateAsync: logoutMutate, isPending: isLoggingOut } = useLogout();\n const { mutateAsync: googleLoginMutate, isPending: isGoogleLogging } =\n useSocialGoogleLogin();\n const { mutateAsync: googleOnboardingMutate, isPending: isGoogleOnboarding } =\n useSocialGoogleOnboarding();\n\n const isAuthenticated = !!user;\n const isLoading =\n isLogging ||\n isRegistering ||\n isLoggingOut ||\n isGoogleLogging ||\n isGoogleOnboarding ||\n isQueryLoading ||\n isAccountLoading ||\n isSessionLoading;\n\n const login = useCallback(\n async (credentials: LoginRequest): Promise<LoginResult> => {\n try {\n const data = await loginMutate(credentials);\n\n if (data.result === \"two_factor_required\") {\n return { result: \"two_factor_required\", cookie: data.cookie, twoFactorMode: data.twoFactorMode };\n }\n\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n\n return { result: \"success\" };\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : \"Ocorreu um erro ao fazer login. Tente novamente.\";\n return { result: \"error\", message };\n }\n },\n [queryClient, setUserData, accountKey],\n );\n\n const register = useCallback(\n async (data: RegisterRequest): Promise<void> => {\n const isFreePlan =\n data.idPlan == null || data.idPlan === \"\" || Number(data.idPlan) === -1;\n await registerMutate(data, {\n onSuccess: (response) => {\n queryClient.clear();\n setUserData(response.user);\n queryClient.setQueryData(accountKey, response.account);\n if (isFreePlan) markFreePlanWelcomePending(response.user.id);\n },\n });\n },\n [queryClient, setUserData, accountKey],\n );\n\n const loginWithGoogle = useCallback(\n async (code: string): Promise<GoogleLoginResult> => {\n try {\n const data = await googleLoginMutate(code);\n\n if (data.result === \"two_factor_required\") {\n return {\n result: \"two_factor_required\",\n cookie: data.cookie,\n twoFactorMode: data.twoFactorMode,\n };\n }\n\n if (data.result === \"needs_onboarding\") {\n return {\n result: \"needs_onboarding\",\n onboardingToken: data.onboardingToken,\n partial: data.partial,\n };\n }\n\n if (data.result === \"link_requires_password\") {\n return { result: \"link_requires_password\", message: data.message };\n }\n\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n\n return { result: \"success\" };\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : \"Ocorreu um erro ao fazer login com Google. Tente novamente.\";\n return { result: \"error\", message };\n }\n },\n [googleLoginMutate, queryClient, setUserData, accountKey],\n );\n\n const completeGoogleOnboarding = useCallback(\n async (data: SocialOnboardingRequest): Promise<void> => {\n await googleOnboardingMutate(data, {\n onSuccess: (data) => {\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n },\n });\n },\n [googleOnboardingMutate, queryClient, setUserData, accountKey],\n );\n\n const resolveLogoutRedirect = useCallback(() => {\n try {\n const currentOrigin = window.location.origin;\n const pagesOrigin = pagesUrl ? new URL(pagesUrl).origin : \"\";\n\n if (pagesOrigin && currentOrigin === pagesOrigin) {\n return `${accountsUrl}/login?redirect=${encodeURIComponent(pagesUrl)}`;\n }\n } catch {\n // fallback below\n }\n\n return `${accountsUrl}/login?redirect=${encodeURIComponent(pagesUrl || \"/\")}`;\n }, [accountsUrl, pagesUrl]);\n\n const logout = useCallback(async (): Promise<void> => {\n try {\n await logoutMutate(undefined);\n } catch {\n // cookie já removido no servidor mesmo se a API falhou\n } finally {\n queryClient.clear();\n window.location.assign(resolveLogoutRedirect());\n }\n }, [queryClient, logoutMutate, resolveLogoutRedirect]);\n\n const value: AuthContextProps = useMemo(\n () => ({\n user: user ?? null,\n account: account ?? null,\n isAuthenticated,\n isLoading,\n login,\n register,\n logout,\n loginWithGoogle,\n completeGoogleOnboarding,\n }),\n [\n user,\n account,\n isAuthenticated,\n isLoading,\n login,\n register,\n logout,\n loginWithGoogle,\n completeGoogleOnboarding,\n ],\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\nexport function useAuth(): AuthContextProps {\n const context = useContext(AuthContext);\n\n if (context === undefined) {\n throw new Error(\"useAuth deve ser usado dentro de um AuthProvider\");\n }\n\n return context;\n}\n"],"mappings":"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","names":["data"]}
1
+ {"version":3,"sources":["../../src/providers/auth.provider.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n ReactNode,\n useCallback,\n useContext,\n useMemo,\n} from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport {\n useUserQuery,\n useSetUserData,\n useUserValidateSession,\n} from \"../modules/auth/hooks/useUserQuery\";\nimport { useLogin } from \"../modules/auth/hooks/login.hook\";\nimport { useRegister } from \"../modules/auth/hooks/register.hook\";\nimport { useLogout } from \"../modules/auth/hooks/logout.hook\";\nimport { useSocialGoogleLogin } from \"../modules/auth/hooks/social-google-login.hook\";\nimport { useSocialGoogleOnboarding } from \"../modules/auth/hooks/social-google-onboarding.hook\";\nimport {\n AuthState,\n LoginRequest,\n RegisterRequest,\n SocialGooglePartial,\n SocialOnboardingRequest,\n} from \"../modules/auth/schema\";\n\nexport type LoginResult =\n | { result: \"success\" }\n | { result: \"two_factor_required\"; cookie: string; twoFactorMode: \"verify\" | \"setup\" }\n | { result: \"error\"; message: string };\n\nexport type GoogleLoginResult =\n | { result: \"success\" }\n | { result: \"two_factor_required\"; cookie: string; twoFactorMode: \"verify\" | \"setup\" }\n | { result: \"needs_onboarding\"; onboardingToken: string; partial: SocialGooglePartial }\n | { result: \"link_requires_password\"; message: string }\n | { result: \"error\"; message: string };\nimport {\n useCurrentAccount,\n ACCOUNT_QUERY_KEY,\n} from \"../modules/accounts/hooks/current-account.hook\";\nimport { useWhitelabelUrls } from \"./whitelabel.provider\";\nimport { useWlQueryKey } from \"../hooks/useAuthQueryKey\";\n\ninterface AuthContextProps extends AuthState {\n login: (credentials: LoginRequest) => Promise<LoginResult>;\n register: (data: RegisterRequest) => Promise<void>;\n logout: () => Promise<void>;\n loginWithGoogle: (code: string) => Promise<GoogleLoginResult>;\n completeGoogleOnboarding: (data: SocialOnboardingRequest) => Promise<void>;\n}\n\nexport const AuthContext = createContext<AuthContextProps | undefined>(\n undefined,\n);\n\ninterface AuthProviderProps {\n children: ReactNode;\n}\n\nexport function AuthProvider({ children }: AuthProviderProps) {\n const { data: user, isLoading: isQueryLoading } = useUserQuery();\n const { data: account, isLoading: isAccountLoading } = useCurrentAccount();\n const { isLoading: isSessionLoading } = useUserValidateSession();\n\n const queryClient = useQueryClient();\n const setUserData = useSetUserData();\n const { accountsUrl, pagesUrl } = useWhitelabelUrls();\n const accountKey = useWlQueryKey([...ACCOUNT_QUERY_KEY]);\n\n const { mutateAsync: loginMutate, isPending: isLogging } = useLogin();\n const { mutateAsync: registerMutate, isPending: isRegistering } =\n useRegister();\n const { mutateAsync: logoutMutate, isPending: isLoggingOut } = useLogout();\n const { mutateAsync: googleLoginMutate, isPending: isGoogleLogging } =\n useSocialGoogleLogin();\n const { mutateAsync: googleOnboardingMutate, isPending: isGoogleOnboarding } =\n useSocialGoogleOnboarding();\n\n const isAuthenticated = !!user;\n const isLoading =\n isLogging ||\n isRegistering ||\n isLoggingOut ||\n isGoogleLogging ||\n isGoogleOnboarding ||\n isQueryLoading ||\n isAccountLoading ||\n isSessionLoading;\n\n const login = useCallback(\n async (credentials: LoginRequest): Promise<LoginResult> => {\n try {\n const data = await loginMutate(credentials);\n\n if (data.result === \"two_factor_required\") {\n return { result: \"two_factor_required\", cookie: data.cookie, twoFactorMode: data.twoFactorMode };\n }\n\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n\n return { result: \"success\" };\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : \"Ocorreu um erro ao fazer login. Tente novamente.\";\n return { result: \"error\", message };\n }\n },\n [queryClient, setUserData, accountKey],\n );\n\n const register = useCallback(\n async (data: RegisterRequest): Promise<void> => {\n await registerMutate(data, {\n onSuccess: (data) => {\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n },\n });\n },\n [queryClient, setUserData, accountKey],\n );\n\n const loginWithGoogle = useCallback(\n async (code: string): Promise<GoogleLoginResult> => {\n try {\n const data = await googleLoginMutate(code);\n\n if (data.result === \"two_factor_required\") {\n return {\n result: \"two_factor_required\",\n cookie: data.cookie,\n twoFactorMode: data.twoFactorMode,\n };\n }\n\n if (data.result === \"needs_onboarding\") {\n return {\n result: \"needs_onboarding\",\n onboardingToken: data.onboardingToken,\n partial: data.partial,\n };\n }\n\n if (data.result === \"link_requires_password\") {\n return { result: \"link_requires_password\", message: data.message };\n }\n\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n\n return { result: \"success\" };\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : \"Ocorreu um erro ao fazer login com Google. Tente novamente.\";\n return { result: \"error\", message };\n }\n },\n [googleLoginMutate, queryClient, setUserData, accountKey],\n );\n\n const completeGoogleOnboarding = useCallback(\n async (data: SocialOnboardingRequest): Promise<void> => {\n await googleOnboardingMutate(data, {\n onSuccess: (data) => {\n queryClient.clear();\n setUserData(data.user);\n queryClient.setQueryData(accountKey, data.account);\n },\n });\n },\n [googleOnboardingMutate, queryClient, setUserData, accountKey],\n );\n\n const resolveLogoutRedirect = useCallback(() => {\n try {\n const currentOrigin = window.location.origin;\n const pagesOrigin = pagesUrl ? new URL(pagesUrl).origin : \"\";\n\n if (pagesOrigin && currentOrigin === pagesOrigin) {\n return `${accountsUrl}/login?redirect=${encodeURIComponent(pagesUrl)}`;\n }\n } catch {\n // fallback below\n }\n\n return `${accountsUrl}/login?redirect=${encodeURIComponent(pagesUrl || \"/\")}`;\n }, [accountsUrl, pagesUrl]);\n\n const logout = useCallback(async (): Promise<void> => {\n try {\n await logoutMutate(undefined);\n } catch {\n // cookie já removido no servidor mesmo se a API falhou\n } finally {\n queryClient.clear();\n window.location.assign(resolveLogoutRedirect());\n }\n }, [queryClient, logoutMutate, resolveLogoutRedirect]);\n\n const value: AuthContextProps = useMemo(\n () => ({\n user: user ?? null,\n account: account ?? null,\n isAuthenticated,\n isLoading,\n login,\n register,\n logout,\n loginWithGoogle,\n completeGoogleOnboarding,\n }),\n [\n user,\n account,\n isAuthenticated,\n isLoading,\n login,\n register,\n logout,\n loginWithGoogle,\n completeGoogleOnboarding,\n ],\n );\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\nexport function useAuth(): AuthContextProps {\n const context = useContext(AuthContext);\n\n if (context === undefined) {\n throw new Error(\"useAuth deve ser usado dentro de um AuthProvider\");\n }\n\n return context;\n}\n"],"mappings":";AA2OS;AAzOT;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,iCAAiC;AAoB1C;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,yBAAyB;AAClC,SAAS,qBAAqB;AAUvB,MAAM,cAAc;AAAA,EACzB;AACF;AAMO,SAAS,aAAa,EAAE,SAAS,GAAsB;AAC5D,QAAM,EAAE,MAAM,MAAM,WAAW,eAAe,IAAI,aAAa;AAC/D,QAAM,EAAE,MAAM,SAAS,WAAW,iBAAiB,IAAI,kBAAkB;AACzE,QAAM,EAAE,WAAW,iBAAiB,IAAI,uBAAuB;AAE/D,QAAM,cAAc,eAAe;AACnC,QAAM,cAAc,eAAe;AACnC,QAAM,EAAE,aAAa,SAAS,IAAI,kBAAkB;AACpD,QAAM,aAAa,cAAc,CAAC,GAAG,iBAAiB,CAAC;AAEvD,QAAM,EAAE,aAAa,aAAa,WAAW,UAAU,IAAI,SAAS;AACpE,QAAM,EAAE,aAAa,gBAAgB,WAAW,cAAc,IAC5D,YAAY;AACd,QAAM,EAAE,aAAa,cAAc,WAAW,aAAa,IAAI,UAAU;AACzE,QAAM,EAAE,aAAa,mBAAmB,WAAW,gBAAgB,IACjE,qBAAqB;AACvB,QAAM,EAAE,aAAa,wBAAwB,WAAW,mBAAmB,IACzE,0BAA0B;AAE5B,QAAM,kBAAkB,CAAC,CAAC;AAC1B,QAAM,YACJ,aACA,iBACA,gBACA,mBACA,sBACA,kBACA,oBACA;AAEF,QAAM,QAAQ;AAAA,IACZ,OAAO,gBAAoD;AACzD,UAAI;AACF,cAAM,OAAO,MAAM,YAAY,WAAW;AAE1C,YAAI,KAAK,WAAW,uBAAuB;AACzC,iBAAO,EAAE,QAAQ,uBAAuB,QAAQ,KAAK,QAAQ,eAAe,KAAK,cAAc;AAAA,QACjG;AAEA,oBAAY,MAAM;AAClB,oBAAY,KAAK,IAAI;AACrB,oBAAY,aAAa,YAAY,KAAK,OAAO;AAEjD,eAAO,EAAE,QAAQ,UAAU;AAAA,MAC7B,SAAS,OAAO;AACd,cAAM,UACJ,iBAAiB,QACb,MAAM,UACN;AACN,eAAO,EAAE,QAAQ,SAAS,QAAQ;AAAA,MACpC;AAAA,IACF;AAAA,IACA,CAAC,aAAa,aAAa,UAAU;AAAA,EACvC;AAEA,QAAM,WAAW;AAAA,IACf,OAAO,SAAyC;AAC9C,YAAM,eAAe,MAAM;AAAA,QACzB,WAAW,CAACA,UAAS;AACnB,sBAAY,MAAM;AAClB,sBAAYA,MAAK,IAAI;AACrB,sBAAY,aAAa,YAAYA,MAAK,OAAO;AAAA,QACnD;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,CAAC,aAAa,aAAa,UAAU;AAAA,EACvC;AAEA,QAAM,kBAAkB;AAAA,IACtB,OAAO,SAA6C;AAClD,UAAI;AACF,cAAM,OAAO,MAAM,kBAAkB,IAAI;AAEzC,YAAI,KAAK,WAAW,uBAAuB;AACzC,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,QAAQ,KAAK;AAAA,YACb,eAAe,KAAK;AAAA,UACtB;AAAA,QACF;AAEA,YAAI,KAAK,WAAW,oBAAoB;AACtC,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,iBAAiB,KAAK;AAAA,YACtB,SAAS,KAAK;AAAA,UAChB;AAAA,QACF;AAEA,YAAI,KAAK,WAAW,0BAA0B;AAC5C,iBAAO,EAAE,QAAQ,0BAA0B,SAAS,KAAK,QAAQ;AAAA,QACnE;AAEA,oBAAY,MAAM;AAClB,oBAAY,KAAK,IAAI;AACrB,oBAAY,aAAa,YAAY,KAAK,OAAO;AAEjD,eAAO,EAAE,QAAQ,UAAU;AAAA,MAC7B,SAAS,OAAO;AACd,cAAM,UACJ,iBAAiB,QACb,MAAM,UACN;AACN,eAAO,EAAE,QAAQ,SAAS,QAAQ;AAAA,MACpC;AAAA,IACF;AAAA,IACA,CAAC,mBAAmB,aAAa,aAAa,UAAU;AAAA,EAC1D;AAEA,QAAM,2BAA2B;AAAA,IAC/B,OAAO,SAAiD;AACtD,YAAM,uBAAuB,MAAM;AAAA,QACjC,WAAW,CAACA,UAAS;AACnB,sBAAY,MAAM;AAClB,sBAAYA,MAAK,IAAI;AACrB,sBAAY,aAAa,YAAYA,MAAK,OAAO;AAAA,QACnD;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,CAAC,wBAAwB,aAAa,aAAa,UAAU;AAAA,EAC/D;AAEA,QAAM,wBAAwB,YAAY,MAAM;AAC9C,QAAI;AACF,YAAM,gBAAgB,OAAO,SAAS;AACtC,YAAM,cAAc,WAAW,IAAI,IAAI,QAAQ,EAAE,SAAS;AAE1D,UAAI,eAAe,kBAAkB,aAAa;AAChD,eAAO,GAAG,WAAW,mBAAmB,mBAAmB,QAAQ,CAAC;AAAA,MACtE;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,WAAO,GAAG,WAAW,mBAAmB,mBAAmB,YAAY,GAAG,CAAC;AAAA,EAC7E,GAAG,CAAC,aAAa,QAAQ,CAAC;AAE1B,QAAM,SAAS,YAAY,YAA2B;AACpD,QAAI;AACF,YAAM,aAAa,MAAS;AAAA,IAC9B,QAAQ;AAAA,IAER,UAAE;AACA,kBAAY,MAAM;AAClB,aAAO,SAAS,OAAO,sBAAsB,CAAC;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,aAAa,cAAc,qBAAqB,CAAC;AAErD,QAAM,QAA0B;AAAA,IAC9B,OAAO;AAAA,MACL,MAAM,QAAQ;AAAA,MACd,SAAS,WAAW;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,oBAAC,YAAY,UAAZ,EAAqB,OAAe,UAAS;AACvD;AAEO,SAAS,UAA4B;AAC1C,QAAM,UAAU,WAAW,WAAW;AAEtC,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,SAAO;AACT;","names":["data"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/common",
3
- "version": "1.1.650",
3
+ "version": "1.1.652",
4
4
  "description": "Shared library for GreatApps frontend applications",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./src/index.ts",
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useEffect, useRef } from 'react';
3
+ import { useEffect, useRef, useState } from 'react';
4
4
  import { useAuth } from '../../providers/auth.provider';
5
5
  import { useIsDefaultWhitelabel, useWhitelabel } from '../../providers/whitelabel.provider';
6
6
  import { useActiveSubscription } from '../../modules/subscriptions/hooks/find-active-subscription.hook';
@@ -54,8 +54,9 @@ export function showCrisp() {
54
54
  crispDo('chat:show');
55
55
  }
56
56
 
57
- const FREE_PLAN_WELCOME_PENDING_KEY = 'crisp:free-plan-welcome:pending';
57
+ const FREE_PLAN_ID = 5;
58
58
  const FREE_PLAN_WELCOME_SHOWN_KEY = 'crisp:free-plan-welcome:shown';
59
+ const FREE_PLAN_WELCOME_QUERY_FLAG = 'createNew';
59
60
  const FREE_PLAN_WELCOME_MESSAGE = `Oi! Tenho uma novidade exclusiva para você 🎉
60
61
 
61
62
  Criamos o Plano Iniciante pensando exatamente em você: R$ 14,90/mês para quem já deu o primeiro passo e quer ir além.
@@ -64,13 +65,6 @@ Com ele você conecta seu próprio domínio, publica até 3 páginas e libera re
64
65
 
65
66
  Acesse o menu "Assinaturas" e assine agora!`;
66
67
 
67
- export function markFreePlanWelcomePending(userId: number | string) {
68
- try {
69
- if (typeof window === 'undefined') return;
70
- window.localStorage.setItem(FREE_PLAN_WELCOME_PENDING_KEY, String(userId));
71
- } catch {}
72
- }
73
-
74
68
  export function sendCrispMessage(text: string) {
75
69
  safeCrispPush(['do', 'message:show', ['text', text]]);
76
70
  }
@@ -180,19 +174,26 @@ export function CrispEmbed() {
180
174
  } catch {}
181
175
  }, [user, account, isV4, shouldLoadCrisp, subscription?.plan_name]);
182
176
 
183
- // Mostra mensagem de boas-vindas no Crisp para quem acabou de se cadastrar no plano free.
177
+ // Captura `?createNew=true` da URL inicial. O register do gapps redireciona
178
+ // para pages com esse flag, e localStorage não cruza origens — então o
179
+ // sinal de "acabou de se cadastrar" vem via query string.
180
+ const [isFreshSignup, setIsFreshSignup] = useState(false);
184
181
  useEffect(() => {
185
- if (!user || !shouldLoadCrisp) return;
186
182
  try {
187
- const userId = String(user.id);
188
- const pending = window.localStorage.getItem(FREE_PLAN_WELCOME_PENDING_KEY);
189
- if (pending !== userId) return;
190
-
191
- const shownKey = `${FREE_PLAN_WELCOME_SHOWN_KEY}:${userId}`;
192
- if (window.localStorage.getItem(shownKey)) {
193
- window.localStorage.removeItem(FREE_PLAN_WELCOME_PENDING_KEY);
194
- return;
183
+ const params = new URLSearchParams(window.location.search);
184
+ if (params.get(FREE_PLAN_WELCOME_QUERY_FLAG) === 'true') {
185
+ setIsFreshSignup(true);
195
186
  }
187
+ } catch {}
188
+ }, []);
189
+
190
+ // Mostra mensagem de boas-vindas no Crisp para quem acabou de se cadastrar no plano free.
191
+ useEffect(() => {
192
+ if (!user || !shouldLoadCrisp || !isFreshSignup) return;
193
+ if (subscription?.id_plan !== FREE_PLAN_ID) return;
194
+ try {
195
+ const shownKey = `${FREE_PLAN_WELCOME_SHOWN_KEY}:${user.id}`;
196
+ if (window.localStorage.getItem(shownKey)) return;
196
197
 
197
198
  // Defer to session:loaded para garantir que a Crisp está pronta antes
198
199
  // de exibir a mensagem. Sem isso, comandos enfileirados pré-load podem
@@ -206,9 +207,8 @@ export function CrispEmbed() {
206
207
  },
207
208
  ]);
208
209
  window.localStorage.setItem(shownKey, '1');
209
- window.localStorage.removeItem(FREE_PLAN_WELCOME_PENDING_KEY);
210
210
  } catch {}
211
- }, [user, shouldLoadCrisp]);
211
+ }, [user, shouldLoadCrisp, isFreshSignup, subscription?.id_plan]);
212
212
 
213
213
  return null;
214
214
  }
@@ -25,7 +25,6 @@ import {
25
25
  SocialGooglePartial,
26
26
  SocialOnboardingRequest,
27
27
  } from "../modules/auth/schema";
28
- import { markFreePlanWelcomePending } from "../components/embeds/CrispEmbed";
29
28
 
30
29
  export type LoginResult =
31
30
  | { result: "success" }
@@ -118,14 +117,11 @@ export function AuthProvider({ children }: AuthProviderProps) {
118
117
 
119
118
  const register = useCallback(
120
119
  async (data: RegisterRequest): Promise<void> => {
121
- const isFreePlan =
122
- data.idPlan == null || data.idPlan === "" || Number(data.idPlan) === -1;
123
120
  await registerMutate(data, {
124
- onSuccess: (response) => {
121
+ onSuccess: (data) => {
125
122
  queryClient.clear();
126
- setUserData(response.user);
127
- queryClient.setQueryData(accountKey, response.account);
128
- if (isFreePlan) markFreePlanWelcomePending(response.user.id);
123
+ setUserData(data.user);
124
+ queryClient.setQueryData(accountKey, data.account);
129
125
  },
130
126
  });
131
127
  },