Retire old jQueryUI help dialog
Closes FOO-4518 flag=none The original Canvas help was implemented via some now very old code using jQuery and jQueryUI to create a help dialog. Since then most displays of the help information (particularly the display on the "Help Tray" which slides out from the side navigation after login) have been reimplemented in React and InstUI. The only holdout was the help dialog available from the Canvas login screen. Time to get rid of all that. This commit removes all of the old jQuery help dialog and replaces it with the existing React/InstUI help displays. Test plan: * be on the login screen * click on the "Help" link * you should see a help dialog pop up just like always but now it will look just like the side nav help tray * you agree that everything the "old" login help dialog provided is still available Change-Id: I367c396d6dc99bf01362e2fa4a4c8df4a3a2ea9f Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/350254 QA-Review: Charley Kline <ckline@instructure.com> Product-Review: Charley Kline <ckline@instructure.com> Reviewed-by: August Thornton <august@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
This commit is contained in:
parent
aeaf4bc879
commit
c5b024ad71
|
@ -28,7 +28,7 @@ describe "help dialog" do
|
|||
get("/login")
|
||||
f("#footer .help_dialog_trigger").click
|
||||
wait_for_ajaximations
|
||||
expect(f("#help-dialog-options")).to be_displayed
|
||||
expect(f('[data-testid="login-help-close-button"]')).to be_displayed
|
||||
end
|
||||
|
||||
it "no longer shows a browser warning for IE" do
|
||||
|
|
|
@ -40,7 +40,7 @@ import {
|
|||
IconHomeLine,
|
||||
} from '@instructure/ui-icons'
|
||||
import {useScope as useI18nScope} from '@canvas/i18n'
|
||||
import HelpDialog from './HelpDialog/index'
|
||||
import HelpDialog from '@canvas/help-dialog'
|
||||
import {Link} from '@instructure/ui-link'
|
||||
import CoursesList from './lists/CoursesList'
|
||||
import GroupsList from './lists/GroupsList'
|
||||
|
|
|
@ -20,7 +20,7 @@ import {useScope as useI18nScope} from '@canvas/i18n'
|
|||
import React from 'react'
|
||||
import {View} from '@instructure/ui-view'
|
||||
import {Heading} from '@instructure/ui-heading'
|
||||
import HelpDialog from '../HelpDialog/index'
|
||||
import HelpDialog from '@canvas/help-dialog'
|
||||
import ReleaseNotesList from '../lists/ReleaseNotesList'
|
||||
|
||||
const I18n = useI18nScope('HelpTray')
|
||||
|
|
|
@ -214,12 +214,13 @@ if (ENV.badge_counts) {
|
|||
import('./boot/initializers/showBadgeCounts')
|
||||
}
|
||||
|
||||
// Load and then display the Canvas help dialog if the user has requested it
|
||||
// Decorate the help link with the React/InstUI dialog from the navigation sidenav
|
||||
async function openHelpDialog(event: Event): Promise<void> {
|
||||
const helpLink = event.target as Element
|
||||
event.preventDefault()
|
||||
try {
|
||||
const {default: helpDialog} = await import('@canvas/common/enableHelpDialog')
|
||||
helpDialog.open()
|
||||
const {renderLoginHelp} = await import('@canvas/help-dialog')
|
||||
renderLoginHelp(helpLink)
|
||||
} catch (e) {
|
||||
/* eslint-disable no-console */
|
||||
console.error('Help dialog could not be displayed')
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import $ from 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import helpDialog from '../enableHelpDialog'
|
||||
import fakeENV from '@canvas/test-utils/fakeENV'
|
||||
import 'jquery-tinypubsub'
|
||||
|
||||
// more tests are in spec/selenium/help_dialog_spec.rb
|
||||
|
||||
QUnit.module('HelpDialog', {
|
||||
setup() {
|
||||
fakeENV.setup({help_link_name: 'Links'})
|
||||
helpDialog.animateDuration = 0
|
||||
this.clock = sinon.useFakeTimers()
|
||||
this.server = sinon.fakeServer.create()
|
||||
this.server.respondWith('/help_links', '[]')
|
||||
return this.server.respondWith('/api/v1/courses.json', '[]')
|
||||
},
|
||||
teardown() {
|
||||
fakeENV.teardown()
|
||||
this.clock.restore()
|
||||
this.server.restore()
|
||||
|
||||
// if we don't close it after each test, subsequent tests get messed up.
|
||||
if (helpDialog.$dialog != null) {
|
||||
helpDialog.$dialog.dialog('close')
|
||||
helpDialog.$dialog = null
|
||||
}
|
||||
helpDialog.dialogInited = false
|
||||
helpDialog.teacherFeedbackInited = false
|
||||
$('.ui-dialog').remove()
|
||||
$('[id^=ui-id-]').remove()
|
||||
$('#help-dialog').remove()
|
||||
$('#fixtures').empty()
|
||||
},
|
||||
})
|
||||
|
||||
test('init', () => {
|
||||
const $tester = $('<a class="help_dialog_trigger" />').appendTo('#fixtures')
|
||||
helpDialog.initTriggers()
|
||||
$tester.click()
|
||||
ok($('.ui-dialog-content').is(':visible'), "help dialog appears when you click 'help' link")
|
||||
equal($('.ui-dialog-title:contains("Links")').length, 1)
|
||||
$tester.remove()
|
||||
})
|
||||
|
||||
test('teacher feedback', function () {
|
||||
helpDialog.open()
|
||||
this.server.respond()
|
||||
helpDialog.switchTo('#teacher_feedback')
|
||||
ok(helpDialog.$dialog.find('#teacher-feedback-body').is(':visible'), 'textarea shows up')
|
||||
})
|
||||
|
||||
// unskip in FOO-4344
|
||||
QUnit.skip('focus management', function () {
|
||||
helpDialog.open()
|
||||
this.server.respond()
|
||||
this.clock.tick(1)
|
||||
helpDialog.switchTo('#create_ticket')
|
||||
this.clock.tick(1)
|
||||
equal(document.activeElement, helpDialog.$dialog.find('#error_subject')[0], 'focuses first input')
|
||||
ok(
|
||||
!helpDialog.$dialog.find('#help-dialog-options').is(':visible'),
|
||||
'out of view screen is hidden'
|
||||
)
|
||||
helpDialog.switchTo('#help-dialog-options')
|
||||
ok(helpDialog.$dialog.find('#help-dialog-options').is(':visible'), 'menu screen appears again')
|
||||
})
|
|
@ -1,211 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2011 - present Instructure, Inc.
|
||||
//
|
||||
// This file is part of Canvas.
|
||||
//
|
||||
// Canvas is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, version 3 of the License.
|
||||
//
|
||||
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License along
|
||||
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// also requires
|
||||
// jquery.formSubmit
|
||||
// jqueryui dialog
|
||||
// jquery disableWhileLoading
|
||||
|
||||
import {useScope as useI18nScope} from '@canvas/i18n'
|
||||
import helpDialogTemplate from './jst/helpDialog.handlebars'
|
||||
import $ from 'jquery'
|
||||
import {find} from 'lodash'
|
||||
import htmlEscape, {raw} from '@instructure/html-escape'
|
||||
import '@canvas/jquery/jquery.instructure_misc_helpers'
|
||||
import '@canvas/jquery/jquery.instructure_forms'
|
||||
import 'jqueryui/dialog'
|
||||
import '@canvas/jquery/jquery.disableWhileLoading'
|
||||
|
||||
const I18n = useI18nScope('helpDialog')
|
||||
|
||||
const helpDialog = {
|
||||
defaultTitle: I18n.t('Help', 'Help'),
|
||||
|
||||
showEmail: () => !ENV.current_user_id,
|
||||
|
||||
animateDuration: 100,
|
||||
|
||||
initDialog() {
|
||||
helpDialog.defaultTitle = ENV.help_link_name || helpDialog.defaultTitle
|
||||
helpDialog.$dialog = $('<div style="padding:0; overflow: visible;" />').dialog({
|
||||
resizable: false,
|
||||
width: 400,
|
||||
title: helpDialog.defaultTitle,
|
||||
close: () => helpDialog.switchTo('#help-dialog-options'),
|
||||
modal: true,
|
||||
zIndex: 1000,
|
||||
})
|
||||
|
||||
helpDialog.$dialog
|
||||
.dialog('widget')
|
||||
.on(
|
||||
'click',
|
||||
'a[href="#teacher_feedback"],a[href="#create_ticket"],a[href="#help-dialog-options"]',
|
||||
event => {
|
||||
if (event) event.preventDefault()
|
||||
helpDialog.switchTo($(event.currentTarget).attr('href'))
|
||||
}
|
||||
)
|
||||
|
||||
helpDialog.helpLinksDfd = $.getJSON('/help_links').done(links => {
|
||||
// only show the links that are available to the roles of this user
|
||||
links = $.grep(links, link =>
|
||||
find(
|
||||
link.available_to,
|
||||
role =>
|
||||
role === 'user' || (ENV.current_user_roles && ENV.current_user_roles.includes(role))
|
||||
)
|
||||
)
|
||||
const locals = {
|
||||
showEmail: helpDialog.showEmail(),
|
||||
helpLinks: links,
|
||||
url: window.location,
|
||||
contextAssetString: ENV.context_asset_string,
|
||||
userRoles: ENV.current_user_roles,
|
||||
}
|
||||
|
||||
helpDialog.$dialog.html(helpDialogTemplate(locals))
|
||||
helpDialog.initTicketForm()
|
||||
|
||||
// recenter the dialog once all the links have been loaded so it is back in the
|
||||
// middle of the page
|
||||
if (helpDialog.$dialog) helpDialog.$dialog.dialog('option', 'position', 'center')
|
||||
|
||||
$(this).trigger('ready')
|
||||
})
|
||||
helpDialog.$dialog.disableWhileLoading(helpDialog.helpLinksDfd)
|
||||
helpDialog.dialogInited = true
|
||||
},
|
||||
|
||||
initTicketForm() {
|
||||
const required = ['error[subject]', 'error[comments]', 'error[user_perceived_severity]']
|
||||
if (helpDialog.showEmail()) required.push('error[email]')
|
||||
|
||||
const $form = helpDialog.$dialog.find('#create_ticket').formSubmit({
|
||||
disableWhileLoading: true,
|
||||
required,
|
||||
success: () => {
|
||||
helpDialog.$dialog.dialog('close')
|
||||
$form.find(':input').val('')
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
switchTo(panelId) {
|
||||
let newTitle
|
||||
const toggleablePanels = '#teacher_feedback, #create_ticket'
|
||||
const homePanel = '#help-dialog-options'
|
||||
helpDialog.$dialog.find(toggleablePanels).hide()
|
||||
const newPanel = helpDialog.$dialog.find(panelId)
|
||||
const newHeight = newPanel.show().outerHeight()
|
||||
helpDialog.$dialog.animate(
|
||||
{left: toggleablePanels.match(panelId) ? -400 : 0, height: newHeight},
|
||||
{
|
||||
step: () => {
|
||||
// reposition vertically to reflect current height
|
||||
if (
|
||||
!(
|
||||
helpDialog.dialogInited &&
|
||||
helpDialog.$dialog &&
|
||||
helpDialog.$dialog.hasClass('ui-dialog-content')
|
||||
)
|
||||
) {
|
||||
helpDialog.initDialog()
|
||||
}
|
||||
helpDialog.$dialog && helpDialog.$dialog.dialog('option', 'position', 'center')
|
||||
},
|
||||
duration: helpDialog.animateDuration,
|
||||
complete() {
|
||||
let toFocus = newPanel.find(':input').not(':disabled')
|
||||
if (!toFocus.length) toFocus = newPanel.find(':focusable')
|
||||
toFocus.first().focus()
|
||||
if (panelId !== homePanel) $(homePanel).hide()
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if ((newTitle = helpDialog.$dialog.find(`a[href='${panelId}'] .text`).text())) {
|
||||
newTitle = $(
|
||||
`<a class='ui-dialog-header-backlink' href='#help-dialog-options'>
|
||||
${htmlEscape(I18n.t('Back', 'Back'))} \
|
||||
</a>
|
||||
<span>
|
||||
${htmlEscape(newTitle)}
|
||||
</span>`
|
||||
)
|
||||
} else {
|
||||
newTitle = helpDialog.defaultTitle
|
||||
}
|
||||
helpDialog.$dialog.dialog('option', 'title', newTitle)
|
||||
},
|
||||
|
||||
open() {
|
||||
if (
|
||||
!(
|
||||
helpDialog.dialogInited &&
|
||||
helpDialog.$dialog &&
|
||||
helpDialog.$dialog.hasClass('ui-dialog-content')
|
||||
)
|
||||
) {
|
||||
helpDialog.initDialog()
|
||||
}
|
||||
helpDialog.$dialog.dialog('open')
|
||||
helpDialog.initTeacherFeedback()
|
||||
},
|
||||
|
||||
initTeacherFeedback() {
|
||||
const currentUserIsStudent =
|
||||
ENV.current_user_roles && ENV.current_user_roles.includes('student')
|
||||
if (!helpDialog.teacherFeedbackInited && currentUserIsStudent) {
|
||||
helpDialog.teacherFeedbackInited = true
|
||||
const coursesDfd = $.getJSON('/api/v1/courses.json')
|
||||
let $form
|
||||
helpDialog.helpLinksDfd.done(() => {
|
||||
$form = helpDialog.$dialog
|
||||
.find('#teacher_feedback')
|
||||
.disableWhileLoading(coursesDfd)
|
||||
.formSubmit({
|
||||
disableWhileLoading: true,
|
||||
required: ['recipients[]', 'body'],
|
||||
success: () => helpDialog.$dialog.dialog('close'),
|
||||
})
|
||||
})
|
||||
|
||||
$.when(coursesDfd, helpDialog.helpLinksDfd).done(([courses]) => {
|
||||
const optionsHtml = $.map(
|
||||
courses,
|
||||
c =>
|
||||
`<option
|
||||
value='course_${c.id}_admins'
|
||||
${raw(ENV.context_id === c.id ? 'selected' : '')}
|
||||
>
|
||||
${htmlEscape(c.name)}
|
||||
</option>`
|
||||
).join('')
|
||||
$form.find('[name="recipients[]"]').html(optionsHtml)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
initTriggers() {
|
||||
$('.help_dialog_trigger').click(event => {
|
||||
event.preventDefault()
|
||||
helpDialog.open()
|
||||
})
|
||||
},
|
||||
}
|
||||
export default helpDialog
|
|
@ -1,64 +0,0 @@
|
|||
<div id="help-dialog">
|
||||
<ul id="help-dialog-options" class="help-dialog-pane">
|
||||
{{#each helpLinks}}
|
||||
<li>
|
||||
<a href="{{#if url}}{{url}}{{else}}#{{/if}}" target="_blank">
|
||||
<span class="text">{{text}}</span>
|
||||
<span class="subtext">{{subtext}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<form class="help-dialog-pane" id="teacher_feedback" style="display:none" action="/api/v1/conversations" method="POST">
|
||||
<label for="teacher-feedback-recipients">
|
||||
{{#t "which_course_is_this_question_about"}}Which course is this question about?{{/t}}
|
||||
<small>{{#t "message_will_be_sent_to_all_the_teachers_tas_in_the_course"}}Message will be sent to all the Teachers / TA's in the course.{{/t}}</small>
|
||||
</label>
|
||||
<select class="input-block-level" name="recipients[]" id="teacher-feedback-recipients"></select>
|
||||
<label for="teacher-feedback-body">{{#t "message"}}Message{{/t}}</label>
|
||||
<textarea id="teacher-feedback-body" name="body"></textarea>
|
||||
<div class="button-container">
|
||||
<button type="submit" class="btn" data-text-while-loading="{{#t "sending"}}Sending...{{/t}}">{{#t "send_message"}}Send Message{{/t}}</button>
|
||||
</div>
|
||||
<input class="input-block-level" type="hidden" name="group_conversation" value="true">
|
||||
</form>
|
||||
<form class="help-dialog-pane bootstrap-form" id="create_ticket" style="display:none" action="/error_reports" method="POST">
|
||||
<h4>{{#t "file_a_ticket_for_a_personal_response_from_our_support_team"}}File a ticket for a personal response from our support team{{/t}}</h4>
|
||||
<div role="alert" class="alert">
|
||||
<strong>{{#t "for_an_instant_answer"}}For an instant answer:{{/t}}</strong>
|
||||
<div>{{#t "see_if_your_issue_is_addressed_in_the_canvas_guides"}}See if your issue is addressed in the <a target="_blank" href="http://guides.canvaslms.com/">Canvas Guides</a>.{{/t}}</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="error_subject">{{#t "subject"}}Subject{{/t}}</label>
|
||||
<input type="text" class="input-block-level" id="error_subject" name="error[subject]" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="error-comments">
|
||||
{{#t "description"}}Description{{/t}}
|
||||
<small>{{#t "include_a_link_to_a_screencast_or_screenshot_using_something_like_jing"}}Include a link to a screencast/screenshot using something like <a target="_blank" href="http://www.techsmith.com/download/jing">Jing</a>.{{/t}}</small>
|
||||
</label>
|
||||
<textarea class="input-block-level" id="error-comments" name="error[comments]"></textarea>
|
||||
</div>
|
||||
<label for="severity">{{#t "how_is_this_affecting_you"}}How is this affecting you?{{/t}}</label>
|
||||
<select class="input-block-level" name="error[user_perceived_severity]" id="severity">
|
||||
<option value="">{{#t "please_select_one"}}Please select one...{{/t}}</option>
|
||||
<option value="just_a_comment">{{#t "just_a_casual_question_comment_idea_suggestion"}}Just a casual question, comment, idea, suggestion{{/t}}</option>
|
||||
<option value="not_urgent">{{#t "i_need_some_help_but_its_not_urgent"}}I need some help but it's not urgent{{/t}}</option>
|
||||
<option value="workaround_possible">{{#t "somethings_broken_but_i_can_work_around_it_for_now"}}Something's broken but I can work around it for now{{/t}}</option>
|
||||
<option value="blocks_what_i_need_to_do">{{#t "i_cant_get_things_done_until_i_hear_back_from_you"}}I can't get things done until I hear back from you{{/t}}</option>
|
||||
<option value="extreme_critical_emergency">{{#t "extreme_critical_emergency"}}EXTREME CRITICAL EMERGENCY!!{{/t}}</option>
|
||||
</select>
|
||||
<div style="{{hiddenUnless showEmail}}">
|
||||
<label for="error-email">{{#t "your_email_address"}}Your email address{{/t}}</label>
|
||||
<input class="input-block-level" type="email" name="error[email]" id="error-email">
|
||||
</div>
|
||||
<input class="input-block-level" type="hidden" name="error[url]" value="{{url}}">
|
||||
<input class="input-block-level" type="hidden" name="error[context_asset_string]" value="{{contextAssetString}}">
|
||||
<input class="input-block-level" type="hidden" name="error[user_roles]" value="{{userRoles}}">
|
||||
{{! this is a honeypot field. it's hidden via css, but spambots don't know that. }}
|
||||
<input class="input-block-level hidden" name="error[username]" value="">
|
||||
<div class="button-container">
|
||||
<button type="submit" data-text-while-loading="{{#t "Submitting_Ticket"}}Submitting Ticket...{{/t}}" class="btn submit_button"><img src="/images/email.png" alt=""/>{{#t "submit_this_support_request"}}Submit Ticket{{/t}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"i18nScope": "help_dialog"
|
||||
}
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (C) 2024 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export {default} from './react/index'
|
||||
export {renderLoginHelp} from './react/loginHelp'
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "@canvas/help-dialog",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"author": "Instructure",
|
||||
"main": "index.tsx"
|
||||
}
|
|
@ -23,8 +23,8 @@ import {Heading} from '@instructure/ui-heading'
|
|||
import {Text} from '@instructure/ui-text'
|
||||
import {View} from '@instructure/ui-view'
|
||||
// @ts-expect-error
|
||||
import PandaMapSVGURL from '../../images/panda-map.svg'
|
||||
import type {HelpLink} from '../../../../api.d'
|
||||
import PandaMapSVGURL from '../images/panda-map.svg'
|
||||
import type {HelpLink} from '../../../api.d'
|
||||
|
||||
type Props = {
|
||||
featuredLink: HelpLink
|
|
@ -30,7 +30,7 @@ import {ScreenReaderContent, PresentationContent} from '@instructure/ui-a11y-con
|
|||
import tourPubSub from '@canvas/tour-pubsub'
|
||||
import {useQuery} from '@canvas/query'
|
||||
import helpLinksQuery from '../queries/helpLinksQuery'
|
||||
import type {HelpLink} from '../../../../api.d'
|
||||
import type {HelpLink} from '../../../api.d'
|
||||
|
||||
const I18n = useI18nScope('HelpLinks')
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* Canvas LMS - The open-source learning management system
|
||||
*
|
||||
* Copyright (C) 2024 Instructure, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.Wh
|
||||
*/
|
||||
|
||||
import {useScope as useI18nScope} from '@canvas/i18n'
|
||||
import React, {useState} from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import {QueryProvider} from '@canvas/query'
|
||||
import HelpDialog from '.'
|
||||
import {Modal} from '@instructure/ui-modal'
|
||||
import {Link} from '@instructure/ui-link'
|
||||
import {Heading} from '@instructure/ui-heading'
|
||||
import {CloseButton} from '@instructure/ui-buttons'
|
||||
|
||||
const I18n = useI18nScope('HelpLinks')
|
||||
|
||||
interface LoginHelpProps {
|
||||
linkText: string
|
||||
}
|
||||
|
||||
const modalLabel = () => I18n.t('Login Help for %{canvas}', {canvas: 'Canvas LMS'})
|
||||
|
||||
const LoginHelp = ({linkText}: LoginHelpProps): JSX.Element => {
|
||||
// Initial modal state is open, because this whole thing initially
|
||||
// loads in response to to the user clicking on the bare "help" link.
|
||||
const [open, setOpen] = useState(true)
|
||||
|
||||
function openHelpModal(): void {
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
function closeHelpModal(): void {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Link href="#" onClick={openHelpModal}>
|
||||
{linkText}
|
||||
</Link>
|
||||
<Modal size="small" label={modalLabel()} open={open} onDismiss={closeHelpModal}>
|
||||
<Modal.Header>
|
||||
<CloseButton
|
||||
data-testid="login-help-close-button"
|
||||
placement="end"
|
||||
offset="medium"
|
||||
onClick={closeHelpModal}
|
||||
screenReaderLabel={I18n.t('Close help dialog')}
|
||||
/>
|
||||
<Heading level="h3" as="h2">
|
||||
{modalLabel()}
|
||||
</Heading>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<HelpDialog onFormSubmit={closeHelpModal} />
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function renderLoginHelp(loginLink: Element): void {
|
||||
// wrap the help link in a span we can hang the modal off of.
|
||||
// then render the React modal into it. Be sure we're actually
|
||||
// getting an anchor element.
|
||||
if (loginLink.tagName !== 'A') throw new TypeError('loginLink must be an <a> element')
|
||||
const linkText = loginLink.textContent ?? ''
|
||||
const wrapper = document.createElement('span')
|
||||
loginLink.replaceWith(wrapper)
|
||||
wrapper.appendChild(loginLink)
|
||||
ReactDOM.render(
|
||||
<QueryProvider>
|
||||
<LoginHelp linkText={linkText} />
|
||||
</QueryProvider>,
|
||||
wrapper
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue