realtimecursor
Version:
Real-time collaboration system with cursor tracking and approval workflow
222 lines (201 loc) • 6.81 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RealtimeCursor</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
margin: 0;
padding: 0;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
.container {
max-width: 800px;
padding: 2rem;
background-color: white;
border-radius: 10px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}
h1 {
color: #4a5568;
margin-bottom: 1rem;
}
p {
color: #718096;
line-height: 1.6;
margin-bottom: 1.5rem;
}
.button {
display: inline-block;
background-color: #4299e1;
color: white;
padding: 0.75rem 1.5rem;
border-radius: 5px;
text-decoration: none;
font-weight: 600;
transition: background-color 0.2s;
margin: 0.5rem;
}
.button:hover {
background-color: #3182ce;
}
.status {
margin-top: 1rem;
padding: 1rem;
border-radius: 5px;
}
.status.online {
background-color: #c6f6d5;
color: #2f855a;
}
.status.offline {
background-color: #fed7d7;
color: #c53030;
}
.login-form {
margin-top: 2rem;
text-align: left;
}
.form-group {
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
}
input {
width: 100%;
padding: 0.75rem;
border: 1px solid #e2e8f0;
border-radius: 5px;
font-size: 1rem;
}
</style>
</head>
<body>
<div class="container">
<h1>RealtimeCursor</h1>
<p>A powerful real-time collaboration platform with live cursor tracking, approval workflows, and GitHub-style history.</p>
<div id="status" class="status">Checking backend status...</div>
<div>
<a href="#" class="button" id="create-admin-button">Create Admin Users</a>
<a href="#" class="button" id="health-check-button">Check Health</a>
</div>
<div class="login-form">
<h2>Login</h2>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" value="superadmin@example.com">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" value="SuperAdmin123!">
</div>
<button id="login-button" class="button">Login</button>
<div id="login-result"></div>
</div>
</div>
<script>
// Get the backend URL from the URL parameter or use default
const urlParams = new URLSearchParams(window.location.search);
const apiUrl = urlParams.get('api') || 'https://realtime-1.onrender.com';
const statusElement = document.getElementById('status');
const createAdminButton = document.getElementById('create-admin-button');
const healthCheckButton = document.getElementById('health-check-button');
const loginButton = document.getElementById('login-button');
const loginResultElement = document.getElementById('login-result');
// Check health endpoint
async function checkHealth() {
try {
statusElement.textContent = "Checking backend status...";
statusElement.className = "status";
const response = await fetch(`${apiUrl}/health`);
const data = await response.json();
if (data.status === 'OK') {
statusElement.textContent = `Backend is online! ${apiUrl}`;
statusElement.className = "status online";
} else {
statusElement.textContent = `Backend returned unexpected response: ${JSON.stringify(data)}`;
statusElement.className = "status offline";
}
} catch (error) {
statusElement.textContent = `Backend is offline or unreachable: ${error.message}`;
statusElement.className = "status offline";
}
}
// Create admin users
async function createAdminUsers() {
try {
statusElement.textContent = "Creating admin users...";
statusElement.className = "status";
const response = await fetch(`${apiUrl}/create-default-admins`, {
method: 'POST'
});
const data = await response.json();
if (data.success) {
statusElement.textContent = `Admin users created: ${JSON.stringify(data.results)}`;
statusElement.className = "status online";
} else {
statusElement.textContent = `Failed to create admin users: ${data.message || JSON.stringify(data)}`;
statusElement.className = "status offline";
}
} catch (error) {
statusElement.textContent = `Error creating admin users: ${error.message}`;
statusElement.className = "status offline";
}
}
// Login
async function login() {
try {
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
loginResultElement.textContent = "Logging in...";
const response = await fetch(`${apiUrl}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});
const data = await response.json();
if (data.success) {
loginResultElement.textContent = `Login successful! Token: ${data.token.substring(0, 20)}...`;
localStorage.setItem('authToken', data.token);
localStorage.setItem('user', JSON.stringify(data.user));
} else {
loginResultElement.textContent = `Login failed: ${data.message || JSON.stringify(data)}`;
}
} catch (error) {
loginResultElement.textContent = `Login error: ${error.message}`;
}
}
// Add event listeners
createAdminButton.addEventListener('click', (e) => {
e.preventDefault();
createAdminUsers();
});
healthCheckButton.addEventListener('click', (e) => {
e.preventDefault();
checkHealth();
});
loginButton.addEventListener('click', (e) => {
e.preventDefault();
login();
});
// Check health on page load
checkHealth();
// Set button URLs
createAdminButton.href = `${apiUrl}/create-default-admins`;
healthCheckButton.href = `${apiUrl}/health`;
</script>
</body>
</html>