@openedx/frontend-app-instructor-dashboard 1.0.0-alpha.25 → 1.0.0-alpha.27

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.
Files changed (108) hide show
  1. package/dist/certificates/CertificatesPage.d.ts +1 -1
  2. package/dist/certificates/CertificatesPage.js +107 -55
  3. package/dist/certificates/CertificatesPage.js.map +1 -1
  4. package/dist/certificates/CertificatesPage.scss +9 -0
  5. package/dist/certificates/components/CertificateTable.d.ts +1 -1
  6. package/dist/certificates/components/CertificateTable.js +9 -6
  7. package/dist/certificates/components/CertificateTable.js.map +1 -1
  8. package/dist/certificates/components/CertificatesPageHeader.js +3 -3
  9. package/dist/certificates/components/CertificatesPageHeader.js.map +1 -1
  10. package/dist/certificates/components/CertificatesToolbar.d.ts +2 -1
  11. package/dist/certificates/components/CertificatesToolbar.js +23 -3
  12. package/dist/certificates/components/CertificatesToolbar.js.map +1 -1
  13. package/dist/certificates/components/DisableCertificatesModal.js +1 -1
  14. package/dist/certificates/components/DisableCertificatesModal.js.map +1 -1
  15. package/dist/certificates/components/FilterDropdown.d.ts +1 -1
  16. package/dist/certificates/components/FilterDropdown.js +2 -2
  17. package/dist/certificates/components/FilterDropdown.js.map +1 -1
  18. package/dist/certificates/components/GenerationHistoryTable.d.ts +2 -2
  19. package/dist/certificates/components/GenerationHistoryTable.js +3 -18
  20. package/dist/certificates/components/GenerationHistoryTable.js.map +1 -1
  21. package/dist/certificates/components/GrantExceptionsModal.d.ts +1 -1
  22. package/dist/certificates/components/GrantExceptionsModal.js +2 -2
  23. package/dist/certificates/components/GrantExceptionsModal.js.map +1 -1
  24. package/dist/certificates/components/InvalidateCertificateModal.d.ts +1 -1
  25. package/dist/certificates/components/InvalidateCertificateModal.js +2 -2
  26. package/dist/certificates/components/InvalidateCertificateModal.js.map +1 -1
  27. package/dist/certificates/components/IssuedCertificatesTab.d.ts +1 -1
  28. package/dist/certificates/components/IssuedCertificatesTab.js +2 -2
  29. package/dist/certificates/components/IssuedCertificatesTab.js.map +1 -1
  30. package/dist/certificates/components/LearnerActionModal.d.ts +1 -1
  31. package/dist/certificates/components/LearnerActionModal.js +7 -2
  32. package/dist/certificates/components/LearnerActionModal.js.map +1 -1
  33. package/dist/certificates/components/RemoveExceptionModal.d.ts +9 -0
  34. package/dist/certificates/components/RemoveExceptionModal.js +10 -0
  35. package/dist/certificates/components/RemoveExceptionModal.js.map +1 -0
  36. package/dist/certificates/components/RemoveInvalidationModal.js +1 -1
  37. package/dist/certificates/components/RemoveInvalidationModal.js.map +1 -1
  38. package/dist/certificates/data/api.d.ts +17 -3
  39. package/dist/certificates/data/api.js +60 -8
  40. package/dist/certificates/data/api.js.map +1 -1
  41. package/dist/certificates/data/apiHook.d.ts +25 -5
  42. package/dist/certificates/data/apiHook.js +30 -2
  43. package/dist/certificates/data/apiHook.js.map +1 -1
  44. package/dist/certificates/data/queryKeys.d.ts +2 -1
  45. package/dist/certificates/data/queryKeys.js +1 -0
  46. package/dist/certificates/data/queryKeys.js.map +1 -1
  47. package/dist/certificates/messages.d.ts +30 -0
  48. package/dist/certificates/messages.js +30 -0
  49. package/dist/certificates/messages.js.map +1 -1
  50. package/dist/certificates/types.d.ts +7 -2
  51. package/dist/certificates/types.js.map +1 -1
  52. package/dist/certificates/utils/filterUtils.d.ts +1 -1
  53. package/dist/certificates/utils/filterUtils.js +1 -1
  54. package/dist/certificates/utils/filterUtils.js.map +1 -1
  55. package/dist/certificates/utils/index.d.ts +2 -2
  56. package/dist/certificates/utils/index.js +1 -1
  57. package/dist/certificates/utils/index.js.map +1 -1
  58. package/dist/components/SpecifyLearnerField.js +10 -4
  59. package/dist/components/SpecifyLearnerField.js.map +1 -1
  60. package/dist/components/messages.d.ts +5 -0
  61. package/dist/components/messages.js +6 -1
  62. package/dist/components/messages.js.map +1 -1
  63. package/dist/courseInfo/types.d.ts +2 -0
  64. package/dist/courseInfo/types.js.map +1 -1
  65. package/dist/courseTeam/CourseTeamPage.js +7 -2
  66. package/dist/courseTeam/CourseTeamPage.js.map +1 -1
  67. package/dist/courseTeam/messages.d.ts +5 -0
  68. package/dist/courseTeam/messages.js +5 -0
  69. package/dist/courseTeam/messages.js.map +1 -1
  70. package/dist/specialExams/SpecialExamsPage.js +6 -2
  71. package/dist/specialExams/SpecialExamsPage.js.map +1 -1
  72. package/dist/specialExams/components/AddAllowanceModal.d.ts +6 -0
  73. package/dist/specialExams/components/AddAllowanceModal.js +84 -0
  74. package/dist/specialExams/components/AddAllowanceModal.js.map +1 -0
  75. package/dist/specialExams/components/Allowances.js +28 -2
  76. package/dist/specialExams/components/Allowances.js.map +1 -1
  77. package/dist/specialExams/components/AllowancesList.d.ts +8 -0
  78. package/dist/specialExams/components/AllowancesList.js +58 -0
  79. package/dist/specialExams/components/AllowancesList.js.map +1 -0
  80. package/dist/specialExams/components/AttemptsList.js +8 -7
  81. package/dist/specialExams/components/AttemptsList.js.map +1 -1
  82. package/dist/specialExams/components/DeleteAllowanceModal.d.ts +8 -0
  83. package/dist/specialExams/components/DeleteAllowanceModal.js +29 -0
  84. package/dist/specialExams/components/DeleteAllowanceModal.js.map +1 -0
  85. package/dist/specialExams/components/EditAllowanceModal.d.ts +8 -0
  86. package/dist/specialExams/components/EditAllowanceModal.js +62 -0
  87. package/dist/specialExams/components/EditAllowanceModal.js.map +1 -0
  88. package/dist/specialExams/constants.d.ts +43 -0
  89. package/dist/specialExams/constants.js +19 -0
  90. package/dist/specialExams/constants.js.map +1 -0
  91. package/dist/specialExams/data/api.d.ts +5 -1
  92. package/dist/specialExams/data/api.js +28 -2
  93. package/dist/specialExams/data/api.js.map +1 -1
  94. package/dist/specialExams/data/apiHook.d.ts +5 -1
  95. package/dist/specialExams/data/apiHook.js +30 -2
  96. package/dist/specialExams/data/apiHook.js.map +1 -1
  97. package/dist/specialExams/data/queryKeys.d.ts +4 -1
  98. package/dist/specialExams/data/queryKeys.js +4 -1
  99. package/dist/specialExams/data/queryKeys.js.map +1 -1
  100. package/dist/specialExams/messages.d.ts +165 -0
  101. package/dist/specialExams/messages.js +165 -0
  102. package/dist/specialExams/messages.js.map +1 -1
  103. package/dist/specialExams/types.d.ts +55 -4
  104. package/dist/specialExams/types.js.map +1 -1
  105. package/package.json +1 -1
  106. package/dist/certificates/data/dummyData.d.ts +0 -2
  107. package/dist/certificates/data/dummyData.js +0 -234
  108. package/dist/certificates/data/dummyData.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/courseInfo/types.ts"],"names":[],"mappings":"","sourcesContent":["import { TabProps } from '@src/instructorNav/InstructorNav';\n\nexport interface CourseInfoResponse {\n courseId: string,\n displayName: string,\n courseNumber: string,\n courseRun: string,\n enrollmentCounts: EnrollmentCounts,\n start: string | null,\n end: string | null,\n tabs?: TabProps[],\n totalEnrollment: number,\n studioUrl: string,\n pacing: string,\n org?: string,\n numSections: number,\n hasStarted: boolean,\n hasEnded: boolean,\n enrollmentEnd: string | null,\n enrollmentStart: string | null,\n gradeCutoffs: string | null,\n staffCount: number,\n learnerCount: number,\n permissions: {\n admin: boolean,\n dataResearcher: boolean,\n [key: string]: boolean,\n },\n gradebookUrl: string,\n studioGradingUrl?: string,\n}\n\ninterface EnrollmentCounts extends Record<string, number> {\n total: number,\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/courseInfo/types.ts"],"names":[],"mappings":"","sourcesContent":["import { TabProps } from '@src/instructorNav/InstructorNav';\n\nexport interface CourseInfoResponse {\n courseId: string,\n displayName: string,\n courseNumber: string,\n courseRun: string,\n enrollmentCounts: EnrollmentCounts,\n start: string | null,\n end: string | null,\n tabs?: TabProps[],\n totalEnrollment: number,\n studioUrl: string,\n pacing: string,\n org?: string,\n numSections: number,\n hasStarted: boolean,\n hasEnded: boolean,\n enrollmentEnd: string | null,\n enrollmentStart: string | null,\n gradeCutoffs: string | null,\n staffCount: number,\n learnerCount: number,\n permissions: {\n admin: boolean,\n dataResearcher: boolean,\n [key: string]: boolean,\n },\n gradebookUrl: string,\n studioGradingUrl?: string,\n certificatesEnabled?: boolean,\n adminConsoleUrl: string | null,\n}\n\ninterface EnrollmentCounts extends Record<string, number> {\n total: number,\n}\n"]}
@@ -2,23 +2,28 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useState } from 'react';
3
3
  import { useIntl } from '@openedx/frontend-base';
4
4
  import { Button, Tab, Tabs, useToggle } from '@openedx/paragon';
5
- import { Plus } from '@openedx/paragon/icons';
5
+ import { Plus, TrendingUp } from '@openedx/paragon/icons';
6
6
  import AddTeamMemberModal from '../courseTeam/components/AddTeamMemberModal';
7
7
  import EditTeamMemberModal from '../courseTeam/components/EditTeamMemberModal';
8
8
  import MembersContent from '../courseTeam/components/MembersContent';
9
9
  import RolesContent from '../courseTeam/components/RolesContent';
10
10
  import messages from '../courseTeam/messages';
11
11
  import { AlertOutlet } from '../providers/AlertProvider';
