Compare commits
No commits in common. "db51e213f1fbf7a1583f77fd46ae72da73254f23" and "9429caacd6a0fe6edd0281b006e802ab195ccdd9" have entirely different histories.
db51e213f1
...
9429caacd6
Binary file not shown.
|
Before Width: | Height: | Size: 504 B |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 27 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 782 B |
Binary file not shown.
|
Before Width: | Height: | Size: 255 B |
|
|
@ -50,8 +50,7 @@ async function va_register(req, res) {
|
|||
// Send data to Salesforce API after successful registration
|
||||
try {
|
||||
const salesforceUrl = `${process.env.SF_DOCTRACKER_API_URL}services/apexrest/docva/api/virtualassistant`;
|
||||
delete created.userDetails._id;
|
||||
created.userDetails._id = created._id; // Include VA's MongoDB ID
|
||||
|
||||
const response = await fetch(salesforceUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ const projectSchema = new Schema({
|
|||
],
|
||||
dedicatedHours: {
|
||||
type: String,
|
||||
default: "0"
|
||||
default: 0
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
|
|
@ -166,7 +166,6 @@ const clientDetailsSchema = new Schema({
|
|||
enum: ["CHECKING", "SAVINGS"],
|
||||
type: String,
|
||||
},
|
||||
|
||||
accountHolderName: {
|
||||
type: String,
|
||||
},
|
||||
|
|
@ -333,7 +332,7 @@ const vaWorkTrackSchema = new Schema({
|
|||
default: 0,
|
||||
},
|
||||
},
|
||||
{ timestamps: true }
|
||||
{ timestamps: true }
|
||||
)
|
||||
|
||||
const passwordResetSchema = new mongoose.Schema({
|
||||
|
|
|
|||
169
src/server.js
169
src/server.js
|
|
@ -13,32 +13,16 @@ import cors from 'cors';
|
|||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
|
||||
import apiRoutes from './routes/index.js'
|
||||
|
||||
|
||||
import { render_reset_form } from "./controllers/passwordReset.controllers.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
const app = express();
|
||||
|
||||
|
||||
const server = new createServer(app);
|
||||
const io = new Server(server);
|
||||
|
||||
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
|
||||
console.log("⚠️ Certificate error:", url);
|
||||
|
||||
// Allow for ngrok only
|
||||
if (url.includes("ngrok")) {
|
||||
event.preventDefault();
|
||||
callback(true); // approve the certificate
|
||||
} else {
|
||||
callback(false); // reject others
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
|
||||
console.log("⚠️ Certificate error:", url);
|
||||
|
||||
|
|
@ -109,18 +93,13 @@ app.get('/varegister/:sf_token?', (req, res) => {
|
|||
});
|
||||
|
||||
app.get('/clientregister/:sf_token?', (req, res) => {
|
||||
const { sf_token } = req.params;
|
||||
try {
|
||||
const decoded = jwt.verify(sf_token, process.env.JWT_SECRET_SF_TOKEN);
|
||||
|
||||
if (decoded) {
|
||||
res.render('va_client_register', { title: "Client Registration" });
|
||||
} else {
|
||||
res.render('not_found', { title: "Client Registration" });
|
||||
}
|
||||
} catch (error) {
|
||||
res.render('not_found', { title: "Client Registration" });
|
||||
}
|
||||
// portalId: RECORDid => 8990928342309
|
||||
// email
|
||||
|
||||
// const { sf_token } = useParams();
|
||||
|
||||
res.render('va_client_register', { title: "Client Registration" });
|
||||
});
|
||||
|
||||
app.get('/auth/password/reset-form', render_reset_form);
|
||||
|
|
@ -159,28 +138,35 @@ app.get('/client/virtual-assistants', async (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
app.get("/live/:projectId/:vaId", async (req, res) => {
|
||||
const { projectId, vaId } = req.params;
|
||||
// app.get('/client/timesheets', async (req, res) => {
|
||||
// try {
|
||||
// const timesheetData = await timesheetService.getClientTimesheets(req.user.id);
|
||||
// res.render('client/dashboard-timesheets', timesheetData);
|
||||
// } catch (error) {
|
||||
// console.error('Timesheets error:', error);
|
||||
// res.status(500).render('client/dashboard-timesheets', { error: 'Failed to load timesheets' });
|
||||
// }
|
||||
// });
|
||||
|
||||
if (!projectId || !vaId) {
|
||||
return res.status(400).send({ "message": "Page not found" });
|
||||
}
|
||||
// app.get('/client/invoices', async (req, res) => {
|
||||
// try {
|
||||
// const invoiceData = await invoiceService.getClientInvoices(req.user.id);
|
||||
// res.render('client/dashboard-invoices', invoiceData);
|
||||
// } catch (error) {
|
||||
// console.error('Invoices error:', error);
|
||||
// res.status(500).render('client/dashboard-invoices', { error: 'Failed to load invoices' });
|
||||
// }
|
||||
// });
|
||||
|
||||
let clientId = null;
|
||||
try {
|
||||
const clientRes = await ProjectModel.findById(projectId);
|
||||
if (clientRes) {
|
||||
clientId = clientRes.clientId.toString();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error fetching client for project:", err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clientId) return res.status(400).send({ "message": "Page not found" });
|
||||
|
||||
res.render("va_live_tracker", { title: "VA Live Tracker", projectId, vaId, clientId })
|
||||
})
|
||||
// app.get('/client/referrals', async (req, res) => {
|
||||
// try {
|
||||
// const referralData = await referralService.getClientReferrals(req.user.id);
|
||||
// res.render('client/dashboard-referrals', referralData);
|
||||
// } catch (error) {
|
||||
// console.error('Referrals error:', error);
|
||||
// res.status(500).render('client/dashboard-referrals', { error: 'Failed to load referrals' });
|
||||
// }
|
||||
// });
|
||||
|
||||
app.get("/live/:projectId/:vaId", async (req, res) => {
|
||||
const { projectId, vaId } = req.params;
|
||||
|
|
@ -207,17 +193,16 @@ app.get("/live/:projectId/:vaId", async (req, res) => {
|
|||
|
||||
// Handling Socket
|
||||
import { VAModel, ProjectModel, ClientModel } from './models/vaModel.js';
|
||||
import { ObjectId } from 'mongodb/lib/bson.js';
|
||||
|
||||
|
||||
const vaSocketRespectToClient = new Map();
|
||||
|
||||
// Handling Socket
|
||||
io.use(async (socket, next) => {
|
||||
try {
|
||||
const token = socket.handshake.auth?.token;
|
||||
const projectId = socket.handshake.auth?.projectId;
|
||||
const userType = socket.handshake.auth?.userType;
|
||||
const vaId = socket.handshake.auth?.vaId;
|
||||
|
||||
|
||||
console.log("🔐 Received token:", token);
|
||||
|
||||
|
|
@ -231,7 +216,7 @@ io.use(async (socket, next) => {
|
|||
return next(new Error("Invalid token payload"));
|
||||
}
|
||||
|
||||
/* ---------------------- 1️⃣ Check if VA ---------------------- */
|
||||
/* ---------------------- 1️⃣ Check if VA ---------------------- */
|
||||
let vaUser = null;
|
||||
let clientData = null;
|
||||
|
||||
|
|
@ -256,13 +241,13 @@ io.use(async (socket, next) => {
|
|||
|
||||
console.log(a, b, c, "vaProjClientId vs clientData.clientId");
|
||||
|
||||
vaSocketRespectToClient.set(`${vaProjClientId.toString()}-${vaUser._id.toString()}-${projectId.toString()}-va`, socket.id)
|
||||
vaSocketRespectToClient.set(`${vaProjClientId.toString()}-${vaUser._id.toString()}`, socket.id)
|
||||
|
||||
console.log("✅ Authenticated VA:", vaUser.userDetails.email);
|
||||
return next();
|
||||
}
|
||||
|
||||
/* ---------------------- 2️⃣ Check if Client ---------------------- */
|
||||
/* ---------------------- 2️⃣ Check if Client ---------------------- */
|
||||
// const clientUser = await ClientModel.findOne({ "userDetails.email": decoded.email });
|
||||
|
||||
// if (clientUser) {
|
||||
|
|
@ -283,7 +268,6 @@ io.use(async (socket, next) => {
|
|||
|
||||
// Get all VA IDs assigned to this client
|
||||
socket.data.allowedVAs = clientData.vaAssigned.map((va) => va.toString());
|
||||
vaSocketRespectToClient.set(`${vaProjClientId.toString()}-${vaId.toString()}-${projectId.toString()}-client`, socket.id)
|
||||
|
||||
// console.log("✅ Authenticated Client:", clientUser.userDetails.email);
|
||||
return next();
|
||||
|
|
@ -296,6 +280,8 @@ io.use(async (socket, next) => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
console.log("User connected:", socket.id);
|
||||
|
||||
|
|
@ -330,7 +316,7 @@ io.on("connection", (socket) => {
|
|||
});
|
||||
|
||||
// When VA sends live image
|
||||
socket.on("sendImage", async ({ token, image, title, projectId }) => {
|
||||
socket.on("sendImage", async ({ token, image, title }) => {
|
||||
try {
|
||||
// Verify token
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET_ACCESS_TOKEN);
|
||||
|
|
@ -343,42 +329,30 @@ io.on("connection", (socket) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const project = await ProjectModel.findById(projectId);
|
||||
if (!project) {
|
||||
console.log("❌ Invalid Project ID");
|
||||
return;
|
||||
}
|
||||
|
||||
const clientId = project.clientId.toString();
|
||||
const vaId = vaUser._id.toString();
|
||||
const clientVaUniqueId = `${clientId}-${vaId}-${projectId}-client`;
|
||||
const socketId = vaSocketRespectToClient.get(clientVaUniqueId);
|
||||
|
||||
console.log("🟢 Received image from VA:", vaId);
|
||||
|
||||
// Broadcast image only to allowed clients
|
||||
// for (let [_, clientSocket] of io.sockets.sockets) {
|
||||
// if (
|
||||
// clientSocket.data.role === "client" &&
|
||||
// clientSocket.data.allowedVAs?.includes(vaId)
|
||||
// ) {
|
||||
// clientSocket.emit("receiveImage", image, title);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Can be like clientId-projectId-vaId to uniquely identify
|
||||
socket.to(socketId).emit("receiveImage", image, title);
|
||||
for (let [_, clientSocket] of io.sockets.sockets) {
|
||||
if (
|
||||
clientSocket.data.role === "client" &&
|
||||
clientSocket.data.allowedVAs?.includes(vaId)
|
||||
) {
|
||||
clientSocket.emit("receiveImage", image, title);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("❌ Token verification failed:", err.message);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("selectApp", ({ appTitle, clientId, vaId, projectId }) => {
|
||||
socket.on("selectApp", ({ appTitle, clientId }) => {
|
||||
console.log(`VA selected app: ${appTitle}`);
|
||||
|
||||
console.log(vaSocketRespectToClient.get(`${clientId}-${vaId}-${projectId}-va`), "vaSocketRespectToClient[clientId]")
|
||||
const sssrrrr = vaSocketRespectToClient.get(`${clientId}-${socket.data.vaId}`);
|
||||
console.log(vaSocketRespectToClient.get(`${clientId}-${socket.data.vaId}`), sssrrrr, "vaSocketRespectToClient[clientId]")
|
||||
// You can forward this info to the respective Electron client
|
||||
socket.to(vaSocketRespectToClient.get(`${clientId}-${vaId}-${projectId}-va`)).emit("appToCapture", { appTitle });
|
||||
socket.to(vaSocketRespectToClient.get(`${clientId}-${socket.data.vaId}`)).emit("appToCapture", { appTitle });
|
||||
});
|
||||
|
||||
socket.on("getVisibleApps", async ({ token, apps }) => {
|
||||
|
|
@ -403,7 +377,7 @@ io.on("connection", (socket) => {
|
|||
clientSocket.data.role === "client" &&
|
||||
clientSocket.data.allowedVAs?.includes(vaId)
|
||||
) {
|
||||
clientSocket.emit("receiveVisibleApps", { apps, vaId });
|
||||
clientSocket.emit("receiveVisibleApps", apps);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
@ -417,10 +391,39 @@ io.on("connection", (socket) => {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// io.on('connection', (socket) => {
|
||||
|
||||
// socket.on("sendImage", (base64String) => {
|
||||
// io.emit("receiveImage", base64String);
|
||||
// });
|
||||
|
||||
|
||||
// socket.on('disconnect', () => {
|
||||
// console.log('a user Disconnected');
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
// Express App Listening
|
||||
// app.listen(PORT, () => {
|
||||
// mongoose
|
||||
// .connect(
|
||||
// process.env.MONGO_URI,
|
||||
// )
|
||||
// .then(() => console.log("mongodb connected"))
|
||||
// .catch((err) => {
|
||||
// console.log(err.message);
|
||||
// process.exit(1);
|
||||
// });
|
||||
// console.log(`Express started on http://localhost:${PORT}`);
|
||||
// });
|
||||
|
||||
app.use((req, res) => {
|
||||
res.status(404).render("not_found", {
|
||||
title: "404 - Page Not Found"
|
||||
});
|
||||
res.status(404).render("not_found", {
|
||||
title: "404 - Page Not Found"
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(PORT, () => {
|
||||
|
|
|
|||
|
|
@ -29,35 +29,4 @@ async function testPaths() {
|
|||
}
|
||||
}
|
||||
|
||||
testPaths();// testVpnApi.js
|
||||
import axios from "axios";
|
||||
|
||||
const apiUrl = "http://165.140.240.203:3000/api";
|
||||
const apiKey = "hellovpn123";
|
||||
|
||||
const possiblePaths = [
|
||||
"/", "/v1", "/servers", "/status", "/vpn", "/health", "/ping",
|
||||
"/nodes", "/list", "/connect", "/config", "/create", "/createConfig",
|
||||
"/check", "/organizations", "/users"
|
||||
];
|
||||
|
||||
async function testPaths() {
|
||||
for (const path of possiblePaths) {
|
||||
try {
|
||||
const res = await axios.get(`${apiUrl}${path}`, {
|
||||
headers: { "x-api-key": apiKey },
|
||||
timeout: 3000
|
||||
});
|
||||
console.log(`✅ ${path} → ${res.status} ${res.statusText}`);
|
||||
console.log("Response:", res.data);
|
||||
} catch (err) {
|
||||
if (err.response) {
|
||||
console.log(`❌ ${path} → ${err.response.status}`);
|
||||
} else {
|
||||
console.log(`⚠️ ${path} → No response`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testPaths();
|
||||
testPaths();
|
||||
Binary file not shown.
|
|
@ -148,7 +148,8 @@
|
|||
<th>Status</th>
|
||||
<th>Virtual Assistant</th>
|
||||
<th>Projects Assigned</th>
|
||||
<th>Worked Time</th>
|
||||
<th>Working from</th>
|
||||
<th>Total Worked</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -221,7 +222,7 @@
|
|||
|
||||
// Format time function
|
||||
function formatTime(seconds) {
|
||||
if (!seconds) return 'Not working';
|
||||
if (!seconds) return '';
|
||||
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
|
|
@ -230,6 +231,8 @@
|
|||
return `${hours}h ${minutes}m`;
|
||||
} else if (minutes > 0) {
|
||||
return `${minutes}m`;
|
||||
} else if (seconds > 0) {
|
||||
return `${seconds}s`;
|
||||
} else {
|
||||
return 'Just started';
|
||||
}
|
||||
|
|
@ -240,6 +243,7 @@
|
|||
const statusClass = va.isCurrentlyActive ? 'active' : 'inactive';
|
||||
const statusText = va.isCurrentlyActive ? 'Active' : 'Inactive';
|
||||
const workedTime = formatTime(va.currentSessionDuration);
|
||||
const totalWorkedTime = formatTime(va.totalWorkedSeconds);
|
||||
const projectsAssigned = va.projectsAssigned || 0;
|
||||
const viewLink = va.isCurrentlyActive ? `<a href="/live/${va.lastProjectId}/${va.id}" class="view-link" data-va-id="${va.id}" target="_blank">
|
||||
<i class="fas fa-eye"></i>
|
||||
|
|
@ -247,7 +251,7 @@
|
|||
</a>` : '';
|
||||
|
||||
return `
|
||||
<tr>
|
||||
<tr data-vaid="${va.id}">
|
||||
<td>
|
||||
<div class="status-indicator">
|
||||
<div class="status-dot ${statusClass}"></div>
|
||||
|
|
@ -256,7 +260,7 @@
|
|||
</td>
|
||||
<td>
|
||||
<div class="va-info">
|
||||
<div class="va-name">${va.firstName} ${va.lastName}</div>
|
||||
<div class="va-name">${va.name}</div>
|
||||
<div class="va-email">${va.email || 'N/A'}</div>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -266,6 +270,9 @@
|
|||
<td>
|
||||
<span class="worked-time">${workedTime}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="worked-time">${totalWorkedTime}</span>
|
||||
</td>
|
||||
<td>
|
||||
${viewLink}
|
||||
</td>
|
||||
|
|
@ -302,16 +309,35 @@
|
|||
vaTableBody.innerHTML = allVAs.map(va => createVATableRow(va)).join('');
|
||||
vaTableBody.style.display = '';
|
||||
vaEmptyState.style.display = 'none';
|
||||
|
||||
// Add event listeners to view links
|
||||
document.querySelectorAll('.view-link').forEach(link => {
|
||||
link.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const vaId = this.getAttribute('data-va-id');
|
||||
// You can update this link as needed
|
||||
window.location.href = `/client/virtual-assistants/${vaId}`;
|
||||
|
||||
// Add event listeners to table rows
|
||||
document.querySelectorAll('tr[data-vaid]').forEach(row => {
|
||||
row.addEventListener('click', async function(e) {
|
||||
// Don't trigger if click is on view link
|
||||
if (e.target.closest('.view-link')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const vaId = this.getAttribute('data-vaid');
|
||||
const vaData = allVAs.find(va => va.id === vaId);
|
||||
|
||||
if (vaData) {
|
||||
// Show loading state
|
||||
const originalContent = this.innerHTML;
|
||||
this.innerHTML = '<td colspan="6" style="text-align: center;"><i class="fas fa-spinner fa-spin"></i> Loading...</td>';
|
||||
|
||||
// Fetch additional VA details from /test API
|
||||
const projectData = await fetchVADetails(vaId);
|
||||
|
||||
// Restore original content
|
||||
this.innerHTML = originalContent;
|
||||
|
||||
// Show popup with VA details
|
||||
showVAPopup(projectData);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
vaTableBody.innerHTML = '';
|
||||
vaTableBody.style.display = 'none';
|
||||
|
|
@ -350,7 +376,128 @@
|
|||
|
||||
// Optional: Auto-refresh data every 30 seconds
|
||||
setInterval(loadDashboardData, 30000);
|
||||
|
||||
|
||||
function createPopup(vaData) {
|
||||
// Extract project details from the API response
|
||||
// The API response is the project array, so use it directly
|
||||
const projectDetails = Array.isArray(vaData) ? vaData : (vaData.projects || []);
|
||||
|
||||
// Create project details HTML
|
||||
const projectsHTML = projectDetails.length > 0
|
||||
? projectDetails.map(project => `
|
||||
<div class="project-item">
|
||||
<div class="project-header">
|
||||
<span class="project-name">${project.projectName || 'Unknown Project'}</span>
|
||||
<span class="project-time">${project.totalTime || '00:00:00'}</span>
|
||||
</div>
|
||||
<div class="project-id">ID: ${project.projectId || 'N/A'}</div>
|
||||
</div>
|
||||
`).join('')
|
||||
: '<div class="no-projects">No project data available</div>';
|
||||
|
||||
return `
|
||||
<div class="popup-overlay" id="vaPopup">
|
||||
<div class="popup-content">
|
||||
<div class="popup-header">
|
||||
<h3>Project Work Details</h3>
|
||||
<button class="popup-close" id="closePopup">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="popup-body">
|
||||
<!-- Project Count -->
|
||||
<div class="project-summary">
|
||||
<div class="total-projects">
|
||||
<i class="fas fa-folder-open"></i>
|
||||
<span>Total Projects: ${projectDetails.length}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Project Details List -->
|
||||
<div class="projects-list">
|
||||
${projectsHTML}
|
||||
</div>
|
||||
</div>
|
||||
<div class="popup-footer">
|
||||
<button class="btn btn-secondary" id="closePopupBtn">
|
||||
<i class="fas fa-times"></i> Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Show popup with VA details
|
||||
function showVAPopup(projectData) {
|
||||
console.log('Project Data:', projectData);
|
||||
|
||||
// Remove existing popup if any
|
||||
const existingPopup = document.getElementById('vaPopup');
|
||||
if (existingPopup) {
|
||||
existingPopup.remove();
|
||||
}
|
||||
|
||||
// Create and show new popup with only project data
|
||||
const popupHTML = createPopup(projectData);
|
||||
document.body.insertAdjacentHTML('beforeend', popupHTML);
|
||||
|
||||
// Add event listeners for closing popup
|
||||
document.getElementById('closePopup').addEventListener('click', closePopup);
|
||||
document.getElementById('closePopupBtn').addEventListener('click', closePopup);
|
||||
|
||||
// Close popup when clicking outside
|
||||
document.getElementById('vaPopup').addEventListener('click', function(e) {
|
||||
if (e.target === this) {
|
||||
closePopup();
|
||||
}
|
||||
});
|
||||
|
||||
// Close popup with Escape key
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
closePopup();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch VA details for popup - now returns only project data
|
||||
async function fetchVADetails(vaId) {
|
||||
try {
|
||||
const response = await fetchWithAuth(`${API_BASE}/dashboard/va-report`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ vaId: vaId }),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response) return;
|
||||
|
||||
const result = await response.json();
|
||||
console.log('API Response:', result);
|
||||
|
||||
if (result.success) {
|
||||
// Return the projects array directly
|
||||
return result.projects || [];
|
||||
} else {
|
||||
console.error('Failed to fetch project details:', result.message);
|
||||
return [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching project details:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Close popup function
|
||||
function closePopup() {
|
||||
const popup = document.getElementById('vaPopup');
|
||||
if (popup) {
|
||||
popup.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -211,7 +211,6 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="logo">
|
||||
<img src="/public/images/logo-white-vertical.svg" alt="DocVA Logo" />
|
||||
</div>
|
||||
|
|
@ -247,7 +246,7 @@
|
|||
|
||||
setTheme(getSystemTheme());
|
||||
checkAuthentication();
|
||||
|
||||
|
||||
document.querySelector("form").addEventListener("submit", async (e) => {
|
||||
e.preventDefault(); // prevent page reload
|
||||
|
||||
|
|
@ -292,11 +291,11 @@
|
|||
alert(err.message || "Something went wrong while logging in");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Check if user is already authenticated and redirect to dashboard
|
||||
async function checkAuthentication() {
|
||||
const authToken = localStorage.getItem("knoptpq");
|
||||
|
||||
|
||||
if (!authToken) {
|
||||
return false; // No token found
|
||||
} else {
|
||||
|
|
@ -333,4 +332,6 @@
|
|||
// }
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -192,4 +192,4 @@
|
|||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -21,7 +21,6 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* SIDEBAR */
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
background: #181818;
|
||||
|
|
@ -82,6 +81,7 @@
|
|||
#liveImage {
|
||||
width: 90%;
|
||||
max-width: 900px;
|
||||
border: 2px solid #555;
|
||||
border-radius: 10px;
|
||||
border: 2px solid #444;
|
||||
object-fit: contain;
|
||||
|
|
@ -185,54 +185,49 @@
|
|||
</div>
|
||||
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script>
|
||||
const vaId = "<%= vaId %>";
|
||||
const clientId = "<%= clientId %>";
|
||||
const projectId = "<%= projectId %>";
|
||||
const token = localStorage.getItem("knoptpq");
|
||||
<script>
|
||||
const vaId = "<%= vaId %>";
|
||||
const clientId = "<%= clientId %>";
|
||||
const token = localStorage.getItem("knoptpq");
|
||||
const socket = io({
|
||||
auth: {
|
||||
token: token,
|
||||
userType: "client",
|
||||
projectId: "<%= projectId %>"
|
||||
},
|
||||
});
|
||||
|
||||
const socket = io({
|
||||
auth: {
|
||||
token: token,
|
||||
userType: "client",
|
||||
projectId: projectId,
|
||||
vaId: vaId
|
||||
},
|
||||
});
|
||||
socket.emit("register", {
|
||||
role: "client",
|
||||
id: vaId,
|
||||
projectId: "<%= projectId %>",
|
||||
clientId: clientId
|
||||
});
|
||||
|
||||
socket.emit("register", {
|
||||
role: "client",
|
||||
id: vaId,
|
||||
projectId: "<%= projectId %>",
|
||||
clientId: clientId
|
||||
});
|
||||
const sidebar = document.getElementById("sidebar");
|
||||
const toggleBtn = document.getElementById("toggleBtn");
|
||||
const overlay = document.getElementById("overlay");
|
||||
|
||||
const sidebar = document.getElementById("sidebar");
|
||||
const toggleBtn = document.getElementById("toggleBtn");
|
||||
const overlay = document.getElementById("overlay");
|
||||
const appsList = document.getElementById("appsList");
|
||||
const liveImage = document.getElementById("liveImage");
|
||||
const selectedAppTitle = document.getElementById("selectedAppTitle");
|
||||
const placeholder = document.getElementById("placeholder");
|
||||
|
||||
const appsList = document.getElementById("appsList");
|
||||
const liveImage = document.getElementById("liveImage");
|
||||
const selectedAppTitle = document.getElementById("selectedAppTitle");
|
||||
const placeholder = document.getElementById("placeholder");
|
||||
let currentApp = null;
|
||||
|
||||
let currentApp = null;
|
||||
/* MOBILE SIDEBAR TOGGLE */
|
||||
toggleBtn.onclick = () => {
|
||||
sidebar.classList.add("open");
|
||||
overlay.classList.add("show");
|
||||
};
|
||||
|
||||
/* MOBILE SIDEBAR TOGGLE */
|
||||
toggleBtn.onclick = () => {
|
||||
sidebar.classList.add("open");
|
||||
overlay.classList.add("show");
|
||||
};
|
||||
|
||||
overlay.onclick = () => {
|
||||
overlay.onclick = () => {
|
||||
sidebar.classList.remove("open");
|
||||
overlay.classList.remove("show");
|
||||
};
|
||||
|
||||
/* Receive visible apps */
|
||||
socket.on("receiveVisibleApps", ({apps, vaId: senderVaId}) => {
|
||||
if (vaId !== senderVaId) return;
|
||||
|
||||
socket.on("receiveVisibleApps", (apps) => {
|
||||
appsList.innerHTML = "";
|
||||
|
||||
if (!apps?.length) {
|
||||
|
|
@ -255,7 +250,7 @@
|
|||
placeholder.style.display = "none";
|
||||
liveImage.style.display = "none";
|
||||
|
||||
socket.emit("selectApp", { appTitle: app.name, clientId, vaId, projectId });
|
||||
socket.emit("selectApp", { appTitle: app.name, clientId, vaId });
|
||||
|
||||
// Close sidebar on mobile
|
||||
sidebar.classList.remove("open");
|
||||
|
|
@ -281,7 +276,7 @@
|
|||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Reference in New Issue