Skip to content

Commit 6005c1b

Browse files
committed
feat: update EmailJS referral template with SVG badge icons and improve layout
- Replace emoji icons with actual SVG badge icons from BADGE_SVG_ICONS - Add points display for each badge in Top Badges section - Update phase character names (Nexus Guardian, Trustless Explorer, Stellar Builder) - Simplify phase descriptions (Baby Steps, Intermediate, Advanced) - Add Extra Badges section with point values - Fix user_email parameter for EmailJS recipient configuration - Improve What You'll Discover section with detailed description - Add Telegram link to footer - Update Special Bonus text to include referrer name - Reorganize layout with 2-column grid for badges - Add all EmailJS template variables at top for reference
1 parent 1ac34fe commit 6005c1b

13 files changed

Lines changed: 1187 additions & 98 deletions

File tree

components/layout/Header.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export const Header = () => {
9898
<span>Demos</span>
9999
</a> */}
100100
{/* Only show Nexus Web3 Playground when wallet is connected */}
101-
{isConnected && (
101+
{/* {isConnected && (
102102
<Tooltip
103103
position='bottom'
104104
content={
@@ -133,7 +133,7 @@ export const Header = () => {
133133
</span>
134134
</a>
135135
</Tooltip>
136-
)}
136+
)} */}
137137
</nav>
138138

139139
{/* Header Controls */}

components/ui/auth/AuthModal.tsx

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import React, { useState, useEffect } from 'react';
44
import { useAuth } from '@/contexts/auth/AuthContext';
55
import { useGlobalWallet } from '@/contexts/wallet/WalletContext';
6+
import { useFirebase } from '@/contexts/data/FirebaseContext';
7+
import { ReferralCodeModal } from '@/components/ui/modals/ReferralCodeModal';
68
import Image from 'next/image';
79

810
interface AuthModalProps {
@@ -14,13 +16,16 @@ interface AuthModalProps {
1416
export const AuthModal: React.FC<AuthModalProps> = ({ isOpen, onClose, mode }) => {
1517
const { signUp, signIn, initializeUserWithFirebase, isLoading, error } = useAuth();
1618
const { walletData, isConnected } = useGlobalWallet();
19+
const { initializeAccount } = useFirebase();
1720
const [currentMode, setCurrentMode] = useState<'signup' | 'signin'>(mode);
1821
const [formData, setFormData] = useState({
1922
username: '',
2023
email: '',
2124
});
2225
const [isSubmitting, setIsSubmitting] = useState(false);
2326
const [isBenefitsExpanded, setIsBenefitsExpanded] = useState(false);
27+
const [showReferralModal, setShowReferralModal] = useState(false);
28+
const [pendingReferralCode, setPendingReferralCode] = useState<string | null>(null);
2429

2530
// Random username suggestions
2631
const usernameSuggestions = [
@@ -251,6 +256,17 @@ export const AuthModal: React.FC<AuthModalProps> = ({ isOpen, onClose, mode }) =
251256
setFormData({ username: '', email: '' });
252257
}, [mode]);
253258

259+
// Check for referral code in URL
260+
useEffect(() => {
261+
if (isOpen && currentMode === 'signup') {
262+
const urlParams = new URLSearchParams(window.location.search);
263+
const refCode = urlParams.get('ref');
264+
if (refCode) {
265+
setPendingReferralCode(refCode);
266+
}
267+
}
268+
}, [isOpen, currentMode]);
269+
254270
// Handle escape key to close modal
255271
useEffect(() => {
256272
const handleEscape = (e: KeyboardEvent) => {
@@ -274,19 +290,46 @@ export const AuthModal: React.FC<AuthModalProps> = ({ isOpen, onClose, mode }) =
274290
setIsSubmitting(true);
275291
try {
276292
if (currentMode === 'signup') {
277-
// Use Firebase initialization for new users
278-
await initializeUserWithFirebase(formData.username);
293+
// Check if we have a pending referral code or need to show referral modal
294+
if (pendingReferralCode || formData.email) {
295+
setShowReferralModal(true);
296+
} else {
297+
// Use Firebase initialization for new users
298+
await initializeAccount(formData.username);
299+
onClose();
300+
}
279301
} else {
280302
await signIn(walletData.publicKey);
303+
onClose();
281304
}
282-
onClose();
283305
} catch (err) {
284306
console.error('Error in signIn:', err);
285307
} finally {
286308
setIsSubmitting(false);
287309
}
288310
};
289311

312+
const handleReferralCodeSubmit = async (referralCode: string) => {
313+
try {
314+
await initializeAccount(formData.username, referralCode, formData.email);
315+
setShowReferralModal(false);
316+
onClose();
317+
} catch (err) {
318+
console.error('Error creating account with referral code:', err);
319+
throw err;
320+
}
321+
};
322+
323+
const handleReferralModalClose = async () => {
324+
try {
325+
await initializeAccount(formData.username, undefined, formData.email);
326+
setShowReferralModal(false);
327+
onClose();
328+
} catch (err) {
329+
console.error('Error creating account:', err);
330+
}
331+
};
332+
290333
const switchMode = () => {
291334
setCurrentMode(currentMode === 'signup' ? 'signin' : 'signup');
292335
setFormData({ username: '', email: '' });
@@ -532,6 +575,14 @@ export const AuthModal: React.FC<AuthModalProps> = ({ isOpen, onClose, mode }) =
532575
</svg>
533576
</button>
534577
</div>
578+
579+
{/* Referral Code Modal */}
580+
<ReferralCodeModal
581+
isOpen={showReferralModal}
582+
onClose={handleReferralModalClose}
583+
onReferralCodeSubmit={handleReferralCodeSubmit}
584+
userEmail={formData.email}
585+
/>
535586
</div>
536587
);
537588
};
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
'use client';
2+
3+
import React, { useState, useEffect } from 'react';
4+
import { ReferralService } from '@/lib/services/referral-service';
5+
import { Account } from '@/lib/firebase/firebase-types';
6+
7+
interface ReferralCodeModalProps {
8+
isOpen: boolean;
9+
onClose: () => void;
10+
onReferralCodeSubmit: (referralCode: string) => Promise<void>;
11+
userEmail?: string;
12+
}
13+
14+
export const ReferralCodeModal: React.FC<ReferralCodeModalProps> = ({
15+
isOpen,
16+
onClose,
17+
onReferralCodeSubmit,
18+
userEmail,
19+
}) => {
20+
const [referralCode, setReferralCode] = useState('');
21+
const [isSubmitting, setIsSubmitting] = useState(false);
22+
const [error, setError] = useState('');
23+
const [hasPendingInvitation, setHasPendingInvitation] = useState(false);
24+
const [pendingReferralCode, setPendingReferralCode] = useState('');
25+
const [referrerName, setReferrerName] = useState('');
26+
27+
useEffect(() => {
28+
if (isOpen && userEmail) {
29+
checkPendingInvitation();
30+
}
31+
}, [isOpen, userEmail]);
32+
33+
const checkPendingInvitation = async () => {
34+
if (!userEmail) return;
35+
36+
try {
37+
const result = await ReferralService.checkPendingInvitation(userEmail);
38+
if (result.success && result.hasInvitation) {
39+
setHasPendingInvitation(true);
40+
setPendingReferralCode(result.referralCode || '');
41+
setReferrerName(result.referrerName || '');
42+
setReferralCode(result.referralCode || '');
43+
}
44+
} catch (error) {
45+
console.error('Error checking pending invitation:', error);
46+
}
47+
};
48+
49+
const handleSubmit = async (e: React.FormEvent) => {
50+
e.preventDefault();
51+
if (!referralCode.trim()) {
52+
setError('Please enter a referral code');
53+
return;
54+
}
55+
56+
setIsSubmitting(true);
57+
setError('');
58+
59+
try {
60+
await onReferralCodeSubmit(referralCode.trim());
61+
onClose();
62+
} catch (err) {
63+
setError(err instanceof Error ? err.message : 'Invalid referral code');
64+
} finally {
65+
setIsSubmitting(false);
66+
}
67+
};
68+
69+
const handleSkip = () => {
70+
onClose();
71+
};
72+
73+
if (!isOpen) return null;
74+
75+
return (
76+
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-50 p-4">
77+
<div className="bg-gradient-to-br from-slate-900 to-slate-800 rounded-2xl p-8 w-full max-w-md border border-white/20 shadow-2xl">
78+
{/* Header */}
79+
<div className="text-center mb-6">
80+
<div className="text-4xl mb-3">🎁</div>
81+
<h2 className="text-2xl font-bold text-white mb-2">
82+
{hasPendingInvitation ? 'Welcome!' : 'Have a Referral Code?'}
83+
</h2>
84+
<p className="text-white/70 text-sm">
85+
{hasPendingInvitation
86+
? `${referrerName} invited you to join Trustless Work!`
87+
: 'Enter a referral code to earn bonus XP when you create your account.'}
88+
</p>
89+
</div>
90+
91+
{/* Referral Code Input */}
92+
<form onSubmit={handleSubmit} className="space-y-4">
93+
<div>
94+
<label className="block text-sm font-medium text-white/70 mb-2">
95+
Referral Code
96+
</label>
97+
<div className="relative">
98+
<input
99+
type="text"
100+
value={referralCode}
101+
onChange={(e) => setReferralCode(e.target.value.toUpperCase())}
102+
placeholder="Enter referral code (e.g., ABC123-XYZ789)"
103+
className="w-full bg-black/20 border border-white/20 rounded-lg px-4 py-3 text-white placeholder-white/50 focus:outline-none focus:border-blue-400 transition-colors font-mono text-center"
104+
maxLength={15}
105+
disabled={isSubmitting}
106+
/>
107+
{hasPendingInvitation && (
108+
<div className="absolute -top-2 -right-2 w-4 h-4 bg-green-500 rounded-full flex items-center justify-center">
109+
<span className="text-white text-xs"></span>
110+
</div>
111+
)}
112+
</div>
113+
{hasPendingInvitation && (
114+
<p className="text-green-400 text-xs mt-1">
115+
This code was found for your email address
116+
</p>
117+
)}
118+
</div>
119+
120+
{/* Error Message */}
121+
{error && (
122+
<div className="bg-red-500/20 border border-red-500/30 rounded-lg p-3">
123+
<p className="text-red-300 text-sm">{error}</p>
124+
</div>
125+
)}
126+
127+
{/* Benefits Info */}
128+
<div className="bg-blue-500/10 border border-blue-500/20 rounded-lg p-4">
129+
<h3 className="text-blue-300 font-medium text-sm mb-2">🎯 Referral Benefits</h3>
130+
<ul className="text-blue-200/80 text-xs space-y-1">
131+
<li>• You get <span className="font-bold text-blue-300">+25 XP</span> bonus</li>
132+
<li>• Your referrer gets <span className="font-bold text-blue-300">+50 XP</span></li>
133+
<li>• Unlock special referral badges</li>
134+
<li>• Join the community together!</li>
135+
</ul>
136+
</div>
137+
138+
{/* Action Buttons */}
139+
<div className="flex gap-3 pt-2">
140+
<button
141+
type="button"
142+
onClick={handleSkip}
143+
disabled={isSubmitting}
144+
className="flex-1 px-4 py-3 bg-white/10 hover:bg-white/20 text-white rounded-lg transition-colors disabled:opacity-50"
145+
>
146+
Skip
147+
</button>
148+
<button
149+
type="submit"
150+
disabled={!referralCode.trim() || isSubmitting}
151+
className="flex-1 px-4 py-3 bg-gradient-to-r from-blue-500 to-purple-500 hover:from-blue-600 hover:to-purple-600 text-white rounded-lg transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed font-medium"
152+
>
153+
{isSubmitting ? 'Processing...' : 'Apply Code'}
154+
</button>
155+
</div>
156+
</form>
157+
158+
{/* Footer */}
159+
<div className="text-center mt-6">
160+
<p className="text-white/50 text-xs">
161+
You can always add a referral code later in your account settings
162+
</p>
163+
</div>
164+
</div>
165+
</div>
166+
);
167+
};

components/ui/modals/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export { DemoFeedbackModal } from './DemoFeedbackModal';
22
export { SimpleFeedbackModal } from './SimpleFeedbackModal';
33
export { ImmersiveDemoModal } from './ImmersiveDemoModal';
4+
export { ReferralCodeModal } from './ReferralCodeModal';
45
export { TechTreeModal } from './TechTreeModal';
56
export { Web3OnboardingModal } from './Web3OnboardingModal';

components/ui/quest/QuestAndReferralSection.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ export const QuestAndReferralSection: React.FC<QuestAndReferralSectionProps> = (
152152
<ReferralSystem
153153
account={account}
154154
onReferralComplete={onReferralComplete}
155+
onAccountRefresh={refreshAccountData}
155156
/>
156157
)}
157158
</div>

0 commit comments

Comments
 (0)