Spaces:
Running
Running
| {% extends "base.html" %} | |
| {% block title %}Credits{% endblock %} | |
| {% block content %} | |
| <div class="container mx-auto px-4 py-8"> | |
| <!-- Header --> | |
| <div class="flex items-center justify-between mb-8"> | |
| <div> | |
| <h1 class="text-3xl font-bold text-gray-900 dark:text-white">Credits</h1> | |
| <p class="mt-2 text-gray-600 dark:text-gray-300">Manage your credits for using AI tools</p> | |
| </div> | |
| <div class="text-right"> | |
| <div class="text-2xl font-bold text-blue-600">{{ user_credits }}</div> | |
| <div class="text-sm text-gray-500">credits available</div> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-8"> | |
| <!-- Earn Credits --> | |
| <div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6"> | |
| <h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Earn Credits</h2> | |
| <!-- Daily Rewards --> | |
| <div class="mb-6"> | |
| <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">Daily Rewards</h3> | |
| <p class="text-gray-600 dark:text-gray-300 mb-4"> | |
| Watch ads to earn up to 30 credits per day (3 rewards of 10 credits each) | |
| </p> | |
| <div class="flex items-center justify-between mb-4"> | |
| <div class="text-sm text-gray-500 dark:text-gray-400"> | |
| <span id="daily-count">0</span>/3 rewards claimed today | |
| </div> | |
| <div id="daily-cooldown" class="text-sm text-gray-500 dark:text-gray-400 hidden"> | |
| Next reward in: <span id="cooldown-timer">5:00</span> | |
| </div> | |
| </div> | |
| <button id="daily-reward-btn" | |
| class="w-full py-3 px-4 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"> | |
| Watch Ad for 10 Credits | |
| </button> | |
| </div> | |
| <!-- Special Reward --> | |
| <div class="mb-6"> | |
| <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">Special Reward</h3> | |
| <p class="text-gray-600 dark:text-gray-300 mb-4"> | |
| Watch a longer ad to earn 25 bonus credits (available once per day) | |
| </p> | |
| <button id="special-reward-btn" | |
| class="w-full py-3 px-4 text-sm font-medium text-white bg-purple-600 rounded-lg hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 disabled:opacity-50 disabled:cursor-not-allowed"> | |
| Watch Special Ad for 25 Credits | |
| </button> | |
| </div> | |
| <!-- Referral Program --> | |
| <div> | |
| <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-2">Referral Program</h3> | |
| <p class="text-gray-600 dark:text-gray-300 mb-4"> | |
| Invite friends to earn 50 credits for each referral | |
| </p> | |
| <div class="flex items-center space-x-4"> | |
| <input type="text" id="referral-link" | |
| value="{{ referral_link }}" | |
| class="flex-1 px-4 py-2 text-gray-900 dark:text-white bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" | |
| readonly> | |
| <button id="copy-referral" | |
| class="px-4 py-2 text-sm font-medium text-white bg-green-600 rounded-lg hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500"> | |
| Copy | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Purchase Credits --> | |
| <div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6"> | |
| <h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Purchase Credits</h2> | |
| <!-- Credit Packages --> | |
| <div class="space-y-4"> | |
| {% for package in credit_packages %} | |
| <div class="border border-gray-200 dark:border-gray-700 rounded-lg p-4"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <div> | |
| <h3 class="text-lg font-medium text-gray-900 dark:text-white">{{ package.name }}</h3> | |
| <p class="text-sm text-gray-500 dark:text-gray-400">{{ package.description }}</p> | |
| </div> | |
| <div class="text-right"> | |
| <div class="text-xl font-bold text-blue-600">${{ package.price }}</div> | |
| <div class="text-sm text-gray-500">{{ package.credits }} credits</div> | |
| </div> | |
| </div> | |
| <button onclick="purchaseCredits('{{ package.id }}')" | |
| class="w-full py-2 px-4 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> | |
| Purchase | |
| </button> | |
| </div> | |
| {% endfor %} | |
| </div> | |
| <!-- Payment Methods --> | |
| <div class="mt-6"> | |
| <h3 class="text-sm font-medium text-gray-900 dark:text-white mb-2">Accepted Payment Methods</h3> | |
| <div class="flex items-center space-x-4"> | |
| <svg class="h-8 w-8 text-gray-400" fill="currentColor" viewBox="0 0 24 24"> | |
| <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/> | |
| </svg> | |
| <svg class="h-8 w-8 text-gray-400" fill="currentColor" viewBox="0 0 24 24"> | |
| <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/> | |
| </svg> | |
| <svg class="h-8 w-8 text-gray-400" fill="currentColor" viewBox="0 0 24 24"> | |
| <path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"/> | |
| </svg> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Credit History --> | |
| <div class="mt-8"> | |
| <h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Credit History</h2> | |
| <div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden"> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700"> | |
| <thead class="bg-gray-50 dark:bg-gray-700"> | |
| <tr> | |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Date</th> | |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Type</th> | |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Amount</th> | |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Details</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700"> | |
| {% for transaction in credit_history %} | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-white"> | |
| {{ transaction.date }} | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-white"> | |
| {{ transaction.type }} | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm {% if transaction.amount > 0 %}text-green-600{% else %}text-red-600{% endif %}"> | |
| {{ transaction.amount }} | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400"> | |
| {{ transaction.details }} | |
| </td> | |
| </tr> | |
| {% endfor %} | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Ad Modal --> | |
| <div id="ad-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center"> | |
| <div class="bg-white dark:bg-gray-800 rounded-lg p-6 max-w-lg w-full mx-4"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="text-xl font-semibold">Watch Ad</h2> | |
| <button id="close-ad-modal" class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"> | |
| <svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/> | |
| </svg> | |
| </button> | |
| </div> | |
| <!-- Ad Container --> | |
| <div id="ad-container" class="aspect-video bg-gray-100 dark:bg-gray-700 rounded-lg mb-4 flex items-center justify-center"> | |
| <div class="text-center"> | |
| <div class="text-2xl font-bold text-gray-400 mb-2" id="ad-countdown">30</div> | |
| <div class="text-sm text-gray-500">seconds remaining</div> | |
| </div> | |
| </div> | |
| <!-- Progress Bar --> | |
| <div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2.5 mb-4"> | |
| <div id="ad-progress" class="bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div> | |
| </div> | |
| <!-- Status Message --> | |
| <div id="ad-status" class="text-center text-sm text-gray-500 dark:text-gray-400"> | |
| Please watch the ad to earn your reward | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const dailyBtn = document.getElementById('daily-reward-btn'); | |
| const specialBtn = document.getElementById('special-reward-btn'); | |
| const adModal = document.getElementById('ad-modal'); | |
| const closeAdModal = document.getElementById('close-ad-modal'); | |
| const copyReferralBtn = document.getElementById('copy-referral'); | |
| const referralLink = document.getElementById('referral-link'); | |
| // Load reward status | |
| loadRewardStatus(); | |
| // Set up event listeners | |
| dailyBtn.addEventListener('click', () => showAdModal('daily')); | |
| specialBtn.addEventListener('click', () => showAdModal('special')); | |
| closeAdModal.addEventListener('click', hideAdModal); | |
| copyReferralBtn.addEventListener('click', copyReferralLink); | |
| // Load reward status | |
| async function loadRewardStatus() { | |
| try { | |
| const response = await fetch('/api/ads/status'); | |
| const data = await response.json(); | |
| if (data.success) { | |
| updateDailyRewardStatus(data.daily_rewards); | |
| updateSpecialRewardStatus(data.special_reward); | |
| } | |
| } catch (error) { | |
| console.error('Error loading reward status:', error); | |
| } | |
| } | |
| // Update daily reward status | |
| function updateDailyRewardStatus(status) { | |
| const dailyCount = document.getElementById('daily-count'); | |
| const cooldownDiv = document.getElementById('daily-cooldown'); | |
| const cooldownTimer = document.getElementById('cooldown-timer'); | |
| dailyCount.textContent = status.count; | |
| if (status.can_claim) { | |
| dailyBtn.disabled = false; | |
| cooldownDiv.classList.add('hidden'); | |
| } else { | |
| dailyBtn.disabled = true; | |
| cooldownDiv.classList.remove('hidden'); | |
| updateCooldownTimer(status.cooldown_remaining); | |
| } | |
| } | |
| // Update special reward status | |
| function updateSpecialRewardStatus(status) { | |
| specialBtn.disabled = !status.can_claim; | |
| } | |
| // Show ad modal | |
| function showAdModal(type) { | |
| currentRewardType = type; | |
| adModal.classList.remove('hidden'); | |
| adModal.classList.add('flex'); | |
| startAdTimer(); | |
| } | |
| // Hide ad modal | |
| function hideAdModal() { | |
| adModal.classList.add('hidden'); | |
| adModal.classList.remove('flex'); | |
| stopAdTimer(); | |
| resetAdProgress(); | |
| } | |
| // Copy referral link | |
| function copyReferralLink() { | |
| referralLink.select(); | |
| document.execCommand('copy'); | |
| showToast('Referral link copied to clipboard!', 'success'); | |
| } | |
| // Purchase credits | |
| window.purchaseCredits = async function(packageId) { | |
| try { | |
| const response = await fetch('/api/credits/purchase', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| package_id: packageId | |
| }) | |
| }); | |
| const data = await response.json(); | |
| if (data.success) { | |
| // Redirect to payment page | |
| window.location.href = data.payment_url; | |
| } else { | |
| showToast(data.error || 'Failed to initiate purchase', 'error'); | |
| } | |
| } catch (error) { | |
| console.error('Error purchasing credits:', error); | |
| showToast('Failed to initiate purchase', 'error'); | |
| } | |
| }; | |
| }); | |
| </script> | |
| {% endblock %} |