@greatapps/common 1.1.630 → 1.1.632

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.
Files changed (37) hide show
  1. package/dist/components/account/sections/SecuritySection.mjs +38 -2
  2. package/dist/components/account/sections/SecuritySection.mjs.map +1 -1
  3. package/dist/index.mjs +6 -0
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/modules/auth/actions/social-google-login.action.mjs +14 -0
  6. package/dist/modules/auth/actions/social-google-login.action.mjs.map +1 -0
  7. package/dist/modules/auth/actions/social-google-onboarding.action.mjs +14 -0
  8. package/dist/modules/auth/actions/social-google-onboarding.action.mjs.map +1 -0
  9. package/dist/modules/auth/actions/unlink-google.action.mjs +10 -0
  10. package/dist/modules/auth/actions/unlink-google.action.mjs.map +1 -0
  11. package/dist/modules/auth/hooks/social-google-login.hook.mjs +13 -0
  12. package/dist/modules/auth/hooks/social-google-login.hook.mjs.map +1 -0
  13. package/dist/modules/auth/hooks/social-google-onboarding.hook.mjs +13 -0
  14. package/dist/modules/auth/hooks/social-google-onboarding.hook.mjs.map +1 -0
  15. package/dist/modules/auth/hooks/unlink-google.hook.mjs +13 -0
  16. package/dist/modules/auth/hooks/unlink-google.hook.mjs.map +1 -0
  17. package/dist/modules/auth/services/auth.service.mjs +168 -0
  18. package/dist/modules/auth/services/auth.service.mjs.map +1 -1
  19. package/dist/modules/users/schema.mjs.map +1 -1
  20. package/dist/providers/auth.provider.mjs +63 -3
  21. package/dist/providers/auth.provider.mjs.map +1 -1
  22. package/dist/server.mjs +6 -0
  23. package/dist/server.mjs.map +1 -1
  24. package/package.json +1 -1
  25. package/src/components/account/sections/SecuritySection.tsx +50 -3
  26. package/src/index.ts +3 -0
  27. package/src/modules/auth/actions/social-google-login.action.ts +12 -0
  28. package/src/modules/auth/actions/social-google-onboarding.action.ts +13 -0
  29. package/src/modules/auth/actions/unlink-google.action.ts +8 -0
  30. package/src/modules/auth/hooks/social-google-login.hook.tsx +13 -0
  31. package/src/modules/auth/hooks/social-google-onboarding.hook.tsx +13 -0
  32. package/src/modules/auth/hooks/unlink-google.hook.tsx +13 -0
  33. package/src/modules/auth/schema.ts +75 -0
  34. package/src/modules/auth/services/auth.service.ts +210 -0
  35. package/src/modules/users/schema.ts +2 -0
  36. package/src/providers/auth.provider.tsx +86 -1
  37. package/src/server.ts +3 -0
@@ -26,9 +26,16 @@ import {
26
26
  SearchPlansApiResponse,
27
27
  SessionKeepRequest,
28
28
  SessionKeepResponse,
29
+ SocialGoogleApiResponse,
30
+ SocialGoogleResponse,
31
+ SocialOnboardingApiResponse,
32
+ SocialOnboardingRequest,
33
+ SocialOnboardingResponse,
29
34
  TwoFactorApiResponse,
30
35
  TwoFactorRequest,
31
36
  TwoFactorResponse,
37
+ UnlinkGoogleApiResponse,
38
+ UnlinkGoogleResponse,
32
39
  VerifyEmailRequest,
33
40
  VerifyEmailResponse,
34
41
  } from "../schema";
@@ -151,6 +158,206 @@ class AuthService {
151
158
 
152
159
  return { status: 1 };
153
160
  }
