@@ -5,18 +5,18 @@ import {
55 PlannableStatus ,
66 Progress ,
77 RequirementRule ,
8- Status ,
98} from "@/lib/general-types" ;
109import { cn } from "@/lib/utils" ;
1110import {
1211 CaretDownIcon ,
1312 CaretUpIcon ,
14- PlusCircleIcon ,
13+ PlusIcon ,
14+ Check ,
15+ Minus ,
16+ X ,
1517} from "@phosphor-icons/react" ;
1618import { CalendarBlankIcon } from "@phosphor-icons/react/dist/ssr" ;
17- import { CheckIcon } from "lucide-react" ;
1819import { useState } from "react" ;
19- import { FramedStatusIcon } from "./gpa-credit-cards" ;
2020import { useAuditContext } from "../providers/audit-provider" ;
2121import { useCourseModalContext } from "../providers/course-modal-provider" ;
2222
@@ -35,50 +35,57 @@ const getRequirementCompletionState = (
3535 return "in-progress" ;
3636} ;
3737
38- const StatusIcon = ( {
39- current,
40- total,
41- } : {
42- current : number ;
43- total : number ;
44- } ) => {
38+ const RequirementStatusIcon = ( { current, total } : { current : number ; total : number } ) => {
4539 const state = getRequirementCompletionState ( current , total ) ;
4640
47- return < FramedStatusIcon state = { state } /> ;
41+ if ( state === "completed" ) {
42+ return (
43+ < div className = "flex items-center justify-center w-6 h-6 bg-[#5BA753] rounded shrink-0 mt-0.5" >
44+ < Check className = "text-white w-4 h-4" weight = "bold" />
45+ </ div >
46+ ) ;
47+ }
48+ if ( state === "not-started" ) {
49+ return (
50+ < div className = "flex items-center justify-center w-6 h-6 bg-[#4A5568] rounded shrink-0 mt-0.5" >
51+ < X className = "text-white w-4 h-4" weight = "bold" />
52+ </ div >
53+ ) ;
54+ }
55+ return (
56+ < div className = "flex items-center justify-center w-6 h-6 bg-[#9CA3AF] rounded shrink-0 mt-0.5" >
57+ < Minus className = "text-white w-4 h-4" weight = "bold" />
58+ </ div >
59+ ) ;
4860} ;
4961
5062// Hours badge component
5163const HoursBadge = ( { current, total } : { current : number ; total : number } ) => {
5264 const isComplete = current >= total ;
5365 const formatHours = ( h : number ) => `${ h } hour${ h === 1 ? '' : 's' } ` ;
5466 return (
55- < span className = "text-sm text-gray-600 border border-gray-300 rounded-full px-3 py-1 " >
67+ < span className = "text-sm text-gray-900 border border-gray-800 rounded-full px-3 py-0.5 font-medium " >
5668 { isComplete ? formatHours ( total ) : `${ current } / ${ formatHours ( total ) } ` }
5769 </ span >
5870 ) ;
5971} ;
6072
6173const statusIcons = {
6274 Completed : {
63- icon : (
64- < CheckIcon className = "-ml-1 text-white w-5 h-5 bg-green-500 rounded-full p-1" />
65- ) ,
66- color : "bg-[var(--color-course-applied)]" ,
75+ icon : null ,
76+ color : "bg-[#ECF8D0] border-[#9FCA5B]" ,
6777 } ,
6878 Planned : {
69- icon : (
70- < CalendarBlankIcon className = "-ml-1 text-white w-5 h-5 bg-blue-500 rounded-full p-1" />
71- ) ,
72- color : "bg-[var(--color-course-applied)]" ,
79+ icon : null ,
80+ color : "bg-[var(--color-course-applied)] border-gray-200" ,
7381 } ,
7482 "In Progress" : {
7583 icon : null ,
76- color : "bg-[var(--color-course-in-progress)]" ,
84+ color : "bg-[var(--color-course-in-progress)] border-gray-200 " ,
7785 } ,
78- // TODO: make sure this is valid
7986 "Not Started" : {
8087 icon : null ,
81- color : "bg-[var(--color-course-unknown)]" ,
88+ color : "bg-[var(--color-course-unknown)] border-gray-200 " ,
8289 } ,
8390} as const satisfies Record <
8491 PlannableStatus ,
@@ -93,17 +100,17 @@ const CoursePill = ({ course }: { course: Course }) => {
93100 return (
94101 < div
95102 className = { cn (
96- "flex items-center gap-6 px-4 py-3 rounded-lg text-sm w-[80%] " ,
103+ "grid grid-cols-[100px_1fr_auto] items-center gap-4 px-4 py-3 rounded-lg text-sm w-full border " ,
97104 statusIcons [ course . status ] . color ,
98105 ) }
99106 >
100- < span className = "font-semibold min-w-[80px] " > { course . code } </ span >
101- < span className = "flex-1 " >
107+ < span className = "font-bold text-gray-900 text-left " > { course . code } </ span >
108+ < span className = "text-left font-medium text-gray-900 " >
102109 { course . name }
103110 </ span >
104- < span className = "text-gray-700 " >
111+ < span className = "text-right text- gray-800 " >
105112 { isValidSemester ? course . semester : '' }
106- { isApplied && course . grade && ` ${ isValidSemester ? ' - ' : '' } Grade: ${ course . grade } `}
113+ { isApplied && course . grade ? ` - Grade: ${ course . grade } ` : '' }
107114 </ span >
108115 </ div >
109116 ) ;
@@ -126,6 +133,8 @@ const parseRequirementCode = (
126133// Individual requirement row with expandable courses
127134const RequirementRow = ( { requirement } : { requirement : RequirementRule } ) => {
128135 const { getCourseById } = useAuditContext ( ) ;
136+ const { openModal } = useCourseModalContext ( ) ;
137+
129138 const courses = requirement . courses . map ( ( courseId ) =>
130139 getCourseById ( courseId ) ,
131140 ) ;
@@ -136,40 +145,51 @@ const RequirementRow = ({ requirement }: { requirement: RequirementRule }) => {
136145 ) ;
137146
138147 return (
139- < div className = "border-b border-gray-100 last:border-b-0 " >
148+ < div className = "border border-gray-200 rounded-lg mb-3 last:mb-0 overflow-hidden " >
140149 { /* Requirement header */ }
141150 < button
142- className = "w-full py-3 px-2 flex items-start gap-3 hover:bg-gray-50 transition-colors"
151+ className = "w-full py-3 px-3 flex items-start gap-3 hover:bg-gray-50 transition-colors bg-white "
143152 onClick = { ( ) => setIsExpanded ( ! isExpanded ) }
144153 >
145- < StatusIcon
154+ < RequirementStatusIcon
146155 current = { requirement . appliedHours }
147156 total = { requirement . requiredHours }
148157 />
149158 < VStack gap = { 0 } className = "flex-1 text-left" >
150- < span className = "font-bold text-base" > { code } </ span >
151- < span className = "text-sm text-gray-500 " > { description } </ span >
159+ < span className = "font-bold text-base text-gray-900 " > { code } </ span >
160+ < span className = "text-sm text-gray-600 mt-0.5 " > { description } </ span >
152161 </ VStack >
153- < HStack y = "middle" gap = { 2 } >
162+ < HStack y = "middle" gap = { 3 } >
154163 < HoursBadge
155164 current = { requirement . appliedHours }
156165 total = { requirement . requiredHours }
157166 />
158167 { isExpanded ? (
159- < CaretUpIcon className = "w-5 h-5 text-gray-400 " />
168+ < CaretUpIcon className = "w-5 h-5 text-gray-900" weight = "bold " />
160169 ) : (
161- < CaretDownIcon className = "w-5 h-5 text-gray-400 " />
170+ < CaretDownIcon className = "w-5 h-5 text-gray-900" weight = "bold " />
162171 ) }
163172 </ HStack >
164173 </ button >
165174
166- { /* Expanded courses */ }
167- { isExpanded && requirement . courses . length > 0 && (
168- < VStack gap = { 2 } className = "pl-11 pr-4 pb-3 " >
175+ { /* Expanded courses and add button */ }
176+ { isExpanded && (
177+ < div className = "flex flex-col gap-3 pl-12 pr-4 pb-4 bg-white " >
169178 { courses . map ( ( course , idx ) => (
170179 < CoursePill key = { `${ course . code } -${ idx } ` } course = { course } />
171180 ) ) }
172- </ VStack >
181+
182+ < div className = "w-full flex justify-center mt-2" >
183+ < Button
184+ fill = "solid"
185+ className = "bg-[var(--color-dap-orange)] hover:opacity-90 text-white border-none w-max px-[24px] h-[40px] rounded-md font-semibold text-base flex items-center justify-center gap-[16px]"
186+ onClick = { openModal }
187+ >
188+ < PlusIcon className = "w-5 h-5" weight = "bold" />
189+ Add Planned Course
190+ </ Button >
191+ </ div >
192+ </ div >
173193 ) }
174194 </ div >
175195 ) ;
@@ -212,9 +232,14 @@ const ProgressBar = ({
212232} ) => {
213233 const color = CATEGORY_COLORS [ colorIndex % CATEGORY_COLORS . length ] ;
214234 const percentage = Math . min ( ( current / total ) * 100 , 100 ) ;
235+
236+ const trackColor = color . rgb . replace ( "rgb" , "rgba" ) . replace ( ")" , ", 0.2)" ) ;
215237
216238 return (
217- < div className = "w-40 h-2 bg-gray-200 rounded-full overflow-hidden" >
239+ < div
240+ className = "w-40 h-2 rounded-full overflow-hidden"
241+ style = { { backgroundColor : trackColor } }
242+ >
218243 < div
219244 className = "h-full rounded-full transition-all"
220245 style = { { width : `${ percentage } %` , backgroundColor : color . tailwind } }
@@ -230,73 +255,56 @@ type RequirementBreakdownProps = {
230255 colorIndex ?: number ;
231256} ;
232257const RequirementBreakdown = ( props : RequirementBreakdownProps ) => {
233- const { openModal } = useCourseModalContext ( ) ;
234258 const { title, hours, requirements, colorIndex = 0 } = props ;
235259 const [ isOpen , setIsOpen ] = useState ( false ) ;
236260 const borderColor = CATEGORY_COLORS [ colorIndex % CATEGORY_COLORS . length ] ;
237261
238262 return (
239263 < div
240- className = "w-full bg-gray-50 rounded-md border border-gray-200 overflow-hidden border-l-8 "
264+ className = "w-full bg-white rounded-md border border-gray-200 overflow-hidden border-l-4 "
241265 style = { { borderLeftColor : borderColor . tailwind } }
242266 >
243267 { /* Main header */ }
244268 < button
245- className = { cn (
246- "w-full p-4 flex items-center justify-between hover:bg-gray-50 transition-colors" ,
247- isOpen && "bg-gray-50" ,
248- ) }
269+ className = "w-full p-4 flex items-center justify-between hover:bg-gray-50 transition-colors bg-white"
249270 onClick = { ( ) => setIsOpen ( ! isOpen ) }
250271 >
251- < VStack gap = { 1 } >
252- < span className = "font-bold text-lg " > { title } </ span >
272+ < VStack gap = { 2 } >
273+ < span className = "font-bold text-base text-gray-900 " > { title } </ span >
253274 < ProgressBar
254275 current = { hours . current }
255276 total = { hours . total }
256277 colorIndex = { colorIndex }
257278 />
258279 </ VStack >
259280 < HStack y = "middle" gap = { 2 } >
260- < span className = "text-gray-600 " >
281+ < span className = "text-gray-900 font-medium text-sm " >
261282 { hours . current . toString ( ) . padStart ( 2 , "0" ) } / { hours . total } hours
262283 </ span >
263284 { isOpen ? (
264- < CaretUpIcon className = "w-5 h-5 text-gray-400 " />
285+ < CaretUpIcon className = "w-5 h-5 text-gray-900" weight = "bold " />
265286 ) : (
266- < CaretDownIcon className = "w-5 h-5 text-gray-400 " />
287+ < CaretDownIcon className = "w-5 h-5 text-gray-900" weight = "bold " />
267288 ) }
268289 </ HStack >
269290 </ button >
270291
271292 { /* Expanded content */ }
272293 { isOpen && (
273- < div className = "border-t border-gray-200 " >
294+ < div className = "bg-white " >
274295 { /* Requirement rows */ }
275- < div className = "px-4 py-2 " >
296+ < div className = "px-4 py-4 " >
276297 { requirements . map ( ( requirement , idx ) => (
277298 < RequirementRow
278299 key = { `${ requirement . text . slice ( 0 , 20 ) } -${ idx } ` }
279300 requirement = { requirement }
280301 />
281302 ) ) }
282303 </ div >
283-
284- { /* Add course button */ }
285- < div className = "px-4 pb-4" >
286- < Button
287- color = "black"
288- fill = "solid"
289- className = "w-full text-base font-semibold py-3 px-6"
290- onClick = { openModal }
291- >
292- < PlusCircleIcon className = "w-5 h-5" />
293- Add Hypothetical Course
294- </ Button >
295- </ div >
296304 </ div >
297305 ) }
298306 </ div >
299307 ) ;
300308} ;
301309
302- export default RequirementBreakdown ;
310+ export default RequirementBreakdown ;
0 commit comments