@@ -3,20 +3,26 @@ import React, {useMemo, useState} from "react";
3
3
import { Button , Col , Collapse , Label , Row } from "reactstrap" ;
4
4
import { Link } from "react-router-dom" ;
5
5
import {
6
+ above ,
6
7
determineGameboardStagesAndDifficulties ,
7
8
determineGameboardSubjects ,
8
9
difficultyShortLabelMap ,
9
10
extractTeacherName ,
10
11
generateGameboardSubjectHexagons ,
12
+ HUMAN_SUBJECTS ,
11
13
isDefined ,
12
14
PATHS ,
13
15
siteSpecific ,
14
16
stageLabelMap ,
15
17
TAG_ID ,
16
- tags
18
+ tags ,
19
+ useDeviceSize
17
20
} from "../../services" ;
18
- import { formatDate } from "./DateString" ;
21
+ import { formatDate , FRIENDLY_DATE , getFriendlyDaysUntil } from "./DateString" ;
19
22
import { Circle } from "./svg/Circle" ;
23
+ import { PhyHexIcon } from "./svg/PhyHexIcon" ;
24
+ import { Subject } from "../../../IsaacAppTypes" ;
25
+ import { HoverableTooltip } from "./HoverableTooltip" ;
20
26
21
27
const midnightOf = ( date : Date | number ) => {
22
28
const d = new Date ( date ) ;
@@ -41,6 +47,8 @@ const PhyAssignmentCard = ({assignment}: {assignment: AssignmentDTO}) => {
41
47
const now = new Date ( ) ;
42
48
const boardStagesAndDifficulties = useMemo ( ( ) => determineGameboardStagesAndDifficulties ( assignment . gameboard ) , [ assignment . gameboard ] ) ;
43
49
50
+ const deviceSize = useDeviceSize ( ) ;
51
+
44
52
const topics = tags . getTopicTags ( Array . from ( ( assignment . gameboard ?. contents || [ ] ) . reduce ( ( a , c ) => {
45
53
if ( isDefined ( c . tags ) && c . tags . length > 0 ) {
46
54
return new Set ( [ ...Array . from ( a ) , ...c . tags . map ( id => id as TAG_ID ) ] ) ;
@@ -49,71 +57,90 @@ const PhyAssignmentCard = ({assignment}: {assignment: AssignmentDTO}) => {
49
57
} , new Set < TAG_ID > ( ) ) ) . filter ( tag => isDefined ( tag ) ) ) . map ( tag => tag . title ) . sort ( ) ;
50
58
const assignmentStartDate = assignment . scheduledStartDate ?? assignment . creationDate ;
51
59
52
- return < >
53
- < hr />
54
- < Row className = "board-card" data-testid = "my-assignment" >
55
- < Col xs = { 8 } sm = { 10 } md = { 8 } >
56
- < Link to = { `${ PATHS . GAMEBOARD } #${ assignment . gameboardId } ` } >
57
- < h4 className = "text-break" > { isDefined ( assignment . gameboard ) && assignment . gameboard . title } </ h4 >
58
- </ Link >
59
- { isDefined ( assignmentStartDate ) &&
60
- < p className = "mb-0" data-testid = { "gameboard-assigned" } > < strong > Assigned:</ strong > { formatDate ( assignmentStartDate ) } </ p >
61
- }
62
- { isDefined ( assignment . dueDate ) && isDefined ( assignment . gameboard ) && now > midnightOf ( assignment . dueDate ) && assignment . gameboard . percentageAttempted !== 100
63
- ? < p className = "mb-0" > < strong className = "overdue" > Overdue:</ strong > { formatDate ( assignment . dueDate ) } </ p >
64
- : < > { assignment . dueDate && < p className = "mb-0" > < strong > Due:</ strong > { formatDate ( assignment . dueDate ) } </ p > } </ >
65
- }
66
- { isDefined ( assignment . groupName ) &&
67
- < p className = "mb-0" > < strong > Group:</ strong > { assignment . groupName } </ p >
68
- }
69
- { isDefined ( assignment . assignerSummary ) &&
70
- < p className = "mb-0" > < strong > By:</ strong > { extractTeacherName ( assignment . assignerSummary ) } </ p >
71
- }
72
- { isDefined ( assignment . notes ) && < p className = "mb-0" > < strong > Notes:</ strong > { assignment . notes } </ p > }
73
- < Button className = "my-2 btn-underline" color = "link" onClick = { ( ) => setShowMore ( ! showMore ) } >
74
- { showMore ? "Show less" : "Show more" }
75
- </ Button >
76
- </ Col >
60
+ const boardSubjects = determineGameboardSubjects ( assignment . gameboard ) ;
77
61
78
- < Col xs = { 4 } sm = { 2 } md = { 4 } >
79
- < Row className = "justify-content-end me-0 me-md-1" >
80
- < Col md = "auto" >
81
- < Label className = "d-block w-100 text-center text-nowrap" >
82
- Attempted
83
- < div className = "d-flex w-100 justify-content-center board-subject-hexagon-size" >
84
- < div className = "board-subject-hexagon-container justify-content-center" >
85
- { isDefined ( assignment . gameboard ) && ( ( assignment . gameboard . percentageAttempted === 100 ) ?
86
- < span className = "board-subject-hexagon subject-complete" /> :
87
- < >
88
- { generateGameboardSubjectHexagons ( determineGameboardSubjects ( assignment . gameboard ) ) }
89
- < div className = "board-percent-completed" > { assignment . gameboard . percentageAttempted ?? 0 } </ div >
90
- </ >
91
- ) }
92
- </ div >
93
- </ div >
94
- </ Label >
95
- </ Col >
96
- < Col md = "auto" >
97
- < Label className = "d-block w-100 text-center text-nowrap" >
98
- Correct
99
- < div className = "d-flex w-100 justify-content-center board-subject-hexagon-size" >
100
- < div className = "board-subject-hexagon-container justify-content-center" >
101
- { isDefined ( assignment . gameboard ) && ( ( assignment . gameboard . percentageCorrect === 100 ) ?
102
- < span className = "board-subject-hexagon subject-complete" /> :
103
- < >
104
- { generateGameboardSubjectHexagons ( determineGameboardSubjects ( assignment . gameboard ) ) }
105
- < div className = "board-percent-completed" > { assignment . gameboard . percentageCorrect ?? 0 } </ div >
106
- </ >
107
- ) }
108
- </ div >
109
- </ div >
110
- </ Label >
62
+ return < Link className = "w-100 assignments-card px-3 py-2 mb-3" to = { `${ PATHS . GAMEBOARD } #${ assignment . gameboardId } ` } >
63
+ < Row data-testid = "my-assignment" >
64
+ < Col xs = { 8 } >
65
+ < div className = "d-flex align-items-center" >
66
+ < div className = "d-flex justify-content-center board-subject-hexagon-size me-4 my-2" >
67
+ < div className = "board-subject-hexagon-container justify-content-center" >
68
+ { generateGameboardSubjectHexagons ( boardSubjects ) }
69
+ </ div >
70
+ < PhyHexIcon icon = "page-icon-question-pack" subject = { boardSubjects [ 0 ] as Subject } className = "assignment-hex ps-3" />
71
+ </ div >
72
+ < div className = "d-flex flex-column flex-grow-1" >
73
+ < h4 className = "text-break m-0" > { isDefined ( assignment . gameboard ) && assignment . gameboard . title } </ h4 >
74
+ { above [ 'sm' ] ( deviceSize ) && boardSubjects . length > 0 && < div className = "d-flex align-items-center mb-2" >
75
+ { boardSubjects . map ( ( subject ) => < span key = { subject } className = "badge rounded-pill bg-theme me-1" data-bs-theme = { subject } > { HUMAN_SUBJECTS [ subject ] } </ span > ) }
76
+ </ div > }
77
+ </ div >
78
+ </ div >
79
+
80
+ < Row >
81
+ < Col >
82
+ { isDefined ( assignmentStartDate ) &&
83
+ < p className = "mb-0" data-testid = { "gameboard-assigned" } >
84
+ Assigned{ " " }
85
+ { getFriendlyDaysUntil ( assignmentStartDate ) . startsWith ( "on " )
86
+ ? < strong > { getFriendlyDaysUntil ( assignmentStartDate ) } </ strong >
87
+ : < HoverableTooltip tooltip = { formatDate ( assignmentStartDate , FRIENDLY_DATE ) } >
88
+ < strong > { getFriendlyDaysUntil ( assignmentStartDate ) } </ strong >
89
+ </ HoverableTooltip >
90
+ }
91
+ </ p >
92
+ }
93
+ { isDefined ( assignment . dueDate ) && isDefined ( assignment . gameboard ) && now > midnightOf ( assignment . dueDate ) && assignment . gameboard . percentageAttempted !== 100
94
+ ? < p className = "mb-0" > < strong className = "overdue" > Overdue</ strong > < span className = "small text-muted" > (due { formatDate ( assignment . dueDate ) } )</ span > </ p >
95
+ : < > { assignment . dueDate && < p className = "mb-0" > Due < strong > { getFriendlyDaysUntil ( assignment . dueDate ) } </ strong > </ p > } </ >
96
+ }
111
97
</ Col >
98
+ { above [ 'md' ] ( deviceSize ) && < Col >
99
+ { isDefined ( assignment . groupName ) &&
100
+ < p className = "mb-0" > < strong > Group:</ strong > { assignment . groupName } </ p >
101
+ }
102
+ { isDefined ( assignment . assignerSummary ) &&
103
+ < p className = "mb-0" > < strong > By:</ strong > { extractTeacherName ( assignment . assignerSummary ) } </ p >
104
+ }
105
+ </ Col > }
112
106
</ Row >
107
+
108
+ { assignment . notes && < p className = "mb-0" > < strong > Notes:</ strong > { assignment . notes } </ p > }
109
+ < Button className = "my-2 btn-underline" color = "link" onClick = { ( e ) => { e . preventDefault ( ) ; setShowMore ( ! showMore ) ; } } >
110
+ { showMore ? "Hide details" : "Show details" }
111
+ </ Button >
112
+ </ Col >
113
+
114
+ < Col xs = { 4 } >
115
+ < div className = "d-flex flex-wrap justify-content-center justify-content-md-end justify-content-lg-center justify-content-xl-end column-gap-4" >
116
+ < Label className = "d-block w-max-content text-center text-nowrap pt-3" >
117
+ { isDefined ( assignment . gameboard ) && ( ( assignment . gameboard . percentageAttempted === 100 ) ?
118
+ < span className = "board-subject-hexagon subject-complete" /> :
119
+ < div className = "board-percent-completed" > { assignment . gameboard . percentageAttempted ?? 0 } </ div >
120
+ ) }
121
+ Attempted
122
+ </ Label >
123
+ < Label className = "d-block w-max-content text-center text-nowrap pt-3" >
124
+ { isDefined ( assignment . gameboard ) && ( ( assignment . gameboard . percentageCorrect === 100 ) ?
125
+ < span className = "board-subject-hexagon subject-complete" /> :
126
+ < div className = "board-percent-completed" > { assignment . gameboard . percentageCorrect ?? 0 } </ div >
127
+ ) }
128
+ Correct
129
+ </ Label >
130
+ </ div >
113
131
</ Col >
114
132
</ Row >
115
133
< Collapse isOpen = { showMore } className = "w-100" >
116
134
< Row >
135
+ { ! above [ 'md' ] ( deviceSize ) && < Col xs = { 12 } >
136
+ { isDefined ( assignment . groupName ) &&
137
+ < p className = "mb-0" > < strong > Group:</ strong > { assignment . groupName } </ p >
138
+ }
139
+ { isDefined ( assignment . assignerSummary ) &&
140
+ < p className = "mb-0" > < strong > By:</ strong > { extractTeacherName ( assignment . assignerSummary ) } </ p >
141
+ }
142
+ </ Col > }
143
+
117
144
< Col xs = { 12 } md = { 8 } className = "mt-sm-2" >
118
145
< p className = "mb-0" > < strong > Questions:</ strong > { assignment . gameboard ?. contents ?. length || "0" } </ p >
119
146
{ isDefined ( topics ) && topics . length > 0 && < p className = "mb-0" >
@@ -149,7 +176,7 @@ const PhyAssignmentCard = ({assignment}: {assignment: AssignmentDTO}) => {
149
176
</ Col >
150
177
</ Row >
151
178
</ Collapse >
152
- </ > ;
179
+ </ Link > ;
153
180
} ;
154
181
155
182
const CSAssignmentCard = ( { assignment} : { assignment : AssignmentDTO } ) => {
0 commit comments