explorak5_canvas_login 3.2.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7981f86c76cbb443863e7f07488c4b9189c59e4dbf98a3a89c587229cdd51f2b
|
4
|
+
data.tar.gz: ff6971539967b149a1b6a0ebce34ba0295dbd38e8b0ebf5ee28735e5ef7b49e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f3a5dbf03c4ad9996810c807cd8ec7e51c07d261a219cccdade8430c0bbf77d58b6bf66e69298affaa93cf1062df389fa077ff9b73d1a518cac985949daa128
|
7
|
+
data.tar.gz: 66fe3b27cf9e1997022e66c1f8375411a730fafdc50facef46bbf8cf1ec1be166959f89e1cbd0b02ac6a86c1b552b656a2b14470a06e68bba683706d8e3bea38
|
@@ -0,0 +1,372 @@
|
|
1
|
+
// @ts-nocheck
|
2
|
+
/*
|
3
|
+
* Copyright (C) 2015 - present Instructure, Inc.
|
4
|
+
*
|
5
|
+
* This file is part of Canvas.
|
6
|
+
*
|
7
|
+
* Canvas is free software: you can redistribute it and/or modify it under
|
8
|
+
* the terms of the GNU Affero General Public License as published by the Free
|
9
|
+
* Software Foundation, version 3 of the License.
|
10
|
+
*
|
11
|
+
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
12
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
13
|
+
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
14
|
+
* details.
|
15
|
+
*
|
16
|
+
* You should have received a copy of the GNU Affero General Public License along
|
17
|
+
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
*/
|
19
|
+
|
20
|
+
import React, {MouseEventHandler, useCallback, useEffect, useRef, useState} from 'react'
|
21
|
+
import {useScope as useI18nScope} from '@canvas/i18n'
|
22
|
+
import axios from '@canvas/axios'
|
23
|
+
|
24
|
+
import DashboardCardAction from './DashboardCardAction'
|
25
|
+
import CourseActivitySummaryStore from './CourseActivitySummaryStore'
|
26
|
+
import DashboardCardMenu from './DashboardCardMenu'
|
27
|
+
import PublishButton from './PublishButton'
|
28
|
+
import {showConfirmUnfavorite} from './ConfirmUnfavoriteCourseModal'
|
29
|
+
import {showFlashError} from '@canvas/alerts/react/FlashAlert'
|
30
|
+
import instFSOptimizedImageUrl from '../util/instFSOptimizedImageUrl'
|
31
|
+
import {ConnectDragSource, ConnectDropTarget} from 'react-dnd'
|
32
|
+
|
33
|
+
const I18n = useI18nScope('dashcards')
|
34
|
+
|
35
|
+
export type DashboardCardHeaderHeroProps = {
|
36
|
+
image?: string
|
37
|
+
backgroundColor?: string
|
38
|
+
hideColorOverlays?: boolean
|
39
|
+
onClick?: MouseEventHandler<HTMLElement>
|
40
|
+
}
|
41
|
+
|
42
|
+
export const DashboardCardHeaderHero = ({
|
43
|
+
image,
|
44
|
+
backgroundColor,
|
45
|
+
hideColorOverlays,
|
46
|
+
onClick,
|
47
|
+
}: DashboardCardHeaderHeroProps) => {
|
48
|
+
if (image) {
|
49
|
+
return (
|
50
|
+
<div
|
51
|
+
className="ic-DashboardCard__header_image"
|
52
|
+
style={{backgroundImage: `url(${instFSOptimizedImageUrl(image, {x: 262, y: 146})})`}}
|
53
|
+
>
|
54
|
+
<div
|
55
|
+
className="ic-DashboardCard__header_hero"
|
56
|
+
style={{backgroundColor, opacity: hideColorOverlays ? 0 : 0.6}}
|
57
|
+
onClick={onClick}
|
58
|
+
aria-hidden="true"
|
59
|
+
/>
|
60
|
+
</div>
|
61
|
+
)
|
62
|
+
}
|
63
|
+
|
64
|
+
return (
|
65
|
+
<div
|
66
|
+
className="ic-DashboardCard__header_hero"
|
67
|
+
style={{backgroundColor}}
|
68
|
+
onClick={onClick}
|
69
|
+
aria-hidden="true"
|
70
|
+
/>
|
71
|
+
)
|
72
|
+
}
|
73
|
+
|
74
|
+
export type DashboardCardProps = {
|
75
|
+
id: string
|
76
|
+
backgroundColor?: string
|
77
|
+
shortName: string
|
78
|
+
originalName: string
|
79
|
+
courseCode: string
|
80
|
+
assetString: string
|
81
|
+
term?: string
|
82
|
+
href: string
|
83
|
+
links: any[] // TODO: improve type
|
84
|
+
image?: string
|
85
|
+
handleColorChange?: (color: string) => void
|
86
|
+
hideColorOverlays?: boolean
|
87
|
+
isDragging?: boolean
|
88
|
+
isFavorited?: boolean
|
89
|
+
connectDragSource?: ConnectDragSource
|
90
|
+
connectDropTarget?: ConnectDropTarget
|
91
|
+
moveCard?: (assetString: string, atIndex: number, callback: () => void) => void
|
92
|
+
onConfirmUnfavorite: (id: string) => void
|
93
|
+
totalCards?: number
|
94
|
+
position?: number | (() => number)
|
95
|
+
enrollmentType?: string
|
96
|
+
observee?: string
|
97
|
+
published?: boolean
|
98
|
+
canChangeCoursePublishState?: boolean
|
99
|
+
defaultView?: string
|
100
|
+
pagesUrl?: string
|
101
|
+
frontPageTitle?: string
|
102
|
+
onPublishedCourse?: (id: string) => void
|
103
|
+
}
|
104
|
+
|
105
|
+
export const DashboardCard = ({
|
106
|
+
id,
|
107
|
+
backgroundColor = '#394B58',
|
108
|
+
shortName,
|
109
|
+
originalName,
|
110
|
+
courseCode,
|
111
|
+
assetString,
|
112
|
+
term,
|
113
|
+
href,
|
114
|
+
links = [],
|
115
|
+
image,
|
116
|
+
handleColorChange = () => {},
|
117
|
+
hideColorOverlays,
|
118
|
+
isDragging,
|
119
|
+
isFavorited,
|
120
|
+
connectDragSource = c => c,
|
121
|
+
connectDropTarget = c => c,
|
122
|
+
moveCard = () => {},
|
123
|
+
onConfirmUnfavorite,
|
124
|
+
totalCards = 0,
|
125
|
+
position = 0,
|
126
|
+
enrollmentType,
|
127
|
+
observee,
|
128
|
+
published,
|
129
|
+
canChangeCoursePublishState,
|
130
|
+
defaultView,
|
131
|
+
pagesUrl,
|
132
|
+
frontPageTitle,
|
133
|
+
onPublishedCourse = () => {},
|
134
|
+
}: DashboardCardProps) => {
|
135
|
+
const handleNicknameChange = nickname => setNicknameInfo(getNicknameInfo(nickname))
|
136
|
+
|
137
|
+
const getNicknameInfo = (nickname: string) => ({
|
138
|
+
nickname,
|
139
|
+
originalName,
|
140
|
+
courseId: id,
|
141
|
+
onNicknameChange: handleNicknameChange,
|
142
|
+
})
|
143
|
+
|
144
|
+
const [nicknameInfo, setNicknameInfo] = useState(getNicknameInfo(shortName))
|
145
|
+
const [course, setCourse] = useState(CourseActivitySummaryStore.getStateForCourse(id))
|
146
|
+
const settingsToggle = useRef<HTMLButtonElement | null>()
|
147
|
+
|
148
|
+
const handleStoreChange = useCallback(
|
149
|
+
() => setCourse(CourseActivitySummaryStore.getStateForCourse(id)),
|
150
|
+
[id]
|
151
|
+
)
|
152
|
+
|
153
|
+
useEffect(() => {
|
154
|
+
CourseActivitySummaryStore.addChangeListener(handleStoreChange)
|
155
|
+
return () => CourseActivitySummaryStore.removeChangeListener(handleStoreChange)
|
156
|
+
}, [handleStoreChange])
|
157
|
+
|
158
|
+
// ===============
|
159
|
+
// ACTIONS
|
160
|
+
// ===============
|
161
|
+
|
162
|
+
const getCardPosition = () => (typeof position === 'function' ? position() : position)
|
163
|
+
|
164
|
+
const headerClick: MouseEventHandler = e => {
|
165
|
+
e.preventDefault()
|
166
|
+
window.location.assign(href)
|
167
|
+
}
|
168
|
+
|
169
|
+
const handleMove = (asset: string, atIndex: number) => {
|
170
|
+
if (moveCard) {
|
171
|
+
moveCard(asset, atIndex, () => settingsToggle.current?.focus())
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
const handleUnfavorite = () => {
|
176
|
+
const modalProps = {
|
177
|
+
courseId: id,
|
178
|
+
courseName: originalName,
|
179
|
+
onConfirm: removeCourseFromFavorites,
|
180
|
+
}
|
181
|
+
showConfirmUnfavorite(modalProps)
|
182
|
+
}
|
183
|
+
|
184
|
+
// ===============
|
185
|
+
// HELPERS
|
186
|
+
// ===============
|
187
|
+
|
188
|
+
const unreadCount = (icon: string, stream?: any[]) => {
|
189
|
+
const activityType = {
|
190
|
+
'icon-announcement': 'Announcement',
|
191
|
+
'icon-assignment': 'Message',
|
192
|
+
'icon-discussion': 'DiscussionTopic',
|
193
|
+
}[icon]
|
194
|
+
|
195
|
+
const itemStream = stream || []
|
196
|
+
const streamItem = itemStream.find(
|
197
|
+
item =>
|
198
|
+
// only return 'Message' type if category is 'Due Date' (for assignments)
|
199
|
+
item.type === activityType &&
|
200
|
+
(activityType !== 'Message' || item.notification_category === I18n.t('Due Date'))
|
201
|
+
)
|
202
|
+
|
203
|
+
// TODO: unread count is always 0 for assignments (see CNVS-21227)
|
204
|
+
return streamItem ? streamItem.unread_count : 0
|
205
|
+
}
|
206
|
+
|
207
|
+
const calculateMenuOptions = () => {
|
208
|
+
const cardPosition = getCardPosition()
|
209
|
+
const isFirstCard = cardPosition === 0
|
210
|
+
const isLastCard = cardPosition === totalCards - 1
|
211
|
+
return {
|
212
|
+
canMoveLeft: !isFirstCard,
|
213
|
+
canMoveRight: !isLastCard,
|
214
|
+
canMoveToBeginning: !isFirstCard,
|
215
|
+
canMoveToEnd: !isLastCard,
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
219
|
+
const removeCourseFromFavorites = () => {
|
220
|
+
const url = `/api/v1/users/self/favorites/courses/${id}`
|
221
|
+
axios
|
222
|
+
.delete(url)
|
223
|
+
.then(response => {
|
224
|
+
if (response.status === 200) {
|
225
|
+
onConfirmUnfavorite(id)
|
226
|
+
}
|
227
|
+
})
|
228
|
+
.catch(() =>
|
229
|
+
showFlashError(I18n.t('We were unable to remove this course from your favorites.'))
|
230
|
+
)
|
231
|
+
}
|
232
|
+
|
233
|
+
const updatePublishedCourse = () => {
|
234
|
+
if (onPublishedCourse) onPublishedCourse(id)
|
235
|
+
}
|
236
|
+
|
237
|
+
// ===============
|
238
|
+
// RENDERING
|
239
|
+
// ===============
|
240
|
+
|
241
|
+
const linksForCard = () =>
|
242
|
+
links.map(link => {
|
243
|
+
if (link.hidden) return null
|
244
|
+
|
245
|
+
const screenReaderLabel = `${link.label} - ${nicknameInfo.nickname}`
|
246
|
+
return (
|
247
|
+
<DashboardCardAction
|
248
|
+
unreadCount={unreadCount(link.icon, course?.stream)}
|
249
|
+
iconClass={link.icon}
|
250
|
+
linkClass={link.css_class}
|
251
|
+
path={link.path}
|
252
|
+
screenReaderLabel={screenReaderLabel}
|
253
|
+
key={link.path}
|
254
|
+
/>
|
255
|
+
)
|
256
|
+
})
|
257
|
+
|
258
|
+
const renderHeaderButton = () => {
|
259
|
+
const reorderingProps = {
|
260
|
+
handleMove,
|
261
|
+
currentPosition: getCardPosition(),
|
262
|
+
lastPosition: totalCards - 1,
|
263
|
+
menuOptions: calculateMenuOptions(),
|
264
|
+
}
|
265
|
+
|
266
|
+
return (
|
267
|
+
<div>
|
268
|
+
<div
|
269
|
+
className="ic-DashboardCard__header-button-bg"
|
270
|
+
style={{backgroundColor, opacity: hideColorOverlays ? 1 : 0}}
|
271
|
+
/>
|
272
|
+
<DashboardCardMenu
|
273
|
+
afterUpdateColor={(c: string) => handleColorChange(`#${c}`)}
|
274
|
+
currentColor={backgroundColor}
|
275
|
+
nicknameInfo={nicknameInfo}
|
276
|
+
assetString={assetString}
|
277
|
+
onUnfavorite={handleUnfavorite}
|
278
|
+
isFavorited={isFavorited}
|
279
|
+
{...reorderingProps}
|
280
|
+
trigger={
|
281
|
+
<button
|
282
|
+
type="button"
|
283
|
+
className="Button Button--icon-action-rev ic-DashboardCard__header-button"
|
284
|
+
ref={c => {
|
285
|
+
settingsToggle.current = c
|
286
|
+
}}
|
287
|
+
>
|
288
|
+
<i className="icon-more" aria-hidden="true" />
|
289
|
+
<span className="screenreader-only">
|
290
|
+
{I18n.t('Choose a color or course nickname or move course card for %{course}', {
|
291
|
+
course: nicknameInfo.nickname,
|
292
|
+
})}
|
293
|
+
</span>
|
294
|
+
</button>
|
295
|
+
}
|
296
|
+
/>
|
297
|
+
</div>
|
298
|
+
)
|
299
|
+
}
|
300
|
+
|
301
|
+
const dashboardCard = (
|
302
|
+
<div
|
303
|
+
className="ic-DashboardCard"
|
304
|
+
style={{opacity: isDragging ? 0 : 1}}
|
305
|
+
aria-label={originalName}
|
306
|
+
>
|
307
|
+
<div className="ic-DashboardCard__header" style={{backgroundColor}}>
|
308
|
+
<span className="screenreader-only">
|
309
|
+
{image
|
310
|
+
? I18n.t('Course image for %{course}', {course: nicknameInfo.nickname})
|
311
|
+
: I18n.t('Course card color region for %{course}', {
|
312
|
+
course: nicknameInfo.nickname,
|
313
|
+
})}
|
314
|
+
</span>
|
315
|
+
<DashboardCardHeaderHero
|
316
|
+
image={image}
|
317
|
+
backgroundColor={backgroundColor}
|
318
|
+
hideColorOverlays={hideColorOverlays}
|
319
|
+
onClick={headerClick}
|
320
|
+
/>
|
321
|
+
<a href={href} className="ic-DashboardCard__link">
|
322
|
+
<div className="ic-DashboardCard__header_content" style={{backgroundColor}}>
|
323
|
+
<h5
|
324
|
+
className="ic-DashboardCard__header-title ellipsis"
|
325
|
+
title={originalName}
|
326
|
+
style={{color: backgroundColor}}
|
327
|
+
>
|
328
|
+
<span style={{color: backgroundColor}}>{nicknameInfo.nickname}</span>
|
329
|
+
</h5>
|
330
|
+
<div
|
331
|
+
className="ic-DashboardCard__header-term ellipsis"
|
332
|
+
title={term}
|
333
|
+
style={{color: backgroundColor}}
|
334
|
+
>
|
335
|
+
{term || null}
|
336
|
+
</div>
|
337
|
+
{enrollmentType === 'ObserverEnrollment' && observee && (
|
338
|
+
<div
|
339
|
+
className="ic-DashboardCard__header-term ellipsis"
|
340
|
+
title={observee}
|
341
|
+
style={{color: backgroundColor}}
|
342
|
+
>
|
343
|
+
{I18n.t('Observing: %{observee}', {observee})}
|
344
|
+
</div>
|
345
|
+
)}
|
346
|
+
</div>
|
347
|
+
</a>
|
348
|
+
{!published && canChangeCoursePublishState && (
|
349
|
+
<PublishButton
|
350
|
+
courseNickname={nicknameInfo.nickname}
|
351
|
+
defaultView={defaultView}
|
352
|
+
pagesUrl={pagesUrl}
|
353
|
+
frontPageTitle={frontPageTitle}
|
354
|
+
courseId={id}
|
355
|
+
/>
|
356
|
+
)}
|
357
|
+
{renderHeaderButton()}
|
358
|
+
</div>
|
359
|
+
<nav
|
360
|
+
className="ic-DashboardCard__action-container"
|
361
|
+
aria-label={I18n.t('Actions for %{course}', {course: nicknameInfo.nickname})}
|
362
|
+
style={{color: backgroundColor}}
|
363
|
+
>
|
364
|
+
{linksForCard()}
|
365
|
+
</nav>
|
366
|
+
</div>
|
367
|
+
)
|
368
|
+
|
369
|
+
return connectDragSource(connectDropTarget(dashboardCard))
|
370
|
+
}
|
371
|
+
|
372
|
+
export default DashboardCard
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: explorak5_canvas_login
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Explorak5
|
@@ -23,6 +23,7 @@ files:
|
|
23
23
|
- lib/explorak5_canvas_login/app/views/login/_login_content.html.erb
|
24
24
|
- lib/explorak5_canvas_login/app/views/login/_logout_confirm_content.html.erb
|
25
25
|
- lib/explorak5_canvas_login/app/views/navbar/_new_nav_header.html.erb
|
26
|
+
- lib/explorak5_canvas_login/ui/dashboard-card/react/DashboardContent.tsx
|
26
27
|
- lib/explorak5_canvas_login/version.rb
|
27
28
|
homepage: https://github.com/kevin523523/explorak5_canvas_login
|
28
29
|
licenses: []
|