<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link rel="stylesheet" type="text/css"
href="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.8/semantic.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/1.11.4/css/dataTables.semanticui.min.css">
<link rel="stylesheet" href="{{ .AppBasePath }}/assets/app.css">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://cdn.datatables.net/1.11.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.11.4/js/dataTables.semanticui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fomantic-ui/2.8.8/semantic.min.js"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://unpkg.com/axios@1.1.2/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<title>WhatsApp API {{ .AppVersion }}</title>
</head>
<body>
<div id="splash-screen">
<!-- Clean squircle logo without background wrapper -->
<img src="{{ .AppBasePath }}/assets/gowa.svg" alt="GoWA Logo" class="splash-icon" id="main-logo">
<h2 class="splash-title">WhatsApp API</h2>
<div class="ui active large inline loader splash-spinner"></div>
</div>
<div class="ui container" id="app" style="display: none;">
<div class="main-header">
<h1 class="ui header center aligned">
<div class="title-container">
<img src="{{ .AppBasePath }}/assets/gowa.svg" alt="GoWA Logo">
<span>WhatsApp API</span>
<div class="version-label">
{{ .AppVersion }}
</div>
</div>
</h1>
</div>
<div class="ui success message" v-if="connected_devices != null">
<div class="header">
<i class="check circle icon"></i>
Device Connected Successfully
</div>
<p>
Device ID: <b>[[ connected_devices[0].device ]]</b>
</p>
</div>
<div class="ui horizontal divider">
App
</div>
<div class="ui three column stackable grid cards">
<app-login :connected="connected_devices"></app-login>
<app-logout @reload-devices="handleReloadDevice"></app-logout>
<app-reconnect @reload-devices="handleReloadDevice"></app-reconnect>
<app-login-with-code :connected="connected_devices"></app-login-with-code>
</div>
<div class="ui horizontal divider">
Send
</div>
<div class="ui three column doubling grid cards">
<send-message></send-message>
<send-image></send-image>
<send-file max-file-size="{{ .MaxFileSize }}"></send-file>
<send-video max-video-size="{{ .MaxVideoSize }}"></send-video>
<send-contact></send-contact>
<send-location></send-location>
<send-audio></send-audio>
<send-poll></send-poll>
<send-presence></send-presence>
<send-chat-presence></send-chat-presence>
<send-link></send-link>
</div>
<div class="ui horizontal divider">
Message
</div>
<div class="ui three column doubling grid cards">
<message-delete></message-delete>
<message-revoke></message-revoke>
<message-react></message-react>
<message-update></message-update>
<message-read></message-read>
</div>
<div class="ui horizontal divider">
Group
</div>
<div class="ui three column doubling grid cards">
<group-list :connected="connected_devices"></group-list>
<group-create></group-create>
<group-join-with-link></group-join-with-link>
<group-info-from-link></group-info-from-link>
<group-add-participants></group-add-participants>
<group-set-photo></group-set-photo>
<group-set-name></group-set-name>
<group-set-locked></group-set-locked>
<group-set-announce></group-set-announce>
<group-set-topic></group-set-topic>
<group-get-invite-link></group-get-invite-link>
<group-info></group-info>
</div>
<div class="ui horizontal divider">
Newsletter
</div>
<div class="ui three column doubling grid cards">
<newsletter-list></newsletter-list>
</div>
<div class="ui horizontal divider">
Account
</div>
<div class="ui three column doubling grid cards">
<account-avatar></account-avatar>
<account-change-avatar></account-change-avatar>
<account-change-push-name></account-change-push-name>
<account-user-info></account-user-info>
<account-business-profile></account-business-profile>
<account-privacy></account-privacy>
<account-contact></account-contact>
<account-user-check></account-user-check>
</div>
<div class="ui horizontal divider">
Chat Management
</div>
<div class="ui three column doubling grid cards">
<chat-pin-manager></chat-pin-manager>
<chat-list></chat-list>
<chat-messages></chat-messages>
</div>
</div>
<script>
window.TYPEGROUP = "@g.us";
window.TYPEUSER = "@s.whatsapp.net";
window.TYPENEWSLETTER = "@newsletter";
window.TYPESTATUS = "status@broadcast";
window.showErrorInfo = (message) => {
$('body').toast({
position: 'bottom right',
title: 'Error',
message: message,
showProgress: 'bottom',
classProgress: 'red'
});
}
window.showSuccessInfo = (message) => {
$('body').toast({
position: 'bottom right',
title: 'Success',
message: message,
showProgress: 'bottom',
classProgress: 'green'
});
}
window.http = axios.create({
baseURL: `${window.location.protocol}//${window.location.hostname}${window.location.port ? ':' + window.location.port : ''}{{ .AppBasePath }}`
});
{{ if isEnableBasicAuth .BasicAuthToken }}
window.http.defaults.headers.common['Authorization'] = "{{ .BasicAuthToken }}";
{{ end }}
</script>
<script type="module">
import AppLogin from "{{ .AppBasePath }}/components/AppLogin.js";
import AppLoginWithCode from "{{ .AppBasePath }}/components/AppLoginWithCode.js";
import AppLogout from "{{ .AppBasePath }}/components/AppLogout.js";
import AppReconnect from "{{ .AppBasePath }}/components/AppReconnect.js";
import SendMessage from "{{ .AppBasePath }}/components/SendMessage.js";
import SendImage from "{{ .AppBasePath }}/components/SendImage.js";
import SendFile from "{{ .AppBasePath }}/components/SendFile.js";
import SendVideo from "{{ .AppBasePath }}/components/SendVideo.js";
import SendLink from "{{ .AppBasePath }}/components/SendLink.js";
import SendContact from "{{ .AppBasePath }}/components/SendContact.js";
import SendLocation from "{{ .AppBasePath }}/components/SendLocation.js";
import SendAudio from "{{ .AppBasePath }}/components/SendAudio.js";
import SendPoll from "{{ .AppBasePath }}/components/SendPoll.js";
import SendPresence from "{{ .AppBasePath }}/components/SendPresence.js";
import SendChatPresence from "{{ .AppBasePath }}/components/SendChatPresence.js";
import MessageDelete from "{{ .AppBasePath }}/components/MessageDelete.js";
import MessageUpdate from "{{ .AppBasePath }}/components/MessageUpdate.js";
import MessageReact from "{{ .AppBasePath }}/components/MessageReact.js";
import MessageRevoke from "{{ .AppBasePath }}/components/MessageRevoke.js";
import MessageRead from "{{ .AppBasePath }}/components/MessageRead.js";
import GroupList from "{{ .AppBasePath }}/components/GroupList.js";
import GroupCreate from "{{ .AppBasePath }}/components/GroupCreate.js";
import GroupJoinWithLink from "{{ .AppBasePath }}/components/GroupJoinWithLink.js";
import GroupInfoFromLink from "{{ .AppBasePath }}/components/GroupInfoFromLink.js";
import GroupAddParticipants from "{{ .AppBasePath }}/components/GroupManageParticipants.js";
import GroupSetPhoto from "{{ .AppBasePath }}/components/GroupSetPhoto.js";
import GroupSetName from "{{ .AppBasePath }}/components/GroupSetName.js";
import GroupSetLocked from "{{ .AppBasePath }}/components/GroupSetLocked.js";
import GroupSetAnnounce from "{{ .AppBasePath }}/components/GroupSetAnnounce.js";
import GroupSetTopic from "{{ .AppBasePath }}/components/GroupSetTopic.js";
import GroupGetInviteLink from "{{ .AppBasePath }}/components/GroupGetInviteLink.js";
import GroupInfo from "{{ .AppBasePath }}/components/GroupInfo.js";
import NewsletterList from "{{ .AppBasePath }}/components/NewsletterList.js";
import AccountAvatar from "{{ .AppBasePath }}/components/AccountAvatar.js";
import AccountChangeAvatar from "{{ .AppBasePath }}/components/AccountChangeAvatar.js";
import AccountChangePushName from "{{ .AppBasePath }}/components/AccountChangePushName.js";
import AccountUserInfo from "{{ .AppBasePath }}/components/AccountUserInfo.js";
import AccountPrivacy from "{{ .AppBasePath }}/components/AccountPrivacy.js";
import AccountContact from "{{ .AppBasePath }}/components/AccountContact.js";
import AccountUserCheck from "{{ .AppBasePath }}/components/AccountUserCheck.js";
import AccountBusinessProfile from "{{ .AppBasePath }}/components/AccountBusinessProfile.js";
import ChatPinManager from "{{ .AppBasePath }}/components/ChatPinManager.js";
import ChatList from "{{ .AppBasePath }}/components/ChatList.js";
import ChatMessages from "{{ .AppBasePath }}/components/ChatMessages.js";
const showErrorInfo = (message) => {
$('body').toast({
position: 'bottom right',
title: 'Error',
message: message,
showProgress: 'bottom',
classProgress: 'red'
});
}
const showSuccessInfo = (message) => {
$('body').toast({
position: 'bottom right',
title: 'Success',
message: message,
showProgress: 'bottom',
classProgress: 'green'
});
}
const constructWebSocketURL = () => {
const protocol = location.protocol === 'https:' ? 'wss://' : 'ws://';
const basePath = '{{ .AppBasePath }}';
return `${protocol}${location.host}${basePath}/ws`;
};
Vue.createApp({
components: {
AppLogin, AppLoginWithCode, AppLogout, AppReconnect,
SendMessage, SendImage, SendFile, SendVideo, SendLink, SendContact, SendLocation, SendAudio, SendPoll, SendPresence, SendChatPresence,
MessageDelete, MessageUpdate, MessageReact, MessageRevoke, MessageRead,
GroupList, GroupCreate, GroupJoinWithLink, GroupInfoFromLink, GroupAddParticipants, GroupSetPhoto, GroupSetName, GroupSetLocked, GroupSetAnnounce, GroupSetTopic, GroupGetInviteLink, GroupInfo,
NewsletterList,
AccountAvatar, AccountUserInfo, AccountPrivacy, AccountChangeAvatar, AccountContact, AccountChangePushName, AccountUserCheck, AccountBusinessProfile,
ChatPinManager, ChatList, ChatMessages
},
delimiters: ['[[', ']]'],
data() {
return {
app_ws: null,
connected_devices: null,
}
},
methods: {
handleReloadDevice() {
this.app_ws.send(JSON.stringify({"code": "FETCH_DEVICES"}))
}
},
mounted() {
// Initialize app container as hidden
document.getElementById('app').style.display = 'none';
if (window["WebSocket"]) {
this.app_ws = new WebSocket(constructWebSocketURL());
this.app_ws.onopen = (evt) => {
this.app_ws.send(JSON.stringify({
"code": "FETCH_DEVICES",
"message": "List device"
}));
// Show app container and hide splash screen with a slight delay
setTimeout(() => {
document.getElementById('app').style.display = 'block';
document.getElementById('splash-screen').classList.add('fade-out');
}, 1000);
};
this.app_ws.onerror = (error) => {
console.error('WebSocket error:', error);
showErrorInfo('Connection error occurred. Please refresh the page.');
// Hide splash screen and show error state
setTimeout(() => {
document.getElementById('app').style.display = 'block';
document.getElementById('splash-screen').classList.add('fade-out');
}, 1000);
};
this.app_ws.onmessage = (evt) => {
const message = JSON.parse(evt.data)
switch (message.code) {
case 'LOGIN_SUCCESS':
showSuccessInfo(message.message)
$('#modalLogin').modal('hide');
// fetch devices
this.handleReloadDevice()
break;
case 'LIST_DEVICES':
this.connected_devices = message.result
break;
case 'LOGOUT_COMPLETE':
// Handle successful cleanup after remote logout
showSuccessInfo('✅ ' + message.message)
console.log('[LOGOUT_COMPLETE] Remote logout cleanup completed:', message)
// Optionally refresh the device list
this.handleReloadDevice()
break;
default:
console.log(message)
}
};
} else {
console.error('Your browser does not support WebSockets');
// Hide splash screen if WebSocket is not supported
document.getElementById('splash-screen').classList.add('fade-out');
}
},
}).mount('#app')
</script>
</body>
</html>