- Enhanced invitations system with role management - Updated beneficiaries routes and screens - Improved activate, purchase and profile flows - Added Maestro E2E tests - Added web invite acceptance page - Database migration for roles update
270 lines
8.1 KiB
HTML
270 lines
8.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Accept Invitation - WellNuo</title>
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
|
|
background: linear-gradient(135deg, #f5f7fa 0%, #e4e8ec 100%);
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 20px;
|
|
}
|
|
.container {
|
|
background: white;
|
|
border-radius: 20px;
|
|
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
|
|
max-width: 400px;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
.header {
|
|
background: #f8f9fa;
|
|
padding: 32px;
|
|
text-align: center;
|
|
border-bottom: 1px solid #eee;
|
|
}
|
|
.logo-img { width: 160px; height: auto; }
|
|
.content { padding: 32px; text-align: center; }
|
|
.btn {
|
|
width: 100%;
|
|
padding: 16px;
|
|
border: none;
|
|
border-radius: 10px;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
.btn-primary {
|
|
background: linear-gradient(135deg, #4A90D9 0%, #357ABD 100%);
|
|
color: white;
|
|
}
|
|
.btn-primary:hover {
|
|
transform: translateY(-1px);
|
|
box-shadow: 0 4px 12px rgba(74, 144, 217, 0.4);
|
|
}
|
|
.btn-primary:disabled { opacity: 0.7; cursor: not-allowed; transform: none; }
|
|
.error-message {
|
|
background: #fee;
|
|
color: #c00;
|
|
padding: 12px;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
margin-bottom: 16px;
|
|
display: none;
|
|
}
|
|
.success-container { display: none; }
|
|
.success-icon {
|
|
width: 80px;
|
|
height: 80px;
|
|
background: #e8f5e9;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin: 0 auto 24px;
|
|
}
|
|
.success-icon svg { width: 40px; height: 40px; color: #4caf50; }
|
|
.success-title { font-size: 24px; font-weight: 600; color: #333; margin-bottom: 12px; }
|
|
.success-text { color: #666; font-size: 15px; line-height: 1.5; margin-bottom: 16px; }
|
|
.success-info {
|
|
background: #f0f7ff;
|
|
border-radius: 12px;
|
|
padding: 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
.role-badge {
|
|
display: inline-block;
|
|
padding: 6px 16px;
|
|
border-radius: 20px;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
margin-bottom: 20px;
|
|
}
|
|
.role-caretaker { background: #e3f2fd; color: #1976d2; }
|
|
.role-guardian { background: #fff3e0; color: #f57c00; }
|
|
.permissions-title {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: #333;
|
|
margin-bottom: 12px;
|
|
text-align: left;
|
|
}
|
|
.permissions-list {
|
|
text-align: left;
|
|
margin-bottom: 20px;
|
|
}
|
|
.permissions-list li {
|
|
font-size: 14px;
|
|
color: #555;
|
|
margin-bottom: 8px;
|
|
padding-left: 24px;
|
|
position: relative;
|
|
list-style: none;
|
|
}
|
|
.permissions-list li:before {
|
|
content: "✓";
|
|
position: absolute;
|
|
left: 0;
|
|
color: #4caf50;
|
|
font-weight: bold;
|
|
}
|
|
.next-step {
|
|
background: #f5f7fa;
|
|
border-radius: 12px;
|
|
padding: 16px;
|
|
margin-top: 20px;
|
|
}
|
|
.next-step-title {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: #333;
|
|
margin-bottom: 8px;
|
|
}
|
|
.next-step-text {
|
|
font-size: 13px;
|
|
color: #666;
|
|
line-height: 1.5;
|
|
}
|
|
.loading {
|
|
display: inline-block;
|
|
width: 20px;
|
|
height: 20px;
|
|
border: 2px solid rgba(255,255,255,0.3);
|
|
border-radius: 50%;
|
|
border-top-color: white;
|
|
animation: spin 1s linear infinite;
|
|
margin-right: 8px;
|
|
vertical-align: middle;
|
|
}
|
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<img src="/logo.png" alt="WellNuo" class="logo-img">
|
|
</div>
|
|
|
|
<div class="content">
|
|
<!-- Accept Section -->
|
|
<div id="acceptSection">
|
|
<div id="errorMessage" class="error-message"></div>
|
|
|
|
<button class="btn btn-primary" id="acceptBtn" onclick="acceptInvitation()">
|
|
Accept Invitation
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Success Section -->
|
|
<div id="successSection" class="success-container">
|
|
<div class="success-icon">
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
|
</svg>
|
|
</div>
|
|
<h2 class="success-title">You're all set!</h2>
|
|
|
|
<div id="roleBadge" class="role-badge"></div>
|
|
|
|
<p class="success-text">
|
|
You have been granted access to monitor a family member through WellNuo.
|
|
</p>
|
|
|
|
<div id="permissionsBlock">
|
|
<div class="permissions-title">With your role you can:</div>
|
|
<ul class="permissions-list" id="permissionsList"></ul>
|
|
</div>
|
|
|
|
<div class="next-step">
|
|
<div class="next-step-title">What's next?</div>
|
|
<div class="next-step-text">
|
|
Download the WellNuo app and sign in with the email address this invitation was sent to. You'll see the beneficiary in your dashboard.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const API_BASE = 'https://wellnuo.smartlaunchhub.com/api';
|
|
|
|
// Get code from URL
|
|
const params = new URLSearchParams(window.location.search);
|
|
const inviteCode = params.get('code') || '';
|
|
|
|
// Show error if no code
|
|
if (!inviteCode) {
|
|
document.getElementById('errorMessage').textContent = 'Invalid invitation link.';
|
|
document.getElementById('errorMessage').style.display = 'block';
|
|
document.getElementById('acceptBtn').disabled = true;
|
|
}
|
|
|
|
async function acceptInvitation() {
|
|
const btn = document.getElementById('acceptBtn');
|
|
const errorEl = document.getElementById('errorMessage');
|
|
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="loading"></span>Accepting...';
|
|
errorEl.style.display = 'none';
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/invitations/accept-public`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ code: inviteCode })
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new Error(data.error || 'Failed to accept invitation');
|
|
}
|
|
|
|
// Show success with role-specific permissions
|
|
const isGuardian = data.role === 'guardian';
|
|
const roleBadge = document.getElementById('roleBadge');
|
|
const permissionsList = document.getElementById('permissionsList');
|
|
|
|
if (isGuardian) {
|
|
roleBadge.textContent = 'Guardian';
|
|
roleBadge.classList.add('role-guardian');
|
|
permissionsList.innerHTML = `
|
|
<li>View real-time health data and activity status</li>
|
|
<li>Receive alerts and notifications about health changes</li>
|
|
<li>Access daily, weekly, and monthly health reports</li>
|
|
<li>Manage device settings and alert preferences</li>
|
|
<li>Invite other family members to join as Caretakers</li>
|
|
<li>Update beneficiary profile information</li>
|
|
`;
|
|
} else {
|
|
roleBadge.textContent = 'Caretaker';
|
|
roleBadge.classList.add('role-caretaker');
|
|
permissionsList.innerHTML = `
|
|
<li>View real-time health data and activity status</li>
|
|
<li>Receive alerts and notifications about health changes</li>
|
|
<li>Access daily, weekly, and monthly health reports</li>
|
|
<li>Check in on your loved one's wellbeing anytime</li>
|
|
`;
|
|
}
|
|
|
|
document.getElementById('acceptSection').style.display = 'none';
|
|
document.getElementById('successSection').style.display = 'block';
|
|
|
|
} catch (error) {
|
|
errorEl.textContent = error.message;
|
|
errorEl.style.display = 'block';
|
|
btn.disabled = false;
|
|
btn.innerHTML = 'Accept Invitation';
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|