Skip to content

Commit 1ac34fe

Browse files
committed
feat: enhance UI components and add quest/referral features
- Enhanced RewardsSidebar with improved functionality - Updated various UI components (badges, cards, spinners, progress bars) - Added quest and referral components and services - Updated Firebase service and types - Added new video assets for phases - Updated package dependencies
1 parent 9880e4c commit 1ac34fe

24 files changed

Lines changed: 2290 additions & 1932 deletions

app/home/page.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import Image from 'next/image';
3131
// Remove unused nexusCodex import
3232
import { getBadgeById, Account, DemoStats, PREDEFINED_DEMOS } from '@/lib/firebase/firebase-types';
3333
import { getBadgeIcon, BADGE_SIZES } from '@/utils/constants/badges/assets';
34+
import { QuestAndReferralSection } from '@/components/ui/quest/QuestAndReferralSection';
3435

3536
// Demo Selection Component
3637
interface DemoCard {
@@ -1021,7 +1022,7 @@ export default function HomePageContent() {
10211022
}
10221023

10231024
// Check if user has earned all required badges
1024-
const requiredBadges = ['escrow_expert', 'trust_guardian', 'stellar_champion', 'nexus_master'];
1025+
const requiredBadges = ['welcome_explorer', 'escrow_expert', 'trust_guardian', 'stellar_champion', 'nexus_master'];
10251026
const hasAllBadges = requiredBadges.every(badgeId => badgesEarnedArray.includes(badgeId));
10261027

10271028
return hasAllBadges;
@@ -1514,6 +1515,30 @@ export default function HomePageContent() {
15141515
</div>
15151516
</section>
15161517

1518+
{/* Quest and Referral System Section */}
1519+
<section className="container mx-auto px-4 py-16">
1520+
<QuestAndReferralSection
1521+
account={account}
1522+
onQuestComplete={(questId, rewards) => {
1523+
addToastHook({
1524+
type: 'success',
1525+
title: '🎯 Quest Completed!',
1526+
message: `Earned ${rewards.experience} XP and ${rewards.points} points!`,
1527+
duration: 5000,
1528+
});
1529+
}}
1530+
onReferralComplete={(referralData) => {
1531+
addToastHook({
1532+
type: 'success',
1533+
title: '👥 Referral Sent!',
1534+
message: `Invitation sent to ${referralData.email}`,
1535+
duration: 5000,
1536+
});
1537+
}}
1538+
refreshAccountData={refreshAccountData}
1539+
/>
1540+
</section>
1541+
15171542
{/* Interactive Tutorial Section - Full Width with Irregular Shape */}
15181543
<section
15191544
id='interactive-tutorial'

components/demos/DisputeResolutionDemo.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ export const DisputeResolutionDemo = () => {
6363

6464
// Individual loading states for each milestone
6565
const [milestoneLoadingStates, setMilestoneLoadingStates] = useState<Record<string, boolean>>({});
66+
67+
// Individual loading states for each dispute resolution
68+
const [disputeLoadingStates, setDisputeLoadingStates] = useState<Record<string, boolean>>({});
6669

6770
// Confetti animation state
6871
const [showConfetti, setShowConfetti] = useState(false);
@@ -605,6 +608,8 @@ export const DisputeResolutionDemo = () => {
605608
if (!contractId) return;
606609

607610
try {
611+
// Set loading state for this specific dispute
612+
setDisputeLoadingStates(prev => ({ ...prev, [disputeId]: true }));
608613
const dispute = disputes.find(d => d.id === disputeId);
609614
if (!dispute) return;
610615

@@ -729,6 +734,9 @@ export const DisputeResolutionDemo = () => {
729734
message: 'Failed to resolve the dispute.',
730735
duration: 5000,
731736
});
737+
} finally {
738+
// Clear loading state for this specific dispute
739+
setDisputeLoadingStates(prev => ({ ...prev, [disputeId]: false }));
732740
}
733741
}
734742

@@ -847,6 +855,7 @@ export const DisputeResolutionDemo = () => {
847855
// Clear individual dispute input states
848856
setDisputeReasons({});
849857
setResolutionReasons({});
858+
setDisputeLoadingStates({});
850859

851860
addToast({
852861
type: 'info',
@@ -1182,24 +1191,24 @@ export const DisputeResolutionDemo = () => {
11821191
<div className='grid grid-cols-3 gap-2'>
11831192
<button
11841193
onClick={() => handleResolveDispute(dispute.id, 'approve')}
1185-
disabled={hooks.resolveDispute.isLoading}
1194+
disabled={disputeLoadingStates[dispute.id]}
11861195
className='px-3 py-2 bg-green-500/20 hover:bg-green-500/30 border border-green-400/30 rounded-lg text-green-300 hover:text-green-200 transition-colors text-sm'
11871196
>
1188-
{hooks.resolveDispute.isLoading ? '...' : 'Approve'}
1197+
{disputeLoadingStates[dispute.id] ? '...' : 'Approve'}
11891198
</button>
11901199
<button
11911200
onClick={() => handleResolveDispute(dispute.id, 'reject')}
1192-
disabled={hooks.resolveDispute.isLoading}
1201+
disabled={disputeLoadingStates[dispute.id]}
11931202
className='px-3 py-2 bg-red-500/20 hover:bg-red-500/30 border border-red-400/30 rounded-lg text-red-300 hover:text-red-200 transition-colors text-sm'
11941203
>
1195-
{hooks.resolveDispute.isLoading ? '...' : 'Reject'}
1204+
{disputeLoadingStates[dispute.id] ? '...' : 'Reject'}
11961205
</button>
11971206
<button
11981207
onClick={() => handleResolveDispute(dispute.id, 'modify')}
1199-
disabled={hooks.resolveDispute.isLoading}
1208+
disabled={disputeLoadingStates[dispute.id]}
12001209
className='px-3 py-2 bg-yellow-500/20 hover:bg-yellow-500/30 border border-yellow-400/30 rounded-lg text-yellow-300 hover:text-yellow-200 transition-colors text-sm'
12011210
>
1202-
{hooks.resolveDispute.isLoading ? '...' : 'Modify'}
1211+
{disputeLoadingStates[dispute.id] ? '...' : 'Modify'}
12031212
</button>
12041213
</div>
12051214
</div>

components/demos/HelloMilestoneDemo.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,18 @@ export const HelloMilestoneDemo = ({
132132
};
133133

134134
// Check if demo was already completed
135-
const isCompleted = account?.demosCompleted?.includes('hello-milestone') || false;
135+
const isCompleted = (() => {
136+
if (!account?.demosCompleted) return false;
137+
138+
// Handle both array and object formats for demosCompleted
139+
if (Array.isArray(account.demosCompleted)) {
140+
return account.demosCompleted.includes('hello-milestone');
141+
} else if (typeof account.demosCompleted === 'object') {
142+
return Object.values(account.demosCompleted).includes('hello-milestone');
143+
}
144+
145+
return false;
146+
})();
136147

137148
// Demo completion tracking is now handled by FirebaseContext
138149

components/layout/Header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export const Header = () => {
151151
</span>
152152
<span className='text-xs text-white/70'>Level:</span>
153153
<span className='text-sm font-semibold text-blue-400'>
154-
{account?.level || 1}
154+
{account ? Math.floor((account.experience || 0) / 1000) + 1 : 1}
155155
</span>
156156
</div>
157157

0 commit comments

Comments
 (0)