Skip to content

Commit da105a3

Browse files
Merge branch 'develop' into develop
2 parents 84b2f15 + f054b9b commit da105a3

File tree

15 files changed

+663
-26
lines changed

15 files changed

+663
-26
lines changed

package-lock.json

Lines changed: 425 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"@radix-ui/react-slot": "^1.1.0",
6464
"@radix-ui/react-switch": "^1.1.0",
6565
"@radix-ui/react-tabs": "^1.1.0",
66+
"@radix-ui/react-tooltip": "^1.2.8",
6667
"@tanstack/react-query": "^5.52.1",
6768
"@tanstack/react-table": "^8.20.1",
6869
"axios": "^1.7.2",

src/components/ui/tooltip.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as Tooltip from "@radix-ui/react-tooltip";
2+
import { ReactNode } from "react";
3+
4+
interface TooltipWrapperProps {
5+
content: ReactNode; // o texto que vai aparecer no tooltip
6+
children: ReactNode; // o trigger (qualquer elemento)
7+
side?: "top" | "right" | "bottom" | "left"; // posição opcional
8+
}
9+
10+
export function TooltipWrapper({ content, children, side = "top" }: TooltipWrapperProps) {
11+
return (
12+
<Tooltip.Provider delayDuration={200}>
13+
<Tooltip.Root>
14+
<Tooltip.Trigger asChild>
15+
{children}
16+
</Tooltip.Trigger>
17+
<Tooltip.Portal>
18+
<Tooltip.Content
19+
side={side}
20+
className="
21+
rounded px-3 py-1.5 text-sm z-50 border shadow-lg
22+
bg-gray-100 text-gray-900 border-gray-300
23+
dark:bg-gray-800 dark:text-gray-100 dark:border-gray-700
24+
"
25+
>
26+
{content}
27+
<Tooltip.Arrow className="fill-gray-100 dark:fill-gray-800" width={18} height={9} />
28+
</Tooltip.Content>
29+
</Tooltip.Portal>
30+
</Tooltip.Root>
31+
</Tooltip.Provider>
32+
);
33+
}

src/contexts/EmbedInstanceContext.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,21 @@ export function EmbedInstanceProvider({ children }: { children: React.ReactNode
2828
const validateAndFetchInstance = async () => {
2929
const token = searchParams.get("token");
3030
const instanceName = searchParams.get("instanceName");
31+
const apiUrl = searchParams.get("apiUrl");
3132

32-
if (!token || !instanceName) {
33-
setError("Token e instanceName são obrigatórios");
33+
if (!token || !instanceName || !apiUrl) {
34+
setError("Token, instanceName e apiUrl são obrigatórios");
3435
setIsLoading(false);
3536
return;
3637
}
3738

3839
try {
39-
const apiUrl = "https://integracaov2.icommarketing.com.br";
40-
localStorage.setItem(TOKEN_ID.API_URL, apiUrl);
40+
// Format URL (remove trailing slash if present)
41+
const formattedUrl = apiUrl.endsWith("/") ? apiUrl.slice(0, -1) : apiUrl;
42+
localStorage.setItem(TOKEN_ID.API_URL, formattedUrl);
4143
localStorage.setItem(TOKEN_ID.INSTANCE_TOKEN, token);
4244

43-
const { data } = await axios.get(`${apiUrl}/instance/fetchInstances?instanceName=${instanceName}`, {
45+
const { data } = await axios.get(`${formattedUrl}/instance/fetchInstances?instanceName=${instanceName}`, {
4446
headers: {
4547
apikey: token,
4648
},

src/pages/Dashboard/index.tsx

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { useManageInstance } from "@/lib/queries/instance/manageInstance";
4141
import { Instance } from "@/types/evolution.types";
4242

4343
import { NewInstance } from "./NewInstance";
44+
import { TooltipWrapper } from "@/components/ui/tooltip";
4445

4546
function Dashboard() {
4647
const { t } = useTranslation();
@@ -147,18 +148,20 @@ function Dashboard() {
147148
</div>
148149
<main className="grid gap-6 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
149150
{filteredInstances.length > 0 &&
150-
Array.isArray(filteredInstances) &&
151+
Array.isArray(filteredInstances) ? (
151152
filteredInstances.map((instance: Instance) => (
152153
<Card key={instance.id}>
153154
<CardHeader>
154-
<Link
155-
to={`/manager/instance/${instance.id}/dashboard`}
156-
className="flex w-full flex-row items-center justify-between gap-4"
157-
>
158-
<h3 className="text-wrap font-semibold">{instance.name}</h3>
159-
<Button variant="ghost" size="icon">
160-
<Cog className="card-icon" size="20" />
161-
</Button>
155+
<Link to={`/manager/instance/${instance.id}/dashboard`} className="flex w-full flex-row items-center justify-between gap-4">
156+
<TooltipWrapper content={instance.name} side="top">
157+
<h3 className="text-wrap font-semibold truncate">{instance.name}</h3>
158+
</TooltipWrapper>
159+
160+
<TooltipWrapper content={t("dashboard.settings")} side="top">
161+
<Button variant="ghost" size="icon">
162+
<Cog className="card-icon" size="20" />
163+
</Button>
164+
</TooltipWrapper>
162165
</Link>
163166
</CardHeader>
164167
<CardContent className="flex-1 space-y-6">
@@ -220,7 +223,9 @@ function Dashboard() {
220223
</Button>
221224
</CardFooter>
222225
</Card>
223-
))}
226+
))) :(
227+
<p>{t("dashboard.instancesNotFound")}</p>
228+
)}
224229
</main>
225230

226231
{!!deleteConfirmation && (

src/pages/Home.tsx

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import { Button } from "@/components/ui/button";
2+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
3+
import { Badge } from "@/components/ui/badge";
4+
import { ArrowRight, Github, Globe, Mail, Shield } from "lucide-react";
5+
import { useNavigate } from "react-router-dom";
6+
import { useTheme } from "@/components/theme-provider";
7+
import { ModeToggle } from "@/components/mode-toggle";
8+
import { LanguageToggle } from "@/components/language-toggle";
9+
10+
export default function Home() {
11+
const navigate = useNavigate();
12+
const { theme } = useTheme();
13+
14+
const handleGoToManager = () => {
15+
navigate("/manager");
16+
};
17+
18+
return (
19+
<div className="min-h-screen bg-background">
20+
{/* Header with theme toggle */}
21+
<header className="flex items-center justify-between px-4 py-2">
22+
<div className="flex items-center">
23+
<img
24+
src={theme === "dark" ? "https://evolution-api.com/files/evo/evolution-logo-white.svg" : "https://evolution-api.com/files/evo/evolution-logo.svg"}
25+
alt="Evolution API Logo"
26+
className="h-8"
27+
/>
28+
</div>
29+
<div className="flex items-center gap-4">
30+
<LanguageToggle />
31+
<ModeToggle />
32+
</div>
33+
</header>
34+
35+
<div className="container mx-auto px-4 py-16">
36+
<div className="max-w-4xl mx-auto">
37+
{/* Header */}
38+
<div className="text-center mb-12">
39+
<div className="flex items-center justify-center mb-6">
40+
<img
41+
src={theme === "dark" ? "https://evolution-api.com/files/evo/evolution-logo-white.svg" : "https://evolution-api.com/files/evo/evolution-logo.svg"}
42+
alt="Evolution Manager Logo"
43+
className="h-10"
44+
/>
45+
</div>
46+
<h1 className="text-4xl font-bold text-foreground mb-4">
47+
Evolution Manager v2
48+
</h1>
49+
<p className="text-xl text-muted-foreground mb-6">
50+
Modern web interface for Evolution API management
51+
</p>
52+
<Badge variant="secondary" className="text-sm px-3 py-1">
53+
Version 2.0.0
54+
</Badge>
55+
</div>
56+
57+
{/* Main Card */}
58+
<Card className="mb-8">
59+
<CardHeader>
60+
<CardTitle className="flex items-center gap-2">
61+
<Shield className="w-5 h-5 text-primary" />
62+
Welcome to Evolution Manager
63+
</CardTitle>
64+
<CardDescription>
65+
A powerful, modern dashboard for managing your WhatsApp API instances with Evolution API
66+
</CardDescription>
67+
</CardHeader>
68+
<CardContent className="space-y-6">
69+
<div className="pt-6 border-t border-border">
70+
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center">
71+
<Button
72+
onClick={handleGoToManager}
73+
size="lg"
74+
className="px-8 py-3"
75+
>
76+
Access Manager Dashboard
77+
<ArrowRight className="w-4 h-4 ml-2" />
78+
</Button>
79+
</div>
80+
</div>
81+
</CardContent>
82+
</Card>
83+
84+
{/* Links Card */}
85+
<Card>
86+
<CardHeader>
87+
<CardTitle>Resources & Support</CardTitle>
88+
<CardDescription>
89+
Get help, contribute, or learn more about Evolution API
90+
</CardDescription>
91+
</CardHeader>
92+
<CardContent>
93+
<div className="grid md:grid-cols-3 gap-4">
94+
<a
95+
href="https://github.com/EvolutionAPI/evolution-manager-v2"
96+
target="_blank"
97+
rel="noopener noreferrer"
98+
className="flex items-center gap-3 p-4 rounded-lg border border-border hover:bg-accent transition-colors"
99+
>
100+
<Github className="w-5 h-5 text-muted-foreground" />
101+
<div>
102+
<div className="font-medium text-foreground">GitHub</div>
103+
<div className="text-sm text-muted-foreground">Source code</div>
104+
</div>
105+
</a>
106+
107+
<a
108+
href="https://evolution-api.com"
109+
target="_blank"
110+
rel="noopener noreferrer"
111+
className="flex items-center gap-3 p-4 rounded-lg border border-border hover:bg-accent transition-colors"
112+
>
113+
<Globe className="w-5 h-5 text-muted-foreground" />
114+
<div>
115+
<div className="font-medium text-foreground">Website</div>
116+
<div className="text-sm text-muted-foreground">Official site</div>
117+
</div>
118+
</a>
119+
120+
<a
121+
href="mailto:[email protected]"
122+
className="flex items-center gap-3 p-4 rounded-lg border border-border hover:bg-accent transition-colors"
123+
>
124+
<Mail className="w-5 h-5 text-muted-foreground" />
125+
<div>
126+
<div className="font-medium text-foreground">Contact</div>
127+
<div className="text-sm text-muted-foreground">Get support</div>
128+
</div>
129+
</a>
130+
</div>
131+
</CardContent>
132+
</Card>
133+
134+
{/* Footer */}
135+
<div className="text-center mt-12 text-sm text-muted-foreground">
136+
<p>© 2025 Evolution API. Licensed under Apache 2.0 with Evolution API custom conditions.</p>
137+
</div>
138+
</div>
139+
</div>
140+
</div>
141+
);
142+
}

src/pages/Login/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { Input } from "@/components/ui/input";
1313
import { verifyCreds } from "@/lib/queries/auth/verifyCreds";
1414
import { verifyServer } from "@/lib/queries/auth/verifyServer";
1515
import { logout, saveToken } from "@/lib/queries/token";
16+
import { useTheme } from "@/components/theme-provider";
1617

1718
const loginSchema = z.object({
1819
serverUrl: z.string({ required_error: "serverUrl is required" }).url("URL inválida"),
@@ -23,6 +24,7 @@ type LoginSchema = z.infer<typeof loginSchema>;
2324
function Login() {
2425
const { t } = useTranslation();
2526
const navigate = useNavigate();
27+
const { theme } = useTheme();
2628
const loginForm = useForm<LoginSchema>({
2729
resolver: zodResolver(loginSchema),
2830
defaultValues: {
@@ -69,7 +71,7 @@ function Login() {
6971
return (
7072
<div className="flex min-h-screen flex-col">
7173
<div className="flex items-center justify-center pt-2">
72-
<img className="h-10" src="/assets/images/evolution-logo.png" alt="logo" />
74+
<img className="h-10" src={theme === "dark" ? "https://evolution-api.com/files/evo/evolution-logo-white.svg" : "https://evolution-api.com/files/evo/evolution-logo.svg"} alt="logo" />
7375
</div>
7476
<div className="flex flex-1 items-center justify-center p-8">
7577
<Card className="b-none w-[350px] shadow-none">

src/pages/instance/Chat/index.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
1111
import { useInstance } from "@/contexts/InstanceContext";
1212

1313
import { useFindChats } from "@/lib/queries/chat/findChats";
14+
import { getToken, TOKEN_ID } from "@/lib/queries/token";
1415

1516
import { Chat as ChatType } from "@/types/evolution.types";
1617

@@ -76,7 +77,12 @@ function Chat() {
7677
useEffect(() => {
7778
if (!instance?.name) return;
7879

79-
const serverUrl = "https://integracaov2.icommarketing.com.br";
80+
const serverUrl = getToken(TOKEN_ID.API_URL);
81+
if (!serverUrl) {
82+
console.error("API URL not found in localStorage");
83+
return;
84+
}
85+
8086
const socket = connectSocket(serverUrl);
8187

8288
// Function to update chats from websocket events

src/pages/instance/Chat/messages.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useInstance } from "@/contexts/InstanceContext";
1313
import { useFindChat } from "@/lib/queries/chat/findChat";
1414
import { useFindMessages } from "@/lib/queries/chat/findMessages";
1515
import { useSendMessage, useSendMedia } from "@/lib/queries/chat/sendMessage";
16+
import { getToken, TOKEN_ID } from "@/lib/queries/token";
1617

1718
import { Message } from "@/types/evolution.types";
1819

@@ -429,7 +430,12 @@ function Messages({ textareaRef, handleTextareaChange, textareaHeight, lastMessa
429430
useEffect(() => {
430431
if (!instance?.name || !remoteJid) return;
431432

432-
const serverUrl = "https://icom-socket-gateway.icommarketing.com.br";
433+
const serverUrl = getToken(TOKEN_ID.API_URL);
434+
if (!serverUrl) {
435+
console.error("API URL not found in localStorage");
436+
return;
437+
}
438+
433439
const socket = connectSocket(serverUrl);
434440

435441
// Function to update messages from websocket events

src/pages/instance/EmbedChatMessage/index.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ import { ReplyMessageProvider } from "@/contexts/ReplyingMessage/ReplyingMessage
2121
// import { useWebphone } from "@/contexts/Webphone";
2222

2323
import { api } from "@/lib/queries/api";
24-
25-
// import { TOKEN_ID, getToken } from "@/lib/queries/token";
24+
import { TOKEN_ID, getToken } from "@/lib/queries/token";
2625

2726
import { connectSocket, disconnectSocket } from "@/services/websocket/socket";
2827

@@ -114,9 +113,12 @@ function EmbedChatMessage() {
114113
useEffect(() => {
115114
if (!activeInstance) return;
116115

117-
const serverUrl = "https://icom-socket-gateway.icommarketing.com.br";
116+
const serverUrl = getToken(TOKEN_ID.API_URL);
118117

119-
if (!serverUrl) return;
118+
if (!serverUrl) {
119+
console.error("API URL not found in localStorage");
120+
return;
121+
}
120122

121123
const currentToken = localStorage.getItem("accessToken");
122124

0 commit comments

Comments
 (0)