diff --git a/.env.example b/.env.example index b0e0288..ec05419 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,9 @@ # API Configuration # Base URL da API do HGTX VITE_API_BASE_URL=https://prod-hgtx-intelligence-n8n.hgtx.com.br +VITE_BASE_URL_OPEN_CODEX_APIs=https://codex-api.hgtx.com.br/api/ +VITE_BASE_URL_HGTX_CORE_API=https://core-api.hgtx.com.br/api/ +VITE_BASE_URL_HGTX_CORE=https://core.hgtx.com.br/ # API Key para autenticação # IMPORTANTE: Mantenha esta chave segura e não compartilhe publicamente diff --git a/index.html b/index.html index 3b041b8..1513c1c 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,5 @@ - + @@ -10,11 +10,11 @@ - + - - + + diff --git a/package-lock.json b/package-lock.json index fc7bedc..6a27f24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "date-fns": "^3.6.0", "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", + "jwt-decode": "^4.0.0", "lucide-react": "^0.462.0", "next-themes": "^0.3.0", "react": "^18.3.1", @@ -4828,6 +4829,14 @@ "dev": true, "license": "MIT" }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "engines": { + "node": ">=18" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", diff --git a/package.json b/package.json index 2ecde5e..e7982a7 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "date-fns": "^3.6.0", "embla-carousel-react": "^8.6.0", "input-otp": "^1.4.2", + "jwt-decode": "^4.0.0", "lucide-react": "^0.462.0", "next-themes": "^0.3.0", "react": "^18.3.1", diff --git a/public/favicon.ico b/public/favicon.ico index dd5a126..70c2a8f 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000..3808375 Binary files /dev/null and b/public/favicon.png differ diff --git a/public/favicon2.ico b/public/favicon2.ico new file mode 100644 index 0000000..dd5a126 Binary files /dev/null and b/public/favicon2.ico differ diff --git a/src/App.tsx b/src/App.tsx index c06f45b..3603675 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,11 +2,13 @@ import { Toaster } from "@/components/ui/toaster"; import { Toaster as Sonner } from "@/components/ui/sonner"; import { TooltipProvider } from "@/components/ui/tooltip"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { BrowserRouter, Routes, Route } from "react-router-dom"; +import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; import { ThemeProvider } from "next-themes"; import Index from "./pages/Index"; import NotFound from "./pages/NotFound"; import Redirect from "./pages/Redirect"; +import { GlobalFunctions } from "./GlobalFunctions"; +import React from "react"; const queryClient = new QueryClient(); @@ -23,7 +25,7 @@ const App = () => ( element={} /> - } /> + : } /> {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */} } /> } /> @@ -35,3 +37,13 @@ const App = () => ( ); export default App; + + +const HGTXLogin = () =>{ + + React.useEffect(() => { + window.location.replace(import.meta.env.VITE_BASE_URL_HGTX_CORE); + }); + + return(<>); +} \ No newline at end of file diff --git a/src/GlobalFunctions.ts b/src/GlobalFunctions.ts new file mode 100644 index 0000000..71834f3 --- /dev/null +++ b/src/GlobalFunctions.ts @@ -0,0 +1,286 @@ +import { jwtDecode } from 'jwt-decode'; +import { RedirectService } from './pages/RedirectService'; + +export class GlobalFunctions { + + public static getTranferAreaObj(): TransferAreaResponse { + let objRetorno: TransferAreaResponse = { + aplicativoID: 0, + aplicativoNome: "", + areaTransferenciaID: 0, + dataRegistro: "", + estabelecimentoID: 0, + usuarioID: 0, + usuarioEmail: "", + usuarioNome: "", + aplicativoShareCode: "", + nivelAcesso: 0 + }; + try { + const objTransferStr = sessionStorage.getItem("TRANSFER_AREA"); + if ( + objTransferStr != null && + objTransferStr != undefined && + objTransferStr.trim() != "" + ) { + const objTransfer = JSON.parse(objTransferStr); + objRetorno = objTransfer; + } + } catch (error) {} + + return objRetorno; + } + + public static getRedirectComponent(): string { + let objRetorno = ""; + try { + const objTransfer = GlobalFunctions.getTranferAreaObj(); + if (objTransfer != null) { + // let objRedir = objTransfer.find(x => x.name == 'REDIRECT'); + // objRetorno = objRedir?.value ?? ''; + objRetorno = objTransfer.urlDestino ?? ""; + if (objRetorno.startsWith("/")) objRetorno = objRetorno.substring(1); + } else { + objRetorno = ""; + } + } catch (error) { + //console.log(error); + objRetorno = ""; + } + + return objRetorno; + } + + public static getTransferProperty(propertyName: TransferAreaProperties): any { + let objRetorno: any = ""; + try { + const objTransfer = this.getTranferAreaObj(); + if (objTransfer != null) { + //let obj: any = objTransfer[propertyName]; + const element = objTransfer[propertyName]; + objRetorno = element; + } else { + objRetorno = null; + } + } catch (error) { + objRetorno = null; + } + + return objRetorno; + } + + public static isUsuarioLogado(): boolean { + let jsonUsuario = sessionStorage.getItem('usuarioLogado'); + if (jsonUsuario) { + let tokenDecode: any = GlobalFunctions.getUsuarioLogado(); + let d: Date = new Date(); + let dateAtual: number = Date.UTC(d.getFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes() + 5, d.getUTCSeconds()) / 1000; + if (dateAtual > tokenDecode.exp) return false; + return true; + } + return false; + } + + public static tokenExpired(tokenDecode: any): boolean { + let d: Date = new Date(); + let dateAtual: number = Date.UTC(d.getFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes() + 5, d.getUTCSeconds()) / 1000; + if (dateAtual > tokenDecode.exp) return true; + return false; + } + + public static handleNavigateBack(): void { + try { + // Verifica se existe histórico de navegação + if (window.history && window.history.length > 1) { + window.history.back(); + return; + } + + // Tenta fechar a janela + if (!window.closed) { + try { + const windowRef = window.open('', '_self'); + if (windowRef) { + windowRef.close(); + + // Pequeno timeout para verificar se a janela foi fechada + setTimeout(() => { + // Se ainda estiver aberta, redireciona + if (!windowRef.closed) { + window.location.href = "https://core.hgtx.com.br/aplicativos/"; + } + }, 100); + return; + } + } catch (closeError) { + console.warn("Não foi possível fechar a janela:", closeError); + } + } + + // Se não conseguiu fechar, redireciona + window.location.href = "https://core.hgtx.com.br/aplicativos/"; + } catch (error) { + // Em caso de qualquer erro, garante o redirecionamento + console.error("Erro ao tentar navegar:", error); + window.location.href = "https://core.hgtx.com.br/aplicativos/"; + } + } + + public static getUsuarioLogado(): UsuarioLogadoData { + const jsonUsuario = sessionStorage.getItem("usuarioLogado") ?? ""; + try { + const objJwt = JSON.parse(jsonUsuario); + //return jwt_decode(objJwt.token); + return jwtDecode(objJwt.token); + } catch (error) {} + + return { + EID: "0", + email: "", + exp: 0, + iat: 0, + jti: "", + name: "", + nbf: 0, + UID: "0", + }; + } + + public static getUsuarioLogadoToken(): string { + let retorno = ""; + const jsonUsuario = sessionStorage.getItem("usuarioLogado") ?? ""; + try { + const objJwt = JSON.parse(jsonUsuario); + retorno = objJwt.token; + } catch (error) {} + + return retorno; + } + + public static getUsuarioLogadoRefreshToken(): string { + let retorno = ""; + const jsonUsuario = sessionStorage.getItem("usuarioLogado") ?? ""; + try { + const objJwt = JSON.parse(jsonUsuario); + retorno = objJwt.refreshToken; + } catch (error) {} + + return retorno; + } + + public static getPerfilUsuario(): PerfilUsuario | null { + let retorno: PerfilUsuario | null = null; + const jsonUsuario = sessionStorage.getItem("perfilUsuario") ?? ""; + try { + const objJwt = JSON.parse(jsonUsuario); + retorno = objJwt; + } catch (error) { + retorno = null; + } + + return retorno; + } + + public static getHighUserProfile(): number { + let retorno = 6; + const objPerfil = GlobalFunctions.getPerfilUsuario(); + + if (objPerfil) { + const tiposPerfil: number[] = objPerfil.results.map((v) => v.tipoPerfil); + retorno = Math.min(...tiposPerfil); + } + + return retorno; + } + + public static async getToken(): Promise { + let token: string = GlobalFunctions.getUsuarioLogadoToken(); + + const tokenDecode: any = GlobalFunctions.getUsuarioLogado(); + + let currentDate = new Date(); + + // JWT exp is in seconds + if ((tokenDecode.exp * 1000) < currentDate.getTime()) { + //console.log("Token expired."); + let gsikey: number = parseInt(sessionStorage.getItem('gsikey') ?? '0'); + RedirectService.loadTransferArea(gsikey).then((response) => { + if(response.data.errorCode == 0){ + sessionStorage.setItem('TRANSFER_AREA',JSON.stringify(response.data.areTrs)); + sessionStorage.setItem('usuarioLogado',JSON.stringify({ + token: response.data.jwt.token, + refreshToken: response.data.jwt.refreshToken + })); + + token = response.data.jwt.token; + } + // else if(error !== 1401){ + // navigate('/',{replace: true}); + // } + }); + } + // else { + // //console.log("Valid token"); + // result = true; + // } + + return token; + } +} + +export interface UsuarioLogadoData { + UID: string; + EID: string; + name: string; + email: string; + jti: string; + nbf: number; + exp: number; + iat: number; +} + +export interface TransferAreaResponse { + estabelecimentoID: number; + nivelAcesso: number; + aplicativoID: number; + usuarioID: number; + areaTransferenciaID: number; + dataRegistro: string; + urlBase?: string; + urlDestino?: string; + aplicativoNome: string; + usuarioNome: string; + usuarioEmail: string; + aplicativoShareCode: string; +} + +export enum TransferAreaProperties { + EstabelecimentoCodigo = "estabelecimentoID", + UsuarioCodigo = "usuarioID", + UsuarioNome = "usuarioNome", + UsuarioEmail = "usuarioEmail", + APP_COD = "aplicativoID", + APP_TITULO = "aplicativoNome", + areaTransferenciaID = "areaTransferenciaID", + urlBase = "urlBase", + urlDestino = "urlDestino", + aplicativoShareCode = "aplicativoShareCode", + nivelAcesso = "nivelAcesso", +} + +type PerfilUsuario = { + errorCode: number; + errorMessage: string; + results: PerfilUsuarioResult[]; +}; + +export type PerfilUsuarioResult = { + tipoPerfil: number; + itens: PerfilUsuarioItem[]; +}; + +type PerfilUsuarioItem = { + id: number; + descricao: string; + identificador: string; +}; diff --git a/src/components/FullScreenLoader.tsx b/src/components/FullScreenLoader.tsx index aed2a98..ff4ad25 100644 --- a/src/components/FullScreenLoader.tsx +++ b/src/components/FullScreenLoader.tsx @@ -27,7 +27,7 @@ export default function FullScreenLoader({ show, text = "Carregando..." }: FullS }`} >
- +

{text}

diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index cdf0350..08eaa8b 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -3,6 +3,7 @@ import { MessageSquare, Image, AudioLines, Mic, ArrowLeft, Plus, ChevronLeft, Ch import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; import { ThemeToggle } from "@/components/ThemeToggle"; +import { GlobalFunctions } from "@/GlobalFunctions"; interface LayoutProps { children: React.ReactNode; @@ -75,7 +76,7 @@ export const Layout = ({ children, activeTab, onTabChange }: LayoutProps) => { Tema - diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 0bbacf8..66118b4 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -49,6 +49,7 @@ const Index = () => { } />
+ } /> ); diff --git a/src/pages/Redirect.tsx b/src/pages/Redirect.tsx index be5a203..02fd83f 100644 --- a/src/pages/Redirect.tsx +++ b/src/pages/Redirect.tsx @@ -1,9 +1,47 @@ import FullScreenLoader from "@/components/FullScreenLoader"; +import { GlobalFunctions } from "@/GlobalFunctions"; +import { RedirectService } from "./RedirectService"; +import React from "react"; +import { useNavigate, useParams } from "react-router-dom"; export default function Redirect() { + const navigate = useNavigate(); + let { gsikey } = useParams(); + + React.useEffect(() => { + let error: number = 0; + sessionStorage.setItem('gsikey', gsikey ?? '0'); + RedirectService.loadTransferArea(parseInt(gsikey ?? '0')).then((response) => { + //console.log(response); + error = response.data.errorCode; + //msg = response.data.errorMessage; + if(response.data.errorCode == 0){ + sessionStorage.setItem('TRANSFER_AREA',JSON.stringify(response.data.areTrs)); + sessionStorage.setItem('usuarioLogado',JSON.stringify({ + token: response.data.jwt.token, + refreshToken: response.data.jwt.refreshToken + })); + } + // else if(error !== 1401){ + // navigate('/',{replace: true}); + // } + }) + .catch((_err) => { + navigate('/404',{replace: true}); + }) + .finally(() => { + if(error == 0 || error === 1401){ + navigate(`/${GlobalFunctions.getRedirectComponent()}`,{replace: true}); + } + // else if(error === 1401){ + // navigate({pathname: '/',search:`?p=${window.btoa(msg)}`},{replace: true}); + // } + }); + }, []); + return ( ); diff --git a/src/pages/RedirectService.ts b/src/pages/RedirectService.ts new file mode 100644 index 0000000..e9d997c --- /dev/null +++ b/src/pages/RedirectService.ts @@ -0,0 +1,34 @@ +import { GlobalFunctions, TransferAreaProperties } from "@/GlobalFunctions"; +import axios from "axios"; +const endPoint: string = 'v1/login/'; + +export class RedirectService{ + + public static loadTransferArea(gsikey: number): Promise{ + return axios.post(`${import.meta.env.VITE_BASE_URL_OPEN_CODEX_APIs}${endPoint}login_by_gsikey`,{ + "gsikey" : gsikey + }); + } + + public static async validaAcessoApp(urlDestino: string): Promise{ + //let token = await GlobalFunctions.getToken(); + let usuLogado = GlobalFunctions.getUsuarioLogado(); + let usuCod: string = GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioCodigo); + let estCod: string = usuLogado.EID; + + let urlDestinoPost: string = urlDestino;//urlDestino.trim().length < 1 ? GlobalFunctions.getTransferProperty(TransferAreaProperties.urlDestino) : urlDestino; + if(urlDestinoPost.trim().length < 1){ + try { + let pathSplit = window.location.pathname.split('/'); + + urlDestinoPost = `/${pathSplit[pathSplit.length-2]}/${pathSplit[pathSplit.length-1]}`; + } catch (error) { + } + } + //const heads = { headers: {'Content-Type':'application/json; charset=utf-8','Authorization': `Bearer ${token}`} }; + const heads = { headers: {'Content-Type':'application/json; charset=utf-8'} }; + return axios.post(`${import.meta.env.VITE_BASE_URL_HGTX_CORE_API}v1/aplicativos/validar_acesso_app?usuCod=${usuCod}&estCod=${estCod}`,{ + "urlDestino": urlDestinoPost + },heads); + } +} diff --git a/src/services/audioGeneration.ts b/src/services/audioGeneration.ts index 8610f19..0a90344 100644 --- a/src/services/audioGeneration.ts +++ b/src/services/audioGeneration.ts @@ -1,3 +1,4 @@ +import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions'; import { apiService } from './api'; /** @@ -83,8 +84,8 @@ class AudioGenerationService { const { message, voice, userEmail, estabelecimentoId } = request; // Usa valores do .env se não forem fornecidos - const email = userEmail || import.meta.env.VITE_USER_EMAIL || ''; - const estabId = estabelecimentoId || parseInt(import.meta.env.VITE_ESTABELECIMENTO_ID) || 1; + const email = GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);//userEmail || import.meta.env.VITE_USER_EMAIL || ''; + const estabId = GlobalFunctions.getTransferProperty(TransferAreaProperties.EstabelecimentoCodigo);//estabelecimentoId || parseInt(import.meta.env.VITE_ESTABELECIMENTO_ID) || 1; // Valida o texto if (!message || message.trim().length === 0) { diff --git a/src/services/chat.ts b/src/services/chat.ts index 8f87389..119aa13 100644 --- a/src/services/chat.ts +++ b/src/services/chat.ts @@ -1,3 +1,4 @@ +import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions'; import { apiService } from './api'; /** @@ -126,8 +127,8 @@ class ChatService { } = request; // Usa valores do .env se não forem fornecidos - const email = userEmail || import.meta.env.VITE_USER_EMAIL || ''; - const estabId = estabelecimentoId || import.meta.env.VITE_ESTABELECIMENTO_ID || ''; + const email = GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);//userEmail || import.meta.env.VITE_USER_EMAIL || ''; + const estabId = GlobalFunctions.getTransferProperty(TransferAreaProperties.EstabelecimentoCodigo);//estabelecimentoId || import.meta.env.VITE_ESTABELECIMENTO_ID || ''; // Validações if (!chatId) { diff --git a/src/services/imageGeneration.ts b/src/services/imageGeneration.ts index fd8dada..94cc701 100644 --- a/src/services/imageGeneration.ts +++ b/src/services/imageGeneration.ts @@ -1,3 +1,4 @@ +import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions'; import { apiService } from './api'; /** @@ -65,8 +66,8 @@ class ImageGenerationService { const { description, size, userEmail, estabelecimentoId } = request; // Usa valores do .env se não forem fornecidos - const email = userEmail || import.meta.env.VITE_USER_EMAIL || ''; - const estabId = estabelecimentoId || parseInt(import.meta.env.VITE_ESTABELECIMENTO_ID) || 1; + const email = GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);//userEmail || import.meta.env.VITE_USER_EMAIL || ''; + const estabId = GlobalFunctions.getTransferProperty(TransferAreaProperties.EstabelecimentoCodigo);//estabelecimentoId || parseInt(import.meta.env.VITE_ESTABELECIMENTO_ID) || 1; // Valida a descrição if (!description || description.trim().length === 0) { diff --git a/src/services/transcription.ts b/src/services/transcription.ts index a112c4b..dcdb955 100644 --- a/src/services/transcription.ts +++ b/src/services/transcription.ts @@ -1,3 +1,4 @@ +import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions'; import { apiService } from './api'; /** @@ -39,8 +40,8 @@ class TranscriptionService { formData.append('data', audioFile); // Usa valores do .env se não forem fornecidos - const email = userEmail || import.meta.env.VITE_USER_EMAIL || ''; - const estabId = estabelecimentoId || import.meta.env.VITE_ESTABELECIMENTO_ID || ''; + const email = GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);//userEmail || import.meta.env.VITE_USER_EMAIL || ''; + const estabId = GlobalFunctions.getTransferProperty(TransferAreaProperties.EstabelecimentoCodigo);//estabelecimentoId || import.meta.env.VITE_ESTABELECIMENTO_ID || ''; formData.append('user_email', email); formData.append('estabelecimento_id', estabId.toString()); diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index a03c102..ce0ba66 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -5,6 +5,9 @@ interface ImportMetaEnv { readonly VITE_API_KEY: string readonly VITE_USER_EMAIL: string readonly VITE_ESTABELECIMENTO_ID: string + readonly VITE_BASE_URL_OPEN_CODEX_APIs: string + readonly VITE_BASE_URL_HGTX_CORE_API: string + readonly VITE_BASE_URL_HGTX_CORE: string } interface ImportMeta {