Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add quiz recipients selector as Side Panel #12952

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,8 @@
v-else
class="items-label"
>
<span v-if="items.length === 1">
{{ items[0] }}
</span>
<span v-else-if="items.length === 2">
{{ $tr('twoItems', { item1: items[0], item2: items[1] }) }}
</span>
<span v-else-if="items.length === 3">
{{ $tr('threeItems', { item1: items[0], item2: items[1], item3: items[2] }) }}
</span>
<span v-else>
{{ $tr('manyItems', { item1: items[0], item2: items[1], count: items.length - 2 }) }}
<span>
{{ getTruncatedItemsString(items) }}
</span>
</div>

Expand All @@ -24,6 +15,8 @@

<script>

import { getTruncatedItemsString } from './commonCoachStrings';

export default {
name: 'TruncatedItemList',
props: {
Expand All @@ -32,21 +25,8 @@
required: true,
},
},
$trs: {
twoItems: {
message: '{item1}, {item2}',
context:
"DO NOT TRANSLATE\nCopy the source string.\n\nFor reference: 'item' will be replaced by the name of the coach(es) in the list of classes.",
},
threeItems: {
message: '{item1}, {item2}, {item3}',
context:
"DO NOT TRANSLATE\nCopy the source string.\n\nFor reference: 'item' will be replaced by the name of the coach(es) in the list of classes.",
},
manyItems: {
message: '{item1}, {item2}, and {count, number, integer} others',
context: "'item' will be replaced by the name of the coach(es) in the list of classes.",
},
methods: {
getTruncatedItemsString,
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
{{ submitErrorMessage }}
</UiAlert>

<!--
TODO: Refactor or rename this component, setting a title or a description
is not part of an "assignment" process (?)
-->
<fieldset>
<KGrid>
<KGridItem
Expand Down Expand Up @@ -78,7 +82,19 @@
<legend>
{{ recipientsLabel$() }}
</legend>

<SidePanelRecipientsSelector
v-if="selectRecipientsWithSidePanel"
ref="recipientsSelector"
v-model="selectedCollectionIds"
:groups="groups"
:classId="classId"
:disabled="disabled || formIsSubmitted"
:adHocLearners.sync="adHocLearners"
:selectedCollectionIds.sync="selectedCollectionIds"
/>
<RecipientSelector
v-else
v-model="selectedCollectionIds"
:groups="groups"
:classId="classId"
Expand Down Expand Up @@ -118,13 +134,15 @@
import commonCoreStrings from 'kolibri/uiText/commonCoreStrings';
import { coachStrings } from '../../common/commonCoachStrings';
import RecipientSelector from './RecipientSelector';
import SidePanelRecipientsSelector from './SidePanelRecipientsSelector';

export default {
name: 'AssignmentDetailsModal',
components: {
BottomAppBar,
RecipientSelector,
UiAlert,
SidePanelRecipientsSelector,
},
mixins: [commonCoreStrings],
setup() {
Expand Down Expand Up @@ -183,6 +201,10 @@
type: Boolean,
default: false,
},
selectRecipientsWithSidePanel: {
type: Boolean,
default: false,
},
},
data() {
return {
Expand Down Expand Up @@ -327,6 +349,30 @@
this.showTitleError = false;
this.showServerError = false;
},
/**
* @public
*/
validate() {
let error = '';
// Validate title
if (this.title === '') {
this.handleSubmitTitleFailure();
error = this.coreString('requiredFieldError');
}

// Validate recipients
const recipientsError = this.$refs.recipientsSelector?.validate();
if (!error && recipientsError) {
error = recipientsError;
this.$refs.recipientsSelector?.handleSubmitRecipientsFailure();
}

if (error) {
this.showServerError = true;
}

return error;
},
},
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,87 +1,62 @@
<template>

<div>
<!-- Main checkbox -->
<KCheckbox
key="adHocLearners"
:checked="isVisible"
:disabled="disabled"
@change="$emit('togglevisibility', $event)"
>
<KLabeledIcon
icon="people"
:label="$tr('individualLearnersLabel')"
/>
</KCheckbox>

<!-- Paginated list of learners -->
<div v-if="isVisible">
<div class="table-title">
{{ $tr('selectedIndividualLearnersLabel') }}
</div>
<div class="table-description">
{{ $tr('onlyShowingEnrolledLabel') }}
</div>

<PaginatedListContainer
:items="allLearners"
:filterPlaceholder="$tr('searchPlaceholder')"
:itemsPerPage="itemsPerPage"
@pageChanged="currentPageLearners = $event.items"
<PaginatedListContainer
:items="allLearners"
:filterPlaceholder="$tr('searchPlaceholder')"
:itemsPerPage="itemsPerPage"
@pageChanged="currentPageLearners = $event.items"
>
<template #default="{ items }">
<CoreTable
:selectable="true"
:emptyMessage="emptyMessage"
>
<template #default="{ items }">
<CoreTable
:selectable="true"
:emptyMessage="emptyMessage"
>
<template #headers>
<th class="table-checkbox-header">
<template #headers>
<th class="table-checkbox-header">
<KCheckbox
key="selectAllOnPage"
:label="$tr('selectAllLabel')"
:checked="selectAllCheckboxProps.checked"
:indeterminate="selectAllCheckboxProps.indeterminate"
:disabled="selectAllCheckboxProps.disabled"
@change="selectVisiblePage"
/>
</th>
<th class="table-header">
{{ coreString('usernameLabel') }}
</th>
<th class="table-header">
{{ coachString('groupsLabel') }}
</th>
</template>

<template #tbody>
<tbody>
<tr
v-for="learner in items"
:key="learner.id"
>
<td>
<KCheckbox
key="selectAllOnPage"
:label="$tr('selectAllLabel')"
:checked="selectAllCheckboxProps.checked"
:indeterminate="selectAllCheckboxProps.indeterminate"
:disabled="selectAllCheckboxProps.disabled"
@change="selectVisiblePage"
:key="`select-learner-${learner.id}`"
:label="learner.name"
:checked="learnerIsSelected(learner)"
:disabled="learnerIsNotSelectable(learner)"
@change="toggleLearner($event, learner)"
/>
</th>
<th class="table-header">
{{ coreString('usernameLabel') }}
</th>
<th class="table-header">
{{ coachString('groupsLabel') }}
</th>
</template>

<template #tbody>
<tbody>
<tr
v-for="learner in items"
:key="learner.id"
>
<td>
<KCheckbox
:key="`select-learner-${learner.id}`"
:label="learner.name"
:checked="learnerIsSelected(learner)"
:disabled="learnerIsNotSelectable(learner)"
@change="toggleLearner($event, learner)"
/>
</td>
<td class="table-data">
{{ learner.username }}
</td>
<td class="table-data">
{{ groupNamesForLearner(learner) }}
</td>
</tr>
</tbody>
</template>
</CoreTable>
</td>
<td class="table-data">
{{ learner.username }}
</td>
<td class="table-data">
{{ groupNamesForLearner(learner) }}
</td>
</tr>
</tbody>
</template>
</PaginatedListContainer>
</div>
</div>
</CoreTable>
</template>
</PaginatedListContainer>

</template>

Expand All @@ -98,8 +73,8 @@
import forEach from 'lodash/forEach';
import countBy from 'lodash/countBy';
import every from 'lodash/every';
import ClassSummaryResource from '../../../apiResources/classSummary';
import commonCoachStrings from '../../common';
import ClassSummaryResource from '../../../../apiResources/classSummary';
import commonCoachStrings from '../../../common';

const DEFAULT_ITEMS_PER_PAGE = 30;

Expand All @@ -115,11 +90,6 @@
};
},
props: {
// If true, the main checkbox is checked and the list of learners is shown
isVisible: {
type: Boolean,
required: true,
},
// Used to disable learner rows if already assigned via learner group
selectedGroupIds: {
type: Array,
Expand Down Expand Up @@ -180,7 +150,10 @@
learnerIdsFromSelectedGroups() {
// If a learner is part of a Learner Group that has already been selected
// in RecipientSelector, then disable their row
return flatMap(this.selectedGroupIds, groupId => this.currentGroupMap[groupId].member_ids);
return flatMap(
this.selectedGroupIds,
groupId => this.currentGroupMap[groupId]?.member_ids || [],
);
},
selectAllCheckboxProps() {
const currentCount = this.currentPageLearners.length;
Expand Down Expand Up @@ -277,25 +250,10 @@
},
},
$trs: {
selectedIndividualLearnersLabel: {
message: 'Select individual learners',
context:
'A bolded header for the table where a Coach will select individual learners who will have access to a quiz.',
},
onlyShowingEnrolledLabel: {
message: 'Only showing learners that are enrolled in this class',
context:
"Shows beneath 'Select individual learners' explaining that the table only includes enrolled learners.",
},
selectAllLabel: {
message: 'Select all on page',
context: 'A checkbox label that will select all visible rows in the table',
},
individualLearnersLabel: {
message: 'Individual learners',
context:
'A label for a checkbox that allows the Coach to assign the quiz to individual learners who may not be in a selected group.',
},
searchPlaceholder: {
message: 'Search for a user…',
context: 'Indicates the search function which allows admins to import users.',
Expand Down
Loading
Loading