contact-gain / index.html
api-ix's picture
Rename create.html to index.html
c2e8d23 verified
Raw
History Blame Contribute Delete
10.4 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Create Contact Session | VCF Session</title>
<style>
:root {
--primary: #2563eb;
--primary-hover: #1d4ed8;
--success: #059669;
--error: #dc2626;
--bg-primary: #ffffff;
--bg-secondary: #f8fafc;
--bg-card: #ffffff;
--text-primary: #0f172a;
--text-secondary: #64748b;
--text-muted: #94a3b8;
--border: #e2e8f0;
--radius: 8px;
--radius-lg: 12px;
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
--transition: all .2s cubic-bezier(.4,0,.2,1);
}
@media (prefers-color-scheme: dark) {
:root {
--primary: #3b82f6;
--primary-hover: #2563eb;
--bg-primary: #0f172a;
--bg-secondary: #1e293b;
--bg-card: #1e293b;
--text-primary: #f1f5f9;
--text-secondary: #cbd5e1;
--text-muted: #64748b;
--border: #334155;
}
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--font-sans);
background: var(--bg-secondary);
color: var(--text-primary);
display: flex;
flex-direction: column;
min-height: 100vh;
}
.container {
width: 90%;
max-width: 480px;
margin: auto;
padding: 2rem 0;
}
.card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
box-shadow: 0 10px 15px -3px rgb(0 0 0 / .07), 0 4px 6px -4px rgb(0 0 0 / .07);
padding: 2rem;
}
.logo {
height: 48px;
margin: 0 auto 1.5rem;
display: block;
}
.header {
text-align: center;
margin-bottom: 1.5rem;
}
.header h1 {
font-size: 1.75rem;
font-weight: 700;
letter-spacing: -.025em;
}
.header p {
color: var(--text-secondary);
font-size: .9rem;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-label {
display: block;
font-size: .875rem;
font-weight: 600;
margin-bottom: .5rem;
}
.form-input {
width: 100%;
padding: .75rem 1rem;
border: 1px solid var(--border);
border-radius: var(--radius);
font-size: 1rem;
background: var(--bg-primary);
color: var(--text-primary);
transition: border-color .2s, box-shadow .2s;
}
.form-input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgb(37 99 235 / .2);
}
.duration-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: .75rem;
}
.duration-option {
position: relative;
}
.duration-radio {
position: absolute;
opacity: 0;
pointer-events: none;
}
.duration-label {
display: flex;
align-items: center;
justify-content: center;
padding: .75rem 1rem;
border: 1px solid var(--border);
border-radius: var(--radius);
cursor: pointer;
font-size: .875rem;
font-weight: 500;
background: var(--bg-primary);
color: var(--text-secondary);
transition: all .2s;
}
.duration-radio:checked + .duration-label {
background: var(--primary);
border-color: var(--primary);
color: #fff;
}
.duration-label:hover {
border-color: var(--primary);
color: var(--primary);
}
.btn {
width: 100%;
padding: .875rem 1.5rem;
font-size: 1rem;
font-weight: 600;
border: none;
border-radius: var(--radius);
cursor: pointer;
transition: background .2s, transform .2s;
position: relative;
overflow: hidden;
}
.btn-primary {
background: var(--primary);
color: #fff;
}
.btn-primary:hover:not(:disabled) {
background: var(--primary-hover);
transform: translateY(-2px);
}
.btn:disabled {
background: var(--text-muted);
cursor: not-allowed;
}
.ripple {
position: absolute;
border-radius: 50%;
transform: scale(0);
background: rgba(255, 255, 255, .6);
opacity: .6;
animation: ripple .6s linear;
}
@keyframes ripple {
to {
transform: scale(4);
opacity: 0;
}
}
.success-box {
display: none;
text-align: center;
}
.success-box.show {
display: block;
}
.url-box {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1rem;
margin: 1rem 0;
display: flex;
gap: .75rem;
}
.url-input {
flex: 1;
border: none;
background: transparent;
color: var(--text-primary);
font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
font-size: .875rem;
outline: none;
}
.copy-btn {
padding: .5rem 1rem;
background: var(--primary);
color: #fff;
border: none;
border-radius: var(--radius);
cursor: pointer;
font-size: .875rem;
transition: background .2s;
}
.copy-btn:hover {
background: var(--primary-hover);
}
.copy-btn.copied {
background: var(--success);
}
.footer {
position: fixed;
bottom: 1rem;
left: 50%;
transform: translateX(-50%);
font-size: .875rem;
color: var(--text-muted);
}
.footer a {
color: var(--primary);
text-decoration: none;
}
.footer a:hover {
text-decoration: underline;
}
@media (max-width: 640px) {
.duration-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<div class="card">
<img src="http://165.227.176.133:2137/media/logo.svg" alt="VCF Session" class="logo">
<div id="createBox">
<div class="header">
<h1>Create Contact Session</h1>
<p>Share contacts securely with automatic expiration</p>
</div>
<form id="createForm">
<div class="form-group">
<label for="sessionName" class="form-label">Session Name</label>
<input id="sessionName" type="text" class="form-input" placeholder="e.g. Team Meeting Contacts" maxlength="60" required autocomplete="off">
</div>
<div class="form-group">
<label class="form-label">Session Duration</label>
<div class="duration-grid">
<div class="duration-option">
<input type="radio" id="dur5" name="duration" value="5" class="duration-radio">
<label for="dur5" class="duration-label">5 min</label>
</div>
<div class="duration-option">
<input type="radio" id="dur15" name="duration" value="15" class="duration-radio">
<label for="dur15" class="duration-label">15 min</label>
</div>
<div class="duration-option">
<input type="radio" id="dur30" name="duration" value="30" class="duration-radio" checked>
<label for="dur30" class="duration-label">30 min</label>
</div>
<div class="duration-option">
<input type="radio" id="dur60" name="duration" value="60" class="duration-radio">
<label for="dur60" class="duration-label">1 hr</label>
</div>
<div class="duration-option">
<input type="radio" id="dur300" name="duration" value="300" class="duration-radio">
<label for="dur300" class="duration-label">5 hrs</label>
</div>
<div class="duration-option">
<input type="radio" id="dur420" name="duration" value="420" class="duration-radio">
<label for="dur420" class="duration-label">7 hrs</label>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary">Create Session</button>
</form>
</div>
<div id="successBox" class="success-box">
<div class="header">
<div class="success-icon"></div>
<h2>Session Created!</h2>
<p>Share this link with participants to collect contacts</p>
</div>
<div class="url-box">
<input id="urlInput" type="text" class="url-input" readonly>
<button id="copyBtn" class="copy-btn">Copy</button>
</div>
<button id="newBtn" class="btn btn-primary">Create Another Session</button>
</div>
</div>
<div class="footer">
Join our WhatsApp group:
<a href="https://chat.whatsapp.com/JRe69IJCINM3qYX3gM8MI9?mode=ems_copy_c" target="_blank" rel="noopener">VCF GROUP</a>
</div>
</div>
<script>
const createForm = document.getElementById('createForm');
const createBox = document.getElementById('createBox');
const successBox = document.getElementById('successBox');
const urlInput = document.getElementById('urlInput');
const copyBtn = document.getElementById('copyBtn');
const newBtn = document.getElementById('newBtn');
createForm.addEventListener('submit', async e => {
e.preventDefault();
const name = createForm.sessionName.value.trim();
const mins = createForm.duration.value;
if (!name) return;
const res = await fetch('/api/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sessionName: name, minutes: parseInt(mins) })
});
const data = await res.json();
if (!res.ok) return alert(data.error || 'Creation failed');
const url = `http://165.227.176.133:2137/session/${data.id}`;
urlInput.value = url;
createBox.style.display = 'none';
successBox.classList.add('show');
});
copyBtn.onclick = async () => {
await navigator.clipboard.writeText(urlInput.value);
copyBtn.textContent = 'Copied';
copyBtn.classList.add('copied');
setTimeout(() => {
copyBtn.textContent = 'Copy';
copyBtn.classList.remove('copied');
}, 2000);
};
newBtn.onclick = () => location.reload();
</script>
</body>
</html>