Spaces:
Running
Running
File size: 14,328 Bytes
2a55e2a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
{% 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 %} |