161
+
162
+ async socialLoginGoogle(
163
+ idToken: string,
164
+ clientInfo: ClientInfo,
165
+ ): Promise<SocialGoogleResponse> {
166
+ const response = await api.apps.post<SocialGoogleApiResponse>(
167
+ "/auth/social/google",
168
+ {
169
+ id_token: idToken,
170
+ location: clientInfo.location,
171
+ ip: clientInfo.ip,
172
+ timezone: clientInfo.timezone,
173
+ agent: clientInfo.agent,
174
+ verification: true,
175
+ },
176
+ );
177
+
178
+ if (response.status === 0) {
179
+ if (response.code === "link_requires_password") {
180
+ return {
181
+ result: "link_requires_password",
182
+ message:
183
+ response.message ||
184
+ "Uma conta com esse e-mail já existe. Faça login com e-mail e senha para vincular sua conta Google.",
185
+ };
186
+ }
187
+ throw new ApiError(
188
+ response.message || "Falha no login com Google",
189
+ response.code || "GOOGLE_LOGIN_FAILED",
190
+ 401,
191
+ );
192
+ }
193
+
194
+ if (response.needs_onboarding) {
195
+ if (!response.onboarding_token || !response.partial?.email) {
196
+ throw new ApiError(
197
+ "Resposta de onboarding inválida",
198
+ "INVALID_RESPONSE",
199
+ 500,
200
+ );
201
+ }
202
+ return {
203
+ result: "needs_onboarding",
204
+ onboardingToken: response.onboarding_token,
205
+ partial: response.partial,
206
+ };
207
+ }
208
+
209
+ if (!response.cookie) {
210
+ throw new ApiError(
211
+ "Resposta de autenticação inválida",
212
+ "INVALID_RESPONSE",
213
+ 500,
214
+ );
215
+ }
216
+
217
+ if (response.two_factor_required) {
218
+ return {
219
+ result: "two_factor_required",
220
+ cookie: response.cookie,
221
+ twoFactorMode: response.two_factor_required,
222
+ };
223
+ }
224
+
225
+ await this.setAuthCookie(response.cookie);
226
+
227
+ const [{ userService }, { accountService }] = await Promise.all([
228
+ import("../../users/services/user.service"),
229
+ import("../../accounts/services/account.service"),
230
+ ]);
231
+ const [user, account] = await Promise.all([
232
+ userService.findById(),
233
+ accountService.findCurrentAccount(),
234
+ ]);
235
+
236
+ return {
237
+ result: "success",
238
+ user,
239
+ account,
240
+ accessToken: response.cookie,
241
+ expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),
242
+ };
243
+ }
244
+
245
+ async completeGoogleOnboarding(
246
+ data: SocialOnboardingRequest,
247
+ clientInfo: ClientInfo,
248
+ ): Promise<SocialOnboardingResponse> {
249
+ const today = new Date();
250
+ const trialEndDate = new Date(today);
251
+ const trialDays = Math.min(Math.max(data.trialDays ?? 7, 1), 90);
252
+ trialEndDate.setDate(today.getDate() + trialDays);
253
+
254
+ const idPlan = await this.resolvePlanId(data.idPlan);
255
+
256
+ const payload = {
257
+ onboarding_token: data.onboardingToken,
258
+ name: data.user.name,
259
+ bussiness_type: 0,
260
+ language: "pt-br",
261
+ timezone: "America/Sao_Paulo",
262
+ currency: "BRL",
263
+ location: clientInfo.location,
264
+ ip: clientInfo.ip,
265
+ agent: clientInfo.agent,
266
+ id_affiliate: data.affiliateId || 0,
267
+ origin: data.origin,
268
+ user: {
269
+ id_api: "",
270
+ name: data.user.name || "",
271
+ last_name: data.user.last_name || "",
272
+ rg: data.user.rg || "",
273
+ cpf: data.user.cpf || "",
274
+ gender: data.user.gender ?? 1,
275
+ ddi: data.user.ddi || "55",
276
+ phone: data.user.phone || "",
277
+ profile: "owner",
278
+ language: "pt-br",
279
+ },
280
+ subscription:
281
+ idPlan === -1
282
+ ? {
283
+ type: "free",
284
+ id_coupon: data.couponId || 0,
285
+ id_plan: 5,
286
+ id_product: 1,
287
+ }
288
+ : {
289
+ type: "trial",
290
+ id_coupon: data.couponId || 0,
291
+ id_plan: idPlan,
292
+ date_due: trialEndDate.toISOString().split("T")[0],
293
+ trial_days: trialDays,
294
+ id_product: 1,
295
+ },
296
+ };
297
+
298
+ const response = await api.apps.post<SocialOnboardingApiResponse>(
299
+ "/auth/social/onboarding",
300
+ payload,
301
+ );
302
+
303
+ if (response.status === 0) {
304
+ throw new ApiError(
305
+ response.message || "Erro ao finalizar cadastro com Google",
306
+ "ONBOARDING_FAILED",
307
+ 400,
308
+ );
309
+ }
310
+
311
+ if (!response.data?.length || !response.cookie) {
312
+ throw new ApiError(
313
+ "Resposta de cadastro inválida",
314
+ "INVALID_RESPONSE",
315
+ 500,
316
+ );
317
+ }
318
+
319
+ await this.setAuthCookie(response.cookie);
320
+
321
+ const [{ userService }, { accountService }] = await Promise.all([
322
+ import("../../users/services/user.service"),
323
+ import("../../accounts/services/account.service"),
324
+ ]);
325
+ const [user, account] = await Promise.all([
326
+ userService.findById(),
327
+ accountService.findCurrentAccount(),
328
+ ]);
329
+
330
+ return {
331
+ user,
332
+ account,
333
+ accessToken: response.cookie,
334
+ expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),
335
+ };
336
+ }
337
+
338
+ async unlinkGoogle(): Promise<UnlinkGoogleResponse> {
339
+ const { id_account, id_user } = await import(
340
+ "../utils/get-user-context"
341
+ ).then((m) => m.getUserContext());
342
+
343
+ const response = await api.apps.delete<UnlinkGoogleApiResponse>(
344
+ `/accounts/${id_account}/users/${id_user}/social/google`,
345
+ );
346
+
347
+ if (response.status === 0) {
348
+ throw new ApiError(
349
+ response.message || "Erro ao desvincular conta Google",
350
+ "UNLINK_FAILED",
351
+ 400,
352
+ );
353
+ }
354
+
355
+ return {
356
+ success: true,
357
+ message: response.message,
358
+ };
359
+ }
360
+
154
361
  async register(
155
362
  data: RegisterRequest,
156
363
  clientInfo: ClientInfo,
@@ -198,7 +405,10 @@ class AuthService {
198
405
  type: "trial",
199
406
  id_coupon: data.couponId || 0,
200
407
  id_plan: idPlan,
408
+ // Fluxo não-Stripe lê `date_due`; fluxo Stripe lê `trial_days`.
409
+ // Mandamos os dois pra cobrir ambos os caminhos da API.
201
410
  date_due: trialEndDate.toISOString().split("T")[0],
411
+ trial_days: trialDays,
202
412
  id_product: 1,
203
413
  },
204
414
  };
