@greatapps/common 1.1.7 → 1.1.8
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/layouts/ProfilePopover.mjs.map +1 -1
- package/dist/infra/api/client.mjs +14 -6
- package/dist/infra/api/client.mjs.map +1 -1
- package/dist/modules/ia-credits/services/ia-credits.service.mjs +2 -2
- package/dist/modules/ia-credits/services/ia-credits.service.mjs.map +1 -1
- package/dist/modules/subscriptions/services/subscriptions.service.mjs +2 -2
- package/dist/modules/subscriptions/services/subscriptions.service.mjs.map +1 -1
- package/dist/modules/users/services/user.service.mjs +1 -1
- package/dist/modules/users/services/user.service.mjs.map +1 -1
- package/dist/modules/whitelabel/services/whitelabel.service.mjs +2 -2
- package/dist/modules/whitelabel/services/whitelabel.service.mjs.map +1 -1
- package/dist/server.mjs +2 -1
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/layouts/ProfilePopover.tsx +109 -107
- package/src/infra/api/client.ts +19 -8
- package/src/modules/ia-credits/services/ia-credits.service.ts +2 -2
- package/src/modules/subscriptions/services/subscriptions.service.ts +2 -2
- package/src/modules/users/services/user.service.ts +1 -1
- package/src/modules/whitelabel/services/whitelabel.service.ts +2 -2
- package/src/server.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/layouts/ProfilePopover.tsx"],"sourcesContent":["\"use client\"
|
|
1
|
+
{"version":3,"sources":["../../../src/components/layouts/ProfilePopover.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport { useState } from \"react\";\r\nimport { useRouter } from \"next/navigation\";\r\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\r\nimport { Popover } from \"../ui/overlay/Popover\";\r\nimport { Button } from \"../ui/buttons/Button\";\r\nimport { Progress } from \"../ui/feedback/Progress\";\r\nimport { Separator } from \"../ui/data-display/Separator\";\r\nimport { NavBarItem } from \"./NavBarItem\";\r\nimport { UserAvatar } from \"../ui/data-display/UserAvatar\";\r\nimport { useAuth } from \"../../providers/auth.provider\";\r\nimport { cn } from \"../../infra/utils/clsx\";\r\nimport { useIaCredits } from \"../../modules/ia-credits/hooks/ia-credits.hook\";\r\n\r\nexport interface ProfileMenuItem {\r\n icon?: React.ReactNode;\r\n label: string;\r\n onClick: () => void;\r\n}\r\n\r\nexport interface ProfilePopoverProps {\r\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\r\n align?: \"start\" | \"center\" | \"end\";\r\n contentClassName?: string;\r\n onEditProfile?: () => void;\r\n onCreditsClick?: () => void;\r\n menuItems?: ProfileMenuItem[];\r\n logoutRedirect?: string;\r\n logoutOverlay?: React.ReactNode;\r\n}\r\n\r\nfunction ProfilePopover({\r\n side = \"top\",\r\n align = \"start\",\r\n contentClassName = \"absolute bottom-2 left-[26px]\",\r\n onEditProfile,\r\n onCreditsClick,\r\n menuItems = [],\r\n logoutRedirect = \"/login\",\r\n logoutOverlay,\r\n}: ProfilePopoverProps) {\r\n const router = useRouter();\r\n const { user, logout } = useAuth();\r\n const [isLoggingOut, setIsLoggingOut] = useState(false);\r\n\r\n const { summary, subscription, isSubscriptionLoading, isCreditsLoading } =\r\n useIaCredits();\r\n\r\n const handleLogout = async () => {\r\n try {\r\n setIsLoggingOut(true);\r\n await logout();\r\n router.push(logoutRedirect);\r\n } catch (error) {\r\n console.error(\"Erro ao fazer logout:\", error);\r\n } finally {\r\n setIsLoggingOut(false);\r\n }\r\n };\r\n\r\n const hasSubscription = !isSubscriptionLoading && subscription !== null;\r\n const showCreditsSkeleton = hasSubscription && isCreditsLoading;\r\n const showCredits =\r\n hasSubscription && !isCreditsLoading && summary.totalCredits > 0;\r\n const creditsPercentage =\r\n showCredits && summary.totalCredits > 0\r\n ? (summary.usedCredits / summary.totalCredits) * 100\r\n : 0;\r\n\r\n return (\r\n <>\r\n {isLoggingOut && logoutOverlay}\r\n <Popover>\r\n <PopoverPrimitive.Trigger className=\"cursor-pointer\">\r\n {user && (\r\n <UserAvatar\r\n key={user.id}\r\n photo={user.photo}\r\n name={user.name}\r\n size={40}\r\n />\r\n )}\r\n </PopoverPrimitive.Trigger>\r\n\r\n <PopoverPrimitive.Portal>\r\n <PopoverPrimitive.Content\r\n className={cn(\r\n \"w-64.75 p-0 bg-white rounded-2xl shadow-md border border-gray-200 z-99\",\r\n contentClassName,\r\n )}\r\n side={side}\r\n align={align}\r\n sideOffset={8}\r\n >\r\n <div className=\"grid grid-cols-[32px_1fr_auto] items-center gap-3 p-3 w-full\">\r\n {user && (\r\n <UserAvatar\r\n key={user.id}\r\n photo={user.photo}\r\n name={user.name}\r\n size={32}\r\n />\r\n )}\r\n\r\n <div className=\"flex flex-col gap-0.5 min-w-0\">\r\n <span className=\"paragraph-small-semibold text-gray-950 truncate\">\r\n {user?.name || \"\"}\r\n </span>\r\n <span className=\"paragraph-xsmall-medium text-gray-500 truncate\">\r\n {user?.email || \"\"}\r\n </span>\r\n </div>\r\n\r\n {onEditProfile && (\r\n <Button\r\n variant=\"secondary\"\r\n className=\"paragraph-small-semibold h-8! whitespace-nowrap px-3 w-fit\"\r\n onClick={onEditProfile}\r\n >\r\n Editar Perfil\r\n </Button>\r\n )}\r\n </div>\r\n\r\n <div className=\"flex flex-col gap-2 border-t border-gray-200 rounded-2xl p-1.5\">\r\n {showCreditsSkeleton && (\r\n <div className=\"flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4\">\r\n <div className=\"flex items-center justify-between gap-2\">\r\n <span className=\"paragraph-xsmall-semibold text-white truncate\">\r\n Créditos usados\r\n </span>\r\n <div className=\"h-3.5 w-16 rounded bg-white/20 animate-pulse\" />\r\n </div>\r\n <div className=\"h-1.5 w-full rounded-full bg-white/20 animate-pulse\" />\r\n </div>\r\n )}\r\n\r\n {showCredits && (\r\n <div\r\n className={cn(\r\n \"flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4 transition-colors\",\r\n onCreditsClick && \"cursor-pointer hover:bg-gray-900\",\r\n )}\r\n onClick={onCreditsClick}\r\n >\r\n <div className=\"flex items-center justify-between gap-2\">\r\n <span className=\"paragraph-xsmall-semibold text-white truncate\">\r\n Créditos usados\r\n </span>\r\n <span className=\"paragraph-xsmall-medium text-white/50\">\r\n {summary.usedCredits.toLocaleString(\"pt-BR\")}/\r\n {summary.totalCredits.toLocaleString(\"pt-BR\")}\r\n </span>\r\n </div>\r\n <Progress\r\n className=\"bg-white/10\"\r\n indicatorColor=\"bg-white\"\r\n value={creditsPercentage}\r\n />\r\n </div>\r\n )}\r\n\r\n <div className=\"flex flex-col gap-2\">\r\n {menuItems.length > 0 && (\r\n <div className=\"flex flex-col\">\r\n {menuItems.map((item, index) => (\r\n <NavBarItem\r\n key={index}\r\n icon={item.icon}\r\n label={item.label}\r\n onClick={item.onClick}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n <Separator />\r\n <NavBarItem label=\"Sair\" onClick={handleLogout} />\r\n </div>\r\n </div>\r\n </PopoverPrimitive.Content>\r\n </PopoverPrimitive.Portal>\r\n </Popover>\r\n </>\r\n );\r\n}\r\n\r\nexport { ProfilePopover };\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { ApiError } from "./types";
|
|
2
2
|
import { findWhitelabel } from "../../modules/whitelabel/actions/find-whitelabel.action";
|
|
3
|
-
const API_BASE_URL = process.env.R3_API_URL || "https://r3-api.greatapps.dev.br";
|
|
4
|
-
const API_VERSION = "v1";
|
|
5
|
-
const API_LOCALE = "pt-br";
|
|
6
3
|
class ApiClient {
|
|
4
|
+
baseUrl;
|
|
5
|
+
apiVersion = "v1";
|
|
6
|
+
apiLocale = "pt-br";
|
|
7
|
+
constructor(baseUrl) {
|
|
8
|
+
this.baseUrl = baseUrl;
|
|
9
|
+
}
|
|
7
10
|
async buildUrl(endpoint, whiteLabelId) {
|
|
8
|
-
const url = `${
|
|
11
|
+
const url = `${this.baseUrl}/${this.apiVersion}/${this.apiLocale}/${whiteLabelId}${endpoint}`;
|
|
9
12
|
console.log("[ApiClient] buildUrl", {
|
|
10
|
-
baseURL:
|
|
13
|
+
baseURL: this.baseUrl,
|
|
11
14
|
whiteLabelId,
|
|
12
15
|
endpoint,
|
|
13
16
|
fullUrl: url
|
|
@@ -106,9 +109,14 @@ class ApiClient {
|
|
|
106
109
|
return this.request(endpoint, { ...config, method: "DELETE" });
|
|
107
110
|
}
|
|
108
111
|
}
|
|
109
|
-
const
|
|
112
|
+
const api = {
|
|
113
|
+
apps: new ApiClient(process.env.GAPPS_R3_API_URL || "https://r3-api.greatapps.dev.br"),
|
|
114
|
+
pages: new ApiClient(process.env.GPAGES_R3_API_URL || "https://r3-api.greatpages.dev.br")
|
|
115
|
+
};
|
|
116
|
+
const apiClient = api.apps;
|
|
110
117
|
export {
|
|
111
118
|
ApiClient,
|
|
119
|
+
api,
|
|
112
120
|
apiClient
|
|
113
121
|
};
|
|
114
122
|
//# sourceMappingURL=client.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/infra/api/client.ts"],"sourcesContent":["import { ApiError } from './types';\r\nimport { findWhitelabel } from '../../modules/whitelabel/actions/find-whitelabel.action';\r\n\r\
|
|
1
|
+
{"version":3,"sources":["../../../src/infra/api/client.ts"],"sourcesContent":["import { ApiError } from './types';\r\nimport { findWhitelabel } from '../../modules/whitelabel/actions/find-whitelabel.action';\r\n\r\ninterface RequestConfig extends RequestInit {\r\n timeout?: number;\r\n}\r\n\r\nclass ApiClient {\r\n private readonly baseUrl: string;\r\n private readonly apiVersion = 'v1';\r\n private readonly apiLocale = 'pt-br';\r\n\r\n constructor(baseUrl: string) {\r\n this.baseUrl = baseUrl;\r\n }\r\n\r\n private async buildUrl(endpoint: string, whiteLabelId: number): Promise<string> {\r\n const url = `${this.baseUrl}/${this.apiVersion}/${this.apiLocale}/${whiteLabelId}${endpoint}`;\r\n console.log('[ApiClient] buildUrl', {\r\n baseURL: this.baseUrl,\r\n whiteLabelId,\r\n endpoint,\r\n fullUrl: url,\r\n });\r\n return url;\r\n }\r\n\r\n private async getDefaultHeaders(token: string): Promise<HeadersInit> {\r\n console.log('[ApiClient] getDefaultHeaders', {\r\n token: token.substring(0, 20) + '...',\r\n });\r\n\r\n const headers: HeadersInit = {\r\n 'Content-Type': 'application/json',\r\n authorization: token,\r\n };\r\n\r\n return headers;\r\n }\r\n\r\n async request<T>(endpoint: string, config: RequestConfig = {}): Promise<T> {\r\n console.log('[ApiClient] request called', { endpoint, method: config.method });\r\n\r\n const { timeout = 30000, ...fetchConfig } = config;\r\n\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), timeout);\r\n\r\n try {\r\n console.log('[ApiClient] Building URL and headers...');\r\n\r\n const { id, token } = await findWhitelabel();\r\n\r\n const [url, defaultHeaders] = await Promise.all([\r\n this.buildUrl(endpoint, id),\r\n this.getDefaultHeaders(token),\r\n ]);\r\n\r\n console.log('[ApiClient] Fetching', {\r\n url,\r\n method: fetchConfig.method,\r\n headers: defaultHeaders,\r\n });\r\n\r\n const response = await fetch(url, {\r\n ...fetchConfig,\r\n headers: {\r\n ...defaultHeaders,\r\n ...fetchConfig.headers,\r\n },\r\n signal: controller.signal,\r\n });\r\n\r\n console.log('[ApiClient] Response received', { status: response.status, ok: response.ok });\r\n\r\n if (!response.ok) {\r\n const errorData = (await response.json().catch(() => ({}))) as Record<string, unknown>;\r\n console.error('[ApiClient] Request failed', { status: response.status, errorData });\r\n throw new ApiError(\r\n (errorData.message as string) || `HTTP error ${response.status}`,\r\n (errorData.code as string) || 'HTTP_ERROR',\r\n response.status\r\n );\r\n }\r\n\r\n const data = (await response.json()) as T;\r\n console.log('[ApiClient] Request successful', { hasData: !!data });\r\n return data;\r\n } catch (error) {\r\n console.error('[ApiClient] Request error', { error });\r\n\r\n if (error instanceof ApiError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error) {\r\n if (error.name === 'AbortError') {\r\n throw new ApiError('Tempo de requisição excedido', 'TIMEOUT', 408);\r\n }\r\n throw new ApiError(error.message, 'NETWORK_ERROR', 0);\r\n }\r\n\r\n throw new ApiError('Erro desconhecido', 'UNKNOWN_ERROR', 500);\r\n } finally {\r\n clearTimeout(timeoutId);\r\n }\r\n }\r\n\r\n async get<T>(endpoint: string, config?: RequestConfig): Promise<T> {\r\n return this.request<T>(endpoint, { ...config, method: 'GET' });\r\n }\r\n\r\n async post<T>(endpoint: string, data?: unknown, config?: RequestConfig): Promise<T> {\r\n return this.request<T>(endpoint, {\r\n ...config,\r\n method: 'POST',\r\n body: data ? JSON.stringify(data) : undefined,\r\n });\r\n }\r\n\r\n async put<T>(endpoint: string, data?: unknown, config?: RequestConfig): Promise<T> {\r\n return this.request<T>(endpoint, {\r\n ...config,\r\n method: 'PUT',\r\n body: data ? JSON.stringify(data) : undefined,\r\n });\r\n }\r\n\r\n async patch<T>(endpoint: string, data?: unknown, config?: RequestConfig): Promise<T> {\r\n return this.request<T>(endpoint, {\r\n ...config,\r\n method: 'PATCH',\r\n body: data ? JSON.stringify(data) : undefined,\r\n });\r\n }\r\n\r\n async delete<T>(endpoint: string, config?: RequestConfig): Promise<T> {\r\n return this.request<T>(endpoint, { ...config, method: 'DELETE' });\r\n }\r\n}\r\n\r\nconst api = {\r\n apps: new ApiClient(process.env.GAPPS_R3_API_URL || 'https://r3-api.greatapps.dev.br'),\r\n pages: new ApiClient(process.env.GPAGES_R3_API_URL || 'https://r3-api.greatpages.dev.br'),\r\n}\r\n\r\n/** @deprecated use api.apps */\r\nexport const apiClient = api.apps;\r\n\r\nexport { api, ApiClient };\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "server-only";
|
|
2
|
-
import {
|
|
2
|
+
import { api } from "../../../infra/api/client";
|
|
3
3
|
import { ApiError } from "../../../infra/api/types";
|
|
4
4
|
import { getUserContext } from "../../auth/utils/get-user-context";
|
|
5
5
|
import { IaCreditOperationSchema } from "../types";
|
|
@@ -7,7 +7,7 @@ class IaCreditsService {
|
|
|
7
7
|
async listOperations(subscriptionId) {
|
|
8
8
|
const { id_account } = await getUserContext();
|
|
9
9
|
const endpoint = `/accounts/${id_account}/subscriptions/${subscriptionId}/items/balance/list?page=1&limit=20&sort=id:DESC`;
|
|
10
|
-
const response = await
|
|
10
|
+
const response = await api.apps.get(endpoint);
|
|
11
11
|
if (response.status === 0) {
|
|
12
12
|
throw new ApiError(
|
|
13
13
|
response.message || "Erro ao listar cr\xE9ditos de IA",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/ia-credits/services/ia-credits.service.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/ia-credits/services/ia-credits.service.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport { api } from '../../../infra/api/client';\r\nimport { ApiError, ApiPaginatedActionResult, PaginatedSuccessResult } from '../../../infra/api/types';\r\nimport { getUserContext } from '../../auth/utils/get-user-context';\r\nimport { IaCreditOperation, IaCreditOperationSchema } from '../types';\r\n\r\nclass IaCreditsService {\r\n async listOperations(\r\n subscriptionId: number | string\r\n ): Promise<PaginatedSuccessResult<IaCreditOperation>> {\r\n const { id_account } = await getUserContext();\r\n\r\n const endpoint = `/accounts/${id_account}/subscriptions/${subscriptionId}/items/balance/list?page=1&limit=20&sort=id:DESC`;\r\n\r\n const response = await api.apps.get<ApiPaginatedActionResult<IaCreditOperation>>(endpoint);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || 'Erro ao listar créditos de IA',\r\n 'LIST_IA_CREDITS_FAILED',\r\n 400\r\n );\r\n }\r\n\r\n const raw = response.data ?? [];\r\n const data = raw.map((item) => IaCreditOperationSchema.parse(item));\r\n\r\n return {\r\n data,\r\n total: response.total ?? data.length,\r\n success: true,\r\n };\r\n }\r\n}\r\n\r\nexport const iaCreditsService = new IaCreditsService();\r\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,WAAW;AACpB,SAAS,gBAAkE;AAC3E,SAAS,sBAAsB;AAC/B,SAA4B,+BAA+B;AAE3D,MAAM,iBAAiB;AAAA,EACrB,MAAM,eACJ,gBACoD;AACpD,UAAM,EAAE,WAAW,IAAI,MAAM,eAAe;AAE5C,UAAM,WAAW,aAAa,UAAU,kBAAkB,cAAc;AAExE,UAAM,WAAW,MAAM,IAAI,KAAK,IAAiD,QAAQ;AAEzF,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM,SAAS,QAAQ,CAAC;AAC9B,UAAM,OAAO,IAAI,IAAI,CAAC,SAAS,wBAAwB,MAAM,IAAI,CAAC;AAElE,WAAO;AAAA,MACL;AAAA,MACA,OAAO,SAAS,SAAS,KAAK;AAAA,MAC9B,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAEO,MAAM,mBAAmB,IAAI,iBAAiB;","names":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "server-only";
|
|
2
|
-
import {
|
|
2
|
+
import { api } from "../../../infra/api/client";
|
|
3
3
|
import { ApiError } from "../../../infra/api/types";
|
|
4
4
|
import { buildQueryParams } from "../../../infra/utils/params";
|
|
5
5
|
import { getUserContext } from "../../auth/utils/get-user-context";
|
|
@@ -9,7 +9,7 @@ class SubscriptionsService {
|
|
|
9
9
|
const { id_account } = await getUserContext();
|
|
10
10
|
const query = buildQueryParams(params);
|
|
11
11
|
const url = `/accounts/${id_account}/subscriptions${query ? `?${query}` : ""}`;
|
|
12
|
-
const response = await
|
|
12
|
+
const response = await api.apps.get(url);
|
|
13
13
|
if (response.status === 0) {
|
|
14
14
|
throw new ApiError(
|
|
15
15
|
response.message || "Erro ao listar assinaturas",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/subscriptions/services/subscriptions.service.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/subscriptions/services/subscriptions.service.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport { api } from '../../../infra/api/client';\r\nimport { ApiError, ApiPaginatedActionResult, PaginatedSuccessResult } from '../../../infra/api/types';\r\nimport { buildQueryParams } from '../../../infra/utils/params';\r\nimport { getUserContext } from '../../auth/utils/get-user-context';\r\nimport { Subscription, SubscriptionSchema, FindSubscriptionsParams } from '../types';\r\n\r\nclass SubscriptionsService {\r\n async listSubscriptions(\r\n params?: Partial<FindSubscriptionsParams>\r\n ): Promise<PaginatedSuccessResult<Subscription>> {\r\n const { id_account } = await getUserContext();\r\n\r\n const query = buildQueryParams(params as Record<string, string | boolean | undefined>);\r\n const url = `/accounts/${id_account}/subscriptions${query ? `?${query}` : ''}`;\r\n\r\n const response = await api.apps.get<ApiPaginatedActionResult<Subscription>>(url);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || 'Erro ao listar assinaturas',\r\n 'LIST_SUBSCRIPTIONS_FAILED',\r\n 400\r\n );\r\n }\r\n\r\n const data = response.data.map((item) => SubscriptionSchema.parse(item));\r\n\r\n return {\r\n data,\r\n total: response.total,\r\n success: true,\r\n } satisfies PaginatedSuccessResult<Subscription>;\r\n }\r\n}\r\n\r\nexport const subscriptionsService = new SubscriptionsService();\r\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,WAAW;AACpB,SAAS,gBAAkE;AAC3E,SAAS,wBAAwB;AACjC,SAAS,sBAAsB;AAC/B,SAAuB,0BAAmD;AAE1E,MAAM,qBAAqB;AAAA,EACzB,MAAM,kBACJ,QAC+C;AAC/C,UAAM,EAAE,WAAW,IAAI,MAAM,eAAe;AAE5C,UAAM,QAAQ,iBAAiB,MAAsD;AACrF,UAAM,MAAM,aAAa,UAAU,iBAAiB,QAAQ,IAAI,KAAK,KAAK,EAAE;AAE5E,UAAM,WAAW,MAAM,IAAI,KAAK,IAA4C,GAAG;AAE/E,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAAO,SAAS,KAAK,IAAI,CAAC,SAAS,mBAAmB,MAAM,IAAI,CAAC;AAEvE,WAAO;AAAA,MACL;AAAA,MACA,OAAO,SAAS;AAAA,MAChB,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAEO,MAAM,uBAAuB,IAAI,qBAAqB;","names":[]}
|
|
@@ -2,7 +2,7 @@ import { cookies } from "next/headers";
|
|
|
2
2
|
import { ApiError } from "../../../infra/api/types";
|
|
3
3
|
import { findWhitelabel } from "../../whitelabel/actions/find-whitelabel.action";
|
|
4
4
|
const AUTH_COOKIE_NAME = "greatapps";
|
|
5
|
-
const API_BASE_URL = process.env.
|
|
5
|
+
const API_BASE_URL = process.env.GAPPS_R3_API_URL || "https://r3-api.greatapps.dev.br";
|
|
6
6
|
class UserService {
|
|
7
7
|
async getAuthToken() {
|
|
8
8
|
const cookieStore = await cookies();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/users/services/user.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { GetUserDataResponse, JWTPayload, User } from '../schema';\r\nimport { findWhitelabel } from '../../whitelabel/actions/find-whitelabel.action';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst API_BASE_URL = process.env.
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/users/services/user.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { GetUserDataResponse, JWTPayload, User } from '../schema';\r\nimport { findWhitelabel } from '../../whitelabel/actions/find-whitelabel.action';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst API_BASE_URL = process.env.GAPPS_R3_API_URL || 'https://r3-api.greatapps.dev.br';\r\n\r\nclass UserService {\r\n private async getAuthToken(): Promise<string> {\r\n const cookieStore = await cookies();\r\n const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n\r\n if (!token) {\r\n throw new ApiError('Não autenticado', 'NOT_AUTHENTICATED', 401);\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private decodeJWT(token: string): JWTPayload {\r\n try {\r\n return JSON.parse(atob(token.split('.')[1])) as JWTPayload;\r\n } catch {\r\n throw new ApiError('Token inválido', 'INVALID_TOKEN', 401);\r\n }\r\n }\r\n\r\n async findById(): Promise<User> {\r\n const token = await this.getAuthToken();\r\n const payload = this.decodeJWT(token);\r\n\r\n const { id_wl, id_account, id_user } = payload;\r\n const { token: wlToken } = await findWhitelabel();\r\n\r\n const url = `${API_BASE_URL}/v1/pt-br/${id_wl}/accounts/${id_account}/users/${id_user}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'GET',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n authorization: wlToken,\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ApiError('Erro ao buscar dados do usuário', 'FETCH_ERROR', response.status);\r\n }\r\n\r\n const data = (await response.json()) as GetUserDataResponse;\r\n\r\n if (data.status === 0 || !data.data || data.data.length === 0) {\r\n throw new ApiError('Dados do usuário não encontrados', 'USER_NOT_FOUND', 404);\r\n }\r\n\r\n return data.data[0];\r\n }\r\n}\r\n\r\nexport const userService = new UserService();\r\n"],"mappings":"AACA,SAAS,eAAe;AAExB,SAAS,gBAAgB;AAEzB,SAAS,sBAAsB;AAE/B,MAAM,mBAAmB;AACzB,MAAM,eAAe,QAAQ,IAAI,oBAAoB;AAErD,MAAM,YAAY;AAAA,EAChB,MAAc,eAAgC;AAC5C,UAAM,cAAc,MAAM,QAAQ;AAClC,UAAM,QAAQ,YAAY,IAAI,gBAAgB,GAAG;AAEjD,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,SAAS,sBAAmB,qBAAqB,GAAG;AAAA,IAChE;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAU,OAA2B;AAC3C,QAAI;AACF,aAAO,KAAK,MAAM,KAAK,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;AAAA,IAC7C,QAAQ;AACN,YAAM,IAAI,SAAS,qBAAkB,iBAAiB,GAAG;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAC9B,UAAM,QAAQ,MAAM,KAAK,aAAa;AACtC,UAAM,UAAU,KAAK,UAAU,KAAK;AAEpC,UAAM,EAAE,OAAO,YAAY,QAAQ,IAAI;AACvC,UAAM,EAAE,OAAO,QAAQ,IAAI,MAAM,eAAe;AAEhD,UAAM,MAAM,GAAG,YAAY,aAAa,KAAK,aAAa,UAAU,UAAU,OAAO;AAErF,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,SAAS,sCAAmC,eAAe,SAAS,MAAM;AAAA,IACtF;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,QAAI,KAAK,WAAW,KAAK,CAAC,KAAK,QAAQ,KAAK,KAAK,WAAW,GAAG;AAC7D,YAAM,IAAI,SAAS,0CAAoC,kBAAkB,GAAG;AAAA,IAC9E;AAEA,WAAO,KAAK,KAAK,CAAC;AAAA,EACpB;AACF;AAEO,MAAM,cAAc,IAAI,YAAY;","names":[]}
|
|
@@ -2,9 +2,9 @@ import greatCache from "@greatapps/cache";
|
|
|
2
2
|
import { ApiError } from "../../../infra/api/types";
|
|
3
3
|
class WhitelabelService {
|
|
4
4
|
getApiUrl() {
|
|
5
|
-
const apiUrl = process.env.
|
|
5
|
+
const apiUrl = process.env.GAPPS_R3_API_URL;
|
|
6
6
|
if (!apiUrl) {
|
|
7
|
-
throw new ApiError("
|
|
7
|
+
throw new ApiError("GAPPS_R3_API_URL not configured", "CONFIG_ERROR", 500);
|
|
8
8
|
}
|
|
9
9
|
return apiUrl;
|
|
10
10
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/whitelabel/services/whitelabel.service.ts"],"sourcesContent":["\r\nimport greatCache from '@greatapps/cache';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { WhitelabelTokenApiResponse, WhitelabelTokenData } from '../schema';\r\n\r\nclass WhitelabelService {\r\n private getApiUrl(): string {\r\n const apiUrl = process.env.
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/whitelabel/services/whitelabel.service.ts"],"sourcesContent":["\r\nimport greatCache from '@greatapps/cache';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { WhitelabelTokenApiResponse, WhitelabelTokenData } from '../schema';\r\n\r\nclass WhitelabelService {\r\n private getApiUrl(): string {\r\n const apiUrl = process.env.GAPPS_R3_API_URL;\r\n if (!apiUrl) {\r\n throw new ApiError('GAPPS_R3_API_URL not configured', 'CONFIG_ERROR', 500);\r\n }\r\n return apiUrl;\r\n }\r\n\r\n private getToken(): string {\r\n const token = process.env.WHITELABEL_TOKEN_MASTER;\r\n if (!token) {\r\n throw new ApiError('WHITELABEL_TOKEN_MASTER not configured', 'CONFIG_ERROR', 500);\r\n }\r\n return token;\r\n }\r\n\r\n async getTokenByDomain(hostname: string): Promise<WhitelabelTokenData> {\r\n hostname = 'greatapps.com.br';\r\n\r\n const apiUrl = this.getApiUrl();\r\n const whitelabelMasterToken = this.getToken();\r\n\r\n const url = `${apiUrl}/v1/pt-br/1/whitelabel/${hostname}/token`;\r\n\r\n console.log('[WhitelabelService] Fetching token for domain', { url });\r\n\r\n const cache = new greatCache({\r\n service: 'whitelabel-service',\r\n version: '1.0',\r\n domain: 'whitelabel-cache.greatapps.com.br',\r\n ambient: process.env.NODE_ENV || 'development',\r\n });\r\n\r\n const cachedData = await cache.select(`whitelabel-token-${hostname}`);\r\n\r\n if (cachedData.status == 1 && 'data' in cachedData && cachedData.data) {\r\n console.log('[WhitelabelService] Cache hit for domain', { hostname });\r\n\r\n return JSON.parse(cachedData.data) as WhitelabelTokenData;\r\n }\r\n\r\n const response = await fetch(url, {\r\n method: 'GET',\r\n headers: {\r\n authorization: whitelabelMasterToken,\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n console.error('[WhitelabelService] Failed to fetch whitelabel token', { response });\r\n throw new ApiError(\r\n `Failed to fetch whitelabel token: ${response.status}`,\r\n 'FETCH_ERROR',\r\n response.status\r\n );\r\n }\r\n\r\n const result: WhitelabelTokenApiResponse = await response.json();\r\n\r\n if (result.status !== 1 || !result.data?.length) {\r\n throw new ApiError('Whitelabel token not found', 'TOKEN_NOT_FOUND', 404);\r\n }\r\n\r\n await cache.insert(`whitelabel-token-${hostname}`, JSON.stringify(result.data[0]), 604800);\r\n\r\n return result.data[0];\r\n }\r\n}\r\n\r\nexport const whitelabelService = new WhitelabelService();\r\n"],"mappings":"AACA,OAAO,gBAAgB;AACvB,SAAS,gBAAgB;AAGzB,MAAM,kBAAkB;AAAA,EACd,YAAoB;AAC1B,UAAM,SAAS,QAAQ,IAAI;AAC3B,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,SAAS,mCAAmC,gBAAgB,GAAG;AAAA,IAC3E;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,WAAmB;AACzB,UAAM,QAAQ,QAAQ,IAAI;AAC1B,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,SAAS,0CAA0C,gBAAgB,GAAG;AAAA,IAClF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,iBAAiB,UAAgD;AACrE,eAAW;AAEX,UAAM,SAAS,KAAK,UAAU;AAC9B,UAAM,wBAAwB,KAAK,SAAS;AAE5C,UAAM,MAAM,GAAG,MAAM,0BAA0B,QAAQ;AAEvD,YAAQ,IAAI,iDAAiD,EAAE,IAAI,CAAC;AAEpE,UAAM,QAAQ,IAAI,WAAW;AAAA,MAC3B,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,SAAS,QAAQ,IAAI,YAAY;AAAA,IACnC,CAAC;AAED,UAAM,aAAa,MAAM,MAAM,OAAO,oBAAoB,QAAQ,EAAE;AAEpE,QAAI,WAAW,UAAU,KAAK,UAAU,cAAc,WAAW,MAAM;AACrE,cAAQ,IAAI,4CAA4C,EAAE,SAAS,CAAC;AAEpE,aAAO,KAAK,MAAM,WAAW,IAAI;AAAA,IACnC;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,cAAQ,MAAM,wDAAwD,EAAE,SAAS,CAAC;AAClF,YAAM,IAAI;AAAA,QACR,qCAAqC,SAAS,MAAM;AAAA,QACpD;AAAA,QACA,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,SAAqC,MAAM,SAAS,KAAK;AAE/D,QAAI,OAAO,WAAW,KAAK,CAAC,OAAO,MAAM,QAAQ;AAC/C,YAAM,IAAI,SAAS,8BAA8B,mBAAmB,GAAG;AAAA,IACzE;AAEA,UAAM,MAAM,OAAO,oBAAoB,QAAQ,IAAI,KAAK,UAAU,OAAO,KAAK,CAAC,CAAC,GAAG,MAAM;AAEzF,WAAO,OAAO,KAAK,CAAC;AAAA,EACtB;AACF;AAEO,MAAM,oBAAoB,IAAI,kBAAkB;","names":[]}
|
package/dist/server.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "server-only";
|
|
2
|
-
import {
|
|
2
|
+
import { ApiClient, api, apiClient } from "./infra/api/client";
|
|
3
3
|
import { authService } from "./modules/auth/services/auth.service";
|
|
4
4
|
import { whitelabelService } from "./modules/whitelabel/services/whitelabel.service";
|
|
5
5
|
import { subscriptionsService } from "./modules/subscriptions/services/subscriptions.service";
|
|
@@ -12,6 +12,7 @@ import { getClientInfoFromRequest } from "./infra/utils/client-info";
|
|
|
12
12
|
import { getUserContext } from "./modules/auth/utils/get-user-context";
|
|
13
13
|
export {
|
|
14
14
|
ApiClient,
|
|
15
|
+
api,
|
|
15
16
|
apiClient,
|
|
16
17
|
authService,
|
|
17
18
|
findWhitelabel,
|
package/dist/server.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only';\r\n\r\n// API Client\r\nexport {
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only';\r\n\r\n// API Client\r\nexport { ApiClient, api, apiClient } from './infra/api/client';\r\n\r\n// Services\r\nexport { authService } from './modules/auth/services/auth.service';\r\nexport { whitelabelService } from './modules/whitelabel/services/whitelabel.service';\r\nexport { subscriptionsService } from './modules/subscriptions/services/subscriptions.service';\r\nexport { iaCreditsService } from './modules/ia-credits/services/ia-credits.service';\r\n\r\n// Actions\r\nexport { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';\r\nexport { validateSessionAction } from './modules/auth/actions/validate-session.action';\r\nexport { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';\r\nexport { listIaCreditsAction } from './modules/ia-credits/actions/list-ia-credits.action';\r\n\r\n// Server Utils\r\nexport { getClientInfoFromRequest } from './infra/utils/client-info';\r\nexport { getUserContext } from './modules/auth/utils/get-user-context';\r\n"],"mappings":"AAAA,OAAO;AAGP,SAAS,WAAW,KAAK,iBAAiB;AAG1C,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,wBAAwB;AAGjC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,2BAA2B;AAGpC,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
"use client"
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import { useState } from
|
|
4
|
-
import { useRouter } from
|
|
5
|
-
import * as PopoverPrimitive from
|
|
6
|
-
import { Popover } from
|
|
7
|
-
import { Button } from
|
|
8
|
-
import { Progress } from
|
|
9
|
-
import { Separator } from
|
|
10
|
-
import { NavBarItem } from
|
|
11
|
-
import { UserAvatar } from
|
|
12
|
-
import { useAuth } from
|
|
13
|
-
import { cn } from
|
|
14
|
-
import { useIaCredits } from
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useRouter } from "next/navigation";
|
|
5
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
6
|
+
import { Popover } from "../ui/overlay/Popover";
|
|
7
|
+
import { Button } from "../ui/buttons/Button";
|
|
8
|
+
import { Progress } from "../ui/feedback/Progress";
|
|
9
|
+
import { Separator } from "../ui/data-display/Separator";
|
|
10
|
+
import { NavBarItem } from "./NavBarItem";
|
|
11
|
+
import { UserAvatar } from "../ui/data-display/UserAvatar";
|
|
12
|
+
import { useAuth } from "../../providers/auth.provider";
|
|
13
|
+
import { cn } from "../../infra/utils/clsx";
|
|
14
|
+
import { useIaCredits } from "../../modules/ia-credits/hooks/ia-credits.hook";
|
|
15
15
|
|
|
16
16
|
export interface ProfileMenuItem {
|
|
17
17
|
icon?: React.ReactNode;
|
|
@@ -20,8 +20,8 @@ export interface ProfileMenuItem {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export interface ProfilePopoverProps {
|
|
23
|
-
side?:
|
|
24
|
-
align?:
|
|
23
|
+
side?: "top" | "bottom" | "left" | "right";
|
|
24
|
+
align?: "start" | "center" | "end";
|
|
25
25
|
contentClassName?: string;
|
|
26
26
|
onEditProfile?: () => void;
|
|
27
27
|
onCreditsClick?: () => void;
|
|
@@ -31,20 +31,21 @@ export interface ProfilePopoverProps {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function ProfilePopover({
|
|
34
|
-
side =
|
|
35
|
-
align =
|
|
36
|
-
contentClassName =
|
|
34
|
+
side = "top",
|
|
35
|
+
align = "start",
|
|
36
|
+
contentClassName = "absolute bottom-2 left-[26px]",
|
|
37
37
|
onEditProfile,
|
|
38
38
|
onCreditsClick,
|
|
39
39
|
menuItems = [],
|
|
40
|
-
logoutRedirect =
|
|
40
|
+
logoutRedirect = "/login",
|
|
41
41
|
logoutOverlay,
|
|
42
42
|
}: ProfilePopoverProps) {
|
|
43
43
|
const router = useRouter();
|
|
44
44
|
const { user, logout } = useAuth();
|
|
45
45
|
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
|
46
46
|
|
|
47
|
-
const { summary, subscription, isSubscriptionLoading, isCreditsLoading } =
|
|
47
|
+
const { summary, subscription, isSubscriptionLoading, isCreditsLoading } =
|
|
48
|
+
useIaCredits();
|
|
48
49
|
|
|
49
50
|
const handleLogout = async () => {
|
|
50
51
|
try {
|
|
@@ -52,7 +53,7 @@ function ProfilePopover({
|
|
|
52
53
|
await logout();
|
|
53
54
|
router.push(logoutRedirect);
|
|
54
55
|
} catch (error) {
|
|
55
|
-
console.error(
|
|
56
|
+
console.error("Erro ao fazer logout:", error);
|
|
56
57
|
} finally {
|
|
57
58
|
setIsLoggingOut(false);
|
|
58
59
|
}
|
|
@@ -60,7 +61,8 @@ function ProfilePopover({
|
|
|
60
61
|
|
|
61
62
|
const hasSubscription = !isSubscriptionLoading && subscription !== null;
|
|
62
63
|
const showCreditsSkeleton = hasSubscription && isCreditsLoading;
|
|
63
|
-
const showCredits =
|
|
64
|
+
const showCredits =
|
|
65
|
+
hasSubscription && !isCreditsLoading && summary.totalCredits > 0;
|
|
64
66
|
const creditsPercentage =
|
|
65
67
|
showCredits && summary.totalCredits > 0
|
|
66
68
|
? (summary.usedCredits / summary.totalCredits) * 100
|
|
@@ -82,101 +84,101 @@ function ProfilePopover({
|
|
|
82
84
|
</PopoverPrimitive.Trigger>
|
|
83
85
|
|
|
84
86
|
<PopoverPrimitive.Portal>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
)}
|
|
90
|
-
side={side}
|
|
91
|
-
align={align}
|
|
92
|
-
sideOffset={8}
|
|
93
|
-
>
|
|
94
|
-
<div className="grid grid-cols-[32px_1fr_auto] items-center gap-3 p-3 w-full">
|
|
95
|
-
{user && (
|
|
96
|
-
<UserAvatar
|
|
97
|
-
key={user.id}
|
|
98
|
-
photo={user.photo}
|
|
99
|
-
name={user.name}
|
|
100
|
-
size={32}
|
|
101
|
-
/>
|
|
87
|
+
<PopoverPrimitive.Content
|
|
88
|
+
className={cn(
|
|
89
|
+
"w-64.75 p-0 bg-white rounded-2xl shadow-md border border-gray-200 z-99",
|
|
90
|
+
contentClassName,
|
|
102
91
|
)}
|
|
92
|
+
side={side}
|
|
93
|
+
align={align}
|
|
94
|
+
sideOffset={8}
|
|
95
|
+
>
|
|
96
|
+
<div className="grid grid-cols-[32px_1fr_auto] items-center gap-3 p-3 w-full">
|
|
97
|
+
{user && (
|
|
98
|
+
<UserAvatar
|
|
99
|
+
key={user.id}
|
|
100
|
+
photo={user.photo}
|
|
101
|
+
name={user.name}
|
|
102
|
+
size={32}
|
|
103
|
+
/>
|
|
104
|
+
)}
|
|
105
|
+
|
|
106
|
+
<div className="flex flex-col gap-0.5 min-w-0">
|
|
107
|
+
<span className="paragraph-small-semibold text-gray-950 truncate">
|
|
108
|
+
{user?.name || ""}
|
|
109
|
+
</span>
|
|
110
|
+
<span className="paragraph-xsmall-medium text-gray-500 truncate">
|
|
111
|
+
{user?.email || ""}
|
|
112
|
+
</span>
|
|
113
|
+
</div>
|
|
103
114
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
115
|
+
{onEditProfile && (
|
|
116
|
+
<Button
|
|
117
|
+
variant="secondary"
|
|
118
|
+
className="paragraph-small-semibold h-8! whitespace-nowrap px-3 w-fit"
|
|
119
|
+
onClick={onEditProfile}
|
|
120
|
+
>
|
|
121
|
+
Editar Perfil
|
|
122
|
+
</Button>
|
|
123
|
+
)}
|
|
111
124
|
</div>
|
|
112
125
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
<div className="flex flex-col gap-2 border-t border-gray-200 rounded-2xl p-1.5">
|
|
127
|
+
{showCreditsSkeleton && (
|
|
128
|
+
<div className="flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4">
|
|
129
|
+
<div className="flex items-center justify-between gap-2">
|
|
130
|
+
<span className="paragraph-xsmall-semibold text-white truncate">
|
|
131
|
+
Créditos usados
|
|
132
|
+
</span>
|
|
133
|
+
<div className="h-3.5 w-16 rounded bg-white/20 animate-pulse" />
|
|
134
|
+
</div>
|
|
135
|
+
<div className="h-1.5 w-full rounded-full bg-white/20 animate-pulse" />
|
|
136
|
+
</div>
|
|
137
|
+
)}
|
|
123
138
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
139
|
+
{showCredits && (
|
|
140
|
+
<div
|
|
141
|
+
className={cn(
|
|
142
|
+
"flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4 transition-colors",
|
|
143
|
+
onCreditsClick && "cursor-pointer hover:bg-gray-900",
|
|
144
|
+
)}
|
|
145
|
+
onClick={onCreditsClick}
|
|
146
|
+
>
|
|
147
|
+
<div className="flex items-center justify-between gap-2">
|
|
148
|
+
<span className="paragraph-xsmall-semibold text-white truncate">
|
|
149
|
+
Créditos usados
|
|
150
|
+
</span>
|
|
151
|
+
<span className="paragraph-xsmall-medium text-white/50">
|
|
152
|
+
{summary.usedCredits.toLocaleString("pt-BR")}/
|
|
153
|
+
{summary.totalCredits.toLocaleString("pt-BR")}
|
|
154
|
+
</span>
|
|
155
|
+
</div>
|
|
156
|
+
<Progress
|
|
157
|
+
className="bg-white/10"
|
|
158
|
+
indicatorColor="bg-white"
|
|
159
|
+
value={creditsPercentage}
|
|
160
|
+
/>
|
|
132
161
|
</div>
|
|
133
|
-
|
|
134
|
-
</div>
|
|
135
|
-
)}
|
|
162
|
+
)}
|
|
136
163
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
164
|
+
<div className="flex flex-col gap-2">
|
|
165
|
+
{menuItems.length > 0 && (
|
|
166
|
+
<div className="flex flex-col">
|
|
167
|
+
{menuItems.map((item, index) => (
|
|
168
|
+
<NavBarItem
|
|
169
|
+
key={index}
|
|
170
|
+
icon={item.icon}
|
|
171
|
+
label={item.label}
|
|
172
|
+
onClick={item.onClick}
|
|
173
|
+
/>
|
|
174
|
+
))}
|
|
175
|
+
</div>
|
|
142
176
|
)}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
<div className="flex items-center justify-between gap-2">
|
|
146
|
-
<span className="paragraph-xsmall-semibold text-white truncate">
|
|
147
|
-
Créditos usados
|
|
148
|
-
</span>
|
|
149
|
-
<span className="paragraph-xsmall-medium text-white/50">
|
|
150
|
-
{summary.usedCredits.toLocaleString('pt-BR')}/
|
|
151
|
-
{summary.totalCredits.toLocaleString('pt-BR')}
|
|
152
|
-
</span>
|
|
153
|
-
</div>
|
|
154
|
-
<Progress
|
|
155
|
-
className="bg-white/10"
|
|
156
|
-
indicatorColor="bg-white"
|
|
157
|
-
value={creditsPercentage}
|
|
158
|
-
/>
|
|
177
|
+
<Separator />
|
|
178
|
+
<NavBarItem label="Sair" onClick={handleLogout} />
|
|
159
179
|
</div>
|
|
160
|
-
)}
|
|
161
|
-
|
|
162
|
-
<div className="flex flex-col gap-2">
|
|
163
|
-
{menuItems.length > 0 && (
|
|
164
|
-
<div className="flex flex-col">
|
|
165
|
-
{menuItems.map((item, index) => (
|
|
166
|
-
<NavBarItem
|
|
167
|
-
key={index}
|
|
168
|
-
icon={item.icon}
|
|
169
|
-
label={item.label}
|
|
170
|
-
onClick={item.onClick}
|
|
171
|
-
/>
|
|
172
|
-
))}
|
|
173
|
-
</div>
|
|
174
|
-
)}
|
|
175
|
-
<Separator />
|
|
176
|
-
<NavBarItem label="Sair" onClick={handleLogout} />
|
|
177
180
|
</div>
|
|
178
|
-
</
|
|
179
|
-
</PopoverPrimitive.Content>
|
|
181
|
+
</PopoverPrimitive.Content>
|
|
180
182
|
</PopoverPrimitive.Portal>
|
|
181
183
|
</Popover>
|
|
182
184
|
</>
|
package/src/infra/api/client.ts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { ApiError } from './types';
|
|
2
2
|
import { findWhitelabel } from '../../modules/whitelabel/actions/find-whitelabel.action';
|
|
3
3
|
|
|
4
|
-
const API_BASE_URL = process.env.R3_API_URL || 'https://r3-api.greatapps.dev.br';
|
|
5
|
-
const API_VERSION = 'v1';
|
|
6
|
-
const API_LOCALE = 'pt-br';
|
|
7
|
-
|
|
8
4
|
interface RequestConfig extends RequestInit {
|
|
9
5
|
timeout?: number;
|
|
10
6
|
}
|
|
11
7
|
|
|
12
8
|
class ApiClient {
|
|
9
|
+
private readonly baseUrl: string;
|
|
10
|
+
private readonly apiVersion = 'v1';
|
|
11
|
+
private readonly apiLocale = 'pt-br';
|
|
12
|
+
|
|
13
|
+
constructor(baseUrl: string) {
|
|
14
|
+
this.baseUrl = baseUrl;
|
|
15
|
+
}
|
|
16
|
+
|
|
13
17
|
private async buildUrl(endpoint: string, whiteLabelId: number): Promise<string> {
|
|
14
|
-
const url = `${
|
|
18
|
+
const url = `${this.baseUrl}/${this.apiVersion}/${this.apiLocale}/${whiteLabelId}${endpoint}`;
|
|
15
19
|
console.log('[ApiClient] buildUrl', {
|
|
16
|
-
baseURL:
|
|
20
|
+
baseURL: this.baseUrl,
|
|
17
21
|
whiteLabelId,
|
|
18
22
|
endpoint,
|
|
19
23
|
fullUrl: url,
|
|
@@ -135,5 +139,12 @@ class ApiClient {
|
|
|
135
139
|
}
|
|
136
140
|
}
|
|
137
141
|
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
const api = {
|
|
143
|
+
apps: new ApiClient(process.env.GAPPS_R3_API_URL || 'https://r3-api.greatapps.dev.br'),
|
|
144
|
+
pages: new ApiClient(process.env.GPAGES_R3_API_URL || 'https://r3-api.greatpages.dev.br'),
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** @deprecated use api.apps */
|
|
148
|
+
export const apiClient = api.apps;
|
|
149
|
+
|
|
150
|
+
export { api, ApiClient };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { api } from '../../../infra/api/client';
|
|
4
4
|
import { ApiError, ApiPaginatedActionResult, PaginatedSuccessResult } from '../../../infra/api/types';
|
|
5
5
|
import { getUserContext } from '../../auth/utils/get-user-context';
|
|
6
6
|
import { IaCreditOperation, IaCreditOperationSchema } from '../types';
|
|
@@ -13,7 +13,7 @@ class IaCreditsService {
|
|
|
13
13
|
|
|
14
14
|
const endpoint = `/accounts/${id_account}/subscriptions/${subscriptionId}/items/balance/list?page=1&limit=20&sort=id:DESC`;
|
|
15
15
|
|
|
16
|
-
const response = await
|
|
16
|
+
const response = await api.apps.get<ApiPaginatedActionResult<IaCreditOperation>>(endpoint);
|
|
17
17
|
|
|
18
18
|
if (response.status === 0) {
|
|
19
19
|
throw new ApiError(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { api } from '../../../infra/api/client';
|
|
4
4
|
import { ApiError, ApiPaginatedActionResult, PaginatedSuccessResult } from '../../../infra/api/types';
|
|
5
5
|
import { buildQueryParams } from '../../../infra/utils/params';
|
|
6
6
|
import { getUserContext } from '../../auth/utils/get-user-context';
|
|
@@ -15,7 +15,7 @@ class SubscriptionsService {
|
|
|
15
15
|
const query = buildQueryParams(params as Record<string, string | boolean | undefined>);
|
|
16
16
|
const url = `/accounts/${id_account}/subscriptions${query ? `?${query}` : ''}`;
|
|
17
17
|
|
|
18
|
-
const response = await
|
|
18
|
+
const response = await api.apps.get<ApiPaginatedActionResult<Subscription>>(url);
|
|
19
19
|
|
|
20
20
|
if (response.status === 0) {
|
|
21
21
|
throw new ApiError(
|
|
@@ -6,7 +6,7 @@ import { GetUserDataResponse, JWTPayload, User } from '../schema';
|
|
|
6
6
|
import { findWhitelabel } from '../../whitelabel/actions/find-whitelabel.action';
|
|
7
7
|
|
|
8
8
|
const AUTH_COOKIE_NAME = 'greatapps';
|
|
9
|
-
const API_BASE_URL = process.env.
|
|
9
|
+
const API_BASE_URL = process.env.GAPPS_R3_API_URL || 'https://r3-api.greatapps.dev.br';
|
|
10
10
|
|
|
11
11
|
class UserService {
|
|
12
12
|
private async getAuthToken(): Promise<string> {
|
|
@@ -5,9 +5,9 @@ import { WhitelabelTokenApiResponse, WhitelabelTokenData } from '../schema';
|
|
|
5
5
|
|
|
6
6
|
class WhitelabelService {
|
|
7
7
|
private getApiUrl(): string {
|
|
8
|
-
const apiUrl = process.env.
|
|
8
|
+
const apiUrl = process.env.GAPPS_R3_API_URL;
|
|
9
9
|
if (!apiUrl) {
|
|
10
|
-
throw new ApiError('
|
|
10
|
+
throw new ApiError('GAPPS_R3_API_URL not configured', 'CONFIG_ERROR', 500);
|
|
11
11
|
}
|
|
12
12
|
return apiUrl;
|
|
13
13
|
}
|
package/src/server.ts
CHANGED