12-08/2025 - va regiseter client register forget password layout fixed

This commit is contained in:
JaiPandey425 2025-12-18 16:20:02 +05:30
parent 5d952b04cf
commit 604afe9b72
14 changed files with 759 additions and 639 deletions

View File

@ -55,26 +55,50 @@ async function render_reset_form(req, res) {
try {
const { token, userType } = req.query;
// ❌ Missing params
if (!token || !userType) {
return res.render('auth/reset-password-error', { error: 'Reset token or user type is missing', userType: userType || 'va' });
return res.render('auth/reset-password-error', {
title: "Reset Password",
layout: 'layouts/auth',
error: 'Reset token or user type is missing',
userType: userType || 'va'
});
}
// Validate token
// ✅ Validate token
const validation = await passwordResetService.validateResetToken(token, userType);
if (!validation.valid) {
return res.render('auth/reset-password-error', { error: validation.message, userType: userType || 'va' });
return res.render('auth/reset-password-error', {
title: "Reset Password",
layout: 'layouts/auth',
error: validation.message,
userType: userType || 'va'
});
}
// Render reset form with token
res.render('auth/reset-password-form', { token, userType, error: null });
// ✅ Render reset password form
return res.render('auth/reset-password-form', {
title: "Reset Password",
layout: 'layouts/auth',
token,
userType,
error: null
});
} catch (error) {
logger.error(`PasswordResetController - Render form error: ${error.message}`);
res.render('auth/reset-password-error', { error: 'Failed to load reset form' });
return res.render('auth/reset-password-error', {
title: "Reset Password",
layout: 'layouts/auth',
error: 'Failed to load reset form',
userType: 'va'
});
}
}
// Process password reset form submission (shared for both VA and Client)
async function process_reset(req, res) {
try {

View File

@ -65,7 +65,9 @@ app.use('/api', apiRoutes);
app.get("/download-tracker", (req, res) => {
res.render("download_tracker", {
version: "3.2.1"
title: 'Download tracker',
version: "3.2.1",
layout: 'layouts/main'
});
});
@ -82,39 +84,61 @@ app.get("/download-file", (req, res) => {
app.get('/varegister/:sf_token?', (req, res) => {
const { sf_token } = req.params;
// No token → invalid request
if (!sf_token) {
return res.status(404).render('not_found', {
title: 'Page Not Found',
layout: 'layouts/error'
});
}
try {
const decoded = jwt.verify(sf_token, process.env.JWT_SECRET_SF_TOKEN);
if (decoded) {
const email = decoded.email;
res.render('va_register', { title: "VA Registration", email });
} else {
res.render('not_found', { title: "VA Registration" });
}
} catch (error) {
res.render('not_found', { title: "VA Registration" });
}
// if(verified) {
// res.render('va_register', { title: "VA Registration" });
// } else {
// res.render('not_founf', { title: "VA Registration" });
// }
// Token valid
return res.render('va_register', {
title: 'VA Registration',
email: decoded.email,
layout: 'layouts/varegisterlayout'
});
} catch (error) {
// Invalid / expired token
return res.status(401).render('not_found', {
title: 'Invalid or Expired Link',
layout: 'layouts/error'
});
}
});
app.get('/clientregister/:sf_token?', (req, res) => {
const { sf_token } = req.params;
// No token → invalid request
if (!sf_token) {
return res.status(404).render('not_found', {
title: 'Page Not Found',
layout: 'layouts/error'
});
}
try {
const decoded = jwt.verify(sf_token, process.env.JWT_SECRET_SF_TOKEN);
if (decoded) {
const email = decoded.email;
res.render('va_client_register', { title: "Client Registration", email });
} else {
res.render('not_found', { title: "Client Registration" });
}
// Token valid
return res.render('va_client_register', {
title: 'Client Registration',
email: decoded.email,
layout: 'layouts/vaclientlayout'
});
} catch (error) {
res.render('not_found', { title: "Client Registration" });
// Invalid / expired token
return res.status(401).render('not_found', {
title: 'Invalid or Expired Link',
layout: 'layouts/error'
});
}
});
@ -135,7 +159,11 @@ app.get("/client/login", (req, res) => {
});
app.get("/client/forgot-password", (req, res) => {
res.render("forgot_password")
res.render("forgot_password", {
title: "Forgot Password",
layout: "layouts/forgotpasswordlayout"
});
})
// Client Dashboard Routes with new file names
@ -208,7 +236,7 @@ app.get("/live/:projectId/:vaId", async (req, res) => {
const { projectId, vaId } = req.params;
if (!projectId || !vaId) {
return res.status(400).send({ "message": "Page not found" });
return res.status(400).render("not_found", { title: "Page not found" });
}
let clientId = null;
@ -219,36 +247,45 @@ app.get("/live/:projectId/:vaId", async (req, res) => {
}
} catch (err) {
console.error("Error fetching client for project:", err.message);
return;
return res.status(500).render("not_found", { title: "Server Error" });
}
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("/live/:projectId/:vaId", async (req, res) => {
const { projectId, vaId } = req.params;
if (!projectId || !vaId) {
return res.status(400).send({ "message": "Page not found" });
if (!clientId) {
return res.status(400).render("not_found", { title: "Page not found" });
}
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;
}
res.render("va_live_tracker", {
title: "VA Live Tracker",
projectId,
vaId,
clientId,
layout: "layouts/valivetrackerlayout" // ✅ ADD THIS
});
});
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("/live/:projectId/:vaId", async (req, res) => {
// const { projectId, vaId } = req.params;
// if (!projectId || !vaId) {
// return res.status(400).send({ "message": "Page not found" });
// }
// 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 })
// })
// Handling Socket
import { VAModel, ProjectModel, ClientModel } from './models/vaModel.js';
@ -512,10 +549,12 @@ io.on("connection", (socket) => {
app.use((req, res) => {
res.status(404).render("not_found", {
layout: "layouts/error",
title: "404 - Page Not Found"
});
});
server.listen(PORT, () => {
mongoose
.connect(

View File

@ -1,121 +1,4 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DocVA | Reset Password</title>
<style>
:root[data-theme="light"] {
--bg: #ffffff;
--text: #111827;
--card-bg: #ffffff;
--border: #e5e7eb;
--btn-bg: #0a0a8f;
--btn-text: #ffffff;
}
:root[data-theme="dark"] {
--bg: #121212;
--text: #f9fafb;
--card-bg: #1e1e1e;
--border: #334155;
--btn-bg: #3b82f6;
--btn-text: #ffffff;
}
body {
background-color: var(--bg);
color: var(--text);
font-family: "Inter", sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
transition: background-color 0.3s, color 0.3s;
}
.container {
text-align: center;
width: 100%;
max-width: 380px;
}
.logo {
width: 170px;
margin-bottom: 1.5rem;
transition: opacity 0.3s;
}
.card {
background: var(--card-bg);
border: 1px solid var(--border);
border-radius: 12px;
padding: 2rem;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
transition: background 0.3s, border-color 0.3s;
}
h2 {
font-size: 1rem;
font-weight: 500;
margin-bottom: 1rem;
}
input {
box-sizing: border-box;
width: 100%;
padding: 0.8rem;
margin-bottom: 1.2rem;
border-radius: 8px;
border: 1px solid var(--border);
background: #fff;
color: #111;
font-size: 0.9rem;
transition: border 0.3s;
}
:root[data-theme="dark"] input {
background: #0f172a;
color: #fff;
border: 1px solid #475569;
}
button {
width: 100%;
background: var(--btn-bg);
color: var(--btn-text);
border: none;
padding: 0.8rem;
border-radius: 8px;
font-size: 0.95rem;
cursor: pointer;
transition: opacity 0.3s;
}
button:hover {
opacity: 0.9;
}
a {
display: block;
margin-top: 1rem;
font-size: 0.85rem;
color: var(--text);
text-decoration: none;
opacity: 0.8;
}
a:hover {
opacity: 1;
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h2>DocTracker</h2>
<form class="card">
@ -200,6 +83,3 @@
});
});
</script>
</body>
</html>

View File

@ -12,6 +12,7 @@
<body>
<%- body %>
</body>
</html>

103
views/layouts/error.ejs Normal file
View File

@ -0,0 +1,103 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>404 - Page Not Found</title>
<style>
:root {
--bg: #ffffff;
--text: #222222;
--subtext: #555555;
--button-bg: #6c63ff;
--button-text: #ffffff;
}
/* Dark mode automatic */
@media (prefers-color-scheme: dark) {
:root {
--bg: #0f0f0f;
--text: #ffffff;
--subtext: #bbbbbb;
--button-bg: #6c63ff;
--button-text: #ffffff;
}
}
body {
margin: 0;
padding: 0;
background: var(--bg);
color: var(--text);
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
font-family: Inter, system-ui, sans-serif;
text-align: center;
padding: 20px;
}
.container {
max-width: 420px;
width: 100%;
}
h1 {
font-size: 7rem;
font-weight: 800;
margin: 0;
line-height: 1;
}
p {
font-size: 1.1rem;
margin-top: 10px;
color: var(--subtext);
}
.btn {
margin-top: 30px;
padding: 14px 26px;
background: var(--button-bg);
color: var(--button-text);
text-decoration: none;
font-weight: 600;
border-radius: 12px;
display: inline-block;
transition: 0.2s;
}
.btn:hover {
opacity: 0.85;
transform: translateY(-2px);
}
img {
width: 150px;
margin-bottom: 25px;
}
/* Responsive */
@media (max-width: 480px) {
h1 {
font-size: 4.5rem;
}
img {
width: 120px;
}
}
</style>
</head>
<body>
<%- body %>
</body>
</html>

View File

@ -0,0 +1,122 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DocVA | Reset Password</title>
<style>
:root[data-theme="light"] {
--bg: #ffffff;
--text: #111827;
--card-bg: #ffffff;
--border: #e5e7eb;
--btn-bg: #0a0a8f;
--btn-text: #ffffff;
}
:root[data-theme="dark"] {
--bg: #121212;
--text: #f9fafb;
--card-bg: #1e1e1e;
--border: #334155;
--btn-bg: #3b82f6;
--btn-text: #ffffff;
}
body {
background-color: var(--bg);
color: var(--text);
font-family: "Inter", sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
transition: background-color 0.3s, color 0.3s;
}
.container {
text-align: center;
width: 100%;
max-width: 380px;
}
.logo {
width: 170px;
margin-bottom: 1.5rem;
transition: opacity 0.3s;
}
.card {
background: var(--card-bg);
border: 1px solid var(--border);
border-radius: 12px;
padding: 2rem;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
transition: background 0.3s, border-color 0.3s;
}
h2 {
font-size: 1rem;
font-weight: 500;
margin-bottom: 1rem;
}
input {
box-sizing: border-box;
width: 100%;
padding: 0.8rem;
margin-bottom: 1.2rem;
border-radius: 8px;
border: 1px solid var(--border);
background: #fff;
color: #111;
font-size: 0.9rem;
transition: border 0.3s;
}
:root[data-theme="dark"] input {
background: #0f172a;
color: #fff;
border: 1px solid #475569;
}
button {
width: 100%;
background: var(--btn-bg);
color: var(--btn-text);
border: none;
padding: 0.8rem;
border-radius: 8px;
font-size: 0.95rem;
cursor: pointer;
transition: opacity 0.3s;
}
button:hover {
opacity: 0.9;
}
a {
display: block;
margin-top: 1rem;
font-size: 0.85rem;
color: var(--text);
text-decoration: none;
opacity: 0.8;
}
a:hover {
opacity: 1;
text-decoration: underline;
}
</style>
</head>
<body>
<%- body %>
</body>
</html>

View File

@ -13,5 +13,7 @@
</head>
<body>
<%- body %>
<script src="/public/js/common/theme.js"></script>
</body>
</html>

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Client Registration</title>
<link href="/public/css/va-register.css" rel="stylesheet">
</head>
<body>
<%- body %>
</body>
</html>

View File

@ -0,0 +1,169 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Live Screen Feed</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
height: 100vh;
display: flex;
background: #0f0f0f;
color: white;
font-family: "Inter", sans-serif;
overflow: hidden;
}
/* SIDEBAR */
.sidebar {
width: 280px;
background: #181818;
border-right: 1px solid #2b2b2b;
padding: 15px;
overflow-y: auto;
transition: transform 0.35s ease;
z-index: 50;
}
.sidebar h3 {
margin-bottom: 15px;
font-size: 18px;
font-weight: 600;
}
.app {
background: #252525;
border: 1px solid #333;
padding: 12px;
margin-bottom: 10px;
border-radius: 8px;
cursor: pointer;
transition: 0.3s ease;
}
.app:hover {
background: #333;
transform: translateX(3px);
}
.app.active {
background: #6c63ff;
border-color: #6c63ff;
color: white;
box-shadow: 0 0 10px rgba(108, 99, 255, 0.5);
}
/* MAIN CONTENT */
.content {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
padding: 20px;
overflow: hidden;
}
#selectedAppTitle {
font-size: 20px;
margin-bottom: 15px;
font-weight: 500;
text-align: center;
}
#liveImage {
width: 90%;
max-width: 900px;
border-radius: 10px;
border: 2px solid #444;
object-fit: contain;
background: black;
display: none;
}
.placeholder {
font-size: 16px;
opacity: 0.8;
color: #bbb;
margin-top: 20px;
}
/* MOBILE RESPONSIVE */
.mobile-toggle {
display: none;
position: fixed;
top: 15px;
left: 15px;
background: #6C63FF;
padding: 14px;
border-radius: 8px;
z-index: 9999;
/* VERY HIGH: always visible */
cursor: pointer;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
.mobile-toggle span {
display: block;
width: 26px;
height: 3px;
background: #fff;
margin: 5px 0;
border-radius: 2px;
}
/* Sidebar Hidden on Mobile */
@media (max-width: 780px) {
body {
flex-direction: column;
}
.sidebar {
position: fixed;
left: 0;
top: 0;
height: 100%;
transform: translateX(-100%);
}
.sidebar.open {
transform: translateX(0%);
}
.mobile-toggle {
display: block !important;
}
.content {
padding-top: 60px;
}
/* Dark overlay when sidebar opens */
#overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
display: none;
z-index: 40;
}
#overlay.show {
display: block;
}
}
</style>
</head>
<body>
<%- body %>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Virtual Assistant Registration</title>
<link href="/public/css/va-register.css" rel="stylesheet">
<style>
select option:disabled {
display: none;
}
</style>
</head>
<body>
<%- body %>
</body>
</html>

View File

@ -1,105 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>404 - Page Not Found</title>
<style>
:root {
--bg: #ffffff;
--text: #222222;
--subtext: #555555;
--button-bg: #6c63ff;
--button-text: #ffffff;
}
/* Dark mode automatic */
@media (prefers-color-scheme: dark) {
:root {
--bg: #0f0f0f;
--text: #ffffff;
--subtext: #bbbbbb;
--button-bg: #6c63ff;
--button-text: #ffffff;
}
}
body {
margin: 0;
padding: 0;
background: var(--bg);
color: var(--text);
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
font-family: Inter, system-ui, sans-serif;
text-align: center;
padding: 20px;
}
.container {
max-width: 420px;
width: 100%;
}
h1 {
font-size: 7rem;
font-weight: 800;
margin: 0;
line-height: 1;
}
p {
font-size: 1.1rem;
margin-top: 10px;
color: var(--subtext);
}
.btn {
margin-top: 30px;
padding: 14px 26px;
background: var(--button-bg);
color: var(--button-text);
text-decoration: none;
font-weight: 600;
border-radius: 12px;
display: inline-block;
transition: 0.2s;
}
.btn:hover {
opacity: 0.85;
transform: translateY(-2px);
}
img {
width: 150px;
margin-bottom: 25px;
}
/* Responsive */
@media (max-width: 480px) {
h1 {
font-size: 4.5rem;
}
img {
width: 120px;
}
}
</style>
</head>
<body>
<div class="container">
<img src="/public/images/logo-white-vertical.svg" alt="404 Icon">
<h1>404</h1>
<p>Oops! The page you're looking for does not exist.</p>
<a href="/" class="btn">Go Home</a>
<a href="/client/login" class="btn">Go Home</a>
</div>
@ -124,6 +29,3 @@
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", applyTheme);
</script>
</body>
</html>

View File

@ -1,15 +1,3 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Client Registration</title>
<link href="/public/css/va-register.css" rel="stylesheet">
</head>
<body>
<div class="container">
<!-- Sidebar for desktop -->
<div class="sidebar">
@ -98,16 +86,20 @@
<form id="account-form">
<div class="form-group">
<div class="input-container">
<input type="text" id="company-name" class="input-field" placeholder=" " oninput="validateCompanyName(this)" required>
<input type="text" id="company-name" class="input-field" placeholder=" "
oninput="validateCompanyName(this)" required>
<label for="company-name" class="input-label">Company / Client Name *</label>
</div>
<div class="invalid-feedback" id="company-name-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
Company name should only contain letters, numbers, spaces, hyphens, apostrophes, ampersands, and periods
<div class="invalid-feedback" id="company-name-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
Company name should only contain letters, numbers, spaces, hyphens, apostrophes,
ampersands, and periods
</div>
</div>
<div class="form-group">
<div class="input-container">
<input type="email" id="email" class="input-field" placeholder=" " value="<%= email %>" readonly disabled required>
<input type="email" id="email" class="input-field" placeholder=" " value="<%= email %>"
readonly disabled required>
<label for="email" class="input-label">Email *</label>
</div>
</div>
@ -133,10 +125,13 @@
</div>
<div class="form-group">
<div class="input-container">
<input type="text" id="city" class="input-field" placeholder=" " oninput="validateCity(this)" onkeypress="return preventInvalidCityChars(event)" required>
<input type="text" id="city" class="input-field" placeholder=" "
oninput="validateCity(this)" onkeypress="return preventInvalidCityChars(event)"
required>
<label for="city" class="input-label">City *</label>
</div>
<div class="invalid-feedback" id="city-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="city-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
City name should contain letters and cannot be only numbers or special characters
</div>
</div>
@ -153,10 +148,13 @@
</div>
<div class="form-group">
<div class="input-container">
<input type="text" id="zip" class="input-field" placeholder=" " oninput="validateZipCode(this)" onkeypress="return preventNonNumericZip(event)" maxlength="10" required>
<input type="text" id="zip" class="input-field" placeholder=" "
oninput="validateZipCode(this)" onkeypress="return preventNonNumericZip(event)"
maxlength="10" required>
<label for="zip" class="input-label">ZIP *</label>
</div>
<div class="invalid-feedback" id="zip-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="zip-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
Invalid Zip code
</div>
</div>
@ -192,10 +190,13 @@
</div>
<div class="form-group">
<div class="input-container">
<input type="text" id="billing-city" class="input-field" placeholder=" " oninput="validateCity(this)" onkeypress="return preventInvalidCityChars(event)" required>
<input type="text" id="billing-city" class="input-field" placeholder=" "
oninput="validateCity(this)" onkeypress="return preventInvalidCityChars(event)"
required>
<label for="billing-city" class="input-label">City *</label>
</div>
<div class="invalid-feedback" id="billing-city-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="billing-city-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
City name should contain letters and cannot be only numbers or special characters
</div>
</div>
@ -211,10 +212,13 @@
</div>
<div class="form-group">
<div class="input-container">
<input type="text" id="billing-zip" class="input-field" placeholder=" " oninput="validateZipCode(this)" onkeypress="return preventNonNumericZip(event)" maxlength="10" required>
<input type="text" id="billing-zip" class="input-field" placeholder=" "
oninput="validateZipCode(this)" onkeypress="return preventNonNumericZip(event)"
maxlength="10" required>
<label for="billing-zip" class="input-label">ZIP *</label>
</div>
<div class="invalid-feedback" id="billing-zip-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="billing-zip-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
ZIP code should contain only numbers
</div>
</div>
@ -242,24 +246,32 @@
<div class="error-message" id="step-4-error-message"></div>
</div>
<p style="margin-bottom: 20px; color: #6b7280; font-size: 14px;">
We will use the details below in the agreement that we will send to your prior to entering the project.
We will use the details below in the agreement that we will send to your prior to entering the
project.
</p>
<form id="signatory-form">
<div class="form-group">
<div class="input-container">
<input type="text" id="position" class="input-field" placeholder=" " oninput="validatePosition(this)" onkeypress="return preventInvalidPositionChars(event)" required>
<label for="position" class="input-label">Position (Owner / CEO / Manager / etc.) *</label>
<input type="text" id="position" class="input-field" placeholder=" "
oninput="validatePosition(this)"
onkeypress="return preventInvalidPositionChars(event)" required>
<label for="position" class="input-label">Position (Owner / CEO / Manager / etc.)
*</label>
</div>
<div class="invalid-feedback" id="position-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="position-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
Position should only contain letters, spaces, and common punctuation
</div>
</div>
<div class="form-group">
<div class="input-container">
<input type="text" id="signatory-name" class="input-field" placeholder=" " oninput="validateSignatoryName(this)" onkeypress="return preventNumbers(event)" required>
<input type="text" id="signatory-name" class="input-field" placeholder=" "
oninput="validateSignatoryName(this)" onkeypress="return preventNumbers(event)"
required>
<label for="signatory-name" class="input-label">Name *</label>
</div>
<div class="invalid-feedback" id="signatory-name-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="signatory-name-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
Name should not contain numbers
</div>
</div>
@ -297,26 +309,33 @@
<div class="row">
<div class="form-group">
<div class="input-container">
<input type="text" id="expiry-date" class="input-field" placeholder=" " required>
<input type="text" id="expiry-date" class="input-field" placeholder=" "
required>
<label for="expiry-date" class="input-label">Expiry Date (MM/YY) *</label>
</div>
</div>
<div class="form-group">
<div class="input-container">
<input type="text" id="security-code" class="input-field" placeholder=" " oninput="validateCVVVV(this)" nkeypress="return preventInvalidCVVChars(event)" maxlength="4" required>
<input type="text" id="security-code" class="input-field" placeholder=" "
oninput="validateCVVVV(this)"
nkeypress="return preventInvalidCVVChars(event)" maxlength="4" required>
<label for="security-code" class="input-label">Security Code *</label>
</div>
<div class="invalid-feedback" id="security-code-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="security-code-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
Please enter a valid security code
</div>
</div>
</div>
<div class="form-group">
<div class="input-container">
<input type="text" id="card-zip" class="input-field" placeholder=" " oninput="validateZipCode(this)" onkeypress="return preventNonNumericZip(event)" maxlength="10" required>
<input type="text" id="card-zip" class="input-field" placeholder=" "
oninput="validateZipCode(this)" onkeypress="return preventNonNumericZip(event)"
maxlength="10" required>
<label for="card-zip" class="input-label">ZIP Code *</label>
</div>
<div class="invalid-feedback" id="card-zip-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="card-zip-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
ZIP code should contain only numbers
</div>
</div>
@ -328,19 +347,25 @@
<div id="bank-details" class="payment-details">
<div class="form-group">
<div class="input-container">
<input type="text" id="bank-name" class="input-field" placeholder=" " oninput="validateBankName(this)" onkeypress="return preventInvalidBankNameChars(event)" required>
<input type="text" id="bank-name" class="input-field" placeholder=" "
oninput="validateBankName(this)"
onkeypress="return preventInvalidBankNameChars(event)" required>
<label for="bank-name" class="input-label">Bank Name *</label>
</div>
<div class="invalid-feedback" id="bank-name-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="bank-name-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
Bank name should contain letters and cannot be only numbers or special characters
</div>
</div>
<div class="form-group">
<div class="input-container">
<input type="text" id="account-number" class="input-field" placeholder=" " oninput="validateAccountNumber(this)" onkeypress="return preventInvalidAccountNumberChars(event)" required>
<input type="text" id="account-number" class="input-field" placeholder=" "
oninput="validateAccountNumber(this)"
onkeypress="return preventInvalidAccountNumberChars(event)" required>
<label for="account-number" class="input-label">Account Number *</label>
</div>
<div class="invalid-feedback" id="account-number-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="account-number-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
Please enter a valid account number
</div>
</div>
@ -362,10 +387,13 @@
</div>
<div class="form-group">
<div class="input-container">
<input type="text" id="account-holder-name" class="input-field" placeholder=" " oninput="validateAccountHolderName(this)" onkeypress="return preventInvalidAccountHolderChars(event)" required>
<input type="text" id="account-holder-name" class="input-field" placeholder=" "
oninput="validateAccountHolderName(this)"
onkeypress="return preventInvalidAccountHolderChars(event)" required>
<label for="account-holder-name" class="input-label">Account Holder Name *</label>
</div>
<div class="invalid-feedback" id="account-holder-name-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
<div class="invalid-feedback" id="account-holder-name-error"
style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
Account holder name should only contain letters and spaces
</div>
</div>
@ -382,7 +410,8 @@
<div class="success-message">
<div class="success-icon">✓</div>
<h3>Registration Complete!</h3>
<p>Your account has been successfully created. You will receive a confirmation email shortly.</p>
<p>Your account has been successfully created. You will receive a confirmation email shortly.
</p>
</div>
</div>
</div>
@ -404,5 +433,3 @@
const savedTheme = getSystemTheme();
setTheme(savedTheme);
</script>
</body>
</html>

View File

@ -1,168 +1,3 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Live Screen Feed</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
height: 100vh;
display: flex;
background: #0f0f0f;
color: white;
font-family: "Inter", sans-serif;
overflow: hidden;
}
/* SIDEBAR */
.sidebar {
width: 280px;
background: #181818;
border-right: 1px solid #2b2b2b;
padding: 15px;
overflow-y: auto;
transition: transform 0.35s ease;
z-index: 50;
}
.sidebar h3 {
margin-bottom: 15px;
font-size: 18px;
font-weight: 600;
}
.app {
background: #252525;
border: 1px solid #333;
padding: 12px;
margin-bottom: 10px;
border-radius: 8px;
cursor: pointer;
transition: 0.3s ease;
}
.app:hover {
background: #333;
transform: translateX(3px);
}
.app.active {
background: #6c63ff;
border-color: #6c63ff;
color: white;
box-shadow: 0 0 10px rgba(108, 99, 255, 0.5);
}
/* MAIN CONTENT */
.content {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
padding: 20px;
overflow: hidden;
}
#selectedAppTitle {
font-size: 20px;
margin-bottom: 15px;
font-weight: 500;
text-align: center;
}
#liveImage {
width: 90%;
max-width: 900px;
border-radius: 10px;
border: 2px solid #444;
object-fit: contain;
background: black;
display: none;
}
.placeholder {
font-size: 16px;
opacity: 0.8;
color: #bbb;
margin-top: 20px;
}
/* MOBILE RESPONSIVE */
.mobile-toggle {
display: none;
position: fixed;
top: 15px;
left: 15px;
background: #6C63FF;
padding: 14px;
border-radius: 8px;
z-index: 9999;
/* VERY HIGH: always visible */
cursor: pointer;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
.mobile-toggle span {
display: block;
width: 26px;
height: 3px;
background: #fff;
margin: 5px 0;
border-radius: 2px;
}
/* Sidebar Hidden on Mobile */
@media (max-width: 780px) {
body {
flex-direction: column;
}
.sidebar {
position: fixed;
left: 0;
top: 0;
height: 100%;
transform: translateX(-100%);
}
.sidebar.open {
transform: translateX(0%);
}
.mobile-toggle {
display: block !important;
}
.content {
padding-top: 60px;
}
/* Dark overlay when sidebar opens */
#overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
display: none;
z-index: 40;
}
#overlay.show {
display: block;
}
}
</style>
</head>
<body>
<!-- Mobile Toggle Button -->
<div class="mobile-toggle" id="toggleBtn">
<span></span>
@ -287,7 +122,3 @@
}
});
</script>
</body>
</html>

View File

@ -1,20 +1,4 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Virtual Assistant Registration</title>
<link href="/public/css/va-register.css" rel="stylesheet">
<style>
select option:disabled {
display: none;
}
</style>
</head>
<body>
<div class="container">
<!-- Sidebar for desktop -->
@ -340,5 +324,4 @@
const savedTheme = getSystemTheme();
setTheme(savedTheme);
</script>
</body>
</html>