@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.
- package/dist/components/embeds/CrispEmbed.mjs +17 -20
- package/dist/components/embeds/CrispEmbed.mjs.map +1 -1
- package/dist/providers/auth.provider.mjs +3 -6
- package/dist/providers/auth.provider.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/embeds/CrispEmbed.tsx +21 -21
- package/src/providers/auth.provider.tsx +3 -7
|
@@ -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
|
|
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
|
|
145
|
-
|
|
146
|
-
|
|
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: (
|
|
65
|
+
onSuccess: (data2) => {
|
|
68
66
|
queryClient.clear();
|
|
69
|
-
setUserData(
|
|
70
|
-
queryClient.setQueryData(accountKey,
|
|
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
|
'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
|
|
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
|
-
//
|
|
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
|
|
188
|
-
|
|
189
|
-
|
|
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: (
|
|
121
|
+
onSuccess: (data) => {
|
|
125
122
|
queryClient.clear();
|
|
126
|
-
setUserData(
|
|
127
|
-
queryClient.setQueryData(accountKey,
|
|
128
|
-
if (isFreePlan) markFreePlanWelcomePending(response.user.id);
|
|
123
|
+
setUserData(data.user);
|
|
124
|
+
queryClient.setQueryData(accountKey, data.account);
|
|
129
125
|
},
|
|
130
126
|
});
|
|
131
127
|
},
|