@@ -24,6 +24,8 @@ export interface User {
24
24
 
25
25
  // Autenticação e segurança
26
26
  two_factor_authentication: boolean;
27
+ google_sub?: string | null;
28
+ google_linked_at?: string | null;
27
29
 
28
30
  // Perfil e permissões
29
31
  profile: UserProfile;
@@ -16,16 +16,27 @@ import {
16
16
  import { useLogin } from "../modules/auth/hooks/login.hook";
17
17
  import { useRegister } from "../modules/auth/hooks/register.hook";
18
18
  import { useLogout } from "../modules/auth/hooks/logout.hook";
19
+ import { useSocialGoogleLogin } from "../modules/auth/hooks/social-google-login.hook";
20
+ import { useSocialGoogleOnboarding } from "../modules/auth/hooks/social-google-onboarding.hook";
19
21
  import {
20
22
  AuthState,
21
23
  LoginRequest,
22
24
  RegisterRequest,
25
+ SocialGooglePartial,
26
+ SocialOnboardingRequest,
23
27
  } from "../modules/auth/schema";
24
28
 
25
29
  export type LoginResult =
26
30
  | { result: "success" }
27
31
  | { result: "two_factor_required"; cookie: string; twoFactorMode: "verify" | "setup" }
28
32
  | { result: "error"; message: string };
33
+
34
+ export type GoogleLoginResult =
35
+ | { result: "success" }
36
+ | { result: "two_factor_required"; cookie: string; twoFactorMode: "verify" | "setup" }
37
+ | { result: "needs_onboarding"; onboardingToken: string; partial: SocialGooglePartial }
38
+ | { result: "link_requires_password"; message: string }
39
+ | { result: "error"; message: string };
29
40
  import {
30
41
  useCurrentAccount,
31
42
  ACCOUNT_QUERY_KEY,
@@ -37,6 +48,8 @@ interface AuthContextProps extends AuthState {
37
48
  login: (credentials: LoginRequest) => Promise<LoginResult>;
38
49
  register: (data: RegisterRequest) => Promise<void>;
39
50
  logout: () => Promise<void>;
51
+ loginWithGoogle: (idToken: string) => Promise<GoogleLoginResult>;
52
+ completeGoogleOnboarding: (data: SocialOnboardingRequest) => Promise<void>;
40
53
  }
41
54
 
42
55
  export const AuthContext = createContext<AuthContextProps | undefined>(
@@ -61,12 +74,18 @@ export function AuthProvider({ children }: AuthProviderProps) {
61
74
  const { mutateAsync: registerMutate, isPending: isRegistering } =
62
75
  useRegister();
63
76
  const { mutateAsync: logoutMutate, isPending: isLoggingOut } = useLogout();
77
+ const { mutateAsync: googleLoginMutate, isPending: isGoogleLogging } =
78
+ useSocialGoogleLogin();
79
+ const { mutateAsync: googleOnboardingMutate, isPending: isGoogleOnboarding } =
80
+ useSocialGoogleOnboarding();
64
81
 
65
82
  const isAuthenticated = !!user;
66
83
  const isLoading =
67
84
  isLogging ||
68
85
  isRegistering ||
69
86
  isLoggingOut ||
87
+ isGoogleLogging ||
88
+ isGoogleOnboarding ||
70
89
  isQueryLoading ||
71
90
  isAccountLoading ||
72
91
  isSessionLoading;
@@ -109,6 +128,60 @@ export function AuthProvider({ children }: AuthProviderProps) {
109
128
  [queryClient, setUserData, accountKey],
110
129
  );
111
130
 
131
+ const loginWithGoogle = useCallback(
132
+ async (idToken: string): Promise<GoogleLoginResult> => {
133
+ try {
134
+ const data = await googleLoginMutate(idToken);
135
+
136
+ if (data.result === "two_factor_required") {
137
+ return {
138
+ result: "two_factor_required",
139
+ cookie: data.cookie,
140
+ twoFactorMode: data.twoFactorMode,
141
+ };
142
+ }
143
+
144
+ if (data.result === "needs_onboarding") {
145
+ return {
146
+ result: "needs_onboarding",
147
+ onboardingToken: data.onboardingToken,
148
+ partial: data.partial,
149
+ };
150
+ }
151
+
152
+ if (data.result === "link_requires_password") {
153
+ return { result: "link_requires_password", message: data.message };
154
+ }
155
+
156
+ queryClient.clear();
157
+ setUserData(data.user);
158
+ queryClient.setQueryData(accountKey, data.account);
159
+
160
+ return { result: "success" };
161
+ } catch (error) {
162
+ const message =
163
+ error instanceof Error
164
+ ? error.message
165
+ : "Ocorreu um erro ao fazer login com Google. Tente novamente.";
166
+ return { result: "error", message };
167
+ }
168
+ },
169
+ [googleLoginMutate, queryClient, setUserData, accountKey],
170
+ );
171
+
172
+ const completeGoogleOnboarding = useCallback(
173
+ async (data: SocialOnboardingRequest): Promise<void> => {
174
+ await googleOnboardingMutate(data, {
175
+ onSuccess: (data) => {
176
+ queryClient.clear();
177
+ setUserData(data.user);
178
+ queryClient.setQueryData(accountKey, data.account);
179
+ },
180
+ });
181
+ },
182
+ [googleOnboardingMutate, queryClient, setUserData, accountKey],
183
+ );
184
+
112
185
  const resolveLogoutRedirect = useCallback(() => {
113
186
  try {
114
187
  const currentOrigin = window.location.origin;
@@ -144,8 +217,20 @@ export function AuthProvider({ children }: AuthProviderProps) {
144
217
  login,
145
218
  register,
146
219
  logout,
220
+ loginWithGoogle,
221
+ completeGoogleOnboarding,
147
222
  }),
148
- [user, account, isAuthenticated, isLoading, login, register, logout],
223
+ [
224
+ user,
225
+ account,
226
+ isAuthenticated,
227
+ isLoading,
228
+ login,
229
+ register,
230
+ logout,
231
+ loginWithGoogle,
232
+ completeGoogleOnboarding,
233
+ ],
149
234
  );
150
235
 
151
236
  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
package/src/server.ts CHANGED
@@ -20,6 +20,9 @@ export { iaCreditsService } from './modules/ia-credits/services/ia-credits.servi
20
20
  // Actions
21
21
  export { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';
22
22
  export { validateSessionAction } from './modules/auth/actions/validate-session.action';
23
+ export { socialGoogleLoginAction } from './modules/auth/actions/social-google-login.action';
24
+ export { socialGoogleOnboardingAction } from './modules/auth/actions/social-google-onboarding.action';
25
+ export { unlinkGoogleAction } from './modules/auth/actions/unlink-google.action';
23
26
  export { findUserById } from './modules/users/action/find-user-by-id.action';
24
27
  export { findCurrentAccount } from './modules/accounts/actions/find-current-account.action';
25
28
  export { getAccountTokenAction } from './modules/accounts/actions/get-account-token.action';