12
+ import { useParams } from 'react-router-dom';
13
+ import { useCourseInfo } from '../data/apiHook';
12
14
  const CourseTeamPage = () => {
13
15
  const intl = useIntl();
16
+ const { courseId = '' } = useParams();
14
17
  const [isOpenAddModal, openAddModal, closeAddModal] = useToggle(false);
15
18
  const [isOpenEditModal, openEditModal, closeEditModal] = useToggle(false);
16
19
  const [selectedUser, setSelectedUser] = useState(null);
20
+ const { data } = useCourseInfo(courseId);
21
+ const { adminConsoleUrl = '' } = data || {};
17
22
  const handleEdit = (user) => {
18
23
  setSelectedUser(user);
19
24
  openEditModal();
20
25
  };
21
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "d-flex justify-content-between align-items-center mb-3", children: [_jsx("h3", { className: "text-primary-700 mb-0", children: intl.formatMessage(messages.courseTeamTitle) }), _jsx(Button, { iconBefore: Plus, variant: "primary", onClick: openAddModal, children: intl.formatMessage(messages.addTeamMember) })] }), _jsx(AlertOutlet, {}), _jsxs(Tabs, { children: [_jsx(Tab, { eventKey: "members", title: intl.formatMessage(messages.membersTab), children: _jsx(MembersContent, { onEdit: handleEdit }) }), _jsx(Tab, { eventKey: "roles", title: intl.formatMessage(messages.rolesTab), children: _jsx(RolesContent, {}) })] }), isOpenAddModal && _jsx(AddTeamMemberModal, { isOpen: isOpenAddModal, onClose: closeAddModal }), isOpenEditModal && selectedUser && _jsx(EditTeamMemberModal, { isOpen: isOpenEditModal, user: selectedUser, onClose: closeEditModal })] }));
26
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "d-flex justify-content-between align-items-center mb-3", children: [_jsx("h3", { className: "text-primary-700 mb-0", children: intl.formatMessage(messages.courseTeamTitle) }), _jsxs("div", { children: [adminConsoleUrl && _jsx(Button, { iconBefore: TrendingUp, variant: "outline-primary", className: "mr-3", as: "a", href: adminConsoleUrl, children: intl.formatMessage(messages.viewStudioRoles) }), _jsx(Button, { iconBefore: Plus, variant: "primary", onClick: openAddModal, children: intl.formatMessage(messages.addTeamMember) })] })] }), _jsx(AlertOutlet, {}), _jsxs(Tabs, { children: [_jsx(Tab, { eventKey: "members", title: intl.formatMessage(messages.membersTab), children: _jsx(MembersContent, { onEdit: handleEdit }) }), _jsx(Tab, { eventKey: "roles", title: intl.formatMessage(messages.rolesTab), children: _jsx(RolesContent, {}) })] }), isOpenAddModal && _jsx(AddTeamMemberModal, { isOpen: isOpenAddModal, onClose: closeAddModal }), isOpenEditModal && selectedUser && _jsx(EditTeamMemberModal, { isOpen: isOpenEditModal, user: selectedUser, onClose: closeEditModal })] }));
22
27
  };
23
28
  export default CourseTeamPage;
24
29
  //# sourceMappingURL=CourseTeamPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CourseTeamPage.js","sourceRoot":"","sources":["../../src/courseTeam/CourseTeamPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,OAAO,kBAAkB,MAAM,+CAA+C,CAAC;AAC/E,OAAO,mBAAmB,MAAM,gDAAgD,CAAC;AACjF,OAAO,cAAc,MAAM,2CAA2C,CAAC;AACvE,OAAO,YAAY,MAAM,yCAAyC,CAAC;AACnE,OAAO,QAAQ,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAG3D,MAAM,cAAc,GAAG,GAAG,EAAE;IAC1B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,cAAc,EAAE,YAAY,EAAE,aAAa,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IACvE,MAAM,CAAC,eAAe,EAAE,aAAa,EAAE,cAAc,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAA0B,IAAI,CAAC,CAAC;IAEhF,MAAM,UAAU,GAAG,CAAC,IAAsB,EAAE,EAAE;QAC5C,eAAe,CAAC,IAAI,CAAC,CAAC;QACtB,aAAa,EAAE,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CACL,8BACE,eAAK,SAAS,EAAC,wDAAwD,aACrE,aAAI,SAAS,EAAC,uBAAuB,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC,GAAM,EACzF,KAAC,MAAM,IAAC,UAAU,EAAE,IAAI,EAAE,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,YAAY,YAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAU,IACpH,EACN,KAAC,WAAW,KAAG,EACf,MAAC,IAAI,eACH,KAAC,GAAG,IAAC,QAAQ,EAAC,SAAS,EAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,YACpE,KAAC,cAAc,IAAC,MAAM,EAAE,UAAU,GAAI,GAClC,EACN,KAAC,GAAG,IAAC,QAAQ,EAAC,OAAO,EAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAChE,KAAC,YAAY,KAAG,GACZ,IACD,EACN,cAAc,IAAI,KAAC,kBAAkB,IAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,GAAI,EACxF,eAAe,IAAI,YAAY,IAAI,KAAC,mBAAmB,IAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAI,IAChI,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,cAAc,CAAC","sourcesContent":["import { useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Button, Tab, Tabs, useToggle } from '@openedx/paragon';\nimport { Plus } from '@openedx/paragon/icons';\nimport AddTeamMemberModal from '@src/courseTeam/components/AddTeamMemberModal';\nimport EditTeamMemberModal from '@src/courseTeam/components/EditTeamMemberModal';\nimport MembersContent from '@src/courseTeam/components/MembersContent';\nimport RolesContent from '@src/courseTeam/components/RolesContent';\nimport messages from '@src/courseTeam/messages';\nimport { AlertOutlet } from '@src/providers/AlertProvider';\nimport { CourseTeamMember } from '@src/courseTeam/types';\n\nconst CourseTeamPage = () => {\n const intl = useIntl();\n const [isOpenAddModal, openAddModal, closeAddModal] = useToggle(false);\n const [isOpenEditModal, openEditModal, closeEditModal] = useToggle(false);\n const [selectedUser, setSelectedUser] = useState<CourseTeamMember | null>(null);\n\n const handleEdit = (user: CourseTeamMember) => {\n setSelectedUser(user);\n openEditModal();\n };\n\n return (\n <>\n <div className=\"d-flex justify-content-between align-items-center mb-3\">\n <h3 className=\"text-primary-700 mb-0\">{intl.formatMessage(messages.courseTeamTitle)}</h3>\n <Button iconBefore={Plus} variant=\"primary\" onClick={openAddModal}>{intl.formatMessage(messages.addTeamMember)}</Button>\n </div>\n <AlertOutlet />\n <Tabs>\n <Tab eventKey=\"members\" title={intl.formatMessage(messages.membersTab)}>\n <MembersContent onEdit={handleEdit} />\n </Tab>\n <Tab eventKey=\"roles\" title={intl.formatMessage(messages.rolesTab)}>\n <RolesContent />\n </Tab>\n </Tabs>\n {isOpenAddModal && <AddTeamMemberModal isOpen={isOpenAddModal} onClose={closeAddModal} />}\n {isOpenEditModal && selectedUser && <EditTeamMemberModal isOpen={isOpenEditModal} user={selectedUser} onClose={closeEditModal} />}\n </>\n );\n};\n\nexport default CourseTeamPage;\n"]}
1
+ {"version":3,"file":"CourseTeamPage.js","sourceRoot":"","sources":["../../src/courseTeam/CourseTeamPage.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Button, Tab, Tabs, useToggle } from '@openedx/paragon';\nimport { Plus, TrendingUp } from '@openedx/paragon/icons';\nimport AddTeamMemberModal from '@src/courseTeam/components/AddTeamMemberModal';\nimport EditTeamMemberModal from '@src/courseTeam/components/EditTeamMemberModal';\nimport MembersContent from '@src/courseTeam/components/MembersContent';\nimport RolesContent from '@src/courseTeam/components/RolesContent';\nimport messages from '@src/courseTeam/messages';\nimport { AlertOutlet } from '@src/providers/AlertProvider';\nimport { CourseTeamMember } from '@src/courseTeam/types';\nimport { useParams } from 'react-router-dom';\nimport { useCourseInfo } from '@src/data/apiHook';\n\nconst CourseTeamPage = () => {\n const intl = useIntl();\n const { courseId = '' } = useParams();\n const [isOpenAddModal, openAddModal, closeAddModal] = useToggle(false);\n const [isOpenEditModal, openEditModal, closeEditModal] = useToggle(false);\n const [selectedUser, setSelectedUser] = useState<CourseTeamMember | null>(null);\n const { data } = useCourseInfo(courseId);\n const { adminConsoleUrl = '' } = data || {};\n\n const handleEdit = (user: CourseTeamMember) => {\n setSelectedUser(user);\n openEditModal();\n };\n\n return (\n <>\n <div className=\"d-flex justify-content-between align-items-center mb-3\">\n <h3 className=\"text-primary-700 mb-0\">{intl.formatMessage(messages.courseTeamTitle)}</h3>\n <div>\n {adminConsoleUrl && <Button iconBefore={TrendingUp} variant=\"outline-primary\" className=\"mr-3\" as=\"a\" href={adminConsoleUrl}>{intl.formatMessage(messages.viewStudioRoles)}</Button>}\n <Button iconBefore={Plus} variant=\"primary\" onClick={openAddModal}>{intl.formatMessage(messages.addTeamMember)}</Button>\n </div>\n </div>\n <AlertOutlet />\n <Tabs>\n <Tab eventKey=\"members\" title={intl.formatMessage(messages.membersTab)}>\n <MembersContent onEdit={handleEdit} />\n </Tab>\n <Tab eventKey=\"roles\" title={intl.formatMessage(messages.rolesTab)}>\n <RolesContent />\n </Tab>\n </Tabs>\n {isOpenAddModal && <AddTeamMemberModal isOpen={isOpenAddModal} onClose={closeAddModal} />}\n {isOpenEditModal && selectedUser && <EditTeamMemberModal isOpen={isOpenEditModal} user={selectedUser} onClose={closeEditModal} />}\n </>\n );\n};\n\nexport default CourseTeamPage;\n"]}
@@ -239,5 +239,10 @@ declare const messages: {
239
239
  defaultMessage: string;
240
240
  description: string;
241
241
  };
242
+ viewStudioRoles: {
243
+ id: string;
244
+ defaultMessage: string;
245
+ description: string;
246
+ };
242
247
  };
243
248
  export default messages;
@@ -239,6 +239,11 @@ const messages = defineMessages({
239
239
  id: 'instruct.courseTeam.addRoleError',
240
240
  defaultMessage: 'Failed to add role to {username}.',
241
241
  description: 'Error message displayed when adding a role to a team member fails',
242
+ },
243
+ viewStudioRoles: {
244
+ id: 'instruct.courseTeam.viewStudioRoles',
245
+ defaultMessage: 'View Studio Roles',
246
+ description: 'Button label for viewing course team roles in Studio',
242
247
  }
243
248
  });
244
249
  export default messages;
