@omnizap-system/omnizap 2.6.0 → 2.6.2
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/.env.example +58 -13
- package/.github/workflows/ci.yml +5 -5
- package/.github/workflows/codeql.yml +1 -1
- package/.github/workflows/db-migration-check.yml +2 -2
- package/.github/workflows/dependency-review.yml +1 -1
- package/.github/workflows/deploy.yml +2 -2
- package/.github/workflows/release.yml +2 -2
- package/.github/workflows/security-attest-provenance.yml +2 -2
- package/.github/workflows/security-gitleaks.yml +13 -4
- package/.github/workflows/security-runner-hardening.yml +2 -2
- package/.github/workflows/security-scorecard.yml +1 -1
- package/.github/workflows/security-zap-baseline.yml +1 -1
- package/.github/workflows/security-zap-full-scan.yml +2 -1
- package/.github/workflows/security-zizmor.yml +1 -1
- package/.github/workflows/wiki-sync.yml +1 -1
- package/.gitleaksignore +9 -0
- package/CODE_OF_CONDUCT.md +2 -2
- package/GEMINI.md +64 -0
- package/README.md +52 -82
- package/SECURITY.md +1 -1
- package/app/config/index.js +2 -0
- package/app/configParts/adminIdentity.js +5 -5
- package/app/configParts/baileysConfig.js +230 -58
- package/app/configParts/groupUtils.js +5 -0
- package/app/configParts/messagePersistenceService.js +145 -4
- package/app/configParts/sessionConfig.js +157 -0
- package/app/connection/baileysCompatibility.test.js +1 -1
- package/app/connection/groupOwnerWriteStateResolver.js +109 -0
- package/app/connection/socketController.js +660 -158
- package/app/connection/socketController.multiSession.test.js +108 -0
- package/app/controllers/messageController.js +1 -1
- package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
- package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
- package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
- package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
- package/app/controllers/messageProcessingPipeline.js +93 -13
- package/app/controllers/messageProcessingPipeline.test.js +200 -0
- package/app/modules/adminModule/AGENT.md +1 -1
- package/app/modules/adminModule/commandConfig.json +3318 -1347
- package/app/modules/adminModule/groupCommandHandlers.js +858 -15
- package/app/modules/adminModule/groupCommandHandlers.test.js +378 -11
- package/app/modules/adminModule/groupWarningRepository.js +152 -0
- package/app/modules/aiModule/AGENT.md +47 -30
- package/app/modules/aiModule/aiConfigRuntime.js +1 -0
- package/app/modules/aiModule/catCommand.js +135 -27
- package/app/modules/aiModule/commandConfig.json +114 -28
- package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
- package/app/modules/gameModule/AGENT.md +1 -1
- package/app/modules/gameModule/commandConfig.json +29 -0
- package/app/modules/menuModule/AGENT.md +1 -1
- package/app/modules/menuModule/commandConfig.json +45 -10
- package/app/modules/menuModule/menuCatalogService.js +190 -0
- package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
- package/app/modules/menuModule/menuDynamicService.js +511 -0
- package/app/modules/menuModule/menuDynamicService.test.js +141 -0
- package/app/modules/menuModule/menus.js +36 -5
- package/app/modules/playModule/AGENT.md +10 -5
- package/app/modules/playModule/commandConfig.json +140 -12
- package/app/modules/playModule/playCommand.js +1 -1417
- package/app/modules/playModule/playCommandConstants.js +80 -0
- package/app/modules/playModule/playCommandCore.js +361 -0
- package/app/modules/playModule/playCommandHandlers.js +41 -0
- package/app/modules/playModule/playCommandMediaClient.js +1872 -0
- package/app/modules/playModule/playConfigRuntime.js +245 -4
- package/app/modules/playModule/playModuleCriticalFlows.test.js +152 -0
- package/app/modules/quoteModule/AGENT.md +1 -1
- package/app/modules/quoteModule/commandConfig.json +29 -0
- package/app/modules/quoteModule/quoteCommand.js +3 -2
- package/app/modules/rpgPokemonModule/AGENT.md +1 -1
- package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
- package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +5 -4
- package/app/modules/rpgPokemonModule/rpgBattleService.test.js +2 -1
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +2 -1
- package/app/modules/rpgPokemonModule/rpgPokemonService.js +38 -37
- package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +4 -3
- package/app/modules/statsModule/AGENT.md +1 -1
- package/app/modules/statsModule/commandConfig.json +58 -0
- package/app/modules/statsModule/rankingCommon.js +5 -4
- package/app/modules/stickerModule/AGENT.md +1 -1
- package/app/modules/stickerModule/addStickerMetadata.js +4 -3
- package/app/modules/stickerModule/commandConfig.json +145 -0
- package/app/modules/stickerModule/stickerCommand.js +1 -1
- package/app/modules/stickerPackModule/AGENT.md +1 -1
- package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
- package/app/modules/stickerPackModule/commandConfig.json +29 -0
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +7 -6
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +10 -9
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +9 -8
- package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +3 -2
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +2 -1
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +80 -58
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +2 -1
- package/app/modules/stickerPackModule/stickerPackRepository.js +2 -1
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +5 -4
- package/app/modules/stickerPackModule/stickerPackService.js +13 -6
- package/app/modules/stickerPackModule/stickerStorageService.js +3 -2
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +2 -1
- package/app/modules/systemMetricsModule/AGENT.md +1 -1
- package/app/modules/systemMetricsModule/commandConfig.json +29 -0
- package/app/modules/systemMetricsModule/pingCommand.js +6 -5
- package/app/modules/tiktokModule/AGENT.md +1 -1
- package/app/modules/tiktokModule/commandConfig.json +29 -0
- package/app/modules/tiktokModule/tiktokCommand.js +2 -1
- package/app/modules/userModule/AGENT.md +1 -1
- package/app/modules/userModule/commandConfig.json +29 -0
- package/app/modules/userModule/userCommand.js +72 -23
- package/app/modules/waifuPicsModule/AGENT.md +57 -27
- package/app/modules/waifuPicsModule/commandConfig.json +87 -0
- package/app/modules/waifuPicsModule/waifuPicsCommand.js +3 -2
- package/app/observability/metrics.js +136 -0
- package/app/services/ai/commandConfigEnrichmentService.js +229 -47
- package/app/services/ai/conversationRouterService.js +4 -3
- package/app/services/ai/geminiService.js +132 -7
- package/app/services/ai/geminiService.test.js +59 -2
- package/app/services/ai/globalModuleAiHelpService.js +3 -2
- package/app/services/ai/messageCommandExecutionService.js +2 -1
- package/app/services/ai/moduleAiHelpCoreService.js +45 -14
- package/app/services/ai/moduleToolExecutorService.js +3 -2
- package/app/services/ai/moduleToolRegistryService.js +2 -1
- package/app/services/ai/toolCandidateSelectorService.js +6 -5
- package/app/services/auth/googleWebLinkService.js +3 -2
- package/app/services/auth/whatsappLoginLinkService.js +3 -2
- package/app/services/external/pokeApiService.js +4 -3
- package/app/services/group/groupMetadataService.js +24 -1
- package/app/services/infra/dbWriteQueue.js +57 -26
- package/app/services/infra/featureFlagService.js +2 -1
- package/app/services/messaging/captchaService.js +3 -2
- package/app/services/messaging/newsBroadcastService.js +846 -29
- package/app/services/multiSession/assignmentBalancerService.js +457 -0
- package/app/services/multiSession/groupOwnershipRepository.js +381 -0
- package/app/services/multiSession/groupOwnershipService.js +890 -0
- package/app/services/multiSession/groupOwnershipService.test.js +309 -0
- package/app/services/multiSession/sessionRegistryService.js +293 -0
- package/app/services/sticker/stickerFocusService.js +11 -10
- package/app/store/aiPromptStore.js +36 -19
- package/app/store/conversationSessionStore.js +7 -6
- package/app/store/groupConfigStore.js +41 -5
- package/app/store/premiumUserStore.js +21 -7
- package/app/utils/antiLink/antiLinkModule.js +352 -16
- package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
- package/app/workers/aiLearningWorker.js +6 -5
- package/app/workers/commandConfigEnrichmentWorker.js +4 -3
- package/database/index.js +14 -8
- package/database/migrations/20260307_d0_hardening_down.sql +1 -1
- package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
- package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
- package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
- package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
- package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
- package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
- package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
- package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
- package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
- package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
- package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
- package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
- package/database/schema.sql +102 -1
- package/docker-compose.yml +4 -1
- package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
- package/docs/compliance/dpa-b2b-standard-2026-03-07.md +1 -1
- package/docs/compliance/privacy-policy-2026-03-07.md +4 -4
- package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
- package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +1 -1
- package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
- package/docs/security/omnizap-static-security-headers.conf +25 -0
- package/docs/wiki/Home.md +1 -1
- package/ecosystem.prod.config.cjs +32 -12
- package/index.js +57 -23
- package/observability/alert-rules.yml +20 -0
- package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
- package/observability/mysql-setup.sql +4 -4
- package/observability/system-admin-observability.md +26 -0
- package/package.json +20 -6
- package/public/apple-touch-icon.png +0 -0
- package/public/comandos/commands-catalog.json +2853 -3326
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/js/apps/apiDocsApp.js +3 -2
- package/public/js/apps/commandsReactApp.js +280 -99
- package/public/js/apps/createPackApp.js +11 -10
- package/public/js/apps/homeReactApp.js +181 -130
- package/public/js/apps/loginReactApp.js +1 -1
- package/public/js/apps/stickersApp.js +263 -110
- package/public/js/apps/termsReactApp.js +73 -24
- package/public/js/apps/userApp.js +4 -3
- package/public/js/apps/userPasswordResetReactApp.js +406 -0
- package/public/js/apps/userReactApp.js +355 -280
- package/public/js/apps/userSystemAdmReactApp.js +1506 -0
- package/public/pages/api-docs.html +1 -1
- package/public/pages/aup.html +2 -2
- package/public/pages/dpa.html +3 -3
- package/public/pages/licenca.html +4 -4
- package/public/pages/login.html +1 -1
- package/public/pages/notice-and-takedown.html +2 -2
- package/public/pages/politica-de-privacidade.html +6 -6
- package/public/pages/seo-bot-whatsapp-para-grupo.html +3 -3
- package/public/pages/seo-bot-whatsapp-sem-programar.html +3 -3
- package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +3 -3
- package/public/pages/seo-como-criar-comandos-whatsapp.html +3 -3
- package/public/pages/seo-como-evitar-spam-no-whatsapp.html +3 -3
- package/public/pages/seo-como-moderar-grupo-whatsapp.html +3 -3
- package/public/pages/seo-como-organizar-comunidade-whatsapp.html +3 -3
- package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +3 -3
- package/public/pages/stickers-admin.html +1 -1
- package/public/pages/stickers-create.html +1 -1
- package/public/pages/stickers.html +6 -6
- package/public/pages/suboperadores.html +2 -2
- package/public/pages/termos-de-uso-texto-integral.html +6 -6
- package/public/pages/termos-de-uso.html +3 -3
- package/public/pages/user-password-reset.html +4 -5
- package/public/pages/user-systemadm.html +9 -463
- package/public/pages/user.html +2 -2
- package/scripts/clear-whatsapp-session.sh +123 -0
- package/scripts/core-ai-mode.mjs +163 -0
- package/scripts/deploy.sh +11 -1
- package/scripts/email-broadcast-terms-update.mjs +2 -1
- package/scripts/enrich-command-config-ux-openai.mjs +492 -0
- package/scripts/generate-commands-catalog.mjs +166 -2
- package/scripts/generate-module-agents.mjs +2 -1
- package/scripts/generate-seo-satellite-pages.mjs +5 -4
- package/scripts/github-deploy-notify.mjs +2 -1
- package/scripts/github-release-notify.mjs +25 -10
- package/scripts/new-whatsapp-session.sh +317 -0
- package/scripts/release.sh +2 -19
- package/scripts/security-smoketest.mjs +6 -5
- package/scripts/security-web-surface-check.mjs +218 -0
- package/scripts/sticker-catalog-loadtest.mjs +5 -4
- package/server/auth/googleWebAuth/googleWebAuthService.js +8 -7
- package/server/auth/jwt/webJwtService.js +1 -1
- package/server/auth/stickerCatalogAuthContext.js +2 -1
- package/server/auth/termsAcceptance/termsAcceptanceHandler.js +2 -1
- package/server/auth/userPassword/userPasswordAuthService.js +2 -1
- package/server/auth/userPassword/userPasswordRecoveryService.js +4 -3
- package/server/auth/webAccount/webAccountHandlers.js +9 -10
- package/server/controllers/admin/adminPanelHandlers.js +267 -16
- package/server/controllers/admin/systemAdminController.js +267 -0
- package/server/controllers/seo/stickerCatalogSeoContext.js +10 -9
- package/server/controllers/sticker/nonCatalogHandlers.js +2 -1
- package/server/controllers/sticker/stickerCatalogController.js +23 -36
- package/server/controllers/system/contactController.js +9 -17
- package/server/controllers/system/githubController.js +3 -2
- package/server/controllers/system/stickerCatalogSystemContext.js +41 -19
- package/server/controllers/system/systemController.js +254 -1
- package/server/controllers/system/systemMetricsController.js +2 -1
- package/server/controllers/userController.js +6 -0
- package/server/email/emailTemplateService.js +5 -3
- package/server/http/httpServer.js +11 -6
- package/server/middleware/rateLimit.js +2 -1
- package/server/middleware/securityHeaders.js +20 -1
- package/server/routes/admin/systemAdminRouter.js +6 -0
- package/server/routes/indexRouter.js +30 -6
- package/server/routes/observability/grafanaProxyRouter.js +254 -0
- package/server/routes/static/staticPageRouter.js +27 -1
- package/server/utils/publicContact.js +31 -0
- package/utils/time/timeModule.js +135 -0
- package/utils/time/timeModule.test.js +65 -0
- package/utils/whatsapp/contactEnv.js +39 -0
- package/vite.config.mjs +7 -1
- package/public/assets/images/brand-icon-192.png +0 -0
- package/scripts/sync-readme-snapshot.mjs +0 -133
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
|
|
1
2
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
3
|
import { createRoot } from 'react-dom/client';
|
|
3
4
|
import htm from 'htm';
|
|
@@ -7,7 +8,10 @@ const html = htm.bind(React.createElement);
|
|
|
7
8
|
|
|
8
9
|
const DEFAULT_API_BASE_PATH = '/api';
|
|
9
10
|
const DEFAULT_LOGIN_PATH = '/login';
|
|
11
|
+
const DEFAULT_PASSWORD_RESET_WEB_PATH = '/user/password-reset';
|
|
10
12
|
const DEFAULT_FALLBACK_AVATAR = '/assets/images/brand-logo-128.webp';
|
|
13
|
+
const DEFAULT_SUPPORT_WHATSAPP_NUMBER = '';
|
|
14
|
+
const DEFAULT_SUPPORT_WHATSAPP_URL = '/termos-de-uso/';
|
|
11
15
|
|
|
12
16
|
const TABS = [
|
|
13
17
|
{ key: 'summary', label: 'Estatísticas', icon: '📊' },
|
|
@@ -16,12 +20,59 @@ const TABS = [
|
|
|
16
20
|
{ key: 'support', label: 'Suporte', icon: '🎧' },
|
|
17
21
|
];
|
|
18
22
|
|
|
23
|
+
const shortNum = (value) =>
|
|
24
|
+
new Intl.NumberFormat('pt-BR', {
|
|
25
|
+
notation: Number(value) >= 1000 ? 'compact' : 'standard',
|
|
26
|
+
maximumFractionDigits: 1,
|
|
27
|
+
}).format(Math.max(0, Number(value) || 0));
|
|
28
|
+
|
|
29
|
+
const normalizeRoutePath = (value, fallback) => {
|
|
30
|
+
const raw = String(value || '').trim();
|
|
31
|
+
if (!raw) return fallback;
|
|
32
|
+
if (!raw.startsWith('/')) return fallback;
|
|
33
|
+
if (/^\/\//.test(raw)) return fallback;
|
|
34
|
+
return raw;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const normalizePhoneDigits = (value) =>
|
|
38
|
+
String(value || '')
|
|
39
|
+
.replace(/\D+/g, '')
|
|
40
|
+
.slice(0, 15);
|
|
41
|
+
|
|
42
|
+
const buildWhatsappUrl = (value) => {
|
|
43
|
+
const digits = normalizePhoneDigits(value);
|
|
44
|
+
if (!digits) return '';
|
|
45
|
+
return `https://wa.me/${digits}`;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const resolveSupportWhatsappUrl = (config) => {
|
|
49
|
+
const explicitUrl = String(config?.supportWhatsappUrl || '').trim();
|
|
50
|
+
if (/^https?:\/\/wa\.me\/\d{8,15}(?:\?.*)?$/i.test(explicitUrl)) return explicitUrl;
|
|
51
|
+
return buildWhatsappUrl(config?.supportWhatsappNumber) || DEFAULT_SUPPORT_WHATSAPP_URL;
|
|
52
|
+
};
|
|
53
|
+
|
|
19
54
|
const UserApp = ({ config }) => {
|
|
20
55
|
const [activeTab, setActiveTab] = useState('summary');
|
|
21
56
|
const [isLoading, setLoading] = useState(true);
|
|
22
57
|
const [summary, setSummary] = useState(null);
|
|
23
58
|
const [session, setSession] = useState(null);
|
|
24
|
-
const [
|
|
59
|
+
const [isSidebarCollapsed, setSidebarCollapsed] = useState(false);
|
|
60
|
+
const [isMobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
61
|
+
const [passwordResetBusy, setPasswordResetBusy] = useState(false);
|
|
62
|
+
const [passwordResetError, setPasswordResetError] = useState('');
|
|
63
|
+
const [passwordResetInfo, setPasswordResetInfo] = useState('');
|
|
64
|
+
|
|
65
|
+
// Lock scroll when mobile menu is open
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (isMobileMenuOpen) {
|
|
68
|
+
document.body.style.overflow = 'hidden';
|
|
69
|
+
} else {
|
|
70
|
+
document.body.style.overflow = '';
|
|
71
|
+
}
|
|
72
|
+
return () => {
|
|
73
|
+
document.body.style.overflow = '';
|
|
74
|
+
};
|
|
75
|
+
}, [isMobileMenuOpen]);
|
|
25
76
|
|
|
26
77
|
useEffect(() => {
|
|
27
78
|
const observer =
|
|
@@ -82,113 +133,217 @@ const UserApp = ({ config }) => {
|
|
|
82
133
|
|
|
83
134
|
const rpgInfo = useMemo(() => summary?.rpg || { level: 1, xp: 0, gold: 0, karma: { score: 0, positive: 0, negative: 0 }, pvp: { matches: 0, wins: 0, losses: 0 }, inventory_count: 0, total_pokemons: 0 }, [summary]);
|
|
84
135
|
const usageInfo = useMemo(() => summary?.usage || { messages: 0, packs: 0, stickers: 0, activity_chart: [], insights: {}, first_message_at: null, last_message_at: null }, [summary]);
|
|
136
|
+
const supportWhatsappUrl = useMemo(() => resolveSupportWhatsappUrl(config), [config.supportWhatsappNumber, config.supportWhatsappUrl]);
|
|
85
137
|
|
|
86
138
|
const daysMember = useMemo(() => {
|
|
87
139
|
if (!rpgInfo.member_since) return 0;
|
|
88
|
-
const diff =
|
|
140
|
+
const diff = __timeNow() - new Date(rpgInfo.member_since);
|
|
89
141
|
return Math.floor(diff / (1000 * 60 * 60 * 24));
|
|
90
142
|
}, [rpgInfo.member_since]);
|
|
91
143
|
|
|
92
144
|
const handleTabChange = (key) => {
|
|
93
145
|
setActiveTab(key);
|
|
94
|
-
|
|
146
|
+
setMobileMenuOpen(false);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const toggleSidebar = () => {
|
|
150
|
+
if (window.innerWidth < 1024) {
|
|
151
|
+
setMobileMenuOpen(!isMobileMenuOpen);
|
|
152
|
+
} else {
|
|
153
|
+
setSidebarCollapsed(!isSidebarCollapsed);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const startPasswordResetFlow = async () => {
|
|
158
|
+
if (passwordResetBusy) return;
|
|
159
|
+
setPasswordResetError('');
|
|
160
|
+
setPasswordResetInfo('');
|
|
161
|
+
setPasswordResetBusy(true);
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
const response = await fetch(`${config.apiBasePath}/auth/password/recovery/session`, {
|
|
165
|
+
method: 'POST',
|
|
166
|
+
credentials: 'include',
|
|
167
|
+
headers: {
|
|
168
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
169
|
+
},
|
|
170
|
+
body: JSON.stringify({}),
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
let payload = null;
|
|
174
|
+
try {
|
|
175
|
+
payload = await response.json();
|
|
176
|
+
} catch {
|
|
177
|
+
payload = null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (!response.ok) {
|
|
181
|
+
throw new Error(payload?.error || `Falha HTTP ${response.status}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const data = payload?.data || {};
|
|
185
|
+
const sessionToken = String(data?.session_token || '')
|
|
186
|
+
.trim()
|
|
187
|
+
.slice(0, 4096);
|
|
188
|
+
const sessionPath = normalizeRoutePath(data?.session_path, config.passwordResetWebPath || DEFAULT_PASSWORD_RESET_WEB_PATH);
|
|
189
|
+
const targetUrl = new URL(sessionPath, window.location.origin);
|
|
190
|
+
if (sessionToken) {
|
|
191
|
+
targetUrl.searchParams.set('session_token', sessionToken);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
setPasswordResetInfo('Sessão de redefinição criada. Redirecionando...');
|
|
195
|
+
window.setTimeout(() => {
|
|
196
|
+
window.location.assign(`${targetUrl.pathname}${targetUrl.search}`);
|
|
197
|
+
}, 120);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
setPasswordResetError(error?.message || 'Não foi possível iniciar a redefinição de senha.');
|
|
200
|
+
} finally {
|
|
201
|
+
setPasswordResetBusy(false);
|
|
202
|
+
}
|
|
95
203
|
};
|
|
96
204
|
|
|
97
205
|
return html`
|
|
206
|
+
<style>
|
|
207
|
+
.sidebar-transition {
|
|
208
|
+
transition:
|
|
209
|
+
width 0.4s cubic-bezier(0.4, 0, 0.2, 1),
|
|
210
|
+
transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
211
|
+
}
|
|
212
|
+
.content-transition {
|
|
213
|
+
transition: margin-left 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
214
|
+
}
|
|
215
|
+
</style>
|
|
216
|
+
|
|
98
217
|
<div className="min-h-screen bg-[#020617] text-white font-sans selection:bg-primary selection:text-primary-content overflow-x-hidden">
|
|
99
|
-
|
|
218
|
+
<!-- Background Elements -->
|
|
219
|
+
<div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
|
|
100
220
|
<div className="absolute top-[-10%] left-[-10%] w-[40%] h-[40%] bg-primary/5 blur-[120px] rounded-full animate-pulse"></div>
|
|
101
221
|
<div className="absolute bottom-[10%] right-[-5%] w-[30%] h-[30%] bg-secondary/5 blur-[100px] rounded-full"></div>
|
|
102
222
|
</div>
|
|
103
223
|
|
|
104
|
-
<!-- Backdrop for mobile sidebar
|
|
105
|
-
<div onClick=${() =>
|
|
224
|
+
<!-- Backdrop for mobile sidebar -->
|
|
225
|
+
<div onClick=${() => setMobileMenuOpen(false)} className=${`fixed inset-0 z-[50] bg-[#020617]/80 lg:hidden transition-opacity duration-300 ${isMobileMenuOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}></div>
|
|
106
226
|
|
|
107
227
|
<!-- Navbar -->
|
|
108
|
-
<header className="
|
|
109
|
-
<div className="
|
|
228
|
+
<header className="fixed inset-x-0 top-0 z-[40] border-b border-white/5 bg-[#020617]/80 backdrop-blur-xl">
|
|
229
|
+
<div className="px-4 lg:px-8">
|
|
110
230
|
<div className="flex h-16 items-center justify-between gap-4">
|
|
111
231
|
<div className="flex items-center gap-4">
|
|
112
|
-
<button onClick=${
|
|
113
|
-
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"
|
|
232
|
+
<button onClick=${toggleSidebar} className="btn btn-ghost btn-square btn-sm bg-white/5 border border-white/10 rounded-xl hover:bg-primary/10 hover:text-primary transition-all">
|
|
233
|
+
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
234
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d=${isSidebarCollapsed ? 'M4 6h16M4 12h16M4 18h16' : 'M4 6h16M4 12h10M4 18h16'} />
|
|
235
|
+
</svg>
|
|
114
236
|
</button>
|
|
115
237
|
|
|
116
238
|
<a href="/" className="flex items-center gap-2.5 hover:opacity-80 transition-opacity">
|
|
117
|
-
<img src="/
|
|
118
|
-
<span className="text-base sm:text-lg font-black tracking-tight">OmniZap<span className="text-primary">.</span></span>
|
|
239
|
+
<img src="/apple-touch-icon.png" className="w-8 h-8 rounded-xl shadow-sm" alt="Logo" />
|
|
240
|
+
<span className="hidden xs:block text-base sm:text-lg font-black tracking-tight">OmniZap<span className="text-primary">.</span></span>
|
|
119
241
|
</a>
|
|
120
242
|
</div>
|
|
121
243
|
|
|
122
244
|
<div className="flex items-center gap-3">
|
|
123
|
-
<button onClick=${() => window.location.assign('/login/')} className="btn btn-ghost btn-sm h-
|
|
245
|
+
<button onClick=${() => window.location.assign('/login/')} className="btn btn-ghost btn-sm h-10 min-h-0 gap-2 rounded-xl bg-white/5 border border-white/10 hover:bg-error hover:text-white transition-all px-5 font-black text-[10px] uppercase tracking-widest group">
|
|
246
|
+
<span className="hidden sm:inline opacity-50 group-hover:opacity-100">Sair da Conta</span>
|
|
247
|
+
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" /></svg>
|
|
248
|
+
</button>
|
|
124
249
|
</div>
|
|
125
250
|
</div>
|
|
126
251
|
</div>
|
|
127
252
|
</header>
|
|
128
253
|
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
<
|
|
136
|
-
|
|
254
|
+
<div className="flex relative pt-16">
|
|
255
|
+
<!-- Sidebar -->
|
|
256
|
+
<aside className=${`fixed lg:fixed top-0 lg:top-[65px] lg:left-0 h-full lg:h-[calc(100vh-65px)] z-[60] lg:z-30 bg-[#020617] border-r border-white/5 sidebar-transition overflow-y-auto no-scrollbar ${isMobileMenuOpen ? 'translate-x-0 w-[280px]' : '-translate-x-full lg:translate-x-0'} ${isSidebarCollapsed ? 'lg:w-[85px]' : 'lg:w-[280px]'}`}>
|
|
257
|
+
<div className="p-4 flex flex-col h-full">
|
|
258
|
+
<!-- Mobile Header inside Sidebar -->
|
|
259
|
+
<div className="lg:hidden flex items-center justify-between mb-6 px-2">
|
|
260
|
+
<span className="text-[10px] font-black uppercase tracking-[0.2em] text-white/30">Menu do Sistema</span>
|
|
261
|
+
<button onClick=${() => setMobileMenuOpen(false)} className="btn btn-ghost btn-square btn-sm hover:bg-white/5">
|
|
262
|
+
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M6 18L18 6M6 6l12 12" /></svg>
|
|
137
263
|
</button>
|
|
138
264
|
</div>
|
|
139
265
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
<
|
|
146
|
-
<
|
|
147
|
-
<div className="absolute -bottom-1 -right-1 w-6 h-6 bg-success border-4 border-[#020617] rounded-full"></div>
|
|
266
|
+
<!-- Profile Snippet -->
|
|
267
|
+
<div className=${`mb-6 p-4 rounded-3xl bg-white/[0.03] border border-white/5 transition-all overflow-hidden ${isSidebarCollapsed ? 'items-center px-2' : ''}`}>
|
|
268
|
+
<div className=${`flex items-center gap-4 ${isSidebarCollapsed ? 'flex-col' : ''}`}>
|
|
269
|
+
<div className="relative flex-shrink-0">
|
|
270
|
+
<div className="absolute inset-0 bg-primary/20 blur-lg rounded-full animate-pulse"></div>
|
|
271
|
+
<img src=${authInfo.image} className="relative w-10 h-10 rounded-xl border border-white/10 p-0.5 object-cover" />
|
|
272
|
+
<div className="absolute -bottom-0.5 -right-0.5 w-3 h-3 bg-success border-2 border-[#020617] rounded-full"></div>
|
|
148
273
|
</div>
|
|
274
|
+
${!isSidebarCollapsed &&
|
|
275
|
+
html`
|
|
276
|
+
<div className="flex-1 min-w-0">
|
|
277
|
+
<h3 className="text-sm font-black tracking-tight truncate text-white">${session?.user?.name || 'User'}</h3>
|
|
278
|
+
<p className="text-[9px] font-black uppercase text-primary/60 tracking-wider">${summary?.plan_label || 'Plano Free'}</p>
|
|
279
|
+
</div>
|
|
280
|
+
`}
|
|
149
281
|
</div>
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
<
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
<div className="p-3 rounded-2xl bg-white/5 border border-white/5 text-center">
|
|
162
|
-
<p className="text-[8px] font-black text-white/30 uppercase tracking-widest mb-1">Gold</p>
|
|
163
|
-
<p className="text-lg font-black text-warning">💰 ${rpgInfo.gold}</p>
|
|
282
|
+
${!isSidebarCollapsed &&
|
|
283
|
+
html`
|
|
284
|
+
<div className="mt-4 pt-4 border-t border-white/5 grid grid-cols-2 gap-2">
|
|
285
|
+
<div className="text-center p-2 rounded-xl bg-white/5">
|
|
286
|
+
<p className="text-[7px] font-black text-white/20 uppercase">Nível</p>
|
|
287
|
+
<p className="text-xs font-black text-primary">${rpgInfo.level}</p>
|
|
288
|
+
</div>
|
|
289
|
+
<div className="text-center p-2 rounded-xl bg-white/5">
|
|
290
|
+
<p className="text-[7px] font-black text-white/20 uppercase">Gold</p>
|
|
291
|
+
<p className="text-xs font-black text-warning">${shortNum(rpgInfo.gold)}</p>
|
|
292
|
+
</div>
|
|
164
293
|
</div>
|
|
165
|
-
|
|
294
|
+
`}
|
|
166
295
|
</div>
|
|
167
296
|
|
|
168
|
-
|
|
297
|
+
<!-- Navigation -->
|
|
298
|
+
<nav className="flex-1 space-y-1.5">
|
|
169
299
|
${TABS.map(
|
|
170
300
|
(tab) => html`
|
|
171
|
-
<button onClick=${() => handleTabChange(tab.key)} className=${`w-full flex items-center gap-4 px-
|
|
172
|
-
<span className
|
|
173
|
-
${tab.label}
|
|
301
|
+
<button onClick=${() => handleTabChange(tab.key)} className=${`w-full flex items-center gap-4 px-4 py-3.5 rounded-2xl font-black text-[10px] uppercase tracking-[0.15em] transition-all relative group ${activeTab === tab.key ? 'bg-primary text-primary-content shadow-lg shadow-primary/10' : 'text-white/40 hover:bg-white/5 hover:text-white'}`}>
|
|
302
|
+
<span className=${`text-xl transition-transform duration-500 ${activeTab === tab.key ? 'scale-110' : 'group-hover:scale-110'}`}>${tab.icon}</span>
|
|
303
|
+
<span className=${`transition-all duration-300 ${isSidebarCollapsed ? 'opacity-0 w-0' : 'opacity-100'}`}>${tab.label}</span>
|
|
304
|
+
${isSidebarCollapsed && activeTab === tab.key && html`<div className="absolute right-0 w-1 h-6 bg-primary rounded-l-full"></div>`}
|
|
174
305
|
</button>
|
|
175
306
|
`,
|
|
176
307
|
)}
|
|
177
308
|
</nav>
|
|
178
|
-
</aside>
|
|
179
309
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
310
|
+
<!-- Sidebar Footer -->
|
|
311
|
+
<div className=${`mt-auto pt-6 border-t border-white/5 ${isSidebarCollapsed ? 'text-center' : ''}`}>
|
|
312
|
+
<div className="flex flex-col gap-2">
|
|
313
|
+
<div className=${`flex items-center gap-2 px-3 py-1.5 rounded-lg bg-white/5 border border-white/5 ${isSidebarCollapsed ? 'justify-center' : ''}`}>
|
|
314
|
+
<div className="w-1.5 h-1.5 rounded-full bg-primary animate-pulse"></div>
|
|
315
|
+
${!isSidebarCollapsed && html`<span className="text-[8px] font-black uppercase tracking-widest text-white/30">v2.6.0 Connected</span>`}
|
|
316
|
+
</div>
|
|
317
|
+
</div>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
</aside>
|
|
321
|
+
|
|
322
|
+
<!-- Main Content -->
|
|
323
|
+
<main className=${`flex-1 min-w-0 content-transition px-4 lg:px-10 py-8 lg:py-12 ${isSidebarCollapsed ? 'lg:ml-[85px]' : 'lg:ml-[280px]'}`}>
|
|
324
|
+
<div className="max-w-5xl mx-auto space-y-10">
|
|
325
|
+
<div data-reveal="fade-up" className="flex flex-col md:flex-row md:items-end justify-between gap-6">
|
|
326
|
+
<div className="space-y-2">
|
|
327
|
+
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/20 text-primary text-[9px] font-black uppercase tracking-widest">Dashboard v3.0</div>
|
|
328
|
+
<h1 className="text-4xl lg:text-6xl font-black tracking-tighter">Painel do <span className="text-transparent bg-clip-text bg-gradient-to-r from-primary to-emerald-400">Usuário</span></h1>
|
|
329
|
+
<p className="text-white/40 text-sm font-medium">Gerencie suas estatísticas, conquistas RPG e segurança em um só lugar.</p>
|
|
330
|
+
</div>
|
|
331
|
+
<div className="hidden md:flex items-center gap-4 text-right">
|
|
332
|
+
<div>
|
|
333
|
+
<p className="text-[10px] font-black uppercase text-white/20 tracking-widest">Status da Sessão</p>
|
|
334
|
+
<p className="text-xs font-bold text-success">Encriptada e Ativa</p>
|
|
335
|
+
</div>
|
|
336
|
+
<div className="w-10 h-10 rounded-xl bg-success/10 border border-success/20 flex items-center justify-center text-success">
|
|
337
|
+
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" /></svg>
|
|
338
|
+
</div>
|
|
339
|
+
</div>
|
|
185
340
|
</div>
|
|
186
341
|
|
|
187
|
-
<div data-reveal="fade-up" className="relative p-1 rounded-[
|
|
188
|
-
<div className="bg-[#020617] rounded-[
|
|
342
|
+
<div data-reveal="fade-up" className="relative p-1 rounded-[3.5rem] bg-gradient-to-br from-white/10 via-transparent to-transparent group">
|
|
343
|
+
<div className="bg-[#020617] rounded-[3.4rem] p-6 lg:p-12 min-h-[600px] overflow-hidden relative shadow-2xl">
|
|
189
344
|
${isLoading
|
|
190
345
|
? html`
|
|
191
|
-
<div className="flex flex-col items-center justify-center h-full space-y-6 py-
|
|
346
|
+
<div className="flex flex-col items-center justify-center h-full space-y-6 py-32 animate-in fade-in">
|
|
192
347
|
<div className="relative">
|
|
193
348
|
<div className="absolute inset-0 bg-primary/20 blur-2xl rounded-full animate-ping"></div>
|
|
194
349
|
<span className="loading loading-ring w-20 h-20 text-primary relative"></span>
|
|
@@ -200,179 +355,131 @@ const UserApp = ({ config }) => {
|
|
|
200
355
|
<div className="animate-in fade-in slide-in-from-bottom-8 duration-700">
|
|
201
356
|
${activeTab === 'summary' &&
|
|
202
357
|
html`
|
|
203
|
-
<div className="grid gap-10
|
|
358
|
+
<div className="grid gap-10">
|
|
204
359
|
<!-- Main Metrics Row -->
|
|
205
360
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
|
206
|
-
<div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group hover:border-primary/30 transition-
|
|
207
|
-
<div className="absolute -right-4 -bottom-4 text-6xl opacity-5">💬</div>
|
|
208
|
-
<p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover:text-primary transition-colors relative z-10">Total de Mensagens</p>
|
|
361
|
+
<div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group/card hover:border-primary/30 transition-all hover:bg-white/[0.05] relative overflow-hidden">
|
|
362
|
+
<div className="absolute -right-4 -bottom-4 text-6xl opacity-5 group-hover/card:scale-110 transition-transform">💬</div>
|
|
363
|
+
<p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover/card:text-primary transition-colors relative z-10">Total de Mensagens</p>
|
|
209
364
|
<p className="text-4xl font-black text-white relative z-10">${usageInfo.messages.toLocaleString()}</p>
|
|
210
365
|
</div>
|
|
211
|
-
<div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group hover:border-emerald-400/30 transition-
|
|
212
|
-
<div className="absolute -right-4 -bottom-4 text-6xl opacity-5">🖼️</div>
|
|
213
|
-
<p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover:text-emerald-400 transition-colors relative z-10">Stickers Criados</p>
|
|
366
|
+
<div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group/card hover:border-emerald-400/30 transition-all hover:bg-white/[0.05] relative overflow-hidden">
|
|
367
|
+
<div className="absolute -right-4 -bottom-4 text-6xl opacity-5 group-hover/card:scale-110 transition-transform">🖼️</div>
|
|
368
|
+
<p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover/card:text-emerald-400 transition-colors relative z-10">Stickers Criados</p>
|
|
214
369
|
<p className="text-4xl font-black text-white relative z-10">${usageInfo.stickers.toLocaleString()}</p>
|
|
215
370
|
</div>
|
|
216
|
-
<div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group hover:border-warning/30 transition-
|
|
217
|
-
<div className="absolute -right-4 -bottom-4 text-6xl opacity-5">📦</div>
|
|
218
|
-
<p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover:text-warning transition-colors relative z-10">Packs
|
|
371
|
+
<div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group/card hover:border-warning/30 transition-all hover:bg-white/[0.05] relative overflow-hidden">
|
|
372
|
+
<div className="absolute -right-4 -bottom-4 text-6xl opacity-5 group-hover/card:scale-110 transition-transform">📦</div>
|
|
373
|
+
<p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover/card:text-warning transition-colors relative z-10">Packs Ativos</p>
|
|
219
374
|
<p className="text-4xl font-black text-white relative z-10">${usageInfo.packs}</p>
|
|
220
375
|
</div>
|
|
221
376
|
</div>
|
|
222
377
|
|
|
223
378
|
<!-- Deep Insights Grid -->
|
|
224
379
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
225
|
-
<div className="p-
|
|
226
|
-
<
|
|
227
|
-
|
|
380
|
+
<div className="p-7 rounded-[2.5rem] bg-white/[0.02] border border-white/5 space-y-5 hover:border-white/10 transition-colors group/insight">
|
|
381
|
+
<div className="flex items-center justify-between">
|
|
382
|
+
<h4 className="text-[10px] font-black uppercase tracking-widest text-white/30 group-hover/insight:text-white/50 transition-colors">Comandos</h4>
|
|
383
|
+
<span className="text-xs">⌨️</span>
|
|
384
|
+
</div>
|
|
385
|
+
<div className="space-y-3.5">
|
|
228
386
|
<div className="flex justify-between items-center">
|
|
229
|
-
<span className="text-xs font-medium text-white/
|
|
387
|
+
<span className="text-xs font-medium text-white/40">Total Usados</span>
|
|
230
388
|
<span className="text-sm font-black">${usageInfo.insights?.commands_total || 0}</span>
|
|
231
389
|
</div>
|
|
232
390
|
<div className="flex justify-between items-center">
|
|
233
|
-
<span className="text-xs font-medium text-white/
|
|
234
|
-
<span className="text-sm font-black text-primary">${usageInfo.insights?.top_command || 'N/D'}</span>
|
|
391
|
+
<span className="text-xs font-medium text-white/40">Favorito</span>
|
|
392
|
+
<span className="text-sm font-black text-primary truncate ml-4">${usageInfo.insights?.top_command || 'N/D'}</span>
|
|
235
393
|
</div>
|
|
236
394
|
<div className="flex justify-between items-center">
|
|
237
|
-
<span className="text-xs font-medium text-white/
|
|
238
|
-
<span className="text-sm font-black">${usageInfo.insights?.top_command_count || 0}
|
|
395
|
+
<span className="text-xs font-medium text-white/40">Frequência</span>
|
|
396
|
+
<span className="text-sm font-black">${usageInfo.insights?.top_command_count || 0} execs</span>
|
|
239
397
|
</div>
|
|
240
398
|
</div>
|
|
241
399
|
</div>
|
|
242
400
|
|
|
243
|
-
<div className="p-
|
|
244
|
-
<
|
|
245
|
-
|
|
401
|
+
<div className="p-7 rounded-[2.5rem] bg-white/[0.02] border border-white/5 space-y-5 hover:border-white/10 transition-colors group/insight">
|
|
402
|
+
<div className="flex items-center justify-between">
|
|
403
|
+
<h4 className="text-[10px] font-black uppercase tracking-widest text-white/30 group-hover/insight:text-white/50 transition-colors">Comunidade</h4>
|
|
404
|
+
<span className="text-xs">👥</span>
|
|
405
|
+
</div>
|
|
406
|
+
<div className="space-y-3.5">
|
|
246
407
|
<div className="flex justify-between items-center">
|
|
247
|
-
<span className="text-xs font-medium text-white/
|
|
408
|
+
<span className="text-xs font-medium text-white/40">Grupos Ativos</span>
|
|
248
409
|
<span className="text-sm font-black">${usageInfo.insights?.groups_active || 0}</span>
|
|
249
410
|
</div>
|
|
250
411
|
<div className="flex justify-between items-center">
|
|
251
|
-
<span className="text-xs font-medium text-white/
|
|
252
|
-
<span className="text-sm font-black text-emerald-400 truncate
|
|
412
|
+
<span className="text-xs font-medium text-white/40">Hub Principal</span>
|
|
413
|
+
<span className="text-sm font-black text-emerald-400 truncate ml-4">${usageInfo.insights?.top_group || 'N/D'}</span>
|
|
253
414
|
</div>
|
|
254
415
|
<div className="flex justify-between items-center">
|
|
255
|
-
<span className="text-xs font-medium text-white/
|
|
256
|
-
<span className="text-sm font-black capitalize">${usageInfo.insights?.top_message_type || '
|
|
416
|
+
<span className="text-xs font-medium text-white/40">Perfil Social</span>
|
|
417
|
+
<span className="text-sm font-black capitalize">${usageInfo.insights?.top_message_type || 'Texto'}</span>
|
|
257
418
|
</div>
|
|
258
419
|
</div>
|
|
259
420
|
</div>
|
|
260
421
|
|
|
261
|
-
<div className="p-
|
|
262
|
-
<
|
|
263
|
-
|
|
422
|
+
<div className="p-7 rounded-[2.5rem] bg-white/[0.02] border border-white/5 space-y-5 hover:border-white/10 transition-colors group/insight">
|
|
423
|
+
<div className="flex items-center justify-between">
|
|
424
|
+
<h4 className="text-[10px] font-black uppercase tracking-widest text-white/30 group-hover/insight:text-white/50 transition-colors">Hábitos</h4>
|
|
425
|
+
<span className="text-xs">⚡</span>
|
|
426
|
+
</div>
|
|
427
|
+
<div className="space-y-3.5">
|
|
264
428
|
<div className="flex justify-between items-center">
|
|
265
|
-
<span className="text-xs font-medium text-white/
|
|
429
|
+
<span className="text-xs font-medium text-white/40">Pico de Atividade</span>
|
|
266
430
|
<span className="text-sm font-black">${usageInfo.insights?.active_hour !== null ? usageInfo.insights.active_hour + ':00' : 'N/D'}</span>
|
|
267
431
|
</div>
|
|
268
432
|
<div className="flex justify-between items-center">
|
|
269
|
-
<span className="text-xs font-medium text-white/
|
|
270
|
-
<span className="text-sm font-black text-info">${usageInfo.insights?.avg_daily || 0}
|
|
433
|
+
<span className="text-xs font-medium text-white/40">Engajamento Médio</span>
|
|
434
|
+
<span className="text-sm font-black text-info">${usageInfo.insights?.avg_daily || 0} msgs/dia</span>
|
|
271
435
|
</div>
|
|
272
436
|
<div className="flex justify-between items-center">
|
|
273
|
-
<span className="text-xs font-medium text-white/
|
|
274
|
-
<span className="text-sm font-black text-warning">${rpgInfo.karma?.score || 0}</span>
|
|
437
|
+
<span className="text-xs font-medium text-white/40">Reputação Karma</span>
|
|
438
|
+
<span className="text-sm font-black text-warning">${rpgInfo.karma?.score || 0} pts</span>
|
|
275
439
|
</div>
|
|
276
440
|
</div>
|
|
277
441
|
</div>
|
|
278
442
|
</div>
|
|
279
443
|
|
|
280
|
-
<!--
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
Fluxo de Mensagens (7 dias)
|
|
287
|
-
</h3>
|
|
288
|
-
<div className="flex items-end justify-between gap-2 h-40 pt-4 px-2">
|
|
289
|
-
${usageInfo.activity_chart.map((data) => {
|
|
290
|
-
const maxCount = Math.max(...usageInfo.activity_chart.map((d) => d.count), 1);
|
|
291
|
-
const heightPercent = Math.max((data.count / maxCount) * 100, 5);
|
|
292
|
-
return html`
|
|
293
|
-
<div key=${data.day} className="flex flex-col items-center gap-2 flex-1 group min-w-0">
|
|
294
|
-
<div className="w-full relative flex justify-center h-full items-end">
|
|
295
|
-
<div className="w-full max-w-[2rem] bg-primary/20 hover:bg-primary transition-all rounded-t-lg group-hover:shadow-[0_0_20px_rgba(34,197,94,0.4)]" style=${{ height: heightPercent + '%' }}>
|
|
296
|
-
<div className="absolute -top-8 left-1/2 -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity bg-white text-[#020617] text-[10px] font-black px-2 py-1 rounded-lg pointer-events-none whitespace-nowrap z-20">${data.count} msgs</div>
|
|
297
|
-
</div>
|
|
298
|
-
</div>
|
|
299
|
-
<span className="text-[8px] font-bold text-white/20 uppercase tracking-tighter truncate w-full text-center">${data.day.split('-').reverse().join('/')}</span>
|
|
300
|
-
</div>
|
|
301
|
-
`;
|
|
302
|
-
})}
|
|
303
|
-
</div>
|
|
304
|
-
</div>
|
|
305
|
-
`
|
|
306
|
-
: null}
|
|
307
|
-
|
|
308
|
-
<!-- RPG & Social Snippet -->
|
|
309
|
-
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
310
|
-
<div className="p-8 rounded-[2.5rem] bg-emerald-500/5 border border-emerald-500/10 space-y-4">
|
|
311
|
-
<h4 className="text-[10px] font-black uppercase tracking-widest text-emerald-400/40">Engajamento Social</h4>
|
|
312
|
-
<div className="grid grid-cols-2 gap-4">
|
|
313
|
-
<div className="space-y-1">
|
|
314
|
-
<p className="text-[8px] font-black text-white/20 uppercase">Votos Positivos</p>
|
|
315
|
-
<p className="text-xl font-black text-emerald-400">+${rpgInfo.karma?.positive || 0}</p>
|
|
316
|
-
</div>
|
|
317
|
-
<div className="space-y-1">
|
|
318
|
-
<p className="text-[8px] font-black text-white/20 uppercase">Votos Negativos</p>
|
|
319
|
-
<p className="text-xl font-black text-rose-500">-${rpgInfo.karma?.negative || 0}</p>
|
|
320
|
-
</div>
|
|
321
|
-
</div>
|
|
322
|
-
</div>
|
|
323
|
-
<div className="p-8 rounded-[2.5rem] bg-info/5 border border-info/10 space-y-4">
|
|
324
|
-
<h4 className="text-[10px] font-black uppercase tracking-widest text-info/40">Exploração</h4>
|
|
325
|
-
<div className="grid grid-cols-2 gap-4">
|
|
326
|
-
<div className="space-y-1">
|
|
327
|
-
<p className="text-[8px] font-black text-white/20 uppercase">Itens Inventário</p>
|
|
328
|
-
<p className="text-xl font-black text-white">${rpgInfo.inventory_count || 0}</p>
|
|
329
|
-
</div>
|
|
330
|
-
<div className="space-y-1">
|
|
331
|
-
<p className="text-[8px] font-black text-white/20 uppercase">Pokémons</p>
|
|
332
|
-
<p className="text-xl font-black text-white">${rpgInfo.total_pokemons || 0}</p>
|
|
333
|
-
</div>
|
|
334
|
-
</div>
|
|
335
|
-
</div>
|
|
336
|
-
</div>
|
|
337
|
-
|
|
338
|
-
<!-- Account Details -->
|
|
339
|
-
<div className="p-6 sm:p-10 rounded-[2.5rem] sm:rounded-[3rem] bg-primary/5 border border-primary/10 relative overflow-hidden">
|
|
340
|
-
<div className="absolute top-[-20%] right-[-10%] w-64 h-64 bg-primary/10 blur-[80px] rounded-full"></div>
|
|
341
|
-
<h3 className="relative font-black text-xl mb-8 flex items-center gap-3">
|
|
342
|
-
<span className="w-2 h-2 rounded-full bg-primary shadow-[0_0_10px_rgba(34,197,94,0.8)]"></span>
|
|
343
|
-
Detalhes da Identidade
|
|
444
|
+
<!-- Details Card -->
|
|
445
|
+
<div className="p-8 lg:p-12 rounded-[3.5rem] bg-white/[0.03] border border-white/5 relative overflow-hidden">
|
|
446
|
+
<div className="absolute top-0 right-0 w-64 h-64 bg-primary/5 blur-[80px] rounded-full -translate-y-1/2 translate-x-1/2"></div>
|
|
447
|
+
<h3 className="relative font-black text-2xl mb-10 flex items-center gap-4">
|
|
448
|
+
<div className="w-10 h-10 rounded-2xl bg-primary/10 flex items-center justify-center text-lg">🪪</div>
|
|
449
|
+
Metadados da Identidade
|
|
344
450
|
</h3>
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
<p className="text-
|
|
451
|
+
|
|
452
|
+
<div className="relative grid grid-cols-1 sm:grid-cols-2 gap-10 border-b border-white/5 pb-10 mb-10">
|
|
453
|
+
<div className="space-y-1.5">
|
|
454
|
+
<p className="text-[10px] font-black uppercase text-white/20 tracking-widest">E-mail de Autenticação</p>
|
|
455
|
+
<p className="text-lg font-bold text-white/80">${session?.user?.email}</p>
|
|
349
456
|
</div>
|
|
350
|
-
<div>
|
|
351
|
-
<p className="text-[
|
|
352
|
-
<p className="text-
|
|
457
|
+
<div className="space-y-1.5">
|
|
458
|
+
<p className="text-[10px] font-black uppercase text-white/20 tracking-widest">WhatsApp Vinculado</p>
|
|
459
|
+
<p className="text-lg font-bold text-primary">${summary?.owner_phone ? formatPhone(summary.owner_phone) : 'Vincular Conta'}</p>
|
|
353
460
|
</div>
|
|
354
|
-
<div>
|
|
355
|
-
<p className="text-[
|
|
356
|
-
<p className="text-
|
|
461
|
+
<div className="space-y-1.5">
|
|
462
|
+
<p className="text-[10px] font-black uppercase text-white/20 tracking-widest">Última Conexão</p>
|
|
463
|
+
<p className="text-lg font-bold text-white/80">${formatDateTime(summary?.last_seen_at) || 'Online agora'}</p>
|
|
357
464
|
</div>
|
|
358
|
-
<div>
|
|
359
|
-
<p className="text-[
|
|
360
|
-
<p className="text-
|
|
465
|
+
<div className="space-y-1.5">
|
|
466
|
+
<p className="text-[10px] font-black uppercase text-white/20 tracking-widest">Membro da Rede Desde</p>
|
|
467
|
+
<p className="text-lg font-bold text-white/80">${formatDateTime(rpgInfo.member_since) || 'Recentemente'}</p>
|
|
361
468
|
</div>
|
|
362
469
|
</div>
|
|
363
470
|
|
|
364
|
-
<div className="relative grid grid-cols-2 sm:grid-cols-3 gap-
|
|
471
|
+
<div className="relative grid grid-cols-2 sm:grid-cols-3 gap-8">
|
|
365
472
|
<div>
|
|
366
|
-
<p className="text-[9px] font-black uppercase text-white/20 mb-1">Tempo
|
|
367
|
-
<p className="text-
|
|
473
|
+
<p className="text-[9px] font-black uppercase text-white/20 mb-1">Tempo de Rede</p>
|
|
474
|
+
<p className="text-base font-black text-primary">${daysMember} dias ativos</p>
|
|
368
475
|
</div>
|
|
369
476
|
<div>
|
|
370
|
-
<p className="text-[9px] font-black uppercase text-white/20 mb-1">Primeira
|
|
371
|
-
<p className="text-[
|
|
477
|
+
<p className="text-[9px] font-black uppercase text-white/20 mb-1">Primeira Interação</p>
|
|
478
|
+
<p className="text-[11px] font-bold text-white/50">${formatDateTime(usageInfo.first_message_at) || 'N/D'}</p>
|
|
372
479
|
</div>
|
|
373
480
|
<div>
|
|
374
|
-
<p className="text-[9px] font-black uppercase text-white/20 mb-1">Última
|
|
375
|
-
<p className="text-[
|
|
481
|
+
<p className="text-[9px] font-black uppercase text-white/20 mb-1">Última Interação</p>
|
|
482
|
+
<p className="text-[11px] font-bold text-white/50">${formatDateTime(usageInfo.last_message_at) || 'N/D'}</p>
|
|
376
483
|
</div>
|
|
377
484
|
</div>
|
|
378
485
|
</div>
|
|
@@ -380,142 +487,107 @@ const UserApp = ({ config }) => {
|
|
|
380
487
|
`}
|
|
381
488
|
${activeTab === 'rpg' &&
|
|
382
489
|
html`
|
|
383
|
-
<div className="space-y-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
<span className="text-6xl font-black text-white">${rpgInfo.level}</span>
|
|
391
|
-
<span className="text-sm font-bold text-white/40 uppercase tracking-widest">Nível Atual</span>
|
|
392
|
-
</div>
|
|
393
|
-
|
|
394
|
-
<div className="space-y-2 w-full max-w-sm">
|
|
395
|
-
<div className="flex justify-between text-[10px] font-black uppercase tracking-widest text-white/50">
|
|
396
|
-
<span>XP Atual: ${rpgInfo.xp}</span>
|
|
397
|
-
<span>Próximo Nível</span>
|
|
490
|
+
<div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500">
|
|
491
|
+
<div className="p-8 rounded-[3rem] bg-gradient-to-br from-primary/10 via-transparent to-transparent border border-primary/20">
|
|
492
|
+
<div className="flex flex-col md:flex-row items-center gap-8">
|
|
493
|
+
<div className="relative">
|
|
494
|
+
<div className="absolute inset-0 bg-primary/20 blur-3xl rounded-full"></div>
|
|
495
|
+
<div className="relative w-32 h-32 rounded-full border-4 border-primary/20 p-2 flex items-center justify-center bg-[#020617]">
|
|
496
|
+
<span className="text-5xl font-black text-white">${rpgInfo.level}</span>
|
|
398
497
|
</div>
|
|
399
|
-
<div className="
|
|
400
|
-
|
|
498
|
+
<div className="absolute -bottom-2 left-1/2 -translate-x-1/2 bg-primary text-primary-content px-4 py-1 rounded-full text-[10px] font-black uppercase tracking-widest shadow-xl">Nível</div>
|
|
499
|
+
</div>
|
|
500
|
+
<div className="flex-1 text-center md:text-left space-y-4">
|
|
501
|
+
<h3 className="text-2xl font-black tracking-tight">Status do Treinador</h3>
|
|
502
|
+
<div className="space-y-2">
|
|
503
|
+
<div className="flex justify-between text-[10px] font-black uppercase tracking-widest text-white/40">
|
|
504
|
+
<span>Experiência: ${rpgInfo.xp} XP</span>
|
|
505
|
+
<span>Próximo nível: ${(rpgInfo.level + 1) * 100}</span>
|
|
506
|
+
</div>
|
|
507
|
+
<div className="h-4 w-full bg-white/5 rounded-full overflow-hidden border border-white/5">
|
|
508
|
+
<div className="h-full bg-gradient-to-r from-primary to-emerald-400 transition-all duration-1000" style=${{ width: Math.min((rpgInfo.xp / ((rpgInfo.level + 1) * 100)) * 100, 100) + '%' }}></div>
|
|
509
|
+
</div>
|
|
401
510
|
</div>
|
|
402
511
|
</div>
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
<span className="text-4xl font-black text-warning mb-1">${rpgInfo.gold}</span>
|
|
408
|
-
<span className="text-[10px] font-black uppercase tracking-widest text-warning/50">Gold Acumulado</span>
|
|
512
|
+
<div className="p-6 rounded-[2.5rem] bg-warning/5 border border-warning/10 text-center min-w-[160px]">
|
|
513
|
+
<p className="text-[9px] font-black uppercase tracking-widest text-warning/50 mb-1">Tesouro</p>
|
|
514
|
+
<p className="text-3xl font-black text-warning">💰 ${shortNum(rpgInfo.gold)}</p>
|
|
515
|
+
</div>
|
|
409
516
|
</div>
|
|
410
517
|
</div>
|
|
411
518
|
|
|
412
|
-
<!-- Pokemon & PvP -->
|
|
413
519
|
<div className="grid md:grid-cols-2 gap-6">
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
<div className="flex items-center gap-3">
|
|
417
|
-
<span className="text-xl">🐉</span>
|
|
418
|
-
<h3 className="font-black text-lg">Pokémon Ativo</h3>
|
|
419
|
-
</div>
|
|
420
|
-
|
|
520
|
+
<div className="p-8 rounded-[3rem] bg-white/[0.03] border border-white/5 space-y-6">
|
|
521
|
+
<h4 className="text-lg font-black flex items-center gap-3">🐉 Pokémon em Destaque</h4>
|
|
421
522
|
${rpgInfo.active_pokemon
|
|
422
523
|
? html`
|
|
423
|
-
<div className="
|
|
524
|
+
<div className="p-6 rounded-3xl bg-white/5 border border-white/10 flex items-center gap-6 group hover:border-primary/40 transition-all">
|
|
424
525
|
<div className="relative">
|
|
425
|
-
<
|
|
426
|
-
|
|
427
|
-
</div>
|
|
428
|
-
${rpgInfo.active_pokemon.is_shiny && html`<div className="absolute -top-2 -right-2 text-warning animate-pulse">✨</div>`}
|
|
526
|
+
<img src=${'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/' + (rpgInfo.active_pokemon.is_shiny ? 'shiny/' : '') + rpgInfo.active_pokemon.poke_id + '.png'} className="w-24 h-24 object-contain drop-shadow-2xl" />
|
|
527
|
+
${rpgInfo.active_pokemon.is_shiny && html`<div className="absolute top-0 right-0 text-xl animate-pulse">✨</div>`}
|
|
429
528
|
</div>
|
|
430
529
|
<div>
|
|
431
|
-
<
|
|
432
|
-
<p className="text-xs font-bold text-white/
|
|
530
|
+
<h5 className="text-xl font-black capitalize text-white group-hover:text-primary transition-colors">${rpgInfo.active_pokemon.nickname}</h5>
|
|
531
|
+
<p className="text-xs font-bold text-white/40 uppercase tracking-widest">Nível ${rpgInfo.active_pokemon.level}</p>
|
|
433
532
|
</div>
|
|
434
533
|
</div>
|
|
435
534
|
`
|
|
436
|
-
: html
|
|
437
|
-
<div className="p-6 text-center rounded-3xl bg-white/5 border border-white/5 border-dashed">
|
|
438
|
-
<p className="text-sm font-bold text-white/40">Nenhum Pokémon ativo no momento.</p>
|
|
439
|
-
</div>
|
|
440
|
-
`}
|
|
441
|
-
|
|
442
|
-
<div className="flex items-center justify-between p-4 rounded-2xl bg-white/5">
|
|
443
|
-
<span className="text-[10px] font-black uppercase tracking-widest text-white/40">Total Capturados</span>
|
|
444
|
-
<span className="text-lg font-black text-white">${rpgInfo.total_pokemons}</span>
|
|
445
|
-
</div>
|
|
535
|
+
: html`<div className="p-10 text-center border-2 border-dashed border-white/5 rounded-3xl text-white/20 font-bold">Nenhum Pokémon ativo</div>`}
|
|
446
536
|
</div>
|
|
447
537
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
<div className="flex items-center gap-3">
|
|
451
|
-
<span className="text-xl">🏆</span>
|
|
452
|
-
<h3 className="font-black text-lg">Arena PvP (Semanal)</h3>
|
|
453
|
-
</div>
|
|
454
|
-
|
|
538
|
+
<div className="p-8 rounded-[3rem] bg-white/[0.03] border border-white/5 space-y-6 text-center">
|
|
539
|
+
<h4 className="text-lg font-black flex items-center gap-3 justify-center">🏆 Arena Competitiva</h4>
|
|
455
540
|
<div className="grid grid-cols-2 gap-4">
|
|
456
|
-
<div className="
|
|
457
|
-
<p className="text-
|
|
458
|
-
<p className="text-[9px] font-black uppercase
|
|
459
|
-
</div>
|
|
460
|
-
<div className="p-4 rounded-2xl bg-success/10 border border-success/20 text-center">
|
|
461
|
-
<p className="text-3xl font-black text-success mb-1">${rpgInfo.pvp?.matches > 0 ? Math.round(((rpgInfo.pvp?.wins || 0) / rpgInfo.pvp.matches) * 100) : 0}%</p>
|
|
462
|
-
<p className="text-[9px] font-black uppercase tracking-widest text-success/60">Vitórias</p>
|
|
463
|
-
</div>
|
|
464
|
-
<div className="p-4 rounded-2xl bg-info/10 text-center">
|
|
465
|
-
<p className="text-xl font-black text-info mb-1">${rpgInfo.pvp?.wins || 0}</p>
|
|
466
|
-
<p className="text-[9px] font-black uppercase tracking-widest text-info/60">Ganha</p>
|
|
541
|
+
<div className="bg-white/5 p-5 rounded-3xl">
|
|
542
|
+
<p className="text-2xl font-black text-white">${rpgInfo.pvp?.wins || 0}</p>
|
|
543
|
+
<p className="text-[9px] font-black uppercase text-white/30">Vitórias</p>
|
|
467
544
|
</div>
|
|
468
|
-
<div className="p-
|
|
469
|
-
<p className="text-
|
|
470
|
-
<p className="text-[9px] font-black uppercase
|
|
545
|
+
<div className="bg-white/5 p-5 rounded-3xl">
|
|
546
|
+
<p className="text-2xl font-black text-white">${rpgInfo.pvp?.losses || 0}</p>
|
|
547
|
+
<p className="text-[9px] font-black uppercase text-white/30">Derrotas</p>
|
|
471
548
|
</div>
|
|
472
549
|
</div>
|
|
550
|
+
<div className="bg-primary/10 p-4 rounded-2xl border border-primary/20">
|
|
551
|
+
<p className="text-sm font-black text-primary">${rpgInfo.karma?.score || 0} Karma Global</p>
|
|
552
|
+
</div>
|
|
473
553
|
</div>
|
|
474
554
|
</div>
|
|
475
555
|
</div>
|
|
476
556
|
`}
|
|
477
557
|
${activeTab === 'account' &&
|
|
478
558
|
html`
|
|
479
|
-
<div className="
|
|
480
|
-
<div className="
|
|
481
|
-
<div className="
|
|
482
|
-
|
|
483
|
-
<
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
</div>
|
|
487
|
-
|
|
488
|
-
<form className="space-y-6">
|
|
489
|
-
<div className="grid sm:grid-cols-2 gap-6">
|
|
490
|
-
<div className="space-y-2">
|
|
491
|
-
<label className="text-[10px] font-black uppercase tracking-widest text-white/30 ml-4">Nova Senha</label>
|
|
492
|
-
<input type="password" placeholder="••••••••" className="w-full h-14 bg-white/5 border border-white/10 rounded-2xl px-6 focus:border-primary outline-none transition-all font-mono" />
|
|
559
|
+
<div className="max-w-xl animate-in fade-in slide-in-from-bottom-4 duration-500">
|
|
560
|
+
<div className="space-y-10">
|
|
561
|
+
<div className="flex items-center gap-6">
|
|
562
|
+
<div className="w-16 h-16 rounded-[2rem] bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-3xl shadow-lg">🛡️</div>
|
|
563
|
+
<div>
|
|
564
|
+
<h3 className="text-2xl font-black tracking-tight">Segurança</h3>
|
|
565
|
+
<p className="text-sm text-white/40 font-medium">Proteja seu acesso ao ecossistema OmniZap.</p>
|
|
493
566
|
</div>
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
567
|
+
</div>
|
|
568
|
+
<div className="p-8 rounded-[3rem] bg-white/[0.03] border border-white/5 space-y-8">
|
|
569
|
+
<div className="space-y-4">
|
|
570
|
+
<p className="text-sm text-white/60 leading-relaxed">Para alterar sua senha com segurança, o OmniZap envia um código de verificação para o e-mail vinculado à sua conta.</p>
|
|
571
|
+
<div className="rounded-2xl border border-white/10 bg-white/[0.02] px-4 py-3 text-xs text-white/50">Fluxo: criar sessão de redefinição → receber código por e-mail → confirmar nova senha.</div>
|
|
497
572
|
</div>
|
|
573
|
+
|
|
574
|
+
<button type="button" className="btn btn-primary btn-block h-14 rounded-2xl font-black uppercase text-[10px] tracking-[0.2em] shadow-xl shadow-primary/20" disabled=${passwordResetBusy} onClick=${startPasswordResetFlow}>${passwordResetBusy ? 'Preparando redefinição...' : 'Alterar Senha com Verificação'}</button>
|
|
575
|
+
|
|
576
|
+
${passwordResetInfo ? html` <div className="rounded-2xl border border-emerald-400/30 bg-emerald-500/10 px-4 py-3 text-xs font-semibold text-emerald-300">${passwordResetInfo}</div> ` : null} ${passwordResetError ? html` <div className="rounded-2xl border border-red-400/30 bg-red-500/10 px-4 py-3 text-xs font-semibold text-red-300">${passwordResetError}</div> ` : null}
|
|
498
577
|
</div>
|
|
499
|
-
|
|
500
|
-
<div className="absolute inset-0 bg-primary/20 blur-xl rounded-xl opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
|
501
|
-
<div className="relative bg-primary text-primary-content px-10 py-4 rounded-xl font-black text-[10px] uppercase tracking-[0.2em] shadow-xl hover:scale-105 transition-all">Atualizar Credenciais</div>
|
|
502
|
-
</button>
|
|
503
|
-
</form>
|
|
578
|
+
</div>
|
|
504
579
|
</div>
|
|
505
580
|
`}
|
|
506
581
|
${activeTab === 'support' &&
|
|
507
582
|
html`
|
|
508
|
-
<div className="text-center max-w-lg mx-auto
|
|
509
|
-
<div className="
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
<h3 className="text-3xl font-black tracking-tighter text-white">Canal de Suporte</h3>
|
|
513
|
-
<p className="text-white/40 font-medium leading-relaxed">Nosso time de especialistas está pronto para te ajudar com qualquer dúvida técnica ou financeira.</p>
|
|
583
|
+
<div className="py-16 text-center max-w-lg mx-auto animate-in fade-in slide-in-from-bottom-4 duration-500">
|
|
584
|
+
<div className="relative inline-block mb-10">
|
|
585
|
+
<div className="absolute inset-0 bg-primary/20 blur-[60px] rounded-full animate-pulse"></div>
|
|
586
|
+
<div className="relative w-28 h-28 rounded-[3rem] bg-white/5 border border-white/10 flex items-center justify-center text-5xl shadow-2xl">🎧</div>
|
|
514
587
|
</div>
|
|
515
|
-
<
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
</a>
|
|
588
|
+
<h3 className="text-3xl font-black tracking-tighter mb-4">Central de Atendimento</h3>
|
|
589
|
+
<p className="text-white/40 font-medium leading-relaxed mb-10 text-lg">Dúvidas sobre o sistema, planos ou bugs? Fale diretamente com nossa equipe técnica.</p>
|
|
590
|
+
<a href=${supportWhatsappUrl} target="_blank" className="btn btn-primary btn-lg btn-block rounded-[2rem] font-black uppercase text-xs tracking-widest h-16 shadow-2xl shadow-primary/20 hover:scale-[1.02] active:scale-95 transition-all">Iniciar Chat Suporte</a>
|
|
519
591
|
</div>
|
|
520
592
|
`}
|
|
521
593
|
</div>
|
|
@@ -523,11 +595,11 @@ const UserApp = ({ config }) => {
|
|
|
523
595
|
</div>
|
|
524
596
|
</div>
|
|
525
597
|
</div>
|
|
526
|
-
</
|
|
527
|
-
</
|
|
598
|
+
</main>
|
|
599
|
+
</div>
|
|
528
600
|
|
|
529
|
-
<!-- Footer
|
|
530
|
-
<footer className="py-12 border-t border-white/5 mt-auto relative z-
|
|
601
|
+
<!-- Footer -->
|
|
602
|
+
<footer className="py-12 border-t border-white/5 mt-auto relative z-[70] bg-[#020617]">
|
|
531
603
|
<div className="container mx-auto px-4 text-center">
|
|
532
604
|
<p className="text-[10px] font-black uppercase tracking-[0.5em] text-white/10">© 2026 OMNIZAP CORE · SECURE USER ENVIRONMENT</p>
|
|
533
605
|
</div>
|
|
@@ -541,7 +613,10 @@ if (rootElement) {
|
|
|
541
613
|
const config = {
|
|
542
614
|
apiBasePath: rootElement.dataset.apiBasePath || DEFAULT_API_BASE_PATH,
|
|
543
615
|
loginPath: rootElement.dataset.loginPath || DEFAULT_LOGIN_PATH,
|
|
616
|
+
passwordResetWebPath: normalizeRoutePath(rootElement.dataset.passwordResetWebPath, DEFAULT_PASSWORD_RESET_WEB_PATH),
|
|
544
617
|
fallbackAvatar: DEFAULT_FALLBACK_AVATAR,
|
|
618
|
+
supportWhatsappNumber: rootElement.dataset.supportWhatsappNumber || DEFAULT_SUPPORT_WHATSAPP_NUMBER,
|
|
619
|
+
supportWhatsappUrl: rootElement.dataset.supportWhatsappUrl || DEFAULT_SUPPORT_WHATSAPP_URL,
|
|
545
620
|
};
|
|
546
621
|
createRoot(rootElement).render(html`<${UserApp} config=${config} />`);
|
|
547
622
|
}
|