Allow selecting sections and groups in BBB modal
This commit should allow all sections and groups to be selected closes: VICE-3096 flag=bbb_modal_update Note Groups and sections prepopulate the address book when: - All of their students have been invited - If they have no users This matches legacy behavior The behavior of the section/group/user selection is not intuitive This commit should match legacy behavior. Please check legacy if you see behavior you think is broken Test Plan: 1. Create course with groups and Sections 2. Create new Conference 3. Verify that groups and sections appear 4. invite a group or section 5. Create the conference 6. Edit the newly created conference and open the addressbook 7. Verify that all users in group or section were invited 8. Verify group/section tag populates the addressbook 8a. Verify that the groups and sections selected match legacy Change-Id: I1881eee5f45b4261c0b8ccf344330a017cc5cf19 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/301675 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Caleb Guanzon <cguanzon@instructure.com> Reviewed-by: Jeffrey Johnson <jeffrey.johnson@instructure.com> Product-Review: Jeffrey Johnson <jeffrey.johnson@instructure.com>
This commit is contained in:
parent
03b4c69b3b
commit
12dbc7e04e
|
@ -82,6 +82,52 @@ describe "BigBlueButton conferences" do
|
|||
end
|
||||
end
|
||||
|
||||
context "attendee selection" do
|
||||
before do
|
||||
@section = @course.course_sections.create!(name: "test section")
|
||||
student_in_section(@section, user: @student)
|
||||
|
||||
@group_category = @course.group_categories.create!(name: "Group Category")
|
||||
@group = @course.groups.create!(group_category: @group_category, name: "Group 1")
|
||||
@group.add_user(@student, "accepted")
|
||||
end
|
||||
|
||||
context "on create" do
|
||||
it "successfully invites a section to the conference" do
|
||||
get "/courses/#{@course.id}/conferences"
|
||||
new_conference_button.click
|
||||
wait_for_ajaximations
|
||||
f("div#tab-attendees").click
|
||||
fj("label:contains('Invite all course members')").click
|
||||
f("[data-testid='address-input']").click
|
||||
f("[data-testid='section-#{@section.id}']").click
|
||||
expect(@section.participants.count).to eq ff("[data-testid='address-tag']").count
|
||||
|
||||
wait_for_new_page_load { f("button[data-testid='submit-button']").click }
|
||||
new_conference = WebConference.last
|
||||
expect(@section.participants.count).to eq new_conference.users.count
|
||||
end
|
||||
|
||||
it "successfully invites a group to the conference" do
|
||||
get "/courses/#{@course.id}/conferences"
|
||||
# Since the teacher isn't a participating user, we have to add 1 to this count
|
||||
group_participant_and_group_tag_count = @group.participating_users_in_context.count + 1
|
||||
|
||||
new_conference_button.click
|
||||
wait_for_ajaximations
|
||||
f("div#tab-attendees").click
|
||||
fj("label:contains('Invite all course members')").click
|
||||
f("[data-testid='address-input']").click
|
||||
f("[data-testid='group-#{@group.id}']").click
|
||||
expect(group_participant_and_group_tag_count).to eq ff("[data-testid='address-tag']").count
|
||||
|
||||
wait_for_new_page_load { f("button[data-testid='submit-button']").click }
|
||||
new_conference = WebConference.last
|
||||
expect(group_participant_and_group_tag_count).to eq new_conference.users.count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "validates name length" do
|
||||
initial_conference_count = WebConference.count
|
||||
get conferences_index_page
|
||||
|
|
|
@ -117,14 +117,35 @@ const ConferencesRouter = Backbone.Router.extend({
|
|||
return {
|
||||
displayName: name,
|
||||
id,
|
||||
type: 'user',
|
||||
assetCode: `user-${id}`,
|
||||
}
|
||||
})
|
||||
|
||||
const availableSectionsList = ENV.sections.map(({id, name}) => {
|
||||
return {
|
||||
displayName: name,
|
||||
id,
|
||||
type: 'section',
|
||||
assetCode: `section-${id}`,
|
||||
}
|
||||
})
|
||||
|
||||
const availableGroupsList = ENV.groups.map(({id, name}) => {
|
||||
return {
|
||||
displayName: name,
|
||||
id,
|
||||
type: 'group',
|
||||
assetCode: `group-${id}`,
|
||||
}
|
||||
})
|
||||
|
||||
const menuData = availableAttendeesList.concat(availableSectionsList, availableGroupsList)
|
||||
ReactDOM.render(
|
||||
<VideoConferenceModal
|
||||
open={true}
|
||||
isEditing={false}
|
||||
availableAttendeesList={availableAttendeesList}
|
||||
availableAttendeesList={menuData}
|
||||
onDismiss={() => {
|
||||
window.location.hash = ''
|
||||
ReactDOM.render(<span />, document.getElementById('react-conference-modal-container'))
|
||||
|
@ -174,8 +195,14 @@ const ConferencesRouter = Backbone.Router.extend({
|
|||
payload[`user[${userId}]`] = 1
|
||||
})
|
||||
} else {
|
||||
data.selectedAttendees.forEach(userId => {
|
||||
payload[`user[${userId}]`] = 1
|
||||
data.selectedAttendees.forEach(menuItem => {
|
||||
if (menuItem.type === 'group') {
|
||||
payload[`group[${menuItem.id}]`] = 1
|
||||
} else if (menuItem.type === 'section') {
|
||||
payload[`section[${menuItem.id}]`] = 1
|
||||
} else {
|
||||
payload[`user[${menuItem.id}]`] = 1
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -242,9 +269,30 @@ const ConferencesRouter = Backbone.Router.extend({
|
|||
return {
|
||||
displayName: name,
|
||||
id,
|
||||
type: 'user',
|
||||
assetCode: `user-${id}`,
|
||||
}
|
||||
})
|
||||
|
||||
const availableSectionsList = ENV.sections.map(({id, name}) => {
|
||||
return {
|
||||
displayName: name,
|
||||
id,
|
||||
type: 'section',
|
||||
assetCode: `section-${id}`,
|
||||
}
|
||||
})
|
||||
|
||||
const availableGroupsList = ENV.groups.map(({id, name}) => {
|
||||
return {
|
||||
displayName: name,
|
||||
id,
|
||||
type: 'group',
|
||||
assetCode: `group-${id}`,
|
||||
}
|
||||
})
|
||||
|
||||
const menuData = availableAttendeesList.concat(availableSectionsList, availableGroupsList)
|
||||
if (attributes.long_running === 1) {
|
||||
options.push('no_time_limit')
|
||||
}
|
||||
|
@ -285,9 +333,10 @@ const ConferencesRouter = Backbone.Router.extend({
|
|||
description={attributes.description}
|
||||
invitationOptions={invitationOptions}
|
||||
attendeesOptions={attendeesOptions}
|
||||
availableAttendeesList={availableAttendeesList}
|
||||
selectedAttendees={attributes.user_ids}
|
||||
savedAttendees={attributes.user_ids}
|
||||
availableAttendeesList={menuData}
|
||||
selectedAttendees={attributes.user_ids.map(u => {
|
||||
return {assetCode: `user-${u}`, id: u}
|
||||
})}
|
||||
startCalendarDate={attributes.start_at}
|
||||
endCalendarDate={attributes.end_at}
|
||||
onDismiss={() => {
|
||||
|
@ -340,8 +389,14 @@ const ConferencesRouter = Backbone.Router.extend({
|
|||
payload[`user[${userId}]`] = 1
|
||||
})
|
||||
} else {
|
||||
data.selectedAttendees.forEach(userId => {
|
||||
payload[`user[${userId}]`] = 1
|
||||
data.selectedAttendees.forEach(menuItem => {
|
||||
if (menuItem.type === 'group') {
|
||||
payload[`group[${menuItem.id}]`] = 1
|
||||
} else if (menuItem.type === 'section') {
|
||||
payload[`section[${menuItem.id}]`] = 1
|
||||
} else {
|
||||
payload[`user[${menuItem.id}]`] = 1
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ const BBBModalOptions = ({addToCalendar, setAddToCalendar, ...props}) => {
|
|||
const [noTimeLimit, setNoTimeLimit] = useState(props.options.includes('no_time_limit')) // match options.no_time_limit default
|
||||
|
||||
const contextIsGroup = ENV.context_asset_string?.split('_')[0] === 'group'
|
||||
const inviteAllMemberstext = contextIsGroup
|
||||
const inviteAllMembersText = contextIsGroup
|
||||
? I18n.t('Invite all group members')
|
||||
: I18n.t('Invite all course members')
|
||||
|
||||
|
@ -249,7 +249,7 @@ const BBBModalOptions = ({addToCalendar, setAddToCalendar, ...props}) => {
|
|||
</View>
|
||||
}
|
||||
>
|
||||
<Checkbox label={inviteAllMemberstext} value="invite_all" disabled={addToCalendar} />
|
||||
<Checkbox label={inviteAllMembersText} value="invite_all" disabled={addToCalendar} />
|
||||
{!contextIsGroup && (
|
||||
<Checkbox
|
||||
label={I18n.t('Remove all course observer members')}
|
||||
|
@ -263,11 +263,10 @@ const BBBModalOptions = ({addToCalendar, setAddToCalendar, ...props}) => {
|
|||
<Flex.Item padding="small">
|
||||
<ConferenceAddressBook
|
||||
data-testId="conference-address-book"
|
||||
selectedIds={props.selectedAttendees}
|
||||
savedAttendees={props.savedAttendees}
|
||||
selectedItems={props.selectedAttendees}
|
||||
menuItemList={props.availableAttendeesList}
|
||||
onChange={userList => {
|
||||
props.onAttendeesChange(userList.map(u => u.id))
|
||||
onChange={menuItemList => {
|
||||
props.onAttendeesChange(menuItemList)
|
||||
}}
|
||||
isEditing={props.isEditing}
|
||||
/>
|
||||
|
@ -335,8 +334,7 @@ BBBModalOptions.propTypes = {
|
|||
showAddressBook: PropTypes.bool,
|
||||
onAttendeesChange: PropTypes.func,
|
||||
availableAttendeesList: PropTypes.arrayOf(PropTypes.object),
|
||||
selectedAttendees: PropTypes.arrayOf(PropTypes.string),
|
||||
savedAttendees: PropTypes.arrayOf(PropTypes.string),
|
||||
selectedAttendees: PropTypes.arrayOf(PropTypes.object),
|
||||
showCalendar: PropTypes.bool,
|
||||
setAddToCalendar: PropTypes.func,
|
||||
addToCalendar: PropTypes.bool,
|
||||
|
|
|
@ -113,11 +113,10 @@ const BaseModalOptions = props => {
|
|||
<Flex.Item padding="medium">
|
||||
<ConferenceAddressBook
|
||||
data-testid="conference-address-book"
|
||||
selectedIds={props.selectedAttendees}
|
||||
savedAttendees={props.savedAttendees}
|
||||
selectedItems={props.selectedAttendees}
|
||||
menuItemList={props.availableAttendeesList}
|
||||
onChange={userList => {
|
||||
props.onAttendeesChange(userList.map(u => u.id))
|
||||
onChange={menuItemList => {
|
||||
props.onAttendeesChange(menuItemList)
|
||||
}}
|
||||
isEditing={props.isEditing}
|
||||
/>
|
||||
|
@ -154,7 +153,6 @@ BaseModalOptions.propTypes = {
|
|||
onAttendeesChange: PropTypes.func,
|
||||
availableAttendeesList: PropTypes.arrayOf(PropTypes.object),
|
||||
selectedAttendees: PropTypes.arrayOf(PropTypes.string),
|
||||
savedAttendees: PropTypes.arrayOf(PropTypes.string),
|
||||
nameValidationMessages: PropTypes.array,
|
||||
descriptionValidationMessages: PropTypes.array,
|
||||
hasBegun: PropTypes.bool,
|
||||
|
|
|
@ -24,27 +24,68 @@ import {Tag} from '@instructure/ui-tag'
|
|||
|
||||
const I18n = useI18nScope('video_conference')
|
||||
|
||||
export const ConferenceAddressBook = ({
|
||||
menuItemList,
|
||||
onChange,
|
||||
selectedIds,
|
||||
isEditing,
|
||||
savedAttendees,
|
||||
}) => {
|
||||
export const ConferenceAddressBook = ({menuItemList, onChange, selectedItems, isEditing}) => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [highlightMenuItem, setHighlightMenuItem] = useState(null)
|
||||
const [inputValue, setInputValue] = useState('')
|
||||
const [selectedMenuItems, setSelectedMenuItems] = useState([])
|
||||
const [announcement, setAnnouncement] = useState('')
|
||||
const [savedAttendees, setSavedAttendees] = useState([])
|
||||
|
||||
// Initial setup of selectd Ids
|
||||
useEffect(() => {
|
||||
const initialSelectedMenuItems = menuItemList.filter(u => selectedIds?.includes(u.id))
|
||||
if (initialSelectedMenuItems !== selectedMenuItems) {
|
||||
setSelectedMenuItems(initialSelectedMenuItems)
|
||||
const groupUserMap = ENV?.group_user_ids_map || {}
|
||||
const sectionUserMap = ENV?.section_user_ids_map || {}
|
||||
|
||||
// Create an array that contains the shared elements between 2 arrays
|
||||
const intersection = (array1, array2) => {
|
||||
let tempSwitchVariable
|
||||
if (array2.length > array1.length) {
|
||||
tempSwitchVariable = array2
|
||||
array2 = array1
|
||||
array1 = tempSwitchVariable
|
||||
}
|
||||
return array1.filter(e => {
|
||||
return array2.indexOf(e) > -1
|
||||
})
|
||||
}
|
||||
// Runs once on startup to set up initially selected items
|
||||
useEffect(() => {
|
||||
const selectedUserIDs = selectedItems?.map(u => u.id)
|
||||
const selectedUserAssetCode = selectedItems?.map(u => u.assetCode)
|
||||
// This should only get set once. Represents users who are already a part of the conference
|
||||
|
||||
const sectionIDs = ENV.sections?.map(u => u.id) || []
|
||||
const groupIDs = ENV.groups?.map(u => u.id) || []
|
||||
|
||||
let selectedSections = []
|
||||
let selectedGroups = []
|
||||
|
||||
// Any section or group that has all of its students selected will be auto selected
|
||||
// Empty groups or sections will be set to selected automatically
|
||||
sectionIDs?.forEach(id => {
|
||||
const sectionUsers = sectionUserMap[id]
|
||||
const intersectionArray = intersection(sectionUsers, selectedUserIDs)
|
||||
if (intersectionArray.length === sectionUsers.length) {
|
||||
selectedSections.push(id)
|
||||
}
|
||||
})
|
||||
|
||||
groupIDs?.forEach(id => {
|
||||
const groupUsers = groupUserMap[id]
|
||||
const intersectionArray = intersection(groupUsers, selectedUserIDs)
|
||||
if (intersectionArray.length === groupUsers.length) {
|
||||
selectedGroups.push(id)
|
||||
}
|
||||
})
|
||||
|
||||
selectedGroups = selectedGroups?.map(u => `group-${u}`)
|
||||
selectedSections = selectedSections?.map(u => `section-${u}`)
|
||||
const initialSelectedMenuItems = menuItemList.filter(u =>
|
||||
selectedGroups.concat(selectedSections, selectedUserAssetCode)?.includes(u.assetCode)
|
||||
)
|
||||
setSavedAttendees(initialSelectedMenuItems.map(u => u.assetCode))
|
||||
setSelectedMenuItems([...selectedMenuItems.concat(initialSelectedMenuItems)])
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedIds, menuItemList])
|
||||
}, [])
|
||||
|
||||
const handleBlur = () => {
|
||||
setHighlightMenuItem(null)
|
||||
|
@ -59,7 +100,7 @@ export const ConferenceAddressBook = ({
|
|||
|
||||
const handleHighlight = (e, {id}) => {
|
||||
if (id) {
|
||||
const menuItem = menuItemList.find(u => u.id === id)
|
||||
const menuItem = menuItemList.find(u => u.assetCode === id)
|
||||
setHighlightMenuItem(menuItem)
|
||||
setAnnouncement(menuItem.displayName)
|
||||
}
|
||||
|
@ -93,24 +134,62 @@ export const ConferenceAddressBook = ({
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [inputValue, menuItemList, selectedMenuItems.length])
|
||||
|
||||
const mapOfFilteredMenuItems = useMemo(() => {
|
||||
const sectionArray = []
|
||||
const groupArray = []
|
||||
const userArray = []
|
||||
|
||||
filteredMenuItems.forEach(menuItem => {
|
||||
if (menuItem.type === 'section') {
|
||||
sectionArray.push(menuItem)
|
||||
} else if (menuItem.type === 'group') {
|
||||
groupArray.push(menuItem)
|
||||
} else {
|
||||
userArray.push(menuItem)
|
||||
}
|
||||
})
|
||||
|
||||
return new Map([
|
||||
['sections', sectionArray],
|
||||
['groups', groupArray],
|
||||
['users', userArray],
|
||||
])
|
||||
}, [filteredMenuItems])
|
||||
|
||||
const removeSelectedItem = menuItem => {
|
||||
if (isEditing) {
|
||||
if (savedAttendees?.includes(menuItem.id))
|
||||
// Change this to work with asset codes
|
||||
if (savedAttendees?.includes(menuItem.assetCode)) {
|
||||
// terminate if menu item has been saved
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Get users from group or section to Remove
|
||||
let additionalUsersToRemove = []
|
||||
if (menuItem.type === 'group') {
|
||||
additionalUsersToRemove = groupUserMap[menuItem.id]?.map(u => `user-${u}`)
|
||||
} else if (menuItem.type === 'section') {
|
||||
additionalUsersToRemove = sectionUserMap[menuItem.id]?.map(u => `user-${u}`)
|
||||
}
|
||||
|
||||
const unsavedUsersToRemove = additionalUsersToRemove.filter(x => !savedAttendees?.includes(x))
|
||||
|
||||
const menuItemsToRemove = menuItemList.filter(u => unsavedUsersToRemove?.includes(u.assetCode))
|
||||
menuItemsToRemove.push(menuItem)
|
||||
const newSelectedMenuItems = selectedMenuItems
|
||||
const removalIndex = newSelectedMenuItems.indexOf(menuItem)
|
||||
if (removalIndex > -1) {
|
||||
newSelectedMenuItems.splice(removalIndex, 1)
|
||||
}
|
||||
menuItemsToRemove.forEach(currentMenuItem => {
|
||||
const removalIndex = newSelectedMenuItems.indexOf(currentMenuItem)
|
||||
if (removalIndex > -1) {
|
||||
newSelectedMenuItems.splice(removalIndex, 1)
|
||||
}
|
||||
})
|
||||
setSelectedMenuItems([...newSelectedMenuItems])
|
||||
onChange([...newSelectedMenuItems])
|
||||
}
|
||||
|
||||
const addSelectedItem = (event, {id}) => {
|
||||
const menuItem = menuItemList.find(u => u.id === id)
|
||||
|
||||
const menuItem = menuItemList.find(u => u.assetCode === id)
|
||||
// Exit if selected menu item is already selected
|
||||
if (selectedMenuItems.includes(menuItem)) {
|
||||
setIsOpen(false)
|
||||
|
@ -118,8 +197,25 @@ export const ConferenceAddressBook = ({
|
|||
return
|
||||
}
|
||||
|
||||
const newSelectedItems = selectedMenuItems
|
||||
newSelectedItems.push(menuItem)
|
||||
// Get users from group or section to add
|
||||
let additionalUsersToAdd = []
|
||||
if (menuItem.type === 'group') {
|
||||
additionalUsersToAdd = groupUserMap[menuItem.id] || []
|
||||
} else if (menuItem.type === 'section') {
|
||||
additionalUsersToAdd = sectionUserMap[menuItem.id] || []
|
||||
}
|
||||
additionalUsersToAdd = additionalUsersToAdd?.map(u => `user-${u}`)
|
||||
// Remove users that have already been selected so duplicates do not occur
|
||||
const selectedMenuItemsAssetCode = selectedMenuItems?.map(u => u.assetCode)
|
||||
const unselectedUsers = additionalUsersToAdd.filter(
|
||||
x => !selectedMenuItemsAssetCode.includes(x)
|
||||
)
|
||||
const additionalUsersToAddMenuItem = menuItemList.filter(u =>
|
||||
unselectedUsers?.includes(u.assetCode)
|
||||
)
|
||||
additionalUsersToAddMenuItem.push(menuItem)
|
||||
|
||||
const newSelectedItems = selectedMenuItems.concat(additionalUsersToAddMenuItem)
|
||||
setAnnouncement(`${menuItem.displayName} selected. List collapsed.`)
|
||||
setSelectedMenuItems([...newSelectedItems])
|
||||
onChange([...newSelectedItems])
|
||||
|
@ -139,7 +235,7 @@ export const ConferenceAddressBook = ({
|
|||
return (
|
||||
<div>
|
||||
<Select
|
||||
data-testId="address-input"
|
||||
data-testid="address-input"
|
||||
renderLabel={I18n.t('Course Members')}
|
||||
assistiveText={I18n.t(
|
||||
'Type or use arrow keys to navigate options. Multiple selections allowed.'
|
||||
|
@ -162,13 +258,57 @@ export const ConferenceAddressBook = ({
|
|||
) : null
|
||||
}
|
||||
>
|
||||
{filteredMenuItems?.map(u => {
|
||||
return (
|
||||
<Select.Option id={u.id} key={u.id} isHighlighted={u.id === highlightMenuItem?.id}>
|
||||
{u.displayName}
|
||||
</Select.Option>
|
||||
)
|
||||
})}
|
||||
{!!mapOfFilteredMenuItems.get('sections')?.length && (
|
||||
<Select.Group
|
||||
key="sections"
|
||||
renderLabel="Sections"
|
||||
data-testid="section-conference-header"
|
||||
>
|
||||
{mapOfFilteredMenuItems.get('sections')?.map(u => {
|
||||
return (
|
||||
<Select.Option
|
||||
id={u.assetCode}
|
||||
key={u.assetCode}
|
||||
isHighlighted={u.assetCode === highlightMenuItem?.assetCode}
|
||||
data-testid={u.assetCode}
|
||||
>
|
||||
{u.displayName}
|
||||
</Select.Option>
|
||||
)
|
||||
})}
|
||||
</Select.Group>
|
||||
)}
|
||||
|
||||
{!!mapOfFilteredMenuItems.get('groups')?.length && (
|
||||
<Select.Group key="groups" renderLabel="Groups" data-testid="group-conference-header">
|
||||
{mapOfFilteredMenuItems.get('groups')?.map(u => {
|
||||
return (
|
||||
<Select.Option
|
||||
id={u.assetCode}
|
||||
key={u.assetCode}
|
||||
isHighlighted={u.assetCode === highlightMenuItem?.assetCode}
|
||||
data-testid={u.assetCode}
|
||||
>
|
||||
{u.displayName}
|
||||
</Select.Option>
|
||||
)
|
||||
})}
|
||||
</Select.Group>
|
||||
)}
|
||||
<Select.Group key="users" renderLabel="Users" data-testid="user-conference-header">
|
||||
{mapOfFilteredMenuItems.get('users')?.map(u => {
|
||||
return (
|
||||
<Select.Option
|
||||
id={u.assetCode}
|
||||
key={u.assetCode}
|
||||
isHighlighted={u.assetCode === highlightMenuItem?.assetCode}
|
||||
data-testid={u.assetCode}
|
||||
>
|
||||
{u.displayName}
|
||||
</Select.Option>
|
||||
)
|
||||
})}
|
||||
</Select.Group>
|
||||
</Select>
|
||||
<Alert
|
||||
liveRegion={() => document.getElementById('flash-messages')}
|
||||
|
@ -183,10 +323,9 @@ export const ConferenceAddressBook = ({
|
|||
|
||||
ConferenceAddressBook.propTypes = {
|
||||
menuItemList: PropTypes.array,
|
||||
selectedIds: PropTypes.arrayOf(PropTypes.string),
|
||||
savedAttendees: PropTypes.arrayOf(PropTypes.string),
|
||||
onChange: PropTypes.func,
|
||||
isEditing: PropTypes.bool,
|
||||
selectedItems: PropTypes.arrayOf(PropTypes.object),
|
||||
}
|
||||
|
||||
ConferenceAddressBook.defaultProps = {
|
||||
|
@ -195,9 +334,9 @@ ConferenceAddressBook.defaultProps = {
|
|||
const ConferenceAddressBookTags = ({selectedMenuItems, onDismiss}) => {
|
||||
return selectedMenuItems.map((menuItem, index) => (
|
||||
<Tag
|
||||
data-testId="address-tag"
|
||||
data-testid="address-tag"
|
||||
dismissable={true}
|
||||
key={menuItem.id}
|
||||
key={menuItem.assetCode}
|
||||
title={`Remove ${menuItem.displayName}`}
|
||||
text={menuItem.displayName}
|
||||
margin={index > 0 ? 'xxx-small 0 xxx-small xx-small' : 'xxx-small 0'}
|
||||
|
|
|
@ -21,14 +21,23 @@ import {fireEvent, render} from '@testing-library/react'
|
|||
import {ConferenceAddressBook} from '../ConferenceAddressBook'
|
||||
|
||||
describe('ConferenceAddressBook', () => {
|
||||
afterEach(() => {
|
||||
window.ENV.sections = []
|
||||
window.ENV.section_user_ids_map = {}
|
||||
window.ENV.groups = []
|
||||
window.ENV.group_user_ids_map = {}
|
||||
})
|
||||
|
||||
const menuItemList = [
|
||||
{displayName: 'Allison', id: '7'},
|
||||
{displayName: 'Caleb', id: '3'},
|
||||
{displayName: 'Chawn', id: '2'},
|
||||
{displayName: 'Allison', id: '7', type: 'user', assetCode: 'user-7'},
|
||||
{displayName: 'Caleb', id: '3', type: 'user', assetCode: 'user-3'},
|
||||
{displayName: 'Chawn', id: '2', type: 'user', assetCode: 'user-2'},
|
||||
{displayName: 'Group1', id: '23', type: 'group', assetCode: 'group-23'},
|
||||
{displayName: 'Section1', id: '24', type: 'section', assetCode: 'section-24'},
|
||||
]
|
||||
|
||||
const setup = (props = {}) => {
|
||||
return render(<ConferenceAddressBook menuItemList={menuItemList} {...props} />)
|
||||
const setup = (props = {}, menuList = menuItemList) => {
|
||||
return render(<ConferenceAddressBook menuItemList={menuList} {...props} />)
|
||||
}
|
||||
|
||||
it('should render', () => {
|
||||
|
@ -62,12 +71,94 @@ describe('ConferenceAddressBook', () => {
|
|||
expect(tag).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should render initial tags when selectedIds is passed', () => {
|
||||
const container = setup({selectedIds: ['2']})
|
||||
it('should add tag when group is selected', () => {
|
||||
const container = setup()
|
||||
const input = container.getByTestId('address-input')
|
||||
input.click()
|
||||
const item = container.getByText('Group1')
|
||||
item.click()
|
||||
const tag = container.getByTestId('address-tag')
|
||||
expect(tag).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should add tag when section is selected', () => {
|
||||
const container = setup()
|
||||
const input = container.getByTestId('address-input')
|
||||
input.click()
|
||||
const item = container.getByText('Section1')
|
||||
item.click()
|
||||
const tag = container.getByTestId('address-tag')
|
||||
expect(tag).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should have section header when section is present', () => {
|
||||
const container = setup()
|
||||
const input = container.getByTestId('address-input')
|
||||
input.click()
|
||||
const item = container.getByTestId('section-conference-header')
|
||||
expect(item).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should have group header when group is present', () => {
|
||||
const container = setup()
|
||||
const input = container.getByTestId('address-input')
|
||||
input.click()
|
||||
const item = container.getByTestId('group-conference-header')
|
||||
expect(item).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should not have group header when no groups exist', () => {
|
||||
const menuItemList = [
|
||||
{displayName: 'Allison', id: '7', type: 'user', assetCode: 'user-7'},
|
||||
{displayName: 'Caleb', id: '3', type: 'user', assetCode: 'user-3'},
|
||||
{displayName: 'Chawn', id: '2', type: 'user', assetCode: 'user-2'},
|
||||
{displayName: 'Section1', id: '24', type: 'section', assetCode: 'section-24'},
|
||||
]
|
||||
const container = setup({}, menuItemList)
|
||||
const input = container.getByTestId('address-input')
|
||||
input.click()
|
||||
const item = container.queryByTestId('group-conference-header')
|
||||
expect(item).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should have User header', () => {
|
||||
const container = setup()
|
||||
const input = container.getByTestId('address-input')
|
||||
input.click()
|
||||
const item = container.getByTestId('user-conference-header')
|
||||
expect(item).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should render initial tags when selectedIds is passed', () => {
|
||||
const container = setup({
|
||||
selectedItems: [{displayName: 'Chawn', id: '2', type: 'user', assetCode: 'user-2'}],
|
||||
})
|
||||
const tag = container.getByTestId('address-tag')
|
||||
expect(tag).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should initially render groups that have all users selected', () => {
|
||||
window.ENV.groups = [{displayName: 'Group1', id: '23'}]
|
||||
window.ENV.group_user_ids_map = {23: ['2']}
|
||||
const container = setup({
|
||||
selectedItems: [{displayName: 'Chawn', id: '2', type: 'user', assetCode: 'user-2'}],
|
||||
})
|
||||
const tag = container.getAllByTestId('address-tag')
|
||||
expect(tag).toBeTruthy()
|
||||
expect(tag.length).toBe(2)
|
||||
})
|
||||
|
||||
it('should initially render sections that have all users selected', () => {
|
||||
window.ENV.sections = [{displayName: 'Section1', id: '24'}]
|
||||
window.ENV.section_user_ids_map = {24: ['2']}
|
||||
const container = setup({
|
||||
selectedItems: [{displayName: 'Chawn', id: '2', type: 'user', assetCode: 'user-2'}],
|
||||
})
|
||||
const tag = container.getAllByTestId('address-tag')
|
||||
expect(tag).toBeTruthy()
|
||||
expect(tag.length).toBe(2)
|
||||
})
|
||||
|
||||
it('should remove selected user when backspace is pressed and input is empty', () => {
|
||||
const container = setup()
|
||||
const input = container.getByTestId('address-input')
|
||||
|
@ -80,7 +171,7 @@ describe('ConferenceAddressBook', () => {
|
|||
})
|
||||
|
||||
it('should not remove saved users when isEditing', () => {
|
||||
const container = setup({isEditing: true, savedAttendees: ['7']})
|
||||
const container = setup({isEditing: true, selectedItems: [menuItemList[0]]})
|
||||
const input = container.getByTestId('address-input')
|
||||
input.click()
|
||||
const item = container.getByText('Allison')
|
||||
|
@ -93,7 +184,7 @@ describe('ConferenceAddressBook', () => {
|
|||
})
|
||||
|
||||
it('should remove unsaved users when isEditing', () => {
|
||||
const container = setup({isEditing: true, savedAttendees: ['25']})
|
||||
const container = setup({isEditing: true, selectedItems: []})
|
||||
const input = container.getByTestId('address-input')
|
||||
input.click()
|
||||
const item = container.getByText('Allison')
|
||||
|
|
|
@ -189,7 +189,6 @@ export const VideoConferenceModal = ({
|
|||
onAttendeesChange={setSelectedAttendees}
|
||||
availableAttendeesList={availableAttendeesList}
|
||||
selectedAttendees={selectedAttendees}
|
||||
savedAttendees={props.savedAttendees}
|
||||
showCalendar={showCalendarOptions}
|
||||
setAddToCalendar={setAddToCalendar}
|
||||
addToCalendar={addToCalendar}
|
||||
|
@ -225,7 +224,6 @@ export const VideoConferenceModal = ({
|
|||
onAttendeesChange={setSelectedAttendees}
|
||||
availableAttendeesList={availableAttendeesList}
|
||||
selectedAttendees={selectedAttendees}
|
||||
savedAttendees={props.savedAttendees}
|
||||
nameValidationMessages={nameValidationMessages}
|
||||
descriptionValidationMessages={descriptionValidationMessages}
|
||||
hasBegun={props.hasBegun}
|
||||
|
@ -337,8 +335,7 @@ VideoConferenceModal.propTypes = {
|
|||
attendeesOptions: PropTypes.arrayOf(PropTypes.string),
|
||||
type: PropTypes.string,
|
||||
availableAttendeesList: PropTypes.arrayOf(PropTypes.object),
|
||||
selectedAttendees: PropTypes.arrayOf(PropTypes.string),
|
||||
savedAttendees: PropTypes.arrayOf(PropTypes.string),
|
||||
selectedAttendees: PropTypes.arrayOf(PropTypes.object),
|
||||
startCalendarDate: PropTypes.string,
|
||||
endCalendarDate: PropTypes.string,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue