1
+ import { useState } from "react" ;
2
+ import { Button } from "@/components/ui/button" ;
3
+ import { Card , CardContent } from "@/components/ui/card" ;
4
+ import { motion } from "framer-motion" ;
5
+ import { AnimatePresence } from "framer-motion" ;
6
+
7
+ interface MissionConfig {
8
+ id : number ;
9
+ title : string ;
10
+ description : string ;
11
+ icon : React . ElementType ;
12
+ points : number ;
13
+ internalComponent : React . ElementType ;
14
+ color : string ;
15
+ action : ( ) => void ;
16
+ completedCount : number ;
17
+ } ;
18
+
19
+ interface MissionShellProps {
20
+ missions : MissionConfig [ ] ;
21
+ experiencePoints : number ;
22
+ level : number ;
23
+ currentChapter : number ;
24
+ } ;
25
+
26
+ const MissionShell = ( { missions, experiencePoints, level, currentChapter } : MissionShellProps ) => {
27
+ const [ selectedMission , setSelectedMission ] = useState < MissionConfig | null > ( null ) ;
28
+
29
+ const renderMission = ( mission : MissionConfig ) => {
30
+ return (
31
+ < div
32
+ key = { mission . id }
33
+ className = { `flex items-center p-6 rounded-2xl cursor-pointer shadow-md ${
34
+ mission . completedCount > 0 ? "bg-gray-700" : "bg-blue-500"
35
+ } `}
36
+ onClick = { ( ) => setSelectedMission ( mission ) }
37
+ >
38
+ < mission . icon className = { `w-10 h-10 ${ mission . color } ` } />
39
+ < div className = "ml-4" >
40
+ < h2 className = { `text-lg font-bold ${ mission . color } ` } > { mission . title } </ h2 >
41
+ < p className = { `text-sm ${ mission . color } ` } > { mission . description } </ p >
42
+ < p className = { `text-sm ${ mission . color } ` } > Points: { mission . points } </ p >
43
+ </ div >
44
+ < div className = "ml-auto text-right" >
45
+ < p className = "text-xs" > Completed: { mission . completedCount } </ p >
46
+ < p className = "text-xl font-bold" > { mission . completedCount } </ p >
47
+ </ div >
48
+ </ div >
49
+ ) ;
50
+ } ;
51
+
52
+ return (
53
+ < div className = "flex flex-col items-center bg-[#1D2833] text-white rounded-2xl shadow-lg p-6 w-full max-w-4xl mx-auto" >
54
+ < div className = "flex justify-between w-full mb-6" >
55
+ < h1 className = "text-xl font-bold" > Chapter { currentChapter } </ h1 >
56
+ </ div >
57
+
58
+ < div className = "flex-1 overflow-y-auto w-full" >
59
+ < div className = "w-full bg-gray-700 rounded-full h-4 mb-6" >
60
+ < div
61
+ className = "bg-[#5FCBC3] h-4 rounded-full"
62
+ style = { { width : `${ ( experiencePoints % 9 ) * 10.5 } %` } }
63
+ > </ div >
64
+ </ div >
65
+ </ div >
66
+ < p className = "text-sm text-center mb-6" >
67
+ Level { level } ({ experiencePoints } points)
68
+ </ p >
69
+
70
+ < div className = "bg-gray-700 p-6 rounded-2xl w-full mb-6" >
71
+ < div className = "grid grid-cols-2 gap-4 w-full" >
72
+ { missions . slice ( 0 , 2 ) . map ( ( mission ) => renderMission ( mission ) ) }
73
+ </ div >
74
+ </ div >
75
+
76
+ { /* Mission 3 & Mission 4 below */ }
77
+ < div className = "grid gap-4 w-full mt-6" >
78
+ { missions . slice ( 2 , 4 ) . map ( ( mission ) => renderMission ( mission ) ) }
79
+ </ div >
80
+
81
+ < AnimatePresence >
82
+ { selectedMission && (
83
+ < motion . div
84
+ className = "fixed inset-0 flex justify-center items-center bg-black bg-opacity-50"
85
+ initial = { { opacity : 0 , y : - 10 } }
86
+ animate = { { opacity : 1 , y : 0 } }
87
+ exit = { { opacity : 0 , y : - 10 } }
88
+ >
89
+ < div className = "bg-[#2C4F64] p-6 rounded-lg max-w-md w-full" >
90
+ < h3 className = "text-xl font-semibold mb-2" > { selectedMission . title } </ h3 >
91
+ < p > { selectedMission . description } </ p >
92
+ < div className = "mt-4" >
93
+ { selectedMission . internalComponent && < selectedMission . internalComponent /> }
94
+ </ div >
95
+ < Button onClick = { ( ) => setSelectedMission ( null ) } className = "mt-4" >
96
+ Close
97
+ </ Button >
98
+ </ div >
99
+ </ motion . div >
100
+ ) }
101
+ </ AnimatePresence >
102
+ </ div >
103
+ ) ;
104
+ } ;
105
+
106
+ export default MissionShell ;
0 commit comments