Commit a9cd8b66 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix: home buttons, daily reward, back navigation — full sweep

1. Removed أحجيات (puzzles) from home quick buttons — chess-only feature
2. Daily reward completely rewritten:
   - 7-day streak timeline showing claimed/today/future days
   - Each day shows reward amount (50→75→100→125→150→200→300)
   - Already-claimed state: shows  with 'عد غداً' message
   - Prevents double claim (checks last_daily_reward date)
   - Coin burst + fly-to-HUD animation on claim
   - Streak badge '🔥 X يوم متتالي'
   - Info text explaining escalating rewards
   - Has back button ←
3. Challenges scene: added back button ←
4. All pushed scenes now have proper back navigation
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 85d39aa0
...@@ -39,10 +39,6 @@ export function mountTable(el) { ...@@ -39,10 +39,6 @@ export function mountTable(el) {
<span class="qb-icon" style="background:linear-gradient(135deg,#92400e,#e4ac38);">🎁</span> <span class="qb-icon" style="background:linear-gradient(135deg,#92400e,#e4ac38);">🎁</span>
<span class="qb-label">هدية</span> <span class="qb-label">هدية</span>
</button> </button>
<button class="quick-btn" id="btn-puzzles-home">
<span class="qb-icon" style="background:linear-gradient(135deg,#065f46,#10b981);">🧩</span>
<span class="qb-label">أحجيات</span>
</button>
</div> </div>
<!-- Games --> <!-- Games -->
...@@ -232,10 +228,6 @@ export function mountTable(el) { ...@@ -232,10 +228,6 @@ export function mountTable(el) {
audio.play('click'); audio.play('click');
scene.push('daily-reward'); scene.push('daily-reward');
}); });
el.querySelector('#btn-puzzles-home')?.addEventListener('click', () => {
audio.play('click');
scene.push('puzzles');
});
// Juice: staggered bounce-in for tiles + floating idle // Juice: staggered bounce-in for tiles + floating idle
const tiles = el.querySelectorAll('.game-tile'); const tiles = el.querySelectorAll('.game-tile');
......
...@@ -3,12 +3,14 @@ import * as audio from '../../../core/audio.js'; ...@@ -3,12 +3,14 @@ import * as audio from '../../../core/audio.js';
import * as juice from '../../../core/juice.js'; import * as juice from '../../../core/juice.js';
import * as bus from '../../../core/bus.js'; import * as bus from '../../../core/bus.js';
import * as store from '../../../core/store.js'; import * as store from '../../../core/store.js';
import * as scene from '../../../core/scene.js';
export async function mountChallenges(el) { export async function mountChallenges(el) {
el.innerHTML = ` el.innerHTML = `
<div style="padding:16px;display:flex;flex-direction:column;gap:14px;"> <div style="padding:16px;display:flex;flex-direction:column;gap:14px;">
<div style="display:flex;align-items:center;justify-content:space-between;"> <div style="display:flex;align-items:center;gap:12px;">
<h2 style="font-size:18px;font-weight:800;color:#f8fafc;">⚡ التحديات اليومية</h2> <button class="btn btn-secondary" id="back-btn" style="min-height:32px;padding:4px 12px;font-size:12px;">←</button>
<h2 style="font-size:18px;font-weight:800;color:#f8fafc;flex:1;">⚡ التحديات اليومية</h2>
<div id="streak-badge" style="background:linear-gradient(135deg,#E4AC38,#FFCC66);color:#1a1a1a;font-size:12px;font-weight:800;padding:5px 12px;border-radius:99px;"></div> <div id="streak-badge" style="background:linear-gradient(135deg,#E4AC38,#FFCC66);color:#1a1a1a;font-size:12px;font-weight:800;padding:5px 12px;border-radius:99px;"></div>
</div> </div>
<div id="challenges-list"></div> <div id="challenges-list"></div>
...@@ -19,6 +21,8 @@ export async function mountChallenges(el) { ...@@ -19,6 +21,8 @@ export async function mountChallenges(el) {
</div> </div>
`; `;
el.querySelector('#back-btn').addEventListener('click', () => { audio.play('click'); scene.pop(); });
try { try {
const data = await net.get('challenges.php'); const data = await net.get('challenges.php');
renderChallenges(el, data); renderChallenges(el, data);
......
...@@ -2,40 +2,112 @@ import * as net from '../../../core/net.js'; ...@@ -2,40 +2,112 @@ import * as net from '../../../core/net.js';
import * as audio from '../../../core/audio.js'; import * as audio from '../../../core/audio.js';
import * as bus from '../../../core/bus.js'; import * as bus from '../../../core/bus.js';
import * as store from '../../../core/store.js'; import * as store from '../../../core/store.js';
import * as scene from '../../../core/scene.js';
import * as juice from '../../../core/juice.js';
import { t } from '../../../core/i18n.js'; import { t } from '../../../core/i18n.js';
const DAY_REWARDS = [50, 75, 100, 125, 150, 200, 300];
export async function mountDaily(el) { export async function mountDaily(el) {
const player = store.get('player') || {};
const lastClaim = player.last_daily_reward || null;
const today = new Date().toISOString().slice(0, 10);
const alreadyClaimed = lastClaim && lastClaim.slice(0, 10) === today;
const streak = player.daily_streak || 0;
el.innerHTML = ` el.innerHTML = `
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:var(--s-6);padding:var(--s-6);"> <div style="display:flex;flex-direction:column;height:100%;background:#0a0a1a;">
<div style="font-size:48px;animation:float 3s ease-in-out infinite;">🎁</div> <!-- Header -->
<div style="font-size:22px;font-weight:700;">${t('daily.claim')}</div> <div style="display:flex;align-items:center;gap:12px;padding:12px 16px;background:#0f0f1e;border-bottom:1px solid rgba(255,255,255,0.06);">
<div style="color:var(--text-secondary);font-size:14px;" id="streak-info"></div> <button class="btn btn-secondary" id="back-btn" style="min-height:32px;padding:4px 12px;font-size:12px;">←</button>
<button class="btn btn-primary" id="claim-btn" style="font-size:18px;padding:var(--s-4) var(--s-8);">${t('daily.claim')}</button> <span style="font-size:16px;font-weight:700;color:#f8fafc;">🎁 المكافأة اليومية</span>
<div id="claim-result" style="text-align:center;min-height:40px;"></div> </div>
<div style="flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;align-items:center;gap:16px;">
<!-- Streak badge -->
<div style="background:linear-gradient(135deg,#92400e,#E4AC38);padding:8px 20px;border-radius:99px;display:flex;align-items:center;gap:6px;">
<span style="font-size:18px;">🔥</span>
<span style="font-size:14px;font-weight:800;color:#1a1a1a;">${streak} يوم متتالي</span>
</div>
<!-- 7-day timeline -->
<div style="display:flex;gap:6px;width:100%;max-width:340px;justify-content:center;">
${DAY_REWARDS.map((coins, i) => {
const dayNum = i + 1;
const isPast = i < streak;
const isToday = i === streak;
const isFuture = i > streak;
const claimed = isPast || (isToday && alreadyClaimed);
return `
<div style="flex:1;display:flex;flex-direction:column;align-items:center;gap:4px;">
<div style="width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;
background:${claimed ? '#1a3a1a' : isToday ? 'linear-gradient(135deg,#E4AC38,#FFCC66)' : '#1a1a2e'};
border:2px solid ${claimed ? '#34D399' : isToday ? '#E4AC38' : 'rgba(255,255,255,0.06)'};
color:${claimed ? '#34D399' : isToday ? '#1a1a1a' : '#64748b'};">
${claimed ? '✓' : coins}
</div>
<span style="font-size:9px;color:${isToday ? '#E4AC38' : '#475569'};font-weight:${isToday ? '700' : '400'};">يوم ${dayNum}</span>
</div>
`;
}).join('')}
</div>
<!-- Today's reward -->
<div style="text-align:center;margin-top:8px;">
${alreadyClaimed ? `
<div style="font-size:48px;margin-bottom:8px;">✅</div>
<div style="font-size:16px;font-weight:700;color:#34D399;">تم استلام مكافأة اليوم</div>
<div style="font-size:13px;color:#64748b;margin-top:4px;">عد غداً لمكافأة أكبر!</div>
` : `
<div style="font-size:56px;margin-bottom:8px;animation:float 3s ease-in-out infinite;">🎁</div>
<div style="font-size:16px;font-weight:700;color:#f8fafc;margin-bottom:4px;">مكافأة اليوم</div>
<div style="font-size:28px;font-weight:800;color:#E4AC38;margin-bottom:16px;">${DAY_REWARDS[Math.min(streak, 6)]} 🪙</div>
<button class="btn btn-primary" id="claim-btn" style="font-size:16px;padding:14px 48px;">استلم المكافأة</button>
`}
</div>
<!-- Info -->
<div style="text-align:center;color:#475569;font-size:11px;margin-top:auto;padding:12px;">
كل يوم تجمع فيه المكافأة يزيد المبلغ • اليوم السابع = 300 عملة!
</div>
</div>
</div> </div>
`; `;
const btn = el.querySelector('#claim-btn'); el.querySelector('#back-btn').addEventListener('click', () => { audio.play('click'); scene.pop(); });
btn.addEventListener('click', async () => {
btn.disabled = true; const claimBtn = el.querySelector('#claim-btn');
try { if (claimBtn) {
const data = await net.post('daily-reward.php', { action: 'claim' }); claimBtn.addEventListener('click', async () => {
if (data.error) { claimBtn.disabled = true;
el.querySelector('#claim-result').innerHTML = `<span style="color:var(--text-secondary);">${data.error}</span>`; claimBtn.textContent = 'جاري الاستلام...';
btn.disabled = false;
return; try {
const data = await net.post('daily-reward.php', { action: 'claim' });
if (data.error) {
claimBtn.textContent = data.error;
claimBtn.disabled = false;
return;
}
audio.play('coin', 'reward');
juice.hapticSuccess();
juice.coinBurst(window.innerWidth / 2, window.innerHeight / 2, 10);
juice.coinFlyTo(window.innerWidth / 2, window.innerHeight / 2, '#hud-coins', 5);
// Update UI to claimed state
claimBtn.textContent = ' تم!';
claimBtn.style.background = '#34D399';
bus.emit('coins:earned', { amount: data.coins || 100 });
const player = store.get('player');
if (player) {
store.set('player', { ...player, coins: data.total_coins || (player.coins || 0) + (data.coins || 100), last_daily_reward: new Date().toISOString() });
}
} catch (e) {
claimBtn.textContent = 'فشل حاول مرة أخرى';
claimBtn.disabled = false;
} }
audio.play('coin', 'reward'); });
audio.playSequence(['coin', 'coin', 'levelUp'], 150); }
el.querySelector('#claim-result').innerHTML = `
<span style="color:var(--gold);font-size:18px;font-weight:700;">+${data.coins || 100} 🪙</span>
`;
bus.emit('coins:earned', { amount: data.coins || 100 });
const player = store.get('player');
if (player) store.set('player', { ...player, coins: (player.coins || 0) + (data.coins || 100) });
} catch (e) {
el.querySelector('#claim-result').innerHTML = `<span style="color:var(--error);">${t('common.error')}</span>`;
btn.disabled = false;
}
});
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment