174 lines
6.0 KiB
JavaScript
174 lines
6.0 KiB
JavaScript
import { useIntl } from '@edx/frontend-platform/i18n';
|
|
import { Button, Form } from '@openedx/paragon';
|
|
import { Add } from '@openedx/paragon/icons';
|
|
|
|
import { FieldArray } from 'formik';
|
|
import PropTypes from 'prop-types';
|
|
import React from 'react';
|
|
import { v4 as uuid } from 'uuid';
|
|
import * as Yup from 'yup';
|
|
import { GroupTypes, TeamSizes } from 'CourseAuthoring/data/constants';
|
|
import FormikControl from 'CourseAuthoring/generic/FormikControl';
|
|
import { setupYupExtensions, useAppSetting } from 'CourseAuthoring/utils';
|
|
import AppSettingsModal from 'CourseAuthoring/pages-and-resources/app-settings-modal/AppSettingsModal';
|
|
import GroupEditor from './GroupEditor';
|
|
import messages from './messages';
|
|
|
|
setupYupExtensions();
|
|
|
|
const TeamSettings = ({
|
|
onClose,
|
|
}) => {
|
|
const intl = useIntl();
|
|
const [teamsConfiguration, saveSettings] = useAppSetting('teamsConfiguration');
|
|
const blankNewGroup = {
|
|
name: '',
|
|
description: '',
|
|
type: GroupTypes.OPEN,
|
|
maxTeamSize: null,
|
|
userPartitionId: null,
|
|
id: null,
|
|
key: uuid(),
|
|
};
|
|
|
|
const handleSettingsSave = async (values) => {
|
|
// For newly-added teams, fill in an id.
|
|
const groups = values.groups?.map(group => ({
|
|
id: group.id || uuid(),
|
|
name: group.name,
|
|
type: group.type,
|
|
description: group.description,
|
|
max_team_size: group.maxTeamSize,
|
|
user_partition_id: group.userPartitionId,
|
|
}));
|
|
return saveSettings({
|
|
team_sets: groups,
|
|
max_team_size: values.maxTeamSize,
|
|
enabled: values.enabled,
|
|
});
|
|
};
|
|
const enableAppError = {
|
|
title: intl.formatMessage(messages.noGroupsErrorTitle),
|
|
message: intl.formatMessage(messages.noGroupsErrorMessage),
|
|
};
|
|
|
|
return (
|
|
<AppSettingsModal
|
|
appId="teams"
|
|
title={intl.formatMessage(messages.heading)}
|
|
enableAppHelp={intl.formatMessage(messages.enableTeamsHelp)}
|
|
enableAppLabel={intl.formatMessage(messages.enableTeamsLabel)}
|
|
learnMoreText={intl.formatMessage(messages.enableTeamsLink)}
|
|
onClose={onClose}
|
|
bodyClassName="bg-light-200"
|
|
// Topic is supported for backwards compatibility, the new field is team_sets:
|
|
// ref: https://github.com/openedx/edx-platform/blob/15461d3b6e6c0a724a7b8ed09241d970f201e5e7/openedx/core/lib/teams_config.py#L104-L108
|
|
initialValues={{
|
|
maxTeamSize: teamsConfiguration?.maxTeamSize,
|
|
groups: teamsConfiguration?.teamSets || teamsConfiguration?.topics,
|
|
}}
|
|
validationSchema={{
|
|
enabled: Yup.boolean()
|
|
.test(
|
|
'has-groups',
|
|
enableAppError,
|
|
(value, context) => (!value || context.parent.groups.length > 0),
|
|
),
|
|
maxTeamSize: Yup.number()
|
|
.required(intl.formatMessage(messages.maxTeamSizeEmpty))
|
|
.min(TeamSizes.MIN, intl.formatMessage(messages.maxTeamSizeInvalid))
|
|
.max(
|
|
TeamSizes.MAX,
|
|
intl.formatMessage(messages.maxTeamSizeTooHigh, {
|
|
max: TeamSizes.MAX,
|
|
}),
|
|
),
|
|
groups: Yup.array().of(
|
|
Yup.object({
|
|
id: Yup.string().nullable(),
|
|
name: Yup.string()
|
|
.required(intl.formatMessage(messages.groupFormNameEmpty))
|
|
.trim(),
|
|
type: Yup.string().oneOf(Object.values(GroupTypes)),
|
|
description: Yup.string()
|
|
.required(intl.formatMessage(messages.groupFormDescriptionError))
|
|
.trim(),
|
|
maxTeamSize: Yup.number()
|
|
.nullable()
|
|
.min(TeamSizes.MIN, intl.formatMessage(messages.maxTeamSizeInvalid))
|
|
.max(
|
|
TeamSizes.MAX,
|
|
intl.formatMessage(messages.maxTeamSizeTooHigh, {
|
|
max: TeamSizes.MAX,
|
|
}),
|
|
)
|
|
.default(null),
|
|
}),
|
|
)
|
|
.when('enabled', {
|
|
is: true,
|
|
// oxlint-disable-next-line unicorn/no-thenable
|
|
then: Yup.array().min(1),
|
|
})
|
|
.default([])
|
|
.uniqueProperty('name', intl.formatMessage(messages.groupFormNameExists)),
|
|
}}
|
|
onSettingsSave={handleSettingsSave}
|
|
configureBeforeEnable
|
|
>
|
|
{
|
|
({
|
|
handleChange, handleBlur, values, errors,
|
|
}) => (
|
|
<>
|
|
<h4 className="my-3 pb-2">{intl.formatMessage(messages.teamSize)}</h4>
|
|
<FormikControl
|
|
name="maxTeamSize"
|
|
value={values.maxTeamSize}
|
|
floatingLabel={intl.formatMessage(messages.maxTeamSize)}
|
|
help={intl.formatMessage(messages.maxTeamSizeHelp)}
|
|
className="pb-1"
|
|
type="number"
|
|
/>
|
|
<div className="bg-light-200 d-flex flex-column mx-n4 px-4 py-4 border border-top mb-n3.5">
|
|
<h4>{intl.formatMessage(messages.groups)}</h4>
|
|
<Form.Text className="mb-3">{intl.formatMessage(messages.groupsHelp)}</Form.Text>
|
|
<FieldArray name="groups">
|
|
{({ push, remove }) => (
|
|
<>
|
|
{values.groups?.map((group, index) => (
|
|
<GroupEditor
|
|
key={group.id || group.key}
|
|
group={group}
|
|
errors={errors.groups?.[index]}
|
|
fieldNameCommonBase={`groups.${index}`}
|
|
onDelete={() => remove(index)}
|
|
onChange={handleChange}
|
|
onBlur={handleBlur}
|
|
/>
|
|
))}
|
|
<Button
|
|
variant="plain"
|
|
className="p-0 align-self-start mt-3"
|
|
iconBefore={Add}
|
|
onClick={() => push(blankNewGroup)}
|
|
>
|
|
{intl.formatMessage(messages.addGroup)}
|
|
</Button>
|
|
</>
|
|
)}
|
|
</FieldArray>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
</AppSettingsModal>
|
|
);
|
|
};
|
|
|
|
TeamSettings.propTypes = {
|
|
onClose: PropTypes.func.isRequired,
|
|
};
|
|
|
|
export default TeamSettings;
|