<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PrimeFlow - Subscribe</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
.container {
max-width: 500px;
width: 90%;
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 40px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.logo {
text-align: center;
margin-bottom: 30px;
}
.logo h1 {
font-size: 32px;
font-weight: 700;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 10px;
}
.tier-selector {
display: flex;
gap: 15px;
margin-bottom: 30px;
}
.tier-card {
flex: 1;
padding: 20px;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
border: 2px solid transparent;
cursor: pointer;
transition: all 0.3s ease;
}
.tier-card:hover {
border-color: rgba(102, 126, 234, 0.5);
transform: translateY(-2px);
}
.tier-card.selected {
border-color: #667eea;
background: rgba(102, 126, 234, 0.1);
}
.tier-name {
font-size: 18px;
font-weight: 600;
margin-bottom: 10px;
}
.tier-price {
font-size: 24px;
font-weight: 700;
color: #667eea;
}
.tier-period {
font-size: 14px;
color: #aaa;
}
.features {
margin: 20px 0;
padding: 20px;
background: rgba(0, 0, 0, 0.2);
border-radius: 12px;
}
.features h3 {
font-size: 16px;
margin-bottom: 15px;
color: #667eea;
}
.features ul {
list-style: none;
}
.features li {
padding: 8px 0;
padding-left: 25px;
position: relative;
font-size: 14px;
color: #ddd;
}
.features li:before {
content: "✓";
position: absolute;
left: 0;
color: #667eea;
font-weight: bold;
}
.discord-btn {
width: 100%;
padding: 16px;
background: #5865F2;
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
transition: background 0.3s ease;
margin-top: 20px;
}
.discord-btn:hover {
background: #4752C4;
}
.discord-btn:disabled {
background: #666;
cursor: not-allowed;
}
.discord-icon {
width: 24px;
height: 24px;
}
.loading {
text-align: center;
padding: 40px;
}
.spinner {
border: 3px solid rgba(255, 255, 255, 0.1);
border-radius: 50%;
border-top: 3px solid #667eea;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.error {
background: rgba(255, 0, 0, 0.1);
border: 1px solid rgba(255, 0, 0, 0.3);
color: #ff6b6b;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
font-size: 14px;
}
</style>
</head>
<body>
<div class="container">
<div class="logo">
<h1>PRIMEFLOW</h1>
<p style="color: #aaa;">Premium Trading Signals</p>
</div>
<div id="app">
<!-- Tier Selection -->
<div id="tier-selection">
<div class="tier-selector">
<div class="tier-card" data-tier="sanctum" onclick="selectTier('sanctum')">
<div class="tier-name">Sanctum</div>
<div class="tier-price">$49<span class="tier-period">/mo</span></div>
</div>
<div class="tier-card" data-tier="conclave" onclick="selectTier('conclave')">
<div class="tier-name">Conclave</div>
<div class="tier-price">$149<span class="tier-period">/mo</span></div>
</div>
</div>
<div class="features" id="features">
<h3>Select a tier to see features</h3>
</div>
<button class="discord-btn" id="subscribe-btn" onclick="loginWithDiscord()" disabled>
<svg class="discord-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418z"/>
</svg>
Subscribe with Discord
</button>
</div>
</div>
</div>
<script>
// Configuration - REPLACE THESE VALUES
const CONFIG = {
discordClientId: '1475897784207937809’,
discordRedirectUri: 'https://primeflow-checkout.pages.dev/callback',
stripePublishableKey: 'YOUR_STRIPE_PUBLISHABLE_KEY',
sanctumPriceId: 'price_SANCTUM_PRICE_ID',
conclavePriceId: 'price_CONCLAVE_PRICE_ID'
};
let selectedTier = null;
const tierFeatures = {
sanctum: [
'Real-time momentum signals',
'Daily market prep (7:30 AM)',
'Midday pulse updates',
'Weekly education series',
'Performance transparency',
'Sanctum community'
],
conclave: [
'Everything in Sanctum',
'Moonshot alerts (50-200% targets)',
'Daily video analysis',
'AI trade insights',
'Quarterly strategy calls',
'Limited to 50 members'
]
};
function selectTier(tier) {
selectedTier = tier;
// Update UI
document.querySelectorAll('.tier-card').forEach(card => {
card.classList.remove('selected');
});
document.querySelector(`[data-tier="${tier}"]`).classList.add('selected');
// Update features
const featuresDiv = document.getElementById('features');
const features = tierFeatures[tier];
featuresDiv.innerHTML = `
<h3>${tier.charAt(0).toUpperCase() + tier.slice(1)} Features</h3>
<ul>
${features.map(f => `<li>${f}</li>`).join('')}
</ul>
`;
// Enable button
document.getElementById('subscribe-btn').disabled = false;
}
function loginWithDiscord() {
if (!selectedTier) {
alert('Please select a tier first');
return;
}
// Store selected tier in localStorage
localStorage.setItem('selectedTier', selectedTier);
// Build Discord OAuth URL
const params = new URLSearchParams({
client_id: CONFIG.discordClientId,
redirect_uri: CONFIG.discordRedirectUri,
response_type: 'code',
scope: 'identify'
});
// Redirect to Discord OAuth
window.location.href = `https://discord.com/api/oauth2/authorize?${params}`;
}
// Handle OAuth callback
if (window.location.pathname === '/callback') {
handleCallback();
}
async function handleCallback() {
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const error = params.get('error');
if (error) {
document.getElementById('app').innerHTML = `
<div class="error">Authorization failed: ${error}</div>
<button class="discord-btn" onclick="window.location.href='/'">Try Again</button>
`;
return;
}
if (!code) {
document.getElementById('app').innerHTML = `
<div class="error">No authorization code received</div>
<button class="discord-btn" onclick="window.location.href='/'">Try Again</button>
`;
return;
}
// Show loading
document.getElementById('app').innerHTML = `
<div class="loading">
<div class="spinner"></div>
<p>Redirecting to checkout...</p>
</div>
`;
// Exchange code for Discord user info
try {
const discordUser = await getDiscordUser(code);
const selectedTier = localStorage.getItem('selectedTier');
// Redirect to Stripe Checkout with Discord ID
redirectToStripe(discordUser, selectedTier);
} catch (err) {
document.getElementById('app').innerHTML = `
<div class="error">Failed to authenticate: ${err.message}</div>
<button class="discord-btn" onclick="window.location.href='/'">Try Again</button>
`;
}
}
async function getDiscordUser(code) {
// This needs to be done server-side to keep client secret secure
// For now, we'll call a Make.com webhook that handles the OAuth exchange
const response = await fetch('YOUR_MAKECOM_WEBHOOK_URL_FOR_DISCORD_OAUTH', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code })
});
if (!response.ok) {
throw new Error('Failed to get Discord user');
}
return await response.json();
}
function redirectToStripe(discordUser, tier) {
const priceId = tier === 'sanctum' ? CONFIG.sanctumPriceId : CONFIG.conclavePriceId;
// Create Stripe Checkout session via Make.com webhook
fetch('YOUR_MAKECOM_WEBHOOK_URL_FOR_STRIPE_CHECKOUT', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
priceId: priceId,
discordUserId: discordUser.id,
discordUsername: `${discordUser.username}#${discordUser.discriminator}`,
customerEmail: discordUser.email || ''
})
})
.then(res => res.json())
.then(data => {
if (data.url) {
window.location.href = data.url;
} else {
throw new Error('No checkout URL received');
}
})
.catch(err => {
document.getElementById('app').innerHTML = `
<div class="error">Failed to create checkout: ${err.message}</div>
<button class="discord-btn" onclick="window.location.href='/'">Try Again</button>
`;
});
}
</script>
</body>
</html>