@@ -1 +1 @@
1
- {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/courseTeam/messages.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n courseTeamTitle: {\n id: 'instruct.courseTeam.page.title',\n defaultMessage: 'Course Team Management',\n description: 'Title for the course team page',\n },\n addTeamMember: {\n id: 'instruct.courseTeam.addTeamMember',\n defaultMessage: 'Add Team Member',\n description: 'Button label for adding a team member',\n },\n membersTab: {\n id: 'instruct.courseTeam.membersTab',\n defaultMessage: 'Members',\n description: 'Tab title for course team members',\n },\n rolesTab: {\n id: 'instruct.courseTeam.rolesTab',\n defaultMessage: 'Roles',\n description: 'Tab title for course team roles',\n },\n username: {\n id: 'instruct.courseTeam.username',\n defaultMessage: 'Username',\n description: 'Column header for team member username',\n },\n email: {\n id: 'instruct.courseTeam.email',\n defaultMessage: 'Email',\n description: 'Column header for team member email',\n },\n role: {\n id: 'instruct.courseTeam.role',\n defaultMessage: 'Role',\n description: 'Column header for team member role',\n },\n actions: {\n id: 'instruct.courseTeam.actions',\n defaultMessage: 'Actions',\n description: 'Column header for team member actions',\n },\n edit: {\n id: 'instruct.courseTeam.edit',\n defaultMessage: 'Edit',\n description: 'Button label for editing a team member',\n },\n noTeamMembers: {\n id: 'instruct.courseTeam.noTeamMembers',\n defaultMessage: 'No team members found.',\n description: 'Message displayed when there are no team members',\n },\n allRoles: {\n id: 'instruct.courseTeam.allRoles',\n defaultMessage: 'All Roles',\n description: 'Option label for filtering by all roles',\n },\n staff: {\n id: 'instruct.courseTeam.roles.staff',\n defaultMessage: 'Staff',\n description: 'Role name for staff members',\n },\n staffDescription: {\n id: 'instruct.courseTeam.roles.staffDescription',\n defaultMessage: 'Course team members with the Staff role help you manage your course. Staff can enroll and unenroll learners, as well as modify their grades and access all course data. Staff also have access to your course in Studio and Insights. Any users not yet enrolled in the course will be automatically enrolled when added as Staff.',\n description: 'Description for staff role',\n },\n limitedStaff: {\n id: 'instruct.courseTeam.roles.limitedStaff',\n defaultMessage: 'Limited Staff',\n description: 'Role name for limited staff members',\n },\n limitedStaffDescription: {\n id: 'instruct.courseTeam.roles.limitedStaffDescription',\n defaultMessage: 'Course team members with the Limited Staff role help you manage your course. Limited Staff can enroll and unenroll learners, as well as modify their grades and access all course data. Limited Staff don\\'t have access to your course in Studio. Any users not yet enrolled in the course will be automatically enrolled when added as Limited Staff.',\n description: 'Description for limited staff role',\n },\n admin: {\n id: 'instruct.courseTeam.roles.admin',\n defaultMessage: 'Admin',\n description: 'Role name for admin members',\n },\n adminDescription: {\n id: 'instruct.courseTeam.roles.adminDescription',\n defaultMessage: 'Course team members with the Admin role help you manage your course. They can do all of the tasks that Staff can do, and can also add and remove the Staff and Admin roles, discussion moderation roles, and the beta tester role to manage course team membership. Any users not yet enrolled in the course will be automatically enrolled when added as Admin.',\n description: 'Description for admin role',\n },\n beta: {\n id: 'instruct.courseTeam.roles.beta',\n defaultMessage: 'Beta Testers',\n description: 'Role name for beta tester members',\n },\n betaDescription: {\n id: 'instruct.courseTeam.roles.betaDescription',\n defaultMessage: 'Beta Testers can see course content before other learners. They can make sure that the content works, but have no additional privileges. Any users not yet enrolled in the course will be automatically enrolled when added as Beta Tester.',\n description: 'Description for beta tester role',\n },\n courseDataResearchers: {\n id: 'instruct.courseTeam.roles.courseDataResearchers',\n defaultMessage: 'Course Data Researchers',\n description: 'Role name for course data researcher members',\n },\n courseDataResearchersDescription: {\n id: 'instruct.courseTeam.roles.courseDataResearchersDescription',\n defaultMessage: 'Course Data Researchers can access the data download tab. Any users not yet enrolled in the course will be automatically enrolled when added as Course Data Researcher.',\n description: 'Description for course data researcher role',\n },\n discussionAdmin: {\n id: 'instruct.courseTeam.roles.discussionAdmin',\n defaultMessage: 'Discussion Admin',\n description: 'Role name for discussion admin members',\n },\n discussionAdminDescription: {\n id: 'instruct.courseTeam.roles.discussionAdminDescription',\n defaultMessage: 'Discussion Admins can edit or delete any post, clear misuse flags, close and re-open threads, endorse responses, and see posts from all groups. Their posts are marked as \\'staff\\'. They can also add and remove the discussion moderation roles to manage course team membership. Any users not yet enrolled in the course will be automatically enrolled when added as Discussion Admin.',\n description: 'Description for discussion admin role',\n },\n discussionModerator: {\n id: 'instruct.courseTeam.roles.discussionModerator',\n defaultMessage: 'Discussion Moderator',\n description: 'Role name for discussion moderator members',\n },\n discussionModeratorDescription: {\n id: 'instruct.courseTeam.roles.discussionModeratorDescription',\n defaultMessage: 'Discussion Moderators can edit or delete any post, clear misuse flags, close and re-open threads, endorse responses, and see posts from all groups. Their posts are marked as \\'staff\\'. They cannot manage course team membership by adding or removing discussion moderation roles. Any users not yet enrolled in the course will be automatically enrolled when added as Discussion Moderator.',\n description: 'Description for discussion moderator role',\n },\n groupCommunityTA: {\n id: 'instruct.courseTeam.roles.groupCommunityTA',\n defaultMessage: 'Group Community TA',\n description: 'Role name for group community TA members',\n },\n groupCommunityTADescription: {\n id: 'instruct.courseTeam.roles.groupCommunityTADescription',\n defaultMessage: 'Group Community TAs are members of the community who help course teams moderate discussions. Group Community TAs see only posts by learners in their assigned group. They can edit or delete posts, clear flags, close and re-open threads, and endorse responses, but only for posts by learners in their group. Their posts are marked as \\'Community TA\\'. Any users not yet enrolled in the course will be automatically enrolled when added as Group Community TA.',\n description: 'Description for group community TA role',\n },\n communityTA: {\n id: 'instruct.courseTeam.roles.communityTA',\n defaultMessage: 'Community TA',\n description: 'Role name for community TA members',\n },\n communityTADescription: {\n id: 'instruct.courseTeam.roles.communityTADescription',\n defaultMessage: 'Community TAs are members of the community who help course teams moderate discussions. They can see posts by learners in their assigned cohort or enrollment track, and can edit or delete posts, clear flags, close or re-open threads, and endorse responses. Their posts are marked as \\'Community TA\\'. Any users not yet enrolled in the course will be automatically enrolled when added as Community TA.',\n description: 'Description for community TA role',\n },\n ccxCoach: {\n id: 'instruct.courseTeam.roles.ccxCoach',\n defaultMessage: 'CCX Coach',\n description: 'Role name for CCX coach members',\n },\n ccxCoachDescription: {\n id: 'instruct.courseTeam.roles.ccxCoachDescription',\n defaultMessage: 'CCX Coaches are able to create their own Custom Courses based on this course, which they can use to provide personalized instruction to their own students based in this course material.',\n description: 'Description for CCX coach role',\n },\n addNewTeamMember: {\n id: 'instruct.courseTeam.addNewTeamMember',\n defaultMessage: 'Add New Team Member',\n description: 'Title for add new team member form',\n },\n addNewTeamMemberDescription: {\n id: 'instruct.courseTeam.addNewTeamMemberDescription',\n defaultMessage: 'Add new members to {courseName}’s Course team and assign them a role to define their permissions.',\n description: 'Description for add new team member form',\n },\n addUsersLabel: {\n id: 'instruct.courseTeam.addUsersLabel',\n defaultMessage: 'Add users by username or email',\n description: 'Label for input to add users to course team',\n },\n usersPlaceholder: {\n id: 'instruct.courseTeam.usersPlaceholder',\n defaultMessage: 'Enter one or more email addresses or usernames',\n description: 'Placeholder for input to add users to course team',\n },\n roleLabel: {\n id: 'instruct.courseTeam.roleLabel',\n defaultMessage: 'Role',\n description: 'Label for role selection when adding users to course team',\n },\n rolePlaceholder: {\n id: 'instruct.courseTeam.rolePlaceholder',\n defaultMessage: 'Select Role',\n description: 'Placeholder for role selection when adding users to course team',\n },\n cancelButton: {\n id: 'instruct.courseTeam.cancelButton',\n defaultMessage: 'Cancel',\n description: 'Label for cancel button when adding users to course team',\n },\n saveButton: {\n id: 'instruct.courseTeam.saveButton',\n defaultMessage: 'Save',\n description: 'Label for save button when adding users to course team',\n },\n addTeamMemberError: {\n id: 'instruct.courseTeam.addTeamMemberError',\n defaultMessage: 'Could not find a user with username or email address “{username}”',\n description: 'Error message displayed when adding a team member fails',\n },\n closeButton: {\n id: 'instruct.courseTeam.closeButton',\n defaultMessage: 'Close',\n description: 'Label for close button in error modal when adding a team member fails',\n },\n failedToAddTeamMembers: {\n id: 'instruct.courseTeam.failedToAddTeamMembers',\n defaultMessage: 'The following usernames and/or email addresses are invalid. All other roles have been added to the team members.',\n description: 'Error message displayed when some team members could not be added',\n },\n unknownLearner: {\n id: 'instruct.courseTeam.unknownLearner',\n defaultMessage: 'Unknown learner: {learner}',\n description: 'Displayed when a learner does not have a full name or username available',\n },\n editTeamTitle: {\n id: 'instruct.courseTeam.editTeamTitle',\n defaultMessage: 'Edit {username} Roles',\n description: 'Title for edit team member modal',\n },\n editInstructions: {\n id: 'instruct.courseTeam.editInstructions',\n defaultMessage: 'Uncheck to remove role from {username}',\n description: 'Instructions for editing a team member',\n },\n addRole: {\n id: 'instruct.courseTeam.addRole',\n defaultMessage: 'Add role',\n description: 'Label for adding a role to a team member',\n },\n removeTeamMemberError: {\n id: 'instruct.courseTeam.removeTeamMemberError',\n defaultMessage: 'Failed to remove one or more roles from {username}.',\n description: 'Error message displayed when removing a team member fails',\n },\n addRoleError: {\n id: 'instruct.courseTeam.addRoleError',\n defaultMessage: 'Failed to add role to {username}.',\n description: 'Error message displayed when adding a role to a team member fails',\n }\n});\n\nexport default messages;\n"]}
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/courseTeam/messages.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineMessages } from '@openedx/frontend-base';\n\nconst messages = defineMessages({\n courseTeamTitle: {\n id: 'instruct.courseTeam.page.title',\n defaultMessage: 'Course Team Management',\n description: 'Title for the course team page',\n },\n addTeamMember: {\n id: 'instruct.courseTeam.addTeamMember',\n defaultMessage: 'Add Team Member',\n description: 'Button label for adding a team member',\n },\n membersTab: {\n id: 'instruct.courseTeam.membersTab',\n defaultMessage: 'Members',\n description: 'Tab title for course team members',\n },\n rolesTab: {\n id: 'instruct.courseTeam.rolesTab',\n defaultMessage: 'Roles',\n description: 'Tab title for course team roles',\n },\n username: {\n id: 'instruct.courseTeam.username',\n defaultMessage: 'Username',\n description: 'Column header for team member username',\n },\n email: {\n id: 'instruct.courseTeam.email',\n defaultMessage: 'Email',\n description: 'Column header for team member email',\n },\n role: {\n id: 'instruct.courseTeam.role',\n defaultMessage: 'Role',\n description: 'Column header for team member role',\n },\n actions: {\n id: 'instruct.courseTeam.actions',\n defaultMessage: 'Actions',\n description: 'Column header for team member actions',\n },\n edit: {\n id: 'instruct.courseTeam.edit',\n defaultMessage: 'Edit',\n description: 'Button label for editing a team member',\n },\n noTeamMembers: {\n id: 'instruct.courseTeam.noTeamMembers',\n defaultMessage: 'No team members found.',\n description: 'Message displayed when there are no team members',\n },\n allRoles: {\n id: 'instruct.courseTeam.allRoles',\n defaultMessage: 'All Roles',\n description: 'Option label for filtering by all roles',\n },\n staff: {\n id: 'instruct.courseTeam.roles.staff',\n defaultMessage: 'Staff',\n description: 'Role name for staff members',\n },\n staffDescription: {\n id: 'instruct.courseTeam.roles.staffDescription',\n defaultMessage: 'Course team members with the Staff role help you manage your course. Staff can enroll and unenroll learners, as well as modify their grades and access all course data. Staff also have access to your course in Studio and Insights. Any users not yet enrolled in the course will be automatically enrolled when added as Staff.',\n description: 'Description for staff role',\n },\n limitedStaff: {\n id: 'instruct.courseTeam.roles.limitedStaff',\n defaultMessage: 'Limited Staff',\n description: 'Role name for limited staff members',\n },\n limitedStaffDescription: {\n id: 'instruct.courseTeam.roles.limitedStaffDescription',\n defaultMessage: 'Course team members with the Limited Staff role help you manage your course. Limited Staff can enroll and unenroll learners, as well as modify their grades and access all course data. Limited Staff don\\'t have access to your course in Studio. Any users not yet enrolled in the course will be automatically enrolled when added as Limited Staff.',\n description: 'Description for limited staff role',\n },\n admin: {\n id: 'instruct.courseTeam.roles.admin',\n defaultMessage: 'Admin',\n description: 'Role name for admin members',\n },\n adminDescription: {\n id: 'instruct.courseTeam.roles.adminDescription',\n defaultMessage: 'Course team members with the Admin role help you manage your course. They can do all of the tasks that Staff can do, and can also add and remove the Staff and Admin roles, discussion moderation roles, and the beta tester role to manage course team membership. Any users not yet enrolled in the course will be automatically enrolled when added as Admin.',\n description: 'Description for admin role',\n },\n beta: {\n id: 'instruct.courseTeam.roles.beta',\n defaultMessage: 'Beta Testers',\n description: 'Role name for beta tester members',\n },\n betaDescription: {\n id: 'instruct.courseTeam.roles.betaDescription',\n defaultMessage: 'Beta Testers can see course content before other learners. They can make sure that the content works, but have no additional privileges. Any users not yet enrolled in the course will be automatically enrolled when added as Beta Tester.',\n description: 'Description for beta tester role',\n },\n courseDataResearchers: {\n id: 'instruct.courseTeam.roles.courseDataResearchers',\n defaultMessage: 'Course Data Researchers',\n description: 'Role name for course data researcher members',\n },\n courseDataResearchersDescription: {\n id: 'instruct.courseTeam.roles.courseDataResearchersDescription',\n defaultMessage: 'Course Data Researchers can access the data download tab. Any users not yet enrolled in the course will be automatically enrolled when added as Course Data Researcher.',\n description: 'Description for course data researcher role',\n },\n discussionAdmin: {\n id: 'instruct.courseTeam.roles.discussionAdmin',\n defaultMessage: 'Discussion Admin',\n description: 'Role name for discussion admin members',\n },\n discussionAdminDescription: {\n id: 'instruct.courseTeam.roles.discussionAdminDescription',\n defaultMessage: 'Discussion Admins can edit or delete any post, clear misuse flags, close and re-open threads, endorse responses, and see posts from all groups. Their posts are marked as \\'staff\\'. They can also add and remove the discussion moderation roles to manage course team membership. Any users not yet enrolled in the course will be automatically enrolled when added as Discussion Admin.',\n description: 'Description for discussion admin role',\n },\n discussionModerator: {\n id: 'instruct.courseTeam.roles.discussionModerator',\n defaultMessage: 'Discussion Moderator',\n description: 'Role name for discussion moderator members',\n },\n discussionModeratorDescription: {\n id: 'instruct.courseTeam.roles.discussionModeratorDescription',\n defaultMessage: 'Discussion Moderators can edit or delete any post, clear misuse flags, close and re-open threads, endorse responses, and see posts from all groups. Their posts are marked as \\'staff\\'. They cannot manage course team membership by adding or removing discussion moderation roles. Any users not yet enrolled in the course will be automatically enrolled when added as Discussion Moderator.',\n description: 'Description for discussion moderator role',\n },\n groupCommunityTA: {\n id: 'instruct.courseTeam.roles.groupCommunityTA',\n defaultMessage: 'Group Community TA',\n description: 'Role name for group community TA members',\n },\n groupCommunityTADescription: {\n id: 'instruct.courseTeam.roles.groupCommunityTADescription',\n defaultMessage: 'Group Community TAs are members of the community who help course teams moderate discussions. Group Community TAs see only posts by learners in their assigned group. They can edit or delete posts, clear flags, close and re-open threads, and endorse responses, but only for posts by learners in their group. Their posts are marked as \\'Community TA\\'. Any users not yet enrolled in the course will be automatically enrolled when added as Group Community TA.',\n description: 'Description for group community TA role',\n },\n communityTA: {\n id: 'instruct.courseTeam.roles.communityTA',\n defaultMessage: 'Community TA',\n description: 'Role name for community TA members',\n },\n communityTADescription: {\n id: 'instruct.courseTeam.roles.communityTADescription',\n defaultMessage: 'Community TAs are members of the community who help course teams moderate discussions. They can see posts by learners in their assigned cohort or enrollment track, and can edit or delete posts, clear flags, close or re-open threads, and endorse responses. Their posts are marked as \\'Community TA\\'. Any users not yet enrolled in the course will be automatically enrolled when added as Community TA.',\n description: 'Description for community TA role',\n },\n ccxCoach: {\n id: 'instruct.courseTeam.roles.ccxCoach',\n defaultMessage: 'CCX Coach',\n description: 'Role name for CCX coach members',\n },\n ccxCoachDescription: {\n id: 'instruct.courseTeam.roles.ccxCoachDescription',\n defaultMessage: 'CCX Coaches are able to create their own Custom Courses based on this course, which they can use to provide personalized instruction to their own students based in this course material.',\n description: 'Description for CCX coach role',\n },\n addNewTeamMember: {\n id: 'instruct.courseTeam.addNewTeamMember',\n defaultMessage: 'Add New Team Member',\n description: 'Title for add new team member form',\n },\n addNewTeamMemberDescription: {\n id: 'instruct.courseTeam.addNewTeamMemberDescription',\n defaultMessage: 'Add new members to {courseName}’s Course team and assign them a role to define their permissions.',\n description: 'Description for add new team member form',\n },\n addUsersLabel: {\n id: 'instruct.courseTeam.addUsersLabel',\n defaultMessage: 'Add users by username or email',\n description: 'Label for input to add users to course team',\n },\n usersPlaceholder: {\n id: 'instruct.courseTeam.usersPlaceholder',\n defaultMessage: 'Enter one or more email addresses or usernames',\n description: 'Placeholder for input to add users to course team',\n },\n roleLabel: {\n id: 'instruct.courseTeam.roleLabel',\n defaultMessage: 'Role',\n description: 'Label for role selection when adding users to course team',\n },\n rolePlaceholder: {\n id: 'instruct.courseTeam.rolePlaceholder',\n defaultMessage: 'Select Role',\n description: 'Placeholder for role selection when adding users to course team',\n },\n cancelButton: {\n id: 'instruct.courseTeam.cancelButton',\n defaultMessage: 'Cancel',\n description: 'Label for cancel button when adding users to course team',\n },\n saveButton: {\n id: 'instruct.courseTeam.saveButton',\n defaultMessage: 'Save',\n description: 'Label for save button when adding users to course team',\n },\n addTeamMemberError: {\n id: 'instruct.courseTeam.addTeamMemberError',\n defaultMessage: 'Could not find a user with username or email address “{username}”',\n description: 'Error message displayed when adding a team member fails',\n },\n closeButton: {\n id: 'instruct.courseTeam.closeButton',\n defaultMessage: 'Close',\n description: 'Label for close button in error modal when adding a team member fails',\n },\n failedToAddTeamMembers: {\n id: 'instruct.courseTeam.failedToAddTeamMembers',\n defaultMessage: 'The following usernames and/or email addresses are invalid. All other roles have been added to the team members.',\n description: 'Error message displayed when some team members could not be added',\n },\n unknownLearner: {\n id: 'instruct.courseTeam.unknownLearner',\n defaultMessage: 'Unknown learner: {learner}',\n description: 'Displayed when a learner does not have a full name or username available',\n },\n editTeamTitle: {\n id: 'instruct.courseTeam.editTeamTitle',\n defaultMessage: 'Edit {username} Roles',\n description: 'Title for edit team member modal',\n },\n editInstructions: {\n id: 'instruct.courseTeam.editInstructions',\n defaultMessage: 'Uncheck to remove role from {username}',\n description: 'Instructions for editing a team member',\n },\n addRole: {\n id: 'instruct.courseTeam.addRole',\n defaultMessage: 'Add role',\n description: 'Label for adding a role to a team member',\n },\n removeTeamMemberError: {\n id: 'instruct.courseTeam.removeTeamMemberError',\n defaultMessage: 'Failed to remove one or more roles from {username}.',\n description: 'Error message displayed when removing a team member fails',\n },\n addRoleError: {\n id: 'instruct.courseTeam.addRoleError',\n defaultMessage: 'Failed to add role to {username}.',\n description: 'Error message displayed when adding a role to a team member fails',\n },\n viewStudioRoles: {\n id: 'instruct.courseTeam.viewStudioRoles',\n defaultMessage: 'View Studio Roles',\n description: 'Button label for viewing course team roles in Studio',\n }\n});\n\nexport default messages;\n"]}
@@ -5,10 +5,14 @@ import { Button, ButtonGroup, Card } from '@openedx/paragon';
5
5
  import messages from './messages';
6
6
  import Allowances from './components/Allowances';
7
7
  import AttemptsList from './components/AttemptsList';
8
+ const SPECIAL_EXAMS_TAB = {
9
+ ATTEMPTS: 'attempts',
10
+ ALLOWANCES: 'allowances',
11
+ };
8
12
  const SpecialExamsPage = () => {
9
13
  const intl = useIntl();
10
- const [selectedTab, setSelectedTab] = useState('attempts');
11
- return (_jsxs(_Fragment, { children: [_jsx("h3", { className: "text-primary-700", children: intl.formatMessage(messages.specialExamsTitle) }), _jsxs(Card, { className: "bg-light-200 mt-4.5", children: [_jsxs(ButtonGroup, { className: "d-block mx-4 mt-4", children: [_jsx(Button, { variant: selectedTab === 'attempts' ? 'primary' : 'outline-primary', onClick: () => setSelectedTab('attempts'), children: intl.formatMessage(messages.examAttempts) }), _jsx(Button, { variant: selectedTab === 'allowances' ? 'primary' : 'outline-primary', onClick: () => setSelectedTab('allowances'), children: intl.formatMessage(messages.allowances) })] }), selectedTab === 'attempts' ? _jsx(AttemptsList, {}) : _jsx(Allowances, {})] })] }));
14
+ const [selectedTab, setSelectedTab] = useState(SPECIAL_EXAMS_TAB.ATTEMPTS);
15
+ return (_jsxs(_Fragment, { children: [_jsx("h3", { className: "text-primary-700", children: intl.formatMessage(messages.specialExamsTitle) }), _jsxs(Card, { className: "bg-light-200 mt-4.5", children: [_jsxs(ButtonGroup, { className: "d-block mx-4 mt-4", children: [_jsx(Button, { variant: selectedTab === SPECIAL_EXAMS_TAB.ATTEMPTS ? 'primary' : 'outline-primary', onClick: () => setSelectedTab(SPECIAL_EXAMS_TAB.ATTEMPTS), children: intl.formatMessage(messages.examAttempts) }), _jsx(Button, { variant: selectedTab === SPECIAL_EXAMS_TAB.ALLOWANCES ? 'primary' : 'outline-primary', onClick: () => setSelectedTab(SPECIAL_EXAMS_TAB.ALLOWANCES), children: intl.formatMessage(messages.allowances) })] }), selectedTab === SPECIAL_EXAMS_TAB.ATTEMPTS ? _jsx(AttemptsList, {}) : _jsx(Allowances, {})] })] }));
12
16
  };
13
17
  export default SpecialExamsPage;
14
18
  //# sourceMappingURL=SpecialExamsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SpecialExamsPage.js","sourceRoot":"","sources":["../../src/specialExams/SpecialExamsPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,UAAU,MAAM,yBAAyB,CAAC;AACjD,OAAO,YAAY,MAAM,2BAA2B,CAAC;AAErD,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAA4B,UAAU,CAAC,CAAC;IAEtF,OAAO,CACL,8BACE,aAAI,SAAS,EAAC,kBAAkB,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,GAAM,EACtF,MAAC,IAAI,IAAC,SAAS,EAAC,qBAAqB,aACnC,MAAC,WAAW,IAAC,SAAS,EAAC,mBAAmB,aACxC,KAAC,MAAM,IAAC,OAAO,EAAE,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,YAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAU,EAC5K,KAAC,MAAM,IAAC,OAAO,EAAE,WAAW,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,YAAY,CAAC,YAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAU,IAClK,EAEZ,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,KAAC,YAAY,KAAG,CAAC,CAAC,CAAC,KAAC,UAAU,KAAG,IAE3D,IACN,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["import { useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Button, ButtonGroup, Card } from '@openedx/paragon';\nimport messages from './messages';\nimport Allowances from './components/Allowances';\nimport AttemptsList from './components/AttemptsList';\n\nconst SpecialExamsPage = () => {\n const intl = useIntl();\n const [selectedTab, setSelectedTab] = useState<'attempts' | 'allowances'>('attempts');\n\n return (\n <>\n <h3 className=\"text-primary-700\">{intl.formatMessage(messages.specialExamsTitle)}</h3>\n <Card className=\"bg-light-200 mt-4.5\">\n <ButtonGroup className=\"d-block mx-4 mt-4\">\n <Button variant={selectedTab === 'attempts' ? 'primary' : 'outline-primary'} onClick={() => setSelectedTab('attempts')}>{intl.formatMessage(messages.examAttempts)}</Button>\n <Button variant={selectedTab === 'allowances' ? 'primary' : 'outline-primary'} onClick={() => setSelectedTab('allowances')}>{intl.formatMessage(messages.allowances)}</Button>\n </ButtonGroup>\n {\n selectedTab === 'attempts' ? <AttemptsList /> : <Allowances />\n }\n </Card>\n </>\n );\n};\n\nexport default SpecialExamsPage;\n"]}
1
+ {"version":3,"file":"SpecialExamsPage.js","sourceRoot":"","sources":["../../src/specialExams/SpecialExamsPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,UAAU,MAAM,yBAAyB,CAAC;AACjD,OAAO,YAAY,MAAM,2BAA2B,CAAC;AAErD,MAAM,iBAAiB,GAAG;IACxB,QAAQ,EAAE,UAAU;IACpB,UAAU,EAAE,YAAY;CACzB,CAAC;AAEF,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC5B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAA6D,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAEvI,OAAO,CACL,8BACE,aAAI,SAAS,EAAC,kBAAkB,YAAE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC,GAAM,EACtF,MAAC,IAAI,IAAC,SAAS,EAAC,qBAAqB,aACnC,MAAC,WAAW,IAAC,SAAS,EAAC,mBAAmB,aACxC,KAAC,MAAM,IACL,OAAO,EAAE,WAAW,KAAK,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,EACnF,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,iBAAiB,CAAC,QAAQ,CAAC,YACzD,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,GAClC,EACT,KAAC,MAAM,IACL,OAAO,EAAE,WAAW,KAAK,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,EACrF,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,iBAAiB,CAAC,UAAU,CAAC,YAC3D,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,GAChC,IACG,EAEZ,WAAW,KAAK,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAC,YAAY,KAAG,CAAC,CAAC,CAAC,KAAC,UAAU,KAAG,IAE3E,IACN,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC","sourcesContent":["import { useState } from 'react';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Button, ButtonGroup, Card } from '@openedx/paragon';\nimport messages from './messages';\nimport Allowances from './components/Allowances';\nimport AttemptsList from './components/AttemptsList';\n\nconst SPECIAL_EXAMS_TAB = {\n ATTEMPTS: 'attempts',\n ALLOWANCES: 'allowances',\n};\n\nconst SpecialExamsPage = () => {\n const intl = useIntl();\n const [selectedTab, setSelectedTab] = useState<(typeof SPECIAL_EXAMS_TAB)[keyof typeof SPECIAL_EXAMS_TAB]>(SPECIAL_EXAMS_TAB.ATTEMPTS);\n\n return (\n <>\n <h3 className=\"text-primary-700\">{intl.formatMessage(messages.specialExamsTitle)}</h3>\n <Card className=\"bg-light-200 mt-4.5\">\n <ButtonGroup className=\"d-block mx-4 mt-4\">\n <Button\n variant={selectedTab === SPECIAL_EXAMS_TAB.ATTEMPTS ? 'primary' : 'outline-primary'}\n onClick={() => setSelectedTab(SPECIAL_EXAMS_TAB.ATTEMPTS)}\n >{intl.formatMessage(messages.examAttempts)}\n </Button>\n <Button\n variant={selectedTab === SPECIAL_EXAMS_TAB.ALLOWANCES ? 'primary' : 'outline-primary'}\n onClick={() => setSelectedTab(SPECIAL_EXAMS_TAB.ALLOWANCES)}\n >{intl.formatMessage(messages.allowances)}\n </Button>\n </ButtonGroup>\n {\n selectedTab === SPECIAL_EXAMS_TAB.ATTEMPTS ? <AttemptsList /> : <Allowances />\n }\n </Card>\n </>\n );\n};\n\nexport default SpecialExamsPage;\n"]}
@@ -0,0 +1,6 @@
1
+ interface AddAllowanceModalProps {
2
+ isOpen: boolean;
3
+ onClose: () => void;
4
+ }
5
+ declare const AddAllowanceModal: ({ isOpen, onClose }: AddAllowanceModalProps) => import("react/jsx-runtime").JSX.Element;
6
+ export default AddAllowanceModal;
@@ -0,0 +1,84 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useState } from 'react';
3
+ import { useParams } from 'react-router-dom';
4
+ import { useIntl } from '@openedx/frontend-base';
5
+ import { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';
6
+ import { addLabel, addPlaceholder, allowanceTypesOptions } from '../../specialExams/constants';
7
+ import { useAddAllowance, useSpecialExams } from '../../specialExams/data/apiHook';
8
+ import messages from '../../specialExams/messages';
9
+ import { useAlert } from '../../providers/AlertProvider';
10
+ const examTypeOptions = [
11
+ { value: '', label: messages.selectExamType },
12
+ { value: 'proctored', label: messages.proctored },
13
+ { value: 'timed', label: messages.timed },
14
+ ];
15
+ const emptyAllowanceData = {
16
+ examType: '',
17
+ examIds: [],
18
+ allowanceType: '',
19
+ value: '',
20
+ users: ''
21
+ };
22
+ const AddAllowanceModal = ({ isOpen, onClose }) => {
23
+ const intl = useIntl();
24
+ const { courseId = '' } = useParams();
25
+ const [newAllowance, setNewAllowance] = useState(emptyAllowanceData);
26
+ const { data: specialExams, refetch } = useSpecialExams(courseId, newAllowance.examType);
27
+ const { mutate: addAllowance } = useAddAllowance(courseId);
28
+ const { showModal } = useAlert();
29
+ const enableSubmitButton = useMemo(() => (allowanceData) => {
30
+ const { examType, allowanceType, value, users, examIds } = allowanceData;
31
+ if (!examType || !allowanceType || !value || !users || examIds.length === 0) {
32
+ return false;
33
+ }
34
+ const userIds = users.split(',').map(user => user.trim()).filter(user => user);
35
+ return userIds.length > 0;
36
+ }, []);
37
+ useEffect(() => {
38
+ if (isOpen && newAllowance.examType) {
39
+ refetch();
40
+ }
41
+ }, [isOpen, newAllowance.examType, refetch]);
42
+ const handleClose = () => {
43
+ setNewAllowance(emptyAllowanceData);
44
+ onClose();
45
+ };
46
+ const handleAdd = (e) => {
47
+ e.preventDefault();
48
+ const userIds = newAllowance.users.split(',').map(user => user.trim()).filter(user => user);
49
+ const allowanceData = {
50
+ userIds,
51
+ examType: newAllowance.examType,
52
+ examIds: newAllowance.examIds,
53
+ allowanceType: newAllowance.allowanceType,
54
+ value: newAllowance.value,
55
+ };
56
+ addAllowance(allowanceData, {
57
+ onSuccess: () => {
58
+ handleClose();
59
+ },
60
+ onError: () => {
61
+ showModal({
62
+ message: intl.formatMessage(messages.addAllowanceError),
63
+ variant: 'danger',
64
+ });
65
+ }
66
+ });
67
+ };
68
+ const handleChanges = (e) => {
69
+ const { value, name } = e.target;
70
+ setNewAllowance(prev => (Object.assign(Object.assign({}, prev), { [name]: value })));
71
+ };
72
+ const handleToggleExam = (value) => {
73
+ setNewAllowance(prev => {
74
+ const examIds = prev.examIds.includes(value)
75
+ ? prev.examIds.filter(id => id !== value)
76
+ : [...prev.examIds, value];
77
+ return Object.assign(Object.assign({}, prev), { examIds });
78
+ });
79
+ };
80
+ return (_jsxs(ModalDialog, { isOpen: isOpen, onClose: handleClose, title: intl.formatMessage(messages.addAllowance), isOverflowVisible: false, size: "lg", children: [_jsx(ModalDialog.Header, { className: "border-bottom border-light-700", children: _jsx(ModalDialog.Title, { className: "text-primary-700", children: intl.formatMessage(messages.addAllowance) }) }), _jsxs(Form, { className: "position-relative overflow-auto", onSubmit: handleAdd, children: [_jsxs(ModalDialog.Body, { children: [_jsxs(Form.Group, { controlId: "specify-learners", children: [_jsxs(Form.Label, { className: "text-primary-500 x-small", children: [intl.formatMessage(messages.specifyLearners), ":"] }), _jsx(Form.Control, { as: "textarea", rows: 3, placeholder: intl.formatMessage(messages.specifyLearnersPlaceholder), name: "users", onChange: handleChanges })] }), _jsxs(Form.Group, { controlId: "select-exam-type", children: [_jsxs(Form.Label, { className: "text-primary-500 x-small", children: [intl.formatMessage(messages.selectExamType), ":"] }), _jsx(Form.Control, { as: "select", name: "examType", onChange: handleChanges, children: examTypeOptions.map(option => (_jsx("option", { value: option.value, children: intl.formatMessage(option.label) }, option.value))) })] }), _jsxs(Form.Group, { controlId: "select-exams", children: [_jsxs(Form.Label, { className: "text-primary-500 x-small", children: [intl.formatMessage(messages.selectExams), ":"] }), newAllowance.examType && (_jsx(Form.CheckboxSet, { onChange: (e) => handleToggleExam(Number(e.target.value)), name: "examIds", children: (specialExams || [])
81
+ .map((exam) => (_jsx(Form.Checkbox, { className: "mt-2", value: exam.id, children: exam.examName }, exam.id))) }))] }), _jsxs(Form.Group, { controlId: "select-allowance-type", children: [_jsxs(Form.Label, { className: "text-primary-500 x-small", children: [intl.formatMessage(messages.selectAllowanceType), ":"] }), _jsx(Form.Control, { as: "select", name: "allowanceType", onChange: handleChanges, children: allowanceTypesOptions.map(option => (_jsx("option", { value: option.value, children: intl.formatMessage(option.label) }, option.value))) })] }), _jsxs(Form.Group, { controlId: "allowance-value", children: [_jsxs(Form.Label, { className: "text-primary-500 x-small", children: [intl.formatMessage(addLabel[newAllowance.allowanceType || 'additional_time_granted']), ":"] }), _jsx(Form.Control, { type: newAllowance.allowanceType === 'review_policy_exception' ? 'text' : 'number', placeholder: intl.formatMessage(addPlaceholder[newAllowance.allowanceType || 'additional_time_granted']), name: "value", onChange: handleChanges })] })] }), _jsx(ModalDialog.Footer, { className: "border-top border-light-700", children: _jsxs(ActionRow, { children: [_jsx(Button, { variant: "tertiary", onClick: handleClose, children: intl.formatMessage(messages.cancel) }), _jsx(Button, { disabled: !enableSubmitButton(newAllowance), variant: "primary", type: "submit", children: intl.formatMessage(messages.createAllowance) })] }) })] })] }));
82
+ };
83
+ export default AddAllowanceModal;
84
+ //# sourceMappingURL=AddAllowanceModal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AddAllowanceModal.js","sourceRoot":"","sources":["../../../src/specialExams/components/AddAllowanceModal.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useIntl } from '@openedx/frontend-base';\nimport { ActionRow, Button, Form, ModalDialog } from '@openedx/paragon';\nimport { addLabel, addPlaceholder, allowanceTypesOptions } from '@src/specialExams/constants';\nimport { useAddAllowance, useSpecialExams } from '@src/specialExams/data/apiHook';\nimport messages from '@src/specialExams/messages';\nimport { AddAllowanceForm, AddAllowanceParams } from '@src/specialExams/types';\nimport { useAlert } from '@src/providers/AlertProvider';\n\ninterface AddAllowanceModalProps {\n isOpen: boolean,\n onClose: () => void,\n}\n\nconst examTypeOptions = [\n { value: '', label: messages.selectExamType },\n { value: 'proctored', label: messages.proctored },\n { value: 'timed', label: messages.timed },\n];\n\nconst emptyAllowanceData = {\n examType: '',\n examIds: [],\n allowanceType: '',\n value: '',\n users: ''\n};\n\nconst AddAllowanceModal = ({ isOpen, onClose }: AddAllowanceModalProps) => {\n const intl = useIntl();\n const { courseId = '' } = useParams();\n const [newAllowance, setNewAllowance] = useState<AddAllowanceForm>(emptyAllowanceData);\n const { data: specialExams, refetch } = useSpecialExams(courseId, newAllowance.examType);\n const { mutate: addAllowance } = useAddAllowance(courseId);\n const { showModal } = useAlert();\n\n const enableSubmitButton = useMemo(() => (allowanceData: AddAllowanceForm) => {\n const { examType, allowanceType, value, users, examIds } = allowanceData;\n if (!examType || !allowanceType || !value || !users || examIds.length === 0) {\n return false;\n }\n const userIds = users.split(',').map(user => user.trim()).filter(user => user);\n return userIds.length > 0;\n }, []);\n\n useEffect(() => {\n if (isOpen && newAllowance.examType) {\n refetch();\n }\n }, [isOpen, newAllowance.examType, refetch]);\n\n const handleClose = () => {\n setNewAllowance(emptyAllowanceData);\n onClose();\n };\n\n const handleAdd = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const userIds = newAllowance.users.split(',').map(user => user.trim()).filter(user => user);\n const allowanceData: AddAllowanceParams = {\n userIds,\n examType: newAllowance.examType,\n examIds: newAllowance.examIds,\n allowanceType: newAllowance.allowanceType,\n value: newAllowance.value,\n };\n\n addAllowance(allowanceData, {\n onSuccess: () => {\n handleClose();\n },\n onError: () => {\n showModal({\n message: intl.formatMessage(messages.addAllowanceError),\n variant: 'danger',\n });\n }\n });\n };\n\n const handleChanges = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const { value, name } = e.target;\n setNewAllowance(prev => ({\n ...prev,\n [name]: value,\n }));\n };\n\n const handleToggleExam = (value: number) => {\n setNewAllowance(prev => {\n const examIds = prev.examIds.includes(value)\n ? prev.examIds.filter(id => id !== value)\n : [...prev.examIds, value];\n return {\n ...prev,\n examIds,\n };\n });\n };\n\n return (\n <ModalDialog isOpen={isOpen} onClose={handleClose} title={intl.formatMessage(messages.addAllowance)} isOverflowVisible={false} size=\"lg\">\n <ModalDialog.Header className=\"border-bottom border-light-700\">\n <ModalDialog.Title className=\"text-primary-700\">{intl.formatMessage(messages.addAllowance)}</ModalDialog.Title>\n </ModalDialog.Header>\n <Form className=\"position-relative overflow-auto\" onSubmit={handleAdd}>\n <ModalDialog.Body>\n <Form.Group controlId=\"specify-learners\">\n <Form.Label className=\"text-primary-500 x-small\">{intl.formatMessage(messages.specifyLearners)}:</Form.Label>\n <Form.Control\n as=\"textarea\"\n rows={3}\n placeholder={intl.formatMessage(messages.specifyLearnersPlaceholder)}\n name=\"users\"\n onChange={handleChanges}\n />\n </Form.Group>\n <Form.Group controlId=\"select-exam-type\">\n <Form.Label className=\"text-primary-500 x-small\">{intl.formatMessage(messages.selectExamType)}:</Form.Label>\n <Form.Control as=\"select\" name=\"examType\" onChange={handleChanges}>\n {examTypeOptions.map(option => (\n <option key={option.value} value={option.value}>{intl.formatMessage(option.label)}</option>\n ))}\n </Form.Control>\n </Form.Group>\n <Form.Group controlId=\"select-exams\">\n <Form.Label className=\"text-primary-500 x-small\">{intl.formatMessage(messages.selectExams)}:</Form.Label>\n {newAllowance.examType && (\n <Form.CheckboxSet onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleToggleExam(Number(e.target.value))} name=\"examIds\">\n {\n (specialExams || [])\n .map((exam) => (\n <Form.Checkbox className=\"mt-2\" key={exam.id} value={exam.id}>\n {exam.examName}\n </Form.Checkbox>\n ))\n }\n </Form.CheckboxSet>\n )}\n </Form.Group>\n <Form.Group controlId=\"select-allowance-type\">\n <Form.Label className=\"text-primary-500 x-small\">{intl.formatMessage(messages.selectAllowanceType)}:</Form.Label>\n <Form.Control as=\"select\" name=\"allowanceType\" onChange={handleChanges}>\n {allowanceTypesOptions.map(option => (\n <option key={option.value} value={option.value}>{intl.formatMessage(option.label)}</option>\n ))}\n </Form.Control>\n </Form.Group>\n <Form.Group controlId=\"allowance-value\">\n <Form.Label className=\"text-primary-500 x-small\">{intl.formatMessage(addLabel[newAllowance.allowanceType || 'additional_time_granted'])}:</Form.Label>\n <Form.Control\n type={newAllowance.allowanceType === 'review_policy_exception' ? 'text' : 'number'}\n placeholder={intl.formatMessage(addPlaceholder[newAllowance.allowanceType || 'additional_time_granted'])}\n name=\"value\"\n onChange={handleChanges}\n />\n </Form.Group>\n </ModalDialog.Body>\n <ModalDialog.Footer className=\"border-top border-light-700\">\n <ActionRow>\n <Button variant=\"tertiary\" onClick={handleClose}>{intl.formatMessage(messages.cancel)}</Button>\n <Button disabled={!enableSubmitButton(newAllowance)} variant=\"primary\" type=\"submit\">{intl.formatMessage(messages.createAllowance)}</Button>\n </ActionRow>\n </ModalDialog.Footer>\n </Form>\n </ModalDialog>\n );\n};\n\nexport default AddAllowanceModal;\n"]}
@@ -1,6 +1,32 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { useToggle } from '@openedx/paragon';
4
+ import AddAllowanceModal from '../../specialExams/components/AddAllowanceModal';
5
+ import AllowancesList from '../../specialExams/components/AllowancesList';
6
+ import EditAllowanceModal from '../../specialExams/components/EditAllowanceModal';
7
+ import DeleteAllowanceModal from '../../specialExams/components/DeleteAllowanceModal';
2
8
  const Allowances = () => {
3
- return _jsx("div", { children: "Allowances" });
9
+ const [isAddModalOpen, openAddModal, closeAddModal] = useToggle(false);
10
+ const [isEditModalOpen, openEditModal, closeEditModal] = useToggle(false);
11
+ const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useToggle(false);
12
+ const [selectedAllowance, setSelectedAllowance] = useState(null);
13
+ const handleEditAllowance = (allowance) => {
14
+ setSelectedAllowance(allowance);
15
+ openEditModal();
16
+ };
17
+ const handleCloseEditModal = () => {
18
+ setSelectedAllowance(null);
19
+ closeEditModal();
20
+ };
21
+ const handleDeleteAllowance = (allowance) => {
22
+ setSelectedAllowance(allowance);
23
+ openDeleteModal();
24
+ };
25
+ const handleCloseDeleteModal = () => {
26
+ setSelectedAllowance(null);
27
+ closeDeleteModal();
28
+ };
29
+ return (_jsxs(_Fragment, { children: [_jsx(AllowancesList, { onClickAdd: openAddModal, onEdit: handleEditAllowance, onDelete: handleDeleteAllowance }), _jsx(AddAllowanceModal, { isOpen: isAddModalOpen, onClose: closeAddModal }), selectedAllowance && _jsx(EditAllowanceModal, { isOpen: isEditModalOpen, onClose: handleCloseEditModal, allowance: selectedAllowance }), selectedAllowance && _jsx(DeleteAllowanceModal, { isOpen: isDeleteModalOpen, onClose: handleCloseDeleteModal, allowance: selectedAllowance })] }));
4
30
  };
5
31
  export default Allowances;
6
32
  //# sourceMappingURL=Allowances.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Allowances.js","sourceRoot":"","sources":["../../../src/specialExams/components/Allowances.tsx"],"names":[],"mappings":";AAAA,MAAM,UAAU,GAAG,GAAG,EAAE;IACtB,OAAO,uCAAqB,CAAC;AAC/B,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["const Allowances = () => {\n return <div>Allowances</div>;\n};\n\nexport default Allowances;\n"]}
1
+ {"version":3,"file":"Allowances.js","sourceRoot":"","sources":["../../../src/specialExams/components/Allowances.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,iBAAiB,MAAM,gDAAgD,CAAC;AAC/E,OAAO,cAAc,MAAM,6CAA6C,CAAC;AACzE,OAAO,kBAAkB,MAAM,iDAAiD,CAAC;AACjF,OAAO,oBAAoB,MAAM,mDAAmD,CAAC;AAGrF,MAAM,UAAU,GAAG,GAAG,EAAE;IACtB,MAAM,CAAC,cAAc,EAAE,YAAY,EAAE,aAAa,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IACvE,MAAM,CAAC,eAAe,EAAE,aAAa,EAAE,cAAc,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,CAAC,iBAAiB,EAAE,eAAe,EAAE,gBAAgB,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAChF,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,QAAQ,CAAmB,IAAI,CAAC,CAAC;IAEnF,MAAM,mBAAmB,GAAG,CAAC,SAAoB,EAAE,EAAE;QACnD,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAChC,aAAa,EAAE,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,oBAAoB,GAAG,GAAG,EAAE;QAChC,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAC3B,cAAc,EAAE,CAAC;IACnB,CAAC,CAAC;IAEF,MAAM,qBAAqB,GAAG,CAAC,SAAoB,EAAE,EAAE;QACrD,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAChC,eAAe,EAAE,CAAC;IACpB,CAAC,CAAC;IAEF,MAAM,sBAAsB,GAAG,GAAG,EAAE;QAClC,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAC3B,gBAAgB,EAAE,CAAC;IACrB,CAAC,CAAC;IAEF,OAAO,CACL,8BACE,KAAC,cAAc,IAAC,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,qBAAqB,GAAI,EAC1G,KAAC,iBAAiB,IAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,GAAI,EACpE,iBAAiB,IAAI,KAAC,kBAAkB,IAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,iBAAiB,GAAI,EACjI,iBAAiB,IAAI,KAAC,oBAAoB,IAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,EAAE,sBAAsB,EAAE,SAAS,EAAE,iBAAiB,GAAI,IACvI,CACJ,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC","sourcesContent":["import { useState } from 'react';\nimport { useToggle } from '@openedx/paragon';\nimport AddAllowanceModal from '@src/specialExams/components/AddAllowanceModal';\nimport AllowancesList from '@src/specialExams/components/AllowancesList';\nimport EditAllowanceModal from '@src/specialExams/components/EditAllowanceModal';\nimport DeleteAllowanceModal from '@src/specialExams/components/DeleteAllowanceModal';\nimport { Allowance } from '@src/specialExams/types';\n\nconst Allowances = () => {\n const [isAddModalOpen, openAddModal, closeAddModal] = useToggle(false);\n const [isEditModalOpen, openEditModal, closeEditModal] = useToggle(false);\n const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useToggle(false);\n const [selectedAllowance, setSelectedAllowance] = useState<Allowance | null>(null);\n\n const handleEditAllowance = (allowance: Allowance) => {\n setSelectedAllowance(allowance);\n openEditModal();\n };\n\n const handleCloseEditModal = () => {\n setSelectedAllowance(null);\n closeEditModal();\n };\n\n const handleDeleteAllowance = (allowance: Allowance) => {\n setSelectedAllowance(allowance);\n openDeleteModal();\n };\n\n const handleCloseDeleteModal = () => {\n setSelectedAllowance(null);\n closeDeleteModal();\n };\n\n return (\n <>\n <AllowancesList onClickAdd={openAddModal} onEdit={handleEditAllowance} onDelete={handleDeleteAllowance} />\n <AddAllowanceModal isOpen={isAddModalOpen} onClose={closeAddModal} />\n {selectedAllowance && <EditAllowanceModal isOpen={isEditModalOpen} onClose={handleCloseEditModal} allowance={selectedAllowance} />}\n {selectedAllowance && <DeleteAllowanceModal isOpen={isDeleteModalOpen} onClose={handleCloseDeleteModal} allowance={selectedAllowance} />}\n </>\n );\n};\n\nexport default Allowances;\n"]}
@@ -0,0 +1,8 @@
1
+ import { Allowance } from '../../specialExams/types';
2
+ interface AllowanceList {
3
+ onClickAdd: () => void;
4
+ onEdit: (allowance: Allowance) => void;
5
+ onDelete: (allowance: Allowance) => void;
6
+ }
7
+ declare const AllowancesList: ({ onClickAdd, onEdit, onDelete }: AllowanceList) => import("react/jsx-runtime").JSX.Element;
8
+ export default AllowancesList;
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { useParams } from 'react-router-dom';
4
+ import { useIntl } from '@openedx/frontend-base';
5
+ import { Button, DataTable, IconButton, OverlayTrigger, Popover } from '@openedx/paragon';
6
+ import { MoreVert, Plus } from '@openedx/paragon/icons';
7
+ import UsernameFilter from '../../components/UsernameFilter';
8
+ import { ALLOWANCES_PAGE_SIZE, allowanceTypesOptions } from '../../specialExams/constants';
9
+ import { useAllowances } from '../../specialExams/data/apiHook';
10
+ import messages from '../../specialExams/messages';
11
+ const AllowancesList = ({ onClickAdd, onEdit, onDelete }) => {
12
+ const intl = useIntl();
13
+ const { courseId = '' } = useParams();
14
+ const [filters, setFilters] = useState({ page: 0, emailOrUsername: '' });
15
+ const { data = { results: [], count: 0, numPages: 1 }, isLoading = false } = useAllowances(courseId, Object.assign({ pageSize: ALLOWANCES_PAGE_SIZE }, filters));
16
+ const ActionCustomCell = ({ row: { original } }) => {
17
+ const popoverContent = (_jsx(Popover, { id: `popover-${original.user.username}-${original.proctoredExam.examName}`, className: "border-0 shadow-sm", children: _jsx(Popover.Content, { className: "p-0 border-0", children: _jsxs("div", { className: "dropdown-menu show position-static border shadow-sm", children: [_jsx("button", { type: "button", className: "dropdown-item", onClick: () => onEdit(original), children: intl.formatMessage(messages.edit) }), _jsx("button", { type: "button", className: "dropdown-item", onClick: () => onDelete(original), children: intl.formatMessage(messages.delete) })] }) }) }));
18
+ return (_jsx(_Fragment, { children: _jsx(OverlayTrigger, { trigger: "click", placement: "bottom-end", overlay: popoverContent, rootClose: true, children: _jsx(IconButton, { alt: intl.formatMessage(messages.actions), className: "lead", iconAs: MoreVert }) }) }));
19
+ };
20
+ const columns = [
21
+ { accessor: 'user.username', Header: intl.formatMessage(messages.username), Filter: UsernameFilter, },
22
+ { accessor: 'user.email', Header: intl.formatMessage(messages.email), disableFilters: true, },
23
+ { accessor: 'proctoredExam.examName', Header: intl.formatMessage(messages.examName), disableFilters: true, },
24
+ { accessor: 'key', Header: intl.formatMessage(messages.allowanceType), disableFilters: true,
25
+ Cell: ({ value }) => {
26
+ const allowanceType = allowanceTypesOptions.find(option => option.value === value);
27
+ return allowanceType ? intl.formatMessage(allowanceType.label) : '';
28
+ }
29
+ },
30
+ { accessor: 'value', Header: intl.formatMessage(messages.allowanceValue), disableFilters: true, },
31
+ ];
32
+ const additionalColumns = [{
33
+ id: 'actions',
34
+ Header: '',
35
+ Cell: ActionCustomCell,
36
+ }];
37
+ const handleFetchData = (data) => {
38
+ var _a;
39
+ const emailOrUsernameFilter = (_a = data.filters) === null || _a === void 0 ? void 0 : _a.find((f) => f.id === 'user.username');
40
+ const newEmailOrUsername = emailOrUsernameFilter ? emailOrUsernameFilter.value : '';
41
+ if (filters.emailOrUsername !== newEmailOrUsername) {
42
+ setFilters((prevFilters) => (Object.assign(Object.assign({}, prevFilters), { emailOrUsername: newEmailOrUsername, page: 0 })));
43
+ return;
44
+ }
45
+ if (data.pageIndex !== filters.page) {
46
+ setFilters((prevFilters) => (Object.assign(Object.assign({}, prevFilters), { page: data.pageIndex })));
47
+ }
48
+ };
49
+ return (_jsxs(DataTable, { additionalColumns: additionalColumns, className: "mt-3", columns: columns, data: data.results, state: {
50
+ pageIndex: filters.page,
51
+ pageSize: ALLOWANCES_PAGE_SIZE,
52
+ filters: [
53
+ { id: 'emailOrUsername', value: filters.emailOrUsername }
54
+ ]
55
+ }, fetchData: handleFetchData, isFilterable: true, isLoading: isLoading, isPaginated: true, isSortable: true, itemCount: data.count, manualFilters: true, manualPagination: true, manualSortBy: true, pageSize: ALLOWANCES_PAGE_SIZE, pageCount: data.numPages, FilterStatusComponent: () => null, children: [_jsxs("div", { className: "bg-light-200 d-flex justify-content-between align-items-center p-3", children: [_jsx(DataTable.TableControlBar, { className: "p-0" }), _jsx(Button, { iconBefore: Plus, variant: "primary", onClick: onClickAdd, children: intl.formatMessage(messages.addAllowance) })] }), _jsx(DataTable.Table, {}), _jsx(DataTable.EmptyTable, { content: intl.formatMessage(messages.noAllowances) }), _jsx(DataTable.TableFooter, {})] }));
56
+ };
57
+ export default AllowancesList;
58
+ //# sourceMappingURL=AllowancesList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AllowancesList.js","sourceRoot":"","sources":["../../../src/specialExams/components/AllowancesList.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useIntl } from '@openedx/frontend-base';\nimport { Button, DataTable, IconButton, OverlayTrigger, Popover } from '@openedx/paragon';\nimport { MoreVert, Plus } from '@openedx/paragon/icons';\nimport UsernameFilter from '@src/components/UsernameFilter';\nimport { ALLOWANCES_PAGE_SIZE, allowanceTypesOptions } from '@src/specialExams/constants';\nimport { useAllowances } from '@src/specialExams/data/apiHook';\nimport messages from '@src/specialExams/messages';\nimport { Allowance } from '@src/specialExams/types';\nimport { DataTableFetchDataProps, TableCellValue } from '@src/types';\n\ninterface AllowanceList {\n onClickAdd: () => void,\n onEdit: (allowance: Allowance) => void,\n onDelete: (allowance: Allowance) => void,\n}\n\nconst AllowancesList = ({ onClickAdd, onEdit, onDelete }: AllowanceList) => {\n const intl = useIntl();\n const { courseId = '' } = useParams<{ courseId: string }>();\n const [filters, setFilters] = useState({ page: 0, emailOrUsername: '' });\n const { data = { results: [], count: 0, numPages: 1 }, isLoading = false } = useAllowances(courseId, {\n pageSize: ALLOWANCES_PAGE_SIZE,\n ...filters,\n });\n\n const ActionCustomCell = ({ row: { original } }: TableCellValue<Allowance>) => {\n const popoverContent = (\n <Popover\n id={`popover-${original.user.username}-${original.proctoredExam.examName}`}\n className=\"border-0 shadow-sm\"\n >\n <Popover.Content className=\"p-0 border-0\">\n <div className=\"dropdown-menu show position-static border shadow-sm\">\n <button\n type=\"button\"\n className=\"dropdown-item\"\n onClick={() => onEdit(original)}\n >\n {intl.formatMessage(messages.edit)}\n </button>\n <button\n type=\"button\"\n className=\"dropdown-item\"\n onClick={() => onDelete(original)}\n >\n {intl.formatMessage(messages.delete)}\n </button>\n </div>\n </Popover.Content>\n </Popover>\n );\n return (\n <>\n <OverlayTrigger\n trigger=\"click\"\n placement=\"bottom-end\"\n overlay={popoverContent}\n rootClose\n >\n <IconButton\n alt={intl.formatMessage(messages.actions)}\n className=\"lead\"\n iconAs={MoreVert}\n />\n </OverlayTrigger>\n </>\n );\n };\n\n const columns = [\n { accessor: 'user.username', Header: intl.formatMessage(messages.username), Filter: UsernameFilter, },\n { accessor: 'user.email', Header: intl.formatMessage(messages.email), disableFilters: true, },\n { accessor: 'proctoredExam.examName', Header: intl.formatMessage(messages.examName), disableFilters: true, },\n { accessor: 'key', Header: intl.formatMessage(messages.allowanceType), disableFilters: true,\n Cell: ({ value }: { value: string }) => {\n const allowanceType = allowanceTypesOptions.find(option => option.value === value);\n return allowanceType ? intl.formatMessage(allowanceType.label) : '';\n }\n },\n { accessor: 'value', Header: intl.formatMessage(messages.allowanceValue), disableFilters: true, },\n ];\n\n const additionalColumns = [{\n id: 'actions',\n Header: '',\n Cell: ActionCustomCell,\n }];\n\n const handleFetchData = (data: DataTableFetchDataProps) => {\n const emailOrUsernameFilter = data.filters?.find((f) => f.id === 'user.username');\n const newEmailOrUsername = emailOrUsernameFilter ? emailOrUsernameFilter.value : '';\n if (filters.emailOrUsername !== newEmailOrUsername) {\n setFilters((prevFilters) => ({ ...prevFilters, emailOrUsername: newEmailOrUsername, page: 0 }));\n return;\n }\n if (data.pageIndex !== filters.page) {\n setFilters((prevFilters) => ({ ...prevFilters, page: data.pageIndex }));\n }\n };\n\n return (\n <DataTable\n additionalColumns={additionalColumns}\n className=\"mt-3\"\n columns={columns}\n data={data.results}\n state={{\n pageIndex: filters.page,\n pageSize: ALLOWANCES_PAGE_SIZE,\n filters: [\n { id: 'emailOrUsername', value: filters.emailOrUsername }\n ]\n }}\n fetchData={handleFetchData}\n isFilterable\n isLoading={isLoading}\n isPaginated\n isSortable\n itemCount={data.count}\n manualFilters\n manualPagination\n manualSortBy\n pageSize={ALLOWANCES_PAGE_SIZE}\n pageCount={data.numPages}\n FilterStatusComponent={() => null}\n >\n <div className=\"bg-light-200 d-flex justify-content-between align-items-center p-3\">\n <DataTable.TableControlBar className=\"p-0\" />\n <Button iconBefore={Plus} variant=\"primary\" onClick={onClickAdd}>\n {intl.formatMessage(messages.addAllowance)}\n </Button>\n </div>\n <DataTable.Table />\n <DataTable.EmptyTable content={intl.formatMessage(messages.noAllowances)} />\n <DataTable.TableFooter />\n </DataTable>\n );\n};\n\nexport default AllowancesList;\n"]}
@@ -13,19 +13,20 @@ const AttemptsList = () => {
13
13
  const [filters, setFilters] = useState({ page: 0, emailOrUsername: '' });
14
14
  const { data = { results: [], count: 0, numPages: 0 }, isLoading = false } = useAttempts(courseId, Object.assign(Object.assign({}, filters), { pageSize: ATTEMPTS_PAGE_SIZE }));
15
15
  const columns = useMemo(() => [
16
- { accessor: 'username', Header: intl.formatMessage(messages.username), Filter: UsernameFilter, },
16
+ { accessor: 'user.username', Header: intl.formatMessage(messages.username), Filter: UsernameFilter, },
17
17
  { accessor: 'examName', Header: intl.formatMessage(messages.examName), disableFilters: true, },
18
- { accessor: 'timeLimit', Header: intl.formatMessage(messages.timeLimit), disableFilters: true, },
18
+ { accessor: 'allowedTimeLimitMins', Header: intl.formatMessage(messages.timeLimit), disableFilters: true, },
19
19
  { accessor: 'type', Header: intl.formatMessage(messages.type), disableFilters: true, },
20
- { accessor: 'startedAt', Header: intl.formatMessage(messages.startedAt), disableFilters: true, },
21
- { accessor: 'completedAt', Header: intl.formatMessage(messages.completedAt), disableFilters: true, },
20
+ { accessor: 'startTime', Header: intl.formatMessage(messages.startedAt), disableFilters: true, },
21
+ { accessor: 'endTime', Header: intl.formatMessage(messages.completedAt), disableFilters: true, },
22
22
  { accessor: 'status', Header: intl.formatMessage(messages.status), disableFilters: true, },
23
23
  ], [intl]);
24
24
  const handleFetchData = (data) => {
25
25
  var _a;
26
- const emailOrUsernameFilter = (_a = data.filters) === null || _a === void 0 ? void 0 : _a.find((f) => f.id === 'username');
27
- if (emailOrUsernameFilter && emailOrUsernameFilter.value !== filters.emailOrUsername) {
28
- setFilters((prevFilters) => (Object.assign(Object.assign({}, prevFilters), { emailOrUsername: emailOrUsernameFilter.value, page: 0 })));
26
+ const emailOrUsernameFilter = (_a = data.filters) === null || _a === void 0 ? void 0 : _a.find((f) => f.id === 'user.username');
27
+ const newEmailOrUsername = emailOrUsernameFilter ? emailOrUsernameFilter.value : '';
28
+ if (filters.emailOrUsername !== newEmailOrUsername) {
29
+ setFilters((prevFilters) => (Object.assign(Object.assign({}, prevFilters), { emailOrUsername: newEmailOrUsername, page: 0 })));
29
30
  return;
30
31
  }
31
32
  if (data.pageIndex !== filters.page) {
@@ -1 +1 @@
1
- {"version":3,"file":"AttemptsList.js","sourceRoot":"","sources":["../../../src/specialExams/components/AttemptsList.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useIntl } from '@openedx/frontend-base';\nimport { DataTable } from '@openedx/paragon';\nimport UsernameFilter from '@src/components/UsernameFilter';\nimport messages from '@src/specialExams/messages';\nimport { useAttempts } from '@src/specialExams/data/apiHook';\nimport { DataTableFetchDataProps } from '@src/types';\n\nexport const ATTEMPTS_PAGE_SIZE = 25;\n\nconst AttemptsList = () => {\n const intl = useIntl();\n const { courseId = '' } = useParams();\n const [filters, setFilters] = useState({ page: 0, emailOrUsername: '' });\n const { data = { results: [], count: 0, numPages: 0 }, isLoading = false } = useAttempts(courseId, {\n ...filters,\n pageSize: ATTEMPTS_PAGE_SIZE\n });\n\n const columns = useMemo(() => [\n { accessor: 'username', Header: intl.formatMessage(messages.username), Filter: UsernameFilter, },\n { accessor: 'examName', Header: intl.formatMessage(messages.examName), disableFilters: true, },\n { accessor: 'timeLimit', Header: intl.formatMessage(messages.timeLimit), disableFilters: true, },\n { accessor: 'type', Header: intl.formatMessage(messages.type), disableFilters: true, },\n { accessor: 'startedAt', Header: intl.formatMessage(messages.startedAt), disableFilters: true, },\n { accessor: 'completedAt', Header: intl.formatMessage(messages.completedAt), disableFilters: true, },\n { accessor: 'status', Header: intl.formatMessage(messages.status), disableFilters: true, },\n ], [intl]);\n\n const handleFetchData = (data: DataTableFetchDataProps) => {\n const emailOrUsernameFilter = data.filters?.find((f) => f.id === 'username');\n if (emailOrUsernameFilter && emailOrUsernameFilter.value !== filters.emailOrUsername) {\n setFilters((prevFilters) => ({ ...prevFilters, emailOrUsername: emailOrUsernameFilter.value, page: 0 }));\n return;\n }\n if (data.pageIndex !== filters.page) {\n setFilters((prevFilters) => ({ ...prevFilters, page: data.pageIndex }));\n }\n };\n\n return (\n <DataTable\n className=\"mt-3\"\n columns={columns}\n data={data.results}\n state={{\n pageIndex: filters.page,\n pageSize: ATTEMPTS_PAGE_SIZE,\n filters: [\n { id: 'emailOrUsername', value: filters.emailOrUsername }\n ]\n }}\n fetchData={handleFetchData}\n isFilterable\n isLoading={isLoading}\n isPaginated\n isSortable\n itemCount={data.count}\n manualFilters\n manualPagination\n manualSortBy\n pageSize={ATTEMPTS_PAGE_SIZE}\n pageCount={data.numPages}\n FilterStatusComponent={() => null}\n >\n <DataTable.TableControlBar className=\"bg-light-200 py-3 px-4\" />\n <DataTable.Table />\n <DataTable.EmptyTable content={intl.formatMessage(messages.noAttempts)} />\n <DataTable.TableFooter />\n </DataTable>\n );\n};\n\nexport default AttemptsList;\n"]}
1
+ {"version":3,"file":"AttemptsList.js","sourceRoot":"","sources":["../../../src/specialExams/components/AttemptsList.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useIntl } from '@openedx/frontend-base';\nimport { DataTable } from '@openedx/paragon';\nimport UsernameFilter from '@src/components/UsernameFilter';\nimport messages from '@src/specialExams/messages';\nimport { useAttempts } from '@src/specialExams/data/apiHook';\nimport { DataTableFetchDataProps } from '@src/types';\n\nexport const ATTEMPTS_PAGE_SIZE = 25;\n\nconst AttemptsList = () => {\n const intl = useIntl();\n const { courseId = '' } = useParams();\n const [filters, setFilters] = useState({ page: 0, emailOrUsername: '' });\n const { data = { results: [], count: 0, numPages: 0 }, isLoading = false } = useAttempts(courseId, {\n ...filters,\n pageSize: ATTEMPTS_PAGE_SIZE\n });\n\n const columns = useMemo(() => [\n { accessor: 'user.username', Header: intl.formatMessage(messages.username), Filter: UsernameFilter, },\n { accessor: 'examName', Header: intl.formatMessage(messages.examName), disableFilters: true, },\n { accessor: 'allowedTimeLimitMins', Header: intl.formatMessage(messages.timeLimit), disableFilters: true, },\n { accessor: 'type', Header: intl.formatMessage(messages.type), disableFilters: true, },\n { accessor: 'startTime', Header: intl.formatMessage(messages.startedAt), disableFilters: true, },\n { accessor: 'endTime', Header: intl.formatMessage(messages.completedAt), disableFilters: true, },\n { accessor: 'status', Header: intl.formatMessage(messages.status), disableFilters: true, },\n ], [intl]);\n\n const handleFetchData = (data: DataTableFetchDataProps) => {\n const emailOrUsernameFilter = data.filters?.find((f) => f.id === 'user.username');\n const newEmailOrUsername = emailOrUsernameFilter ? emailOrUsernameFilter.value : '';\n if (filters.emailOrUsername !== newEmailOrUsername) {\n setFilters((prevFilters) => ({ ...prevFilters, emailOrUsername: newEmailOrUsername, page: 0 }));\n return;\n }\n if (data.pageIndex !== filters.page) {\n setFilters((prevFilters) => ({ ...prevFilters, page: data.pageIndex }));\n }\n };\n\n return (\n <DataTable\n className=\"mt-3\"\n columns={columns}\n data={data.results}\n state={{\n pageIndex: filters.page,\n pageSize: ATTEMPTS_PAGE_SIZE,\n filters: [\n { id: 'emailOrUsername', value: filters.emailOrUsername }\n ]\n }}\n fetchData={handleFetchData}\n isFilterable\n isLoading={isLoading}\n isPaginated\n isSortable\n itemCount={data.count}\n manualFilters\n manualPagination\n manualSortBy\n pageSize={ATTEMPTS_PAGE_SIZE}\n pageCount={data.numPages}\n FilterStatusComponent={() => null}\n >\n <DataTable.TableControlBar className=\"bg-light-200 py-3 px-4\" />\n <DataTable.Table />\n <DataTable.EmptyTable content={intl.formatMessage(messages.noAttempts)} />\n <DataTable.TableFooter />\n </DataTable>\n );\n};\n\nexport default AttemptsList;\n"]}
@@ -0,0 +1,8 @@
1
+ import { Allowance } from '../../specialExams/types';
2
+ interface DeleteAllowanceProps {
3
+ allowance: Allowance;
4
+ isOpen: boolean;
5
+ onClose: () => void;
6
+ }
7
+ declare const DeleteAllowanceModal: ({ allowance, isOpen, onClose }: DeleteAllowanceProps) => import("react/jsx-runtime").JSX.Element;
8
+ export default DeleteAllowanceModal;