explorak5_canvas_login 3.5.0 → 3.6.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: 2e42d97cbce1b95b492f9bdfc626fa2d6bca7f81e262b3e72b37ff077355c5a7
4
- data.tar.gz: c8debc781c4263f93d0f53850645b0a0632daaa14a38d3c25adc914d3f5967a3
3
+ metadata.gz: fb7ff2ea417b6fe94fbfd3ff1fda26b8f2dbb51d7a3df1a1191d41848305e773
4
+ data.tar.gz: 0ee9275fb1fc8d4c6820e776ca7352eccaa447777d44a5c545abfe3f3836b480
5
5
  SHA512:
6
- metadata.gz: e8e5a60fc9707f3cb21adce6cbb5011249d1183da7023dcc86297cbeddf4656d3ad838d4d1cfd7b6cabd81c4320928354c87e29e312911eac38584d745e02ae2
7
- data.tar.gz: 882d42305f390cca4edda3a66210720cd1e4d5535cbf57110ebf04beb96d250308b23f202324650cc48806404c51bd64c79b080518f046847d4441df823e9e39
6
+ metadata.gz: 4deb8d8674e8dad80c9e9e00843e7efcd3e9cd32feb29cd7abf92ff62ff438d81c99b880100578705797e1df08d0df95df9988514539f9f1e2d1b00cbf210864
7
+ data.tar.gz: 6324a65db00352674201a0055fd05a4753ac5f870b76f2eff505d8a8b0ad093b90941b552287750b657e7c2b036b27c172c915ed7a044fdba8e3470ab14176c8
@@ -117,6 +117,35 @@
117
117
  margin: 0;
118
118
  box-shadow: 0 0 1px rgb(0 0 0 / 8%), 0 1px 6px rgb(0 0 0 / 8%), 0 5px 5px rgb(0 0 0 /8%);
119
119
  }
120
+ .img-logout{
121
+ height: 50px !important;
122
+ width: 50px !important;
123
+ }
124
+ .avatar-img {
125
+ height: 100% !important;
126
+ width: 50px !important;
127
+ }
128
+
129
+ .avatar-img{
130
+ width: 100px !important;
131
+ height: 100% !important
132
+ }
133
+ .ic-avatar {
134
+ margin-right: 50px;
135
+ border: 2px solid #3d88d9 !important;
136
+ width: 70px !important;
137
+ height: 70px !important;
138
+ box-sizing: border-box;
139
+ display: inline-block;
140
+ vertical-align: middle;
141
+ }
142
+ .ic-Dashboard-header__layout {
143
+ border-bottom: unset !important;
144
+ color: #3d88d9
145
+ }
146
+ .unpublished_courses_redesign {
147
+ color: #3d88d9
148
+ }
120
149
  </style>
121
150
  <%
122
151
  # Copyright (C) 2015 - present Instructure, Inc.
@@ -0,0 +1,292 @@
1
+ <%
2
+ # Copyright (C) 2011 - present Instructure, Inc.
3
+ #
4
+ # This file is part of Canvas.
5
+ #
6
+ # Canvas is free software: you can redistribute it and/or modify it under
7
+ # the terms of the GNU Affero General Public License as published by the Free
8
+ # Software Foundation, version 3 of the License.
9
+ #
10
+ # Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ # A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ # details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License along
16
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ %>
18
+ <%-
19
+ css_bundle(:instructure_eportfolio) if @eportfolio_view === true
20
+ css_bundle(:new_user_tutorials) if tutorials_enabled?
21
+ js_bundle(:navigation_header) unless @headers == false
22
+
23
+ if @domain_root_account&.feature_enabled?(:top_navigation_placement)
24
+ js_env INIT_DRAWER_LAYOUT_MUTEX: "init-drawer-layout"
25
+ js_bundle(:top_navigation_tools)
26
+ end
27
+
28
+ load_blueprint_courses_ui
29
+ @has_content_notices = load_content_notices
30
+ provide :head, include_common_stylesheets
31
+ set_badge_counts_for(@context, @current_user) if @set_badge_counts
32
+ js_env notices: flash_notices()
33
+ -%>
34
+ <%= render :partial => "layouts/head" %>
35
+ <%-
36
+ left_side = nil
37
+ left_side_custom = nil
38
+ right_side = (yield :right_side).presence
39
+
40
+ # Collapse the course menu according to user preference, unless a certain action
41
+ # requests that it default to collapsed for that page
42
+ @collapse_course_menu ||= @current_user&.reload&.collapse_course_nav?
43
+ context_is_course_or_account = @context&.is_a?(Course) || @context&.is_a?(Account)
44
+ @enhanced_rubrics_enabled = context_is_course_or_account ? @context.feature_enabled?(:enhanced_rubrics) : false
45
+
46
+ if @collapse_course_menu
47
+ subnav_menu_text = t('Show Navigation Menu')
48
+ subnav_menu_text = t('Show Courses Navigation Menu') if active_path?('/courses')
49
+ subnav_menu_text = t('Show Account Navigation Menu') if active_path?('/profile')
50
+ subnav_menu_text = t('Show Admin Navigation Menu') if active_path?('/accounts')
51
+ subnav_menu_text = t('Show Groups Navigation Menu') if active_path?('/groups')
52
+ else
53
+ subnav_menu_text = t('Hide Navigation Menu')
54
+ subnav_menu_text = t('Hide Courses Navigation Menu') if active_path?('/courses')
55
+ subnav_menu_text = t('Hide Account Navigation Menu') if active_path?('/profile')
56
+ subnav_menu_text = t('Hide Admin Navigation Menu') if active_path?('/accounts')
57
+ subnav_menu_text = t('Hide Groups Navigation Menu') if active_path?('/groups')
58
+ end
59
+
60
+ @collapse_global_nav = @current_user.try(:collapse_global_nav?)
61
+ @body_class_no_headers = @headers == false
62
+ @show_embedded_chat = embedded_chat_visible
63
+ @show_fixed_bottom = (@fixed_warnings.present? || (@real_current_user && @real_current_user != @current_user)) && (!@body_class_no_headers || @outer_frame)
64
+ body_classes << "no-headers" if @body_class_no_headers
65
+ unless (body_classes.include? "no-headers") || (@show_left_side == false)
66
+ left_side = nil
67
+ skip_for_streaming :left_side, except: ["eportfolios/show", "eportfolio_categories/show", "eportfolio_entries/show"] do
68
+ left_side = (yield :left_side).presence
69
+ end
70
+ @show_left_side ||= (section_tabs.length > 0)
71
+ end
72
+ body_classes << "with-left-side" if @show_left_side
73
+ body_classes << "course-menu-expanded" if body_classes.include?("with-left-side") && !@collapse_course_menu
74
+ #we dont want to render a right side unless there is actually content in it.
75
+ body_classes << "with-right-side" if right_side and not right_side.strip.empty?
76
+ body_classes << "padless-content" if @padless
77
+ body_classes << "with-embedded-chat" if @show_embedded_chat
78
+ body_classes << 'with-fixed-bottom' if @show_fixed_bottom
79
+ body_classes << 'pages' if controller.js_env[:WIKI_PAGE].present?
80
+ body_classes << get_active_tab
81
+ body_classes << 'Underline-All-Links__enabled' if @current_user && @current_user.feature_enabled?(:underline_all_links)
82
+ body_classes << 'is-masquerading-or-student-view' if @real_current_user && @real_current_user != @current_user
83
+ body_classes << 'primary-nav-expanded' unless @collapse_global_nav
84
+ body_classes << 'primary-nav-transitions' if @collapse_global_nav
85
+ # We probably want to consider doing this everywhere, all the time, but when I did
86
+ # for LS-1745, people complained a lot, so maybe not.
87
+ body_classes << 'full-width' if @domain_root_account.try(:feature_enabled?, :new_user_tutorial)
88
+ body_classes << "context-#{@context.asset_string}" if @context
89
+ body_classes << "responsive_student_grades_page" if !!@domain_root_account&.feature_enabled?(:responsive_student_grades_page)
90
+ -%>
91
+ <body class="<%= (body_classes).uniq.join(" ") %>">
92
+ <%if @current_user && @real_current_user && @real_current_user != @current_user %>
93
+ <div role="alert" class="screenreader-only">
94
+ <% if @current_user.fake_student? %>
95
+ <%= t("You are currently logged into Student View") %>
96
+ <% else %>
97
+ <%= t("You are currently acting as %{user_name}", :user_name => @current_user.short_name) %>
98
+ <% end %>
99
+ </div>
100
+ <% end %>
101
+ <%# Flash messages must be outside of #application or they won't work in screenreaders with modals open. %>
102
+ <%= render :partial => 'shared/static_notices' %>
103
+ <%= render :partial => 'shared/flash_notices' %>
104
+ <%if @domain_root_account&.feature_enabled?(:top_navigation_placement) %>
105
+ <div id="drawer-layout-mount-point"></div>
106
+ <% end %>
107
+ <div id="application" class="ic-app">
108
+ <%= render(:partial => 'shared/new_nav_header') unless @headers == false %>
109
+
110
+ <div id="instructure_ajax_error_box">
111
+ <div style="text-align: <%= direction('right') %>; background-color: #fff;"><a href="#" class="close_instructure_ajax_error_box_link"><%= t('links.close', 'Close') %></a></div>
112
+ <iframe id="instructure_ajax_error_result" src="about:blank" style="border: 0;" title="<%= t('Error') %>"></iframe>
113
+ </div>
114
+
115
+ <div id="wrapper" class="ic-Layout-wrapper">
116
+ <% if crumbs.length > 1 %>
117
+ <% if @instui_topnav %>
118
+ <div class="instui-topnav-container">
119
+ <div id="react-instui-topnav"></div>
120
+ </div>
121
+ <% else %>
122
+ <div class="ic-app-nav-toggle-and-crumbs no-print">
123
+ <% if @show_left_side %>
124
+ <button type="button" id="courseMenuToggle" class="Button Button--link ic-app-course-nav-toggle" aria-live="polite" aria-label="<%= subnav_menu_text %>">
125
+ <i class="icon-hamburger" aria-hidden="true"></i>
126
+ </button>
127
+ <% end %>
128
+
129
+ <div class="ic-app-crumbs <%= 'ic-app-crumbs-enhanced-rubrics' if @enhanced_rubrics_enabled %>">
130
+ <% if @context&.is_a?(Course) && @context.elementary_subject_course? %>
131
+ <%= link_to course_path(id: @context.id), :class => "btn k5-back-to-subject", :id => "back_to_subject" do %>
132
+ <i class="icon-arrow-open-left"></i> <%= t('Back to Subject') %>
133
+ <% end %>
134
+ <% else %>
135
+ <%= render_crumbs %>
136
+ <% end %>
137
+ </div>
138
+
139
+ <% if @context&.is_a?(Course) && @context.elementary_subject_course? %>
140
+ <span class="k5-heading-course-name"><%= @context.nickname_for(@current_user) %></span>
141
+ <% end %>
142
+
143
+ <div class="right-of-crumbs">
144
+ <% if tutorials_enabled? %>
145
+ <div class="TutorialToggleHolder"></div>
146
+ <% end %>
147
+ <%if @domain_root_account&.feature_enabled?(:top_navigation_placement) %>
148
+ <div id="top-nav-tools-mount-point"></div>
149
+ <% end %>
150
+ <% if show_immersive_reader? %>
151
+ <div id="immersive_reader_mount_point"></div>
152
+ <% end %>
153
+ <% if show_student_view_button? %>
154
+ <%= link_to course_student_view_path(course_id: @context, redirect_to_referer: 1), :class => "btn btn-top-nav", :id => "easy_student_view", :method => :post, :role => "complementary", :"aria-label" => t("View as Student") do %>
155
+ <i class="icon-student-view"></i> <%= t('View as Student') %>
156
+ <% end %>
157
+ <% end %>
158
+ <% if (@context&.is_a?(Course) || @context&.is_a?(Assignment)) && @context_enrollment&.observer? %>
159
+ <div id='observer-picker-mountpoint' style="margin: 3px;"></div>
160
+ <% end %>
161
+ </div>
162
+
163
+ </div>
164
+ <% end %>
165
+ <% end %>
166
+ <div id="main" class="ic-Layout-columns">
167
+ <% if !@body_class_no_headers %>
168
+ <div class="ic-Layout-watermark"></div>
169
+ <% end %>
170
+ <% if @show_left_side %>
171
+ <% if @no_left_side_list_view
172
+ list_view_class = ''
173
+ else
174
+ list_view_class = 'list-view'
175
+ end
176
+ %>
177
+ <div id="left-side"
178
+ class="ic-app-course-menu ic-sticky-on <%= list_view_class %>"
179
+ style="display: <%= @collapse_course_menu ? "none" : "block" %>"
180
+ >
181
+ <div id="sticky-container" class="ic-sticky-frame">
182
+ <% if left_side %>
183
+ <%= left_side %>
184
+ <% else %>
185
+ <% if @context && @context.is_a?(Group) && can_do(@context, @current_user, :manage) && @context.group_category %>
186
+ <span id="group-switch-mount-point"></span>
187
+ <% end %>
188
+ <% if @context && @context.respond_to?(:enrollment_term) && !@context.enrollment_term.default_term? %>
189
+ <span id="section-tabs-header-subtitle" class="ellipsis"><%= @context.enrollment_term.name %></span>
190
+ <% end %>
191
+ <%= section_tabs %>
192
+ <% end %>
193
+ </div>
194
+ </div>
195
+ <% end %>
196
+ <div id="not_right_side" class="ic-app-main-content">
197
+ <div id="content-wrapper" class="ic-Layout-contentWrapper">
198
+ <% if should_show_migration_limitation_message %>
199
+ <% js_bundle :quiz_migration_alerts %>
200
+ <div class="ic-notification ic-notification--info quiz_migration_notification">
201
+ <div class="ic-notification__icon" role="presentation">
202
+ <i class="icon-info"></i>
203
+ <span class="screenreader-only">
204
+ <%= accessible_message_icon_text('information') %>
205
+ </span>
206
+ </div>
207
+ <div class="ic-notification__content">
208
+ <div class="ic-notification__message notification_message" style="margin-bottom:1rem;">
209
+ <%= t 'Your Classic Quizzes have been migrated to New Quizzes! ' %><br />
210
+ <%= t 'Please note:' %>
211
+ <ul>
212
+ <li><%= t 'Text No Question has moved to a Stimulus; please add a question so it can display within the quiz.' %></li>
213
+ </ul>
214
+ <%= t 'We apologize for the inconvenience and thank you for your patience as we continue to improve the migration experience!' %>
215
+ </div>
216
+ <div class="ic-notification__actions">
217
+ <a href="#"
218
+ rel="<%= api_v1_course_dismiss_migration_limitation_msg_url(@context.id) %>"
219
+ class="close_migration_notification_link Button Button--info"
220
+ role="button"
221
+ >
222
+ <%= t('Close') %>
223
+ </a>
224
+ </div>
225
+ </div>
226
+ </div>
227
+ <% end %>
228
+ <%= render :partial => 'shared/content_notices' if @has_content_notices && @show_left_side %>
229
+ <div id="content" class="ic-Layout-contentMain" role="main">
230
+ <%= yield %>
231
+ </div>
232
+ </div>
233
+ </div>
234
+ </div>
235
+ <% if @show_footer %>
236
+ <%= render :partial => 'shared/canvas_footer' %>
237
+ <% end %>
238
+ </div>
239
+
240
+ <% if @show_embedded_chat %>
241
+ <%= render :partial => 'shared/embedded_chat' %>
242
+ <% end %>
243
+
244
+ <% if @show_fixed_bottom %>
245
+ <%= render :partial => 'layouts/fixed_bottom' %>
246
+ <% end %>
247
+
248
+ <% if (wizard = (yield :wizard_box).presence) %>
249
+ <div id="wizard_box" tabindex="-1">
250
+ <div class="wizard_content">
251
+ <div class="links">
252
+ <a href="#" class="close_wizard_link"><i class="icon-x"></i><span class="screenreader-only"><%= t('links.close', 'Close') %></span></a>
253
+ </div>
254
+ <%= wizard %>
255
+ </div>
256
+ </div>
257
+ <% end %>
258
+ <% if (keyboard_navigation = (yield :keyboard_navigation).presence) %>
259
+ <div id="keyboard_navigation">
260
+ <%= keyboard_navigation %>
261
+ <div class='hidden-readable' tabindex='0'>
262
+ <%= t('keyboard_navigation.close', 'Press comma to close this dialog') %>
263
+ </div>
264
+ </div>
265
+ <% end %>
266
+ <div style="display:none;"><!-- Everything inside of this should always stay hidden -->
267
+ <% if @context && session && temp_type = session["role_#{@context.asset_string}"] %>
268
+ <span id="switched_role_type" class="<%= @context.asset_string %>" data-role="<%= temp_type %>"><%= Enrollment.readable_type(temp_type) %></span>
269
+ <% end %>
270
+ <% if @page_view %>
271
+ <div id="page_view_id"><%= @page_view.id %></div>
272
+ <% end %>
273
+ <% if equella_enabled? %>
274
+ <a id="equella_endpoint_url" href="<%= @equella_settings[:endpoint] %>">&nbsp;</a>
275
+ <a id="equella_callback_url" href="<%= external_content_success_url('equella') %>">&nbsp;</a>
276
+ <a id="equella_cancel_url" href="<%= external_content_cancel_url('equella') %>">&nbsp;</a>
277
+ <a id="equella_action" href="<%= @equella_settings[:default_action] %>">&nbsp;</a>
278
+ <% if @equella_settings[:teaser] %>
279
+ <div id="equella_teaser"><%= @equella_settings[:teaser] %></div>
280
+ <% end %>
281
+ <% end %>
282
+ </div>
283
+ <div id='aria_alerts' class='hide-text affix' role="alert" aria-live="assertive"></div>
284
+ <div id='StudentTray__Container'></div>
285
+ <% if tutorials_enabled? %>
286
+ <div class="NewUserTutorialTray__Container"></div>
287
+ <% end %>
288
+ <div id="react-router-portals"></div>
289
+ <%= render :partial => 'layouts/foot', :locals => { :include_common_bundle => true } %>
290
+ </div> <!-- #application -->
291
+ </body>
292
+ </html>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Explorak5CanvasLogin
4
- VERSION = "3.5.0"
4
+ VERSION = "3.6.0"
5
5
  end
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.5.0
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Explorak5
@@ -20,10 +20,10 @@ extensions: []
20
20
  extra_rdoc_files: []
21
21
  files:
22
22
  - lib/explorak5_canvas_login/app/views/dashboard/_dashboard_card.html.erb
23
+ - lib/explorak5_canvas_login/app/views/layout/aplication.html.erb
23
24
  - lib/explorak5_canvas_login/app/views/login/_login_content.html.erb
24
25
  - lib/explorak5_canvas_login/app/views/login/_logout_confirm_content.html.erb
25
26
  - lib/explorak5_canvas_login/app/views/navbar/_new_nav_header.html.erb
26
- - lib/explorak5_canvas_login/ui/dashboard-card/react/DashboardCard.tsx
27
27
  - lib/explorak5_canvas_login/version.rb
28
28
  homepage: https://github.com/kevin523523/explorak5_canvas_login
29
29
  licenses: []
@@ -1,372 +0,0 @@
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