Skip to content

Commit db0ace9

Browse files
committed
Implement dummy quests in QuestsTab + Quest component
1 parent 744ad08 commit db0ace9

2 files changed

Lines changed: 237 additions & 2 deletions

File tree

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,88 @@
1+
'use client';
2+
3+
import QuestItem, { Quest } from '@/components/QuestItem';
4+
5+
const dummyQuests: Quest[] = [
6+
{
7+
number: 1,
8+
quest_id: 'quest_1',
9+
type: 'wallet',
10+
title: 'Create your wallet',
11+
description:
12+
'Set up your first Web3 wallet to start your blockchain journey. This will be your digital identity for all future interactions.',
13+
points: 20,
14+
action: 'View wallet',
15+
status: 'completed',
16+
is_locked: false,
17+
},
18+
{
19+
number: 2,
20+
quest_id: 'quest_2',
21+
type: 'ticket',
22+
title: 'Connect your event ticket',
23+
description:
24+
'Scan the QR code on your attendee badge to connect your Devconnect ticket to your wallet.',
25+
points: 10,
26+
action: 'Open camera',
27+
status: 'active',
28+
is_locked: false,
29+
},
30+
{
31+
number: 3,
32+
quest_id: 'quest_3',
33+
type: 'profile',
34+
title: 'Set up your profile',
35+
description:
36+
"Customize your profile with your name, avatar, and social links. Let other attendees know who you are and what you're working on.",
37+
points: 10,
38+
action: 'Edit profile',
39+
status: 'locked',
40+
is_locked: true,
41+
},
42+
{
43+
number: 4,
44+
quest_id: 'quest_4',
45+
type: 'glossary',
46+
title: 'Visit the Glossary',
47+
description:
48+
'Explore our comprehensive glossary of blockchain and Web3 terms. Perfect for newcomers and a great refresher for veterans.',
49+
points: 20,
50+
action: 'Browse terms',
51+
status: 'locked',
52+
is_locked: true,
53+
},
54+
{
55+
number: 5,
56+
quest_id: 'quest_5',
57+
type: 'quiz',
58+
title: "Complete the 'Crypto Risks' mini-quiz",
59+
description:
60+
'Test your knowledge about cryptocurrency risks and security best practices. Learn how to protect your digital assets.',
61+
points: 50,
62+
action: 'Start quiz',
63+
status: 'locked',
64+
is_locked: true,
65+
},
66+
{
67+
number: 6,
68+
quest_id: 'quest_6',
69+
type: 'funds',
70+
title: 'Add funds to your wallet',
71+
description:
72+
'Add some ETH or other supported tokens to your wallet to participate in transactions and interact with dApps.',
73+
points: 30,
74+
action: 'Add funds',
75+
status: 'locked',
76+
is_locked: true,
77+
},
78+
];
79+
180
export default function QuestsTab() {
2-
return <div className="py-8 text-center">Quests tab content here</div>;
3-
}
81+
return (
82+
<div className="w-full max-w-2xl mx-auto flex flex-col justify-start items-start gap-3">
83+
{dummyQuests.map((quest) => (
84+
<QuestItem key={quest.quest_id} quest={quest} />
85+
))}
86+
</div>
87+
);
88+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
'use client';
2+
3+
import { useState } from 'react';
4+
5+
interface Quest {
6+
number: number;
7+
quest_id: string;
8+
type: string;
9+
title: string;
10+
description?: string;
11+
points: number;
12+
action?: string;
13+
status: 'completed' | 'active' | 'locked';
14+
is_locked: boolean;
15+
}
16+
17+
const StarIcon = ({ isCompleted }: { isCompleted: boolean }) => {
18+
const fillColor = isCompleted ? '#232336' : '#F6B40E';
19+
20+
return (
21+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
22+
<path d="M11.43 3.9975H7.99875V4.57125H7.42875V5.14125H6.85875V5.71125H6.285V1.71375H6.85875V0.57H6.285V0H5.715V0.57H5.14125V1.71375H4.57125V2.8575H4.00125V3.9975H0.57V4.57125H0V5.14125H0.57V5.71125H1.14375V6.285H2.2875V6.855H2.8575V7.99875H3.4275V7.42875H4.57125V6.855H5.715V7.42875H5.14125V7.99875H4.57125V8.56875H4.00125V9.1425H3.4275V9.7125H2.8575V10.2863H2.2875V10.8563H1.71375V10.2863H1.14375V11.4262H1.71375V12H2.8575V11.4262H3.4275V10.8563H4.57125V10.2863H5.14125V9.7125H5.715V9.1425H6.285V7.42875H6.85875V7.99875H7.42875V8.56875H7.99875V9.1425H8.5725V9.7125H9.1425V10.2863H9.7125V11.4262H9.1425V12H10.2863V11.4262H10.8563V10.2863H10.2863V9.1425H9.7125V7.99875H9.1425V6.855H9.7125V6.285H8.5725V6.855H6.285V6.285H7.99875V5.71125H8.5725V5.14125H10.8563V5.71125H11.43V5.14125H12V4.57125H11.43V3.9975ZM5.14125 6.285H4.00125V5.71125H2.8575V5.14125H1.71375V4.57125H4.57125V5.14125H5.14125V6.285Z" fill={fillColor}/>
23+
<path d="M10.8557 5.71204H9.71191V6.28579H10.8557V5.71204Z" fill={fillColor}/>
24+
<path d="M9.14227 10.8549H8.57227V11.4249H9.14227V10.8549Z" fill={fillColor}/>
25+
<path d="M8.57258 10.2858H7.42883V10.8558H8.57258V10.2858Z" fill={fillColor}/>
26+
<path d="M7.99883 2.85608H7.42883V3.99608H7.99883V2.85608Z" fill={fillColor}/>
27+
<path d="M7.4284 9.71289H6.8584V10.2866H7.4284V9.71289Z" fill={fillColor}/>
28+
<path d="M7.4284 1.71423H6.8584V2.85798H7.4284V1.71423Z" fill={fillColor}/>
29+
<path d="M6.85793 9.14392H6.28418V9.71392H6.85793V9.14392Z" fill={fillColor}/>
30+
<path d="M2.85711 7.99902H2.28711V9.14277H2.85711V7.99902Z" fill={fillColor}/>
31+
<path d="M2.28762 9.14392H1.71387V10.2877H2.28762V9.14392Z" fill={fillColor}/>
32+
</svg>
33+
);
34+
};
35+
36+
const LockIcon = () => {
37+
return (
38+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
39+
<path d="M10.2844 5.14136H9.71436V10.8564H10.2844V5.14136Z" fill="white"/>
40+
<path d="M9.71438 10.8562H9.14062V11.43H9.71438V10.8562Z" fill="white"/>
41+
<path d="M9.14059 11.4299H2.85559V11.9999H9.14059V11.4299Z" fill="white"/>
42+
<path d="M8.57061 0.570068H8.00061V1.14382H8.57061V0.570068Z" fill="white"/>
43+
<path d="M6.85684 7.42866H6.28684V6.85866H6.85684V6.28491H5.14309V6.85866H4.56934V7.99866H5.14309V8.57241H5.71309V10.2862H6.28684V8.57241H6.85684V7.99866H7.42684V6.85866H6.85684V7.42866Z" fill="white"/>
44+
<path d="M8.00052 0H3.99927V0.57H8.00052V0Z" fill="white"/>
45+
<path d="M3.99932 0.570068H3.42932V1.14382H3.99932V0.570068Z" fill="white"/>
46+
<path d="M9.71427 5.1413V4.5713H9.14052V1.1438H8.57052V4.5713H3.42927V1.1438H2.85552V4.5713H2.28552V5.1413H9.71427Z" fill="white"/>
47+
<path d="M2.85552 10.8562H2.28552V11.43H2.85552V10.8562Z" fill="white"/>
48+
<path d="M2.28558 5.14136H1.71558V10.8564H2.28558V5.14136Z" fill="white"/>
49+
</svg>
50+
);
51+
};
52+
53+
const QuestItem = ({ quest }: { quest: Quest }) => {
54+
const [isExpanded, setIsExpanded] = useState(false);
55+
56+
const getStatusStyles = () => {
57+
switch (quest.status) {
58+
case 'completed':
59+
return {
60+
container: 'bg-[#eaf9eb]',
61+
badge: 'bg-[#9aeea0]',
62+
points: 'text-[#232336]',
63+
};
64+
case 'active':
65+
return {
66+
container: 'bg-[#e8f3fb] outline outline-1 outline-offset-[-1px] outline-[#1b6fae]',
67+
badge: 'bg-[#4b4b66] rounded-[1px]',
68+
points: 'text-[#f6b40e]',
69+
};
70+
case 'locked':
71+
return {
72+
container: 'bg-[#f5f5f9] outline outline-1 outline-offset-[-1px] outline-[#dfdfeb]',
73+
badge: 'bg-[#4b4b66] rounded-[1px]',
74+
points: 'text-[#f6b40e]',
75+
};
76+
}
77+
};
78+
79+
const styles = getStatusStyles();
80+
81+
const handleClick = () => {
82+
setIsExpanded(!isExpanded);
83+
};
84+
85+
return (
86+
<div
87+
className={`w-full p-4 relative ${styles.container} rounded-[1px] flex flex-col justify-start items-start gap-2 cursor-pointer transition-all duration-200 min-h-[80px] ${
88+
isExpanded ? 'shadow-lg' : 'hover:shadow-md'
89+
}`}
90+
onClick={handleClick}
91+
>
92+
<div className="w-full flex flex-col justify-start items-start gap-1">
93+
<div className={`w-full justify-start text-[11px] font-medium font-['Roboto'] leading-[14.30px] tracking-wide ${
94+
quest.status === 'completed' ? 'text-[#199821]' : 'text-[#4b4b66]'
95+
}`}>
96+
{quest.number === 6 ? 'FINAL QUEST' : `QUEST ${quest.type.toUpperCase()}`}
97+
</div>
98+
<div className="w-full justify-start text-[#232336] text-lg font-bold font-['Roboto'] leading-normal">
99+
{quest.title}
100+
</div>
101+
{isExpanded && quest.description && (
102+
<div className="w-full justify-start text-[#232336] text-sm font-normal font-['Roboto'] leading-[21px] mt-2">
103+
{quest.description}
104+
</div>
105+
)}
106+
</div>
107+
108+
{/* Points badge */}
109+
<div className={`size- p-1 left-[${quest.number >= 3 ? '300' : '292'}px] top-[8px] absolute ${styles.badge} inline-flex justify-center items-center gap-1`}>
110+
<StarIcon isCompleted={quest.status === 'completed'} />
111+
<div className={`justify-start ${styles.points} text-${quest.number >= 3 ? 'xs' : 'sm'} font-black font-['Unibody_8_Pro'] leading-${quest.number >= 3 ? '3' : '[14px]'}`}>
112+
{quest.points}
113+
</div>
114+
</div>
115+
116+
{/* Action button - only show when expanded */}
117+
{isExpanded && quest.action && (
118+
<div className={`w-full pl-6 pr-4 py-4 flex justify-center items-center gap-1 mt-2 ${
119+
quest.status === 'active'
120+
? 'bg-[#1b6fae] shadow-[inset_0px_6px_0px_0px_rgba(75,138,185,1.00)] shadow-[inset_0px_-6px_0px_0px_rgba(19,79,124,1.00)]'
121+
: 'bg-[#4b4b66] shadow-[inset_0px_6px_0px_0px_rgba(75,75,102,1.00)] shadow-[inset_0px_-6px_0px_0px_rgba(37,37,51,1.00)]'
122+
}`}>
123+
<div className="text-center text-white text-sm font-bold font-['Roboto'] uppercase leading-[14px]">
124+
{quest.action}
125+
</div>
126+
<div className="size-5 relative overflow-hidden">
127+
<div className="w-[7.20px] h-3 left-[6.40px] top-[4px] absolute bg-white" />
128+
</div>
129+
</div>
130+
)}
131+
132+
{/* Lock icon for locked quests */}
133+
{quest.status === 'locked' && quest.number === 6 && (
134+
<div className="size- p-1 left-[276px] top-[8px] absolute bg-[#4b4b66] rounded-[1px] inline-flex justify-center items-center gap-1">
135+
<LockIcon />
136+
</div>
137+
)}
138+
139+
{/* Expand/collapse indicator */}
140+
<div className={`absolute right-4 top-4 transition-transform duration-200 ${isExpanded ? 'rotate-180' : ''}`}>
141+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
142+
<path d="M2 4L6 8L10 4" stroke={quest.status === 'completed' ? '#232336' : '#4b4b66'} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
143+
</svg>
144+
</div>
145+
</div>
146+
);
147+
};
148+
149+
export default QuestItem;
150+
export type { Quest };

0 commit comments

Comments
 (0)