@nualang/nualang-ui-components 0.1.1172 → 0.1.1174

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.
@@ -24,7 +24,6 @@ const StyledDiv = (0, _material.styled)("div")(() => ({
24
24
  }));
25
25
  function CreateFeedbackDialog({
26
26
  handleSubmit = () => {},
27
- attendees = [],
28
27
  attendeesData = [],
29
28
  data = {},
30
29
  handleGradeConversation = () => {},
@@ -95,7 +94,6 @@ function CreateFeedbackDialog({
95
94
  handleGradeConversation: handleGradeConversation,
96
95
  aiGrade: aiGrade,
97
96
  attendeesData: attendeesData,
98
- attendees: attendees,
99
97
  handleClosefeedbackForm: handleClosefeedbackForm,
100
98
  handleSubmit: handleSubmit,
101
99
  initialValues: values,
@@ -119,7 +117,6 @@ CreateFeedbackDialog.propTypes = {
119
117
  saveTranscript: _propTypes.default.func,
120
118
  attendeesData: _propTypes.default.array,
121
119
  t: _propTypes.default.func,
122
- attendees: _propTypes.default.object,
123
120
  data: _propTypes.default.object,
124
121
  handleGradeConversation: _propTypes.default.func,
125
122
  aiGrade: _propTypes.default.string,
@@ -78,7 +78,6 @@ function RecordingDialog({
78
78
  open,
79
79
  handleClose,
80
80
  meetingID,
81
- attendees,
82
81
  meetingPrompt,
83
82
  isTeacher,
84
83
  goToTimestamp,
@@ -95,7 +94,7 @@ function RecordingDialog({
95
94
  handleCreateFeedback,
96
95
  attendeesData
97
96
  }) {
98
- return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_ResponsiveDialog.default, {
97
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, attendeesData.length > 0 && /*#__PURE__*/_react.default.createElement(_ResponsiveDialog.default, {
99
98
  open: open,
100
99
  handleClose: handleClose,
101
100
  maxWidth: 1,
@@ -145,16 +144,15 @@ function RecordingDialog({
145
144
  }, /*#__PURE__*/_react.default.createElement(_RecordingInfo.default, {
146
145
  t: t,
147
146
  meetingID: meetingID,
148
- attendees: attendees,
149
147
  attendeesData: attendeesData,
150
148
  meetingPrompt: meetingPrompt,
151
- meetingTopic: meetingTopic
149
+ meetingTopic: meetingTopic,
150
+ isTeacher: isTeacher
152
151
  }), isTeacher ? /*#__PURE__*/_react.default.createElement(_FeedbackDialog.default, {
153
152
  t: t,
154
153
  loading: loading,
155
154
  saveTranscript: saveTranscript,
156
155
  attendeesData: attendeesData,
157
- attendees: attendees,
158
156
  data: selectedRecording,
159
157
  selectedRecording: selectedRecording,
160
158
  handleGradeConversation: handleGradeConversation,
@@ -172,8 +170,7 @@ RecordingDialog.propTypes = {
172
170
  open: _propTypes.default.bool,
173
171
  handleClose: _propTypes.default.func,
174
172
  meetingID: _propTypes.default.string,
175
- attendees: _propTypes.default.object,
176
- attendeesData: _propTypes.default.object,
173
+ attendeesData: _propTypes.default.array,
177
174
  meetingTopic: _propTypes.default.string,
178
175
  meetingPrompt: _propTypes.default.string,
179
176
  isTeacher: _propTypes.default.bool,
@@ -744,9 +744,9 @@ FeedbackForm.propTypes = {
744
744
  handleChange: _propTypes.default.func,
745
745
  handleBlur: _propTypes.default.func,
746
746
  handleSubmit: _propTypes.default.func,
747
- attendees: _propTypes.default.object,
748
747
  aiGrade: _propTypes.default.object,
749
- t: _propTypes.default.func
748
+ t: _propTypes.default.func,
749
+ attendeesData: _propTypes.default.array
750
750
  };
751
751
  function CreateFeedbackForm({
752
752
  initialValues = {
@@ -780,7 +780,6 @@ function CreateFeedbackForm({
780
780
  },
781
781
  handleSubmit: handleSubmitFeedback,
782
782
  enableReinitialize,
783
- attendees,
784
783
  attendeesData,
785
784
  handleGradeConversation,
786
785
  aiGrade = {},
@@ -839,7 +838,6 @@ function CreateFeedbackForm({
839
838
  handleClosefeedbackForm: handleClosefeedbackForm,
840
839
  handleChange: handleChange,
841
840
  values: values,
842
- attendees: attendees,
843
841
  attendeesData: attendeesData,
844
842
  handleGradeConversation: handleGradeConversation,
845
843
  conversation: conversation,
@@ -869,7 +867,7 @@ CreateFeedbackForm.propTypes = {
869
867
  onSubmit: _propTypes.default.func,
870
868
  handleSubmit: _propTypes.default.func,
871
869
  handleGradeConversation: _propTypes.default.func,
872
- attendees: _propTypes.default.object,
873
870
  aiGrade: _propTypes.default.object,
874
- conversation: _propTypes.default.object
871
+ conversation: _propTypes.default.object,
872
+ attendeesData: _propTypes.default.array
875
873
  };
@@ -4,19 +4,34 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = RecordingInfo;
7
- var _react = _interopRequireDefault(require("react"));
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _FeedbackInfoDialog = _interopRequireDefault(require("../../Dialogs/FeedbackInfoDialog/FeedbackInfoDialog"));
8
9
  var _material = require("@mui/material");
9
10
  var _propTypes = _interopRequireDefault(require("prop-types"));
10
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
13
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
11
14
  // eslint-disable-next-line no-unused-vars
12
15
 
13
16
  function RecordingInfo({
14
17
  meetingPrompt = "",
15
18
  meetingTopic = "",
16
19
  t = text => text,
17
- attendeesData
20
+ attendeesData,
21
+ isTeacher
18
22
  }) {
19
- return /*#__PURE__*/_react.default.createElement(_material.Box, {
23
+ const [viewFeedbackOpen, setViewFeedbackOpen] = (0, _react.useState)(false);
24
+ const [recordingFeedback, setRecordingFeedback] = (0, _react.useState)({});
25
+ const theme = (0, _material.useTheme)();
26
+ const isLgUp = (0, _material.useMediaQuery)(theme.breakpoints.up("lg"));
27
+ const handleCloseViewFeedback = () => {
28
+ setViewFeedbackOpen(false);
29
+ };
30
+ const handleViewFeedbackOpen = attendee => {
31
+ setRecordingFeedback(attendee.feedback);
32
+ setViewFeedbackOpen(true);
33
+ };
34
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Box, {
20
35
  p: 3
21
36
  }, /*#__PURE__*/_react.default.createElement(_material.Box, null, /*#__PURE__*/_react.default.createElement(_material.Typography, {
22
37
  fontWeight: "bold",
@@ -30,31 +45,71 @@ function RecordingInfo({
30
45
  variant: "h6"
31
46
  }, t("discussion_prompt")), /*#__PURE__*/_react.default.createElement(_material.Typography, {
32
47
  variant: "body1"
33
- }, meetingPrompt)), /*#__PURE__*/_react.default.createElement(_material.Box, {
34
- mt: 3
48
+ }, meetingPrompt)), /*#__PURE__*/_react.default.createElement(_material.Grid, {
49
+ container: true,
50
+ spacing: 1,
51
+ sx: {
52
+ mt: 2
53
+ },
54
+ alignItems: "center"
55
+ }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
56
+ item: true,
57
+ xs: 12
35
58
  }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
36
59
  fontWeight: "bold",
37
60
  variant: "h6"
38
- }, t("attendees")), /*#__PURE__*/_react.default.createElement(_material.List, null, [attendeesData].flat()?.map((attendee, index) => /*#__PURE__*/_react.default.createElement(_material.Box, {
39
- key: attendee?.memberId,
61
+ }, t("attendees"))), [attendeesData].flat()?.map((attendee, index) => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, {
62
+ key: attendee.memberId
63
+ }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
64
+ item: true,
65
+ xs: 12,
66
+ lg: isTeacher ? 4 : 12
67
+ }, /*#__PURE__*/_react.default.createElement(_material.Box, {
40
68
  display: "flex",
41
69
  alignItems: "center",
42
- sx: {
43
- marginBottom: 2
44
- }
70
+ sx: isLgUp || !isTeacher ? {
71
+ mb: 2
72
+ } : {}
45
73
  }, /*#__PURE__*/_react.default.createElement(_material.Avatar, {
46
- alt: attendee?.username,
47
- src: attendee?.userImage
74
+ alt: attendee.username,
75
+ src: attendee.userImage
48
76
  }), /*#__PURE__*/_react.default.createElement(_material.Typography, {
49
77
  sx: {
50
78
  marginLeft: 2
51
79
  }
52
- }, attendee?.username))))));
80
+ }, attendee.username))), isTeacher && /*#__PURE__*/_react.default.createElement(_material.Grid, {
81
+ item: true,
82
+ xs: 12,
83
+ lg: 8,
84
+ sx: isLgUp ? {
85
+ display: "flex",
86
+ justifyContent: "flex-end",
87
+ alignItems: "center"
88
+ } : {}
89
+ }, /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
90
+ title: Object.keys(attendee.feedback).length === 0 ? t("no_feedback") : "",
91
+ placement: "top",
92
+ arrow: true
93
+ }, /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement(_material.Button, {
94
+ "aria-label": t("view_feedback"),
95
+ variant: "outlined",
96
+ onClick: () => handleViewFeedbackOpen(attendee),
97
+ disabled: Object.keys(attendee.feedback).length === 0,
98
+ sx: isLgUp ? {
99
+ mb: 2
100
+ } : {
101
+ mb: 1
102
+ }
103
+ }, t("view_feedback"))))))))), /*#__PURE__*/_react.default.createElement(_FeedbackInfoDialog.default, {
104
+ feedbackOpen: viewFeedbackOpen,
105
+ feedbackHandleClose: handleCloseViewFeedback,
106
+ recordingFeedback: recordingFeedback,
107
+ t: t
108
+ }));
53
109
  }
54
110
  RecordingInfo.propTypes = {
55
111
  meetingPrompt: _propTypes.default.string,
56
112
  meetingTopic: _propTypes.default.string,
57
- meetingID: _propTypes.default.string,
58
- attendees: _propTypes.default.array,
59
- t: _propTypes.default.func
113
+ t: _propTypes.default.func,
114
+ attendeesData: _propTypes.default.array
60
115
  };
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.props = exports.default = exports.Default = void 0;
6
+ exports.props = exports.default = exports.Teacher = exports.Default = void 0;
7
7
  var _react = _interopRequireDefault(require("react"));
8
8
  var _RecordingInfo = _interopRequireDefault(require("./RecordingInfo"));
9
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -11,8 +11,58 @@ const Template = args => /*#__PURE__*/_react.default.createElement(_RecordingInf
11
11
  const props = exports.props = {
12
12
  meetingTopic: "The Beach",
13
13
  meetingPrompt: "Going to the beach with friends",
14
- emails: ["aaron.cullen@fathomtech.io", "connor.cawley@fathomtech.io", "stephen.kelly@fathomtech.io"],
15
- meetingID: "abcdef123456"
14
+ attendeesData: [{
15
+ classroomId: "test-classroom",
16
+ createdAt: 1719919556228,
17
+ createdBy: "user1",
18
+ memberId: "user1",
19
+ role: "student",
20
+ updatedAt: 1719919556228,
21
+ username: "Diego Maradona",
22
+ feedback: {
23
+ feedback1: [{
24
+ feedbackLevel: 0,
25
+ feedbackLevelName: "Novice Low",
26
+ methodCheck: "Teacher"
27
+ }],
28
+ feedback2: [{
29
+ feedbackLevel: 1,
30
+ feedbackLevelName: "Novice Mid",
31
+ methodCheck: "Teacher"
32
+ }],
33
+ feedback3: [{
34
+ feedbackLevel: 2,
35
+ feedbackLevelName: "Novice High",
36
+ methodCheck: "Teacher"
37
+ }],
38
+ feedback4: [{
39
+ feedbackLevel: 3,
40
+ feedbackLevelName: "Intermediate Low",
41
+ methodCheck: "Teacher"
42
+ }],
43
+ feedback5: [{
44
+ feedbackLevel: 3,
45
+ feedbackLevelName: "Intermediate Low",
46
+ methodCheck: "Teacher"
47
+ }],
48
+ feedback6: [{
49
+ feedbackLevel: 0,
50
+ feedbackLevelName: "Not Applicable",
51
+ fromTeacher: true
52
+ }],
53
+ feedbackText: "You did great!",
54
+ gradingOption: "Individual Grade"
55
+ }
56
+ }, {
57
+ classroomId: "test-classroom",
58
+ createdAt: 1719919556229,
59
+ createdBy: "user2",
60
+ memberId: "user2",
61
+ role: "student",
62
+ updatedAt: 1719919556229,
63
+ username: "Cristiano Ronaldofsdfsfsfsfdsfsdfds",
64
+ feedback: {}
65
+ }]
16
66
  };
17
67
  var _default = exports.default = {
18
68
  title: "Forms/RecordingInfo",
@@ -24,4 +74,10 @@ Default.args = {
24
74
  ...props,
25
75
  loading: false
26
76
  };
27
- Default.storyName = "default";
77
+ Default.storyName = "default";
78
+ const Teacher = exports.Teacher = Template.bind({});
79
+ Teacher.args = {
80
+ ...props,
81
+ isTeacher: true
82
+ };
83
+ Teacher.storyName = "teacher";
@@ -78,12 +78,14 @@ function VoiceSelector(props) {
78
78
  value = "",
79
79
  onVoicePitchChange,
80
80
  voicePitch,
81
+ generateAudio = false,
82
+ csv = false,
81
83
  ...otherProps
82
84
  } = props;
83
85
  const voiceAccents = Object.values(voices);
84
86
  const voicesArray = voiceAccents.flatMap(voiceOption => voiceOption.voiceOptions);
85
87
  const selectedVoice = (voicesArray || []).find(v => v.name === value);
86
- const devOrStorybook = process.env.REACT_APP_STAGE === "dev" || window.location.host === "localhost:9009";
88
+ const audioOrStorybook = generateAudio || window.location.host === "localhost:9009";
87
89
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.TextField, _extends({
88
90
  select: true,
89
91
  value: value
@@ -106,11 +108,11 @@ function VoiceSelector(props) {
106
108
  alt: ""
107
109
  }))), /*#__PURE__*/_react.default.createElement(_material.Grid, _extends({
108
110
  item: true
109
- }, devOrStorybook ? {
111
+ }, audioOrStorybook ? {
110
112
  sx: {
111
113
  flexGrow: 1
112
114
  }
113
- } : {}), voiceOption.isChild && voiceOption.isChild === true ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, " ", `${voiceOption.name} (${t("child")}) `, " ") : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, voiceOption.name)), devOrStorybook && /*#__PURE__*/_react.default.createElement(_material.Grid, {
115
+ } : {}), voiceOption.isChild && voiceOption.isChild === true ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, " ", `${voiceOption.name} (${t("child")}) `, " ") : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, voiceOption.name)), audioOrStorybook && /*#__PURE__*/_react.default.createElement(_material.Grid, {
114
116
  item: true,
115
117
  sx: {
116
118
  mr: 2,
@@ -122,7 +124,7 @@ function VoiceSelector(props) {
122
124
  }) : /*#__PURE__*/_react.default.createElement("img", {
123
125
  src: _aws.default,
124
126
  alt: "AWS Icon"
125
- }))))])])), value && /*#__PURE__*/_react.default.createElement(_material.Box, {
127
+ }))))])])), value && !csv && /*#__PURE__*/_react.default.createElement(_material.Box, {
126
128
  sx: {
127
129
  width: "100%",
128
130
  px: 1,
@@ -374,7 +374,8 @@ function Classroom({
374
374
  handleEditDiscussion,
375
375
  editBackgroundImages,
376
376
  editMeetingImages,
377
- setSelectedDiscussion
377
+ setSelectedDiscussion,
378
+ meetingRecsData
378
379
  } = vchatProps;
379
380
  const isSmallScreen = (0, _useMediaQuery.default)("(max-width:410px)");
380
381
  const {
@@ -837,7 +838,8 @@ function Classroom({
837
838
  getMeeting: getMeeting,
838
839
  getRecordings: getRecordings,
839
840
  selectedRecording: selectedRecording,
840
- setSelectedRecording: setSelectedRecording
841
+ setSelectedRecording: setSelectedRecording,
842
+ meetingRecsData: meetingRecsData
841
843
  }))), discussions?.length > 0 && /*#__PURE__*/_react.default.createElement("div", {
842
844
  id: "discussScheduled"
843
845
  }, /*#__PURE__*/_react.default.createElement(_ScheduleListCards.default, {
@@ -14,8 +14,6 @@ var _Forum = _interopRequireDefault(require("@mui/icons-material/Forum"));
14
14
  var _BubbleChart = _interopRequireDefault(require("@mui/icons-material/BubbleChart"));
15
15
  var _Add = _interopRequireDefault(require("@mui/icons-material/Add"));
16
16
  var _Courses = _interopRequireDefault(require("../../Lists/Courses"));
17
- var _Roleplays = _interopRequireDefault(require("../../Lists/Roleplays"));
18
- var _Bots = _interopRequireDefault(require("../../Lists/Bots"));
19
17
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
20
18
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
21
19
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -50,24 +48,12 @@ function Dashboard({
50
48
  t = text => text,
51
49
  completions = [],
52
50
  avatars = [],
53
- newRoleplays = [],
54
- handleSelectRoleplay,
55
- newBots = [],
56
- handleSelectBot,
57
- handleShareBot,
58
- handlePlayBot,
59
- handleShareRoleplay,
60
- handlePlayRoleplay,
61
51
  newCourses = [],
62
52
  recommendedCourses = [],
63
53
  popularCourses = [],
64
54
  isNewCoursesLoading,
65
55
  isRecommendedCoursesLoading,
66
- isNewRoleplaysLoading,
67
- isNewBotsLoading,
68
56
  isPopularCoursesLoading,
69
- handleDuplicateBot,
70
- handleDuplicateRoleplay,
71
57
  singleLineGrid = true,
72
58
  singleLineGridCols = 4,
73
59
  handleStartCourse,
@@ -91,7 +77,6 @@ function Dashboard({
91
77
  getCourseMember,
92
78
  getCourseMembers,
93
79
  username,
94
- subscription,
95
80
  memberId,
96
81
  handleDuplicateCourse
97
82
  }) {
@@ -317,98 +302,5 @@ function Dashboard({
317
302
  handleDuplicateCourse: handleDuplicateCourse
318
303
  })), /*#__PURE__*/_react.default.createElement(_material.Box, {
319
304
  pb: 2
320
- }, /*#__PURE__*/_react.default.createElement(_material.Divider, null))) : null, isNewRoleplaysLoading || newRoleplays.length > 0 ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Box, {
321
- pb: 2
322
- }, /*#__PURE__*/_react.default.createElement("div", {
323
- className: classes.header
324
- }, /*#__PURE__*/_react.default.createElement("div", {
325
- className: classes.headerText
326
- }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
327
- variant: "h5",
328
- component: "h2"
329
- }, newRoleplays.length > 0 ? t("new_roleplays") : /*#__PURE__*/_react.default.createElement(_Skeleton.default, {
330
- variant: "rectangular",
331
- height: 32,
332
- width: 250
333
- }))), /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
334
- title: t("find_roleplay")
335
- }, /*#__PURE__*/_react.default.createElement(_material.IconButton, {
336
- onClick: handleSearchRoleplays,
337
- "aria-label": t("find_roleplay"),
338
- color: "inherit",
339
- "data-cy": "search-roleplay-fab",
340
- size: "large",
341
- role: "link"
342
- }, /*#__PURE__*/_react.default.createElement(_Search.default, null))), /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
343
- title: t("create_roleplay")
344
- }, /*#__PURE__*/_react.default.createElement(_material.IconButton, {
345
- onClick: handleCreateRoleplay,
346
- "aria-label": t("create_roleplay"),
347
- color: "inherit",
348
- "data-cy": "add-roleplay-fab",
349
- size: "large",
350
- role: "link"
351
- }, /*#__PURE__*/_react.default.createElement(_Add.default, null)))), /*#__PURE__*/_react.default.createElement(_Roleplays.default, {
352
- t: t,
353
- roleplays: Array.isArray(newRoleplays) && newRoleplays.length ? newRoleplays : null,
354
- handleSelectRoleplay: handleSelectRoleplay,
355
- handlePlayRoleplay: handlePlayRoleplay,
356
- handleShareRoleplay: handleShareRoleplay,
357
- selectText: "play",
358
- avatars: avatars,
359
- handleDuplicateRoleplay: handleDuplicateRoleplay,
360
- singleLineGrid: singleLineGrid,
361
- singleLineGridCols: singleLineGridCols,
362
- handleViewUserProfile: handleViewUserProfile,
363
- subscription: subscription
364
- })), /*#__PURE__*/_react.default.createElement(_material.Box, {
365
- pb: 2
366
- }, /*#__PURE__*/_react.default.createElement(_material.Divider, null))) : null, isNewBotsLoading || newBots.length > 0 ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Box, {
367
- pb: 2
368
- }, /*#__PURE__*/_react.default.createElement("div", {
369
- className: classes.header
370
- }, /*#__PURE__*/_react.default.createElement("div", {
371
- className: classes.headerText
372
- }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
373
- variant: "h5",
374
- component: "h2"
375
- }, newBots.length > 0 ? t("new_bots") : /*#__PURE__*/_react.default.createElement(_Skeleton.default, {
376
- variant: "rectangular",
377
- height: 32,
378
- width: 250
379
- }))), /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
380
- title: t("find_bot")
381
- }, /*#__PURE__*/_react.default.createElement(_material.IconButton, {
382
- onClick: handleSearchBots,
383
- "aria-label": t("find_bot"),
384
- color: "inherit",
385
- "data-cy": "search-bot-fab",
386
- size: "large",
387
- role: "link"
388
- }, /*#__PURE__*/_react.default.createElement(_Search.default, null))), /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
389
- title: t("create_bot")
390
- }, /*#__PURE__*/_react.default.createElement(_material.IconButton, {
391
- onClick: handleCreateBot,
392
- "aria-label": t("create_bot"),
393
- color: "inherit",
394
- "data-cy": "add-bot-fab",
395
- size: "large",
396
- role: "link"
397
- }, /*#__PURE__*/_react.default.createElement(_Add.default, null)))), /*#__PURE__*/_react.default.createElement(_Bots.default, {
398
- t: t,
399
- bots: Array.isArray(newBots) && newBots.length ? newBots : null,
400
- handleSelectBot: handleSelectBot,
401
- handlePlayBot: handlePlayBot,
402
- handleShareBot: handleShareBot,
403
- selectText: "play",
404
- avatars: avatars,
405
- handleDuplicateBot: handleDuplicateBot,
406
- singleLineGrid: singleLineGrid,
407
- singleLineGridCols: singleLineGridCols,
408
- handleViewUserProfile: handleViewUserProfile,
409
- subscription: subscription,
410
- disablePreview: true
411
- })), /*#__PURE__*/_react.default.createElement(_material.Box, {
412
- pb: 2
413
305
  }, /*#__PURE__*/_react.default.createElement(_material.Divider, null))) : null);
414
306
  }
@@ -14,6 +14,16 @@ var _AvatarSelector = _interopRequireDefault(require("../../Misc/AvatarSelector/
14
14
  var _InputHelper = _interopRequireDefault(require("../../Forms/InputHelper/InputHelper"));
15
15
  var _utils = require("../../utils");
16
16
  var _AudioNuala = _interopRequireDefault(require("../../img/AudioNuala.svg"));
17
+ var _papaparse = _interopRequireDefault(require("papaparse"));
18
+ var _PlayArrow = _interopRequireDefault(require("@mui/icons-material/PlayArrow"));
19
+ var _jszip = _interopRequireDefault(require("jszip"));
20
+ var _fileSaver = require("file-saver");
21
+ var _lab = require("@mui/lab");
22
+ var _Add = _interopRequireDefault(require("@mui/icons-material/Add"));
23
+ var _Download = _interopRequireDefault(require("@mui/icons-material/Download"));
24
+ var _FileUpload = _interopRequireDefault(require("@mui/icons-material/FileUpload"));
25
+ var _ResponsiveDialog = _interopRequireDefault(require("../../Dialogs/ResponsiveDialog/ResponsiveDialog"));
26
+ var _Delete = _interopRequireDefault(require("@mui/icons-material/Delete"));
17
27
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
28
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
19
29
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -97,7 +107,8 @@ function ActorForm({
97
107
  filteredVoices,
98
108
  setFieldValue,
99
109
  setCheckAudioUrl,
100
- formik
110
+ formik,
111
+ csv = false
101
112
  }) {
102
113
  const [avatarSelector, setAvatarSelector] = (0, _react.useState)(false);
103
114
  const handleAvatarSelection = value => {
@@ -149,7 +160,9 @@ function ActorForm({
149
160
  helperText: touched?.actor?.voice && errors?.actor?.voice,
150
161
  error: touched?.actor?.voice && Boolean(errors?.actor?.voice),
151
162
  voicePitch: actor.voicePitch,
152
- onVoicePitchChange: handleVoicePitchChange
163
+ onVoicePitchChange: handleVoicePitchChange,
164
+ csv: csv,
165
+ generateAudio: true
153
166
  }), /*#__PURE__*/_react.default.createElement(_AvatarSelector.default, {
154
167
  t: t,
155
168
  open: avatarSelector,
@@ -157,7 +170,7 @@ function ActorForm({
157
170
  picture: actor.picture,
158
171
  handleClose: () => setAvatarSelector(false),
159
172
  handleSubmit: handleAvatarSelection
160
- }), formik.values.actor.voice && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Box, {
173
+ }), formik.values.actor.voice && !csv && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Box, {
161
174
  sx: {
162
175
  width: "100%",
163
176
  px: 1,
@@ -180,6 +193,193 @@ function ActorForm({
180
193
  learnLang: learnLang
181
194
  }))));
182
195
  }
196
+ function getVoiceLanguageCode(voice, languages) {
197
+ for (const languageCode in languages) {
198
+ const voicesObject = languages[languageCode].Voices;
199
+ if (voicesObject) {
200
+ for (const langKey in voicesObject) {
201
+ const voiceOptions = voicesObject[langKey].voiceOptions;
202
+ const matchingVoice = voiceOptions?.find(option => option.name === voice);
203
+ if (matchingVoice) {
204
+ return langKey;
205
+ }
206
+ }
207
+ }
208
+ }
209
+ return null;
210
+ }
211
+ function AddPhraseDialog({
212
+ t,
213
+ open,
214
+ onClose,
215
+ handleAddPhrase,
216
+ languages,
217
+ avatars,
218
+ handleSpeak,
219
+ langChar
220
+ }) {
221
+ const [checkAudioUrl, setCheckAudioUrl] = (0, _react.useState)(false);
222
+ const [filteredVoices, setFilteredVoices] = (0, _react.useState)([]);
223
+ const [learnLang, setLearnLang] = (0, _react.useState)("english");
224
+ const formik = (0, _formik.useFormik)({
225
+ initialValues: {
226
+ learnLang: "english",
227
+ actor: {
228
+ voice: "",
229
+ voiceLanguageCode: "",
230
+ voicePitch: "",
231
+ picture: ""
232
+ },
233
+ phraseToSpeak: "",
234
+ voiceSpeed: "",
235
+ fileName: ""
236
+ },
237
+ validationSchema: Yup.object({
238
+ actor: Yup.object().shape({
239
+ voice: Yup.string().nullable(),
240
+ voiceLanguageCode: Yup.string().nullable(),
241
+ voicePitch: Yup.string().nullable(),
242
+ picture: Yup.string().nullable()
243
+ }),
244
+ phraseToSpeak: Yup.string().required("Required"),
245
+ fileName: Yup.string()
246
+ }),
247
+ onSubmit: values => {
248
+ const phraseToAdd = {
249
+ phrase: values.phraseToSpeak,
250
+ actor: values.actor,
251
+ fileName: values.fileName
252
+ };
253
+ handleAddPhrase(phraseToAdd);
254
+ formik.resetForm();
255
+ onClose();
256
+ }
257
+ });
258
+ (0, _react.useEffect)(() => {
259
+ setCheckAudioUrl(true);
260
+ }, [formik.values.phraseToSpeak]);
261
+ (0, _react.useEffect)(() => {
262
+ if (learnLang) {
263
+ const voicesForLang = languages[learnLang]?.Voices || [];
264
+ setFilteredVoices(voicesForLang);
265
+ }
266
+ }, [learnLang, languages]);
267
+ const handleLanguageChange = e => {
268
+ const selectedLang = e.target.value;
269
+ setLearnLang(selectedLang);
270
+ formik.setFieldValue("actor.voice", "");
271
+ setCheckAudioUrl(true);
272
+ };
273
+ return /*#__PURE__*/_react.default.createElement(_ResponsiveDialog.default, {
274
+ open: open,
275
+ onClose: onClose,
276
+ maxWidth: "80%"
277
+ }, /*#__PURE__*/_react.default.createElement(_material.DialogTitle, null, t("add_phrase")), /*#__PURE__*/_react.default.createElement(_material.DialogContent, null, /*#__PURE__*/_react.default.createElement(_material.Grid, {
278
+ container: true,
279
+ spacing: 2
280
+ }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
281
+ item: true,
282
+ xs: 12,
283
+ marginTop: 2
284
+ }, /*#__PURE__*/_react.default.createElement(_LanguageSelector.default, {
285
+ id: "learnLang",
286
+ name: "learnLang",
287
+ label: t("language"),
288
+ fullWidth: true,
289
+ required: true,
290
+ t: t,
291
+ languages: languages,
292
+ value: learnLang,
293
+ onChange: handleLanguageChange,
294
+ onBlur: formik.handleBlur
295
+ })), /*#__PURE__*/_react.default.createElement(_material.Grid, {
296
+ item: true,
297
+ xs: 12
298
+ }, /*#__PURE__*/_react.default.createElement(ActorForm, {
299
+ t: t,
300
+ actor: formik.values.actor,
301
+ handleBlur: formik.handleBlur,
302
+ touched: formik.touched,
303
+ errors: formik.errors,
304
+ learnLang: learnLang,
305
+ filteredVoices: filteredVoices,
306
+ handleSpeak: handleSpeak,
307
+ avatars: avatars,
308
+ langChar: langChar,
309
+ setFieldValue: formik.setFieldValue,
310
+ formik: formik,
311
+ setCheckAudioUrl: setCheckAudioUrl,
312
+ csv: true
313
+ })), /*#__PURE__*/_react.default.createElement(_material.Grid, {
314
+ item: true,
315
+ xs: 12
316
+ }, /*#__PURE__*/_react.default.createElement(_material.TextField, {
317
+ id: "fileName",
318
+ "data-cy": "fileName",
319
+ name: "fileName",
320
+ label: t("file_name"),
321
+ value: formik.values.fileName,
322
+ onChange: formik.handleChange,
323
+ onBlur: formik.handleBlur,
324
+ type: "text",
325
+ margin: "normal",
326
+ variant: "outlined",
327
+ fullWidth: true,
328
+ helperText: formik.touched.fileName && formik.errors.fileName,
329
+ error: formik.touched.fileName && Boolean(formik.errors.fileName),
330
+ InputProps: {
331
+ endAdornment: /*#__PURE__*/_react.default.createElement(_material.InputAdornment, {
332
+ position: "end"
333
+ }, ".mp3")
334
+ }
335
+ })), /*#__PURE__*/_react.default.createElement(_material.Grid, {
336
+ item: true,
337
+ xs: 12,
338
+ marginTop: -1
339
+ }, /*#__PURE__*/_react.default.createElement(_InputHelper.default, {
340
+ t: t,
341
+ id: "phraseToSpeak",
342
+ "data-cy": "phraseToSpeak",
343
+ name: "phraseToSpeak",
344
+ label: t("phrase_to_speak"),
345
+ value: formik.values.phraseToSpeak,
346
+ onChange: formik.handleChange,
347
+ onBlur: formik.handleBlur,
348
+ type: "text",
349
+ margin: "normal",
350
+ variant: "outlined",
351
+ fullWidth: true,
352
+ required: true,
353
+ multiline: true,
354
+ characters: langChar,
355
+ learnLang: learnLang,
356
+ helperText: formik.touched.phraseToSpeak && formik.errors.phraseToSpeak,
357
+ error: formik.touched.phraseToSpeak && Boolean(formik.errors.phraseToSpeak)
358
+ })))), /*#__PURE__*/_react.default.createElement(_material.DialogActions, null, /*#__PURE__*/_react.default.createElement(_material.Button, {
359
+ onClick: onClose
360
+ }, t("close")), /*#__PURE__*/_react.default.createElement(_material.Button, {
361
+ variant: "outlined",
362
+ color: "primary",
363
+ disabled: formik.values.phraseToSpeak === "" || !formik.values.actor.voice,
364
+ onClick: () => handleSpeak({
365
+ text: formik.values.phraseToSpeak,
366
+ learnLanguage: learnLang,
367
+ voiceName: formik.values.actor.voice,
368
+ mute: false,
369
+ callback: () => {},
370
+ textContainer: null,
371
+ languageCode: formik.values.actor.voiceLanguageCode,
372
+ isHoverText: false,
373
+ pitch: formik.values.actor.voicePitch,
374
+ voiceSpeed: formik.values.voiceSpeed
375
+ })
376
+ }, t("play_audio")), /*#__PURE__*/_react.default.createElement(_material.Button, {
377
+ variant: "contained",
378
+ onClick: formik.handleSubmit,
379
+ color: "primary",
380
+ disabled: formik.values.phraseToSpeak === "" || !formik.values.actor.voice
381
+ }, t("add_phrase"))));
382
+ }
183
383
  function GenerateAudio({
184
384
  t,
185
385
  handleSpeak,
@@ -187,12 +387,18 @@ function GenerateAudio({
187
387
  languages,
188
388
  langChar,
189
389
  downloadAudio,
190
- audioUrl
390
+ audioUrl,
391
+ openSnackbar
191
392
  }) {
192
393
  const [learnLang, setLearnLang] = (0, _react.useState)("english");
193
394
  const [filteredVoices, setFilteredVoices] = (0, _react.useState)([]);
194
395
  const [checkAudioUrl, setCheckAudioUrl] = (0, _react.useState)(false);
195
396
  const [voiceSpeed, setVoiceSpeed] = (0, _react.useState)(50);
397
+ const [showCSV, setShowCSV] = (0, _react.useState)(false);
398
+ const [csvData, setCsvData] = (0, _react.useState)([]);
399
+ const [csvHeaders, setCsvHeaders] = (0, _react.useState)(["phrase", "fileName", "voice"]);
400
+ const [isGenerating, setIsGenerating] = (0, _react.useState)(false);
401
+ const [dialogOpen, setDialogOpen] = (0, _react.useState)(false);
196
402
  const formik = (0, _formik.useFormik)({
197
403
  initialValues: {
198
404
  actor: {
@@ -216,7 +422,7 @@ function GenerateAudio({
216
422
  phraseToSpeak: Yup.string().required("Required").test("noSpecialChars", "No special characters", value => !(0, _utils.containsInvalidSymbols)(value))
217
423
  }),
218
424
  onSubmit: values => {
219
- handleSpeak(values.phraseToSpeak, learnLang, values.actor.voice);
425
+ handleSpeak(values.phraseToSpeak, values.actor.voice);
220
426
  }
221
427
  });
222
428
  (0, _react.useEffect)(() => {
@@ -237,6 +443,187 @@ function GenerateAudio({
237
443
  const handleSpeedChange = (event, newValue) => {
238
444
  setVoiceSpeed(newValue);
239
445
  };
446
+ const playPhraseAudio = (phrase, rowVoice) => {
447
+ const voiceToUse = rowVoice || formik.values.actor.voice || "Joey";
448
+ handleSpeak({
449
+ text: phrase,
450
+ learnLanguage: formik.values.learnLang || "english",
451
+ voiceName: voiceToUse,
452
+ mute: false,
453
+ callback: () => {},
454
+ textContainer: null,
455
+ languageCode: getVoiceLanguageCode(voiceToUse, languages),
456
+ isHoverText: false,
457
+ pitch: null,
458
+ voiceSpeed: null
459
+ });
460
+ };
461
+ const languagesContainsVoice = voice => {
462
+ for (const languageCode in languages) {
463
+ const voicesObject = languages[languageCode].Voices;
464
+ if (voicesObject) {
465
+ for (const langKey in voicesObject) {
466
+ const voiceOptions = voicesObject[langKey].voiceOptions;
467
+ if (voiceOptions?.find(option => option.name === voice)) {
468
+ return true;
469
+ }
470
+ }
471
+ }
472
+ }
473
+ return false;
474
+ };
475
+ const handleAddPhrase = newPhrase => {
476
+ csvHeaders.length === 0 && setCsvHeaders(["phrase", "fileName", "voice"]);
477
+ const fileName = `audio_${csvData.length + 1}_${new Date().toISOString().replace(/:/g, "-").slice(0, 19)}.mp3`;
478
+ if (newPhrase.fileName && !newPhrase.fileName.endsWith(".mp3")) {
479
+ newPhrase.fileName = `${newPhrase.fileName}.mp3`;
480
+ }
481
+ const phraseWithDefaults = {
482
+ phrase: newPhrase.phrase,
483
+ fileName: newPhrase.fileName || fileName,
484
+ voice: newPhrase.actor.voice || "Joey"
485
+ };
486
+ setCsvData([...csvData, phraseWithDefaults]);
487
+ };
488
+ const downloadCSVTemplate = () => {
489
+ const csvTemplate = "phrase,fileName,voice\nThis is a test phrase,Test.mp3,Joey\n";
490
+ downloadCSV(csvTemplate, "template.csv");
491
+ };
492
+ const handleCSVUpload = event => {
493
+ const file = event.target.files[0];
494
+ if (file) {
495
+ _papaparse.default.parse(file, {
496
+ header: true,
497
+ skipEmptyLines: true,
498
+ complete: function (results) {
499
+ let headers = results.meta.fields || [];
500
+
501
+ // Ensure 'phrase' is present in the headers
502
+ if (headers.includes("phrase")) {
503
+ if (!headers.includes("fileName")) {
504
+ headers.push("fileName");
505
+ }
506
+ if (!headers.includes("voice")) {
507
+ headers.push("voice");
508
+ }
509
+ const data = results.data.map((row, index) => {
510
+ if (!row.phrase) {
511
+ openSnackbar(`Row ${index + 1} is missing a phrase.`, "error");
512
+ return null; // Invalid row, will be filtered out
513
+ }
514
+ if (!row.fileName) {
515
+ row.fileName = `audio_${index + 1}_${new Date().toISOString().replace(/:/g, "-").slice(0, 19)}.mp3`;
516
+ } else {
517
+ row.fileName = row.fileName.endsWith(".mp3") ? row.fileName : `${row.fileName}.mp3`;
518
+ }
519
+ row.voice = languagesContainsVoice(row.voice) ? row.voice : "Joey";
520
+ return row;
521
+ }).filter(Boolean);
522
+ setCsvData(csvData.length > 0 ? [...csvData, ...data] : data);
523
+ setCsvHeaders(csvHeaders.length > 0 ? csvHeaders : headers);
524
+ } else {
525
+ openSnackbar("CSV must contain 'phrase' header.", "error");
526
+ removeCSVFile();
527
+ }
528
+ },
529
+ error: function (error) {
530
+ console.error("Error parsing CSV: ", error);
531
+ }
532
+ });
533
+ }
534
+ };
535
+ const removeCSVFile = () => {
536
+ setCsvData([]);
537
+ setCsvHeaders([]);
538
+ };
539
+ const handleDeleteRow = rowIndex => {
540
+ const updatedCsvData = csvData.filter((_, index) => index !== rowIndex);
541
+ setCsvData(updatedCsvData);
542
+ };
543
+ const handleChange = (event, newValue) => {
544
+ setShowCSV(newValue);
545
+ };
546
+ const downloadCSV = (text, filename) => {
547
+ const element = document.createElement("a");
548
+ const file = new Blob([text], {
549
+ type: "text/plain"
550
+ });
551
+ element.href = URL.createObjectURL(file);
552
+ element.download = filename;
553
+ document.body.appendChild(element); // Required for this to work in FireFox
554
+ element.click();
555
+ };
556
+ const generateAudioForCSV = async () => {
557
+ const zip = new _jszip.default();
558
+ const timestamp = new Date().toISOString().replace(/:/g, "-").slice(0, 19);
559
+ const folder = zip.folder(`audio_files_${timestamp}`);
560
+ setIsGenerating(true);
561
+ const fileNameCount = {};
562
+ try {
563
+ for (const row of csvData) {
564
+ const phrase = row.phrase;
565
+ let fileName = row.fileName || `audio_${new Date().toISOString().replace(/:/g, "-").slice(0, 19)}`;
566
+ const rowVoice = row.voice || formik.values.actor.voice;
567
+ if (!phrase) {
568
+ openSnackbar("Invalid CSV data: 'phrase' column is required", "error");
569
+ continue;
570
+ }
571
+ try {
572
+ const result = await handleSpeak({
573
+ text: phrase,
574
+ learnLanguage: learnLang,
575
+ voiceName: rowVoice,
576
+ mute: true,
577
+ callback: () => {},
578
+ textContainer: null,
579
+ languageCode: getVoiceLanguageCode(rowVoice, languages),
580
+ isHoverText: false,
581
+ pitch: null,
582
+ voiceSpeed: null
583
+ });
584
+ const audioUrl = result ? result.audioUrl : null;
585
+ if (!audioUrl) continue;
586
+ const response = await fetch(audioUrl);
587
+ if (!response.ok) {
588
+ openSnackbar(`Failed to fetch audio for phrase: "${phrase}"`, "error");
589
+ continue;
590
+ }
591
+ const blob = await response.blob();
592
+ let fileNameWithExtension = fileName.endsWith(".mp3") ? fileName : `${fileName}.mp3`;
593
+ const contentType = blob.type;
594
+ const allowedAudioTypes = ["audio/mpeg", "audio/wav", "audio/ogg", "application/octet-stream"];
595
+ if (!allowedAudioTypes.includes(contentType)) {
596
+ openSnackbar(`Unsupported audio type for phrase: "${phrase}"`, "error");
597
+ continue;
598
+ }
599
+ if (fileNameCount[fileNameWithExtension]) {
600
+ fileNameCount[fileNameWithExtension] += 1;
601
+ const baseName = fileNameWithExtension.replace(".mp3", "");
602
+ fileNameWithExtension = `${baseName}_${fileNameCount[fileNameWithExtension]}.mp3`;
603
+ } else {
604
+ fileNameCount[fileNameWithExtension] = 1;
605
+ }
606
+ folder.file(fileNameWithExtension, blob);
607
+ } catch (error) {
608
+ console.error(`Error generating audio for ${fileName}: ${error.message}`);
609
+ }
610
+ }
611
+
612
+ // Prepare CSV data with updated headers and rows
613
+ const csvContent = [csvHeaders.join(","), ...csvData.map(row => csvHeaders.map(header => row[header]).join(","))].join("\n");
614
+
615
+ // Add CSV file to zip
616
+ zip.file(`updated_data_${timestamp}.csv`, csvContent);
617
+ const zipBlob = await zip.generateAsync({
618
+ type: "blob"
619
+ });
620
+ (0, _fileSaver.saveAs)(zipBlob, `audio_files_${timestamp}.zip`);
621
+ } catch (error) {
622
+ console.error(`Error generating audio files: ${error.message}`);
623
+ } finally {
624
+ setIsGenerating(false);
625
+ }
626
+ };
240
627
  return /*#__PURE__*/_react.default.createElement("form", {
241
628
  onSubmit: formik.handleSubmit
242
629
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
@@ -248,16 +635,43 @@ function GenerateAudio({
248
635
  }
249
636
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
250
637
  item: true,
251
- xs: 12,
638
+ xs: 6,
639
+ md: 4,
252
640
  style: {
253
- textAlign: "center"
641
+ textAlign: "center",
642
+ marginTop: "15px"
254
643
  }
255
644
  }, /*#__PURE__*/_react.default.createElement("img", {
256
645
  src: _AudioNuala.default,
257
646
  alt: "Audio Nuala",
258
647
  style: {
259
- maxWidth: "400px",
260
- marginTop: "15px"
648
+ maxWidth: "300px"
649
+ }
650
+ })), /*#__PURE__*/_react.default.createElement(_material.Grid, {
651
+ item: true,
652
+ xs: 6,
653
+ md: 4,
654
+ style: {
655
+ textAlign: "left"
656
+ }
657
+ }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
658
+ variant: "h5",
659
+ fontWeight: "bold"
660
+ }, t("text_studio")), /*#__PURE__*/_react.default.createElement(_material.Typography, {
661
+ variant: "body1",
662
+ gutterBottom: true
663
+ }, t("text_studio_description"))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
664
+ item: true,
665
+ xs: 12,
666
+ md: 8,
667
+ marginTop: 2,
668
+ marginBottom: 1,
669
+ style: {
670
+ textAlign: "center"
671
+ }
672
+ }, /*#__PURE__*/_react.default.createElement(_material.Divider, {
673
+ sx: {
674
+ borderBottomWidth: 4
261
675
  }
262
676
  })), /*#__PURE__*/_react.default.createElement(_material.Grid, {
263
677
  item: true,
@@ -268,9 +682,28 @@ function GenerateAudio({
268
682
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
269
683
  item: true,
270
684
  xs: 12,
271
- md: 6,
272
- paddingRight: 1
273
- }, /*#__PURE__*/_react.default.createElement(_LanguageSelector.default, {
685
+ md: 12,
686
+ marginTop: 2,
687
+ marginBottom: 1.5
688
+ }, /*#__PURE__*/_react.default.createElement(_material.ToggleButtonGroup, {
689
+ color: "primary",
690
+ value: showCSV,
691
+ exclusive: true,
692
+ onChange: handleChange,
693
+ "aria-label": "Platform",
694
+ sx: {
695
+ marginLeft: "auto",
696
+ height: "30px"
697
+ }
698
+ }, /*#__PURE__*/_react.default.createElement(_material.ToggleButton, {
699
+ value: false
700
+ }, t("single_phrase")), /*#__PURE__*/_react.default.createElement(_material.ToggleButton, {
701
+ value: true
702
+ }, t("list_of_phrases")))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
703
+ item: true,
704
+ xs: 12,
705
+ md: 12
706
+ }, !showCSV && /*#__PURE__*/_react.default.createElement(_LanguageSelector.default, {
274
707
  id: "learnLang",
275
708
  name: "learnLang",
276
709
  "data-cy": "learnLang",
@@ -287,9 +720,8 @@ function GenerateAudio({
287
720
  })), /*#__PURE__*/_react.default.createElement(_material.Grid, {
288
721
  item: true,
289
722
  xs: 12,
290
- md: 6,
291
- paddingLeft: 1
292
- }, /*#__PURE__*/_react.default.createElement(ActorForm, {
723
+ md: 12
724
+ }, !showCSV && /*#__PURE__*/_react.default.createElement(ActorForm, {
293
725
  t: t,
294
726
  actor: formik.values.actor,
295
727
  handleBlur: formik.handleBlur,
@@ -311,7 +743,7 @@ function GenerateAudio({
311
743
  xs: 12,
312
744
  md: 12,
313
745
  marginBottom: 2
314
- }, /*#__PURE__*/_react.default.createElement(_InputHelper.default, {
746
+ }, !showCSV ? /*#__PURE__*/_react.default.createElement(_InputHelper.default, {
315
747
  t: t,
316
748
  id: "phraseToSpeak",
317
749
  "data-cy": "phraseToSpeak",
@@ -330,7 +762,144 @@ function GenerateAudio({
330
762
  learnLang: learnLang,
331
763
  helperText: formik.touched.phraseToSpeak && formik.errors.phraseToSpeak,
332
764
  error: formik.touched.phraseToSpeak && Boolean(formik.errors.phraseToSpeak)
765
+ }) : /*#__PURE__*/_react.default.createElement(_material.Grid, {
766
+ container: true,
767
+ item: true,
768
+ xs: 12,
769
+ md: 12,
770
+ spacing: 1,
771
+ marginTop: 0.5,
772
+ marginBottom: 1,
773
+ sx: {
774
+ display: "flex",
775
+ justifyContent: "left",
776
+ alignItems: "center"
777
+ }
778
+ }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
779
+ item: true
780
+ }, /*#__PURE__*/_react.default.createElement(_material.Button, {
781
+ startIcon: /*#__PURE__*/_react.default.createElement(_Add.default, null),
782
+ onClick: () => setDialogOpen(true),
783
+ variant: "contained",
784
+ sx: {
785
+ marginBottom: 2
786
+ }
787
+ }, t("add_phrase"))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
788
+ item: true
789
+ }, /*#__PURE__*/_react.default.createElement("label", {
790
+ htmlFor: "upload-csv"
791
+ }, /*#__PURE__*/_react.default.createElement(_material.Button, {
792
+ variant: "contained",
793
+ component: "span",
794
+ startIcon: /*#__PURE__*/_react.default.createElement(_FileUpload.default, null),
795
+ sx: {
796
+ marginBottom: 2
797
+ }
798
+ }, t("upload_csv"))), /*#__PURE__*/_react.default.createElement("input", {
799
+ id: "upload-csv",
800
+ type: "file",
801
+ accept: ".csv",
802
+ onChange: handleCSVUpload,
803
+ style: {
804
+ display: "none"
805
+ }
333
806
  })), /*#__PURE__*/_react.default.createElement(_material.Grid, {
807
+ item: true
808
+ }, /*#__PURE__*/_react.default.createElement(_material.Button, {
809
+ variant: "outlined",
810
+ startIcon: /*#__PURE__*/_react.default.createElement(_Download.default, null),
811
+ onClick: downloadCSVTemplate,
812
+ sx: {
813
+ marginBottom: 2
814
+ }
815
+ }, t("download_csv_template"))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
816
+ item: true,
817
+ xs: 12,
818
+ sx: {
819
+ justifyContent: "left"
820
+ }
821
+ }, csvData.length === 0 && /*#__PURE__*/_react.default.createElement(_material.Typography, {
822
+ variant: "body1",
823
+ sx: {
824
+ marginTop: 1
825
+ }
826
+ }, t("no_phrases_yet"))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
827
+ container: true,
828
+ item: true,
829
+ xs: 12,
830
+ md: 12,
831
+ spacing: 1,
832
+ marginBottom: 1
833
+ }, csvData.length > 0 && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Grid, {
834
+ item: true,
835
+ xs: 12
836
+ }, /*#__PURE__*/_react.default.createElement(_material.TableContainer, {
837
+ component: _material.Paper
838
+ }, /*#__PURE__*/_react.default.createElement(_material.Table, {
839
+ sx: {
840
+ minWidth: 650
841
+ },
842
+ "aria-label": "csv table"
843
+ }, /*#__PURE__*/_react.default.createElement(_material.TableHead, null, /*#__PURE__*/_react.default.createElement(_material.TableRow, null, csvHeaders.map((header, index) => /*#__PURE__*/_react.default.createElement(_material.TableCell, {
844
+ key: index,
845
+ align: "center"
846
+ }, /*#__PURE__*/_react.default.createElement("strong", null, header))), /*#__PURE__*/_react.default.createElement(_material.TableCell, {
847
+ align: "center"
848
+ }, /*#__PURE__*/_react.default.createElement("strong", null, t("play_audio"))), /*#__PURE__*/_react.default.createElement(_material.TableCell, {
849
+ align: "center"
850
+ }, /*#__PURE__*/_react.default.createElement("strong", null, t("delete")), " "))), /*#__PURE__*/_react.default.createElement(_material.TableBody, null, csvData.map((row, rowIndex) => /*#__PURE__*/_react.default.createElement(_material.TableRow, {
851
+ key: rowIndex
852
+ }, csvHeaders.map((header, colIndex) => /*#__PURE__*/_react.default.createElement(_material.TableCell, {
853
+ key: colIndex,
854
+ align: "center"
855
+ }, row[header] || null)), /*#__PURE__*/_react.default.createElement(_material.TableCell, {
856
+ align: "center"
857
+ }, /*#__PURE__*/_react.default.createElement(_material.IconButton, {
858
+ onClick: () => playPhraseAudio(row.phrase, row.voice),
859
+ "aria-label": "play"
860
+ }, /*#__PURE__*/_react.default.createElement(_PlayArrow.default, null))), /*#__PURE__*/_react.default.createElement(_material.TableCell, {
861
+ align: "center"
862
+ }, /*#__PURE__*/_react.default.createElement(_material.IconButton, {
863
+ onClick: () => handleDeleteRow(rowIndex) // Call the row deletion function
864
+ ,
865
+ "aria-label": "delete"
866
+ }, /*#__PURE__*/_react.default.createElement(_Delete.default, null))))))))))), csvData.length > 0 && /*#__PURE__*/_react.default.createElement(_material.Grid, {
867
+ item: true,
868
+ xs: 12,
869
+ sx: {
870
+ display: "flex",
871
+ justifyContent: "left",
872
+ alignItems: "center",
873
+ marginTop: 1
874
+ }
875
+ }, /*#__PURE__*/_react.default.createElement(_lab.LoadingButton, {
876
+ variant: "contained",
877
+ onClick: generateAudioForCSV,
878
+ loading: isGenerating,
879
+ startIcon: /*#__PURE__*/_react.default.createElement(_Download.default, null),
880
+ sx: {
881
+ marginBottom: 2
882
+ }
883
+ }, t("download_audio")))), /*#__PURE__*/_react.default.createElement(AddPhraseDialog, {
884
+ t: t,
885
+ open: dialogOpen,
886
+ onClose: () => setDialogOpen(false),
887
+ handleAddPhrase: handleAddPhrase,
888
+ initialValues: {
889
+ learnLang: "english",
890
+ actor: {
891
+ voice: "",
892
+ voiceLanguageCode: "",
893
+ voicePitch: "",
894
+ picture: ""
895
+ },
896
+ phraseToSpeak: "",
897
+ voiceSpeed: 50
898
+ },
899
+ languages: languages,
900
+ avatars: avatars,
901
+ handleSpeak: handleSpeak
902
+ })), !showCSV && /*#__PURE__*/_react.default.createElement(_material.Grid, {
334
903
  container: true,
335
904
  item: true,
336
905
  xs: 12,
@@ -34,11 +34,13 @@ const SubmissionsTableCards = (0, _mui.withStyles)(({
34
34
  selectedRecording,
35
35
  setSelectedRecording,
36
36
  saveTranscript = () => {},
37
+ meetingRecsData,
37
38
  t = text => text
38
39
  }) => {
39
40
  const [open, setOpen] = (0, _react.useState)(false);
40
41
  const [feedbackOpen, setFeedbackOpen] = (0, _react.useState)(false);
41
42
  const [cardsToShow, setCardsToShow] = (0, _react.useState)(3);
43
+ const [attendeesData, setAttendeesData] = (0, _react.useState)([]);
42
44
 
43
45
  // const handleRefresh = async () => {
44
46
  // await getRecordings();
@@ -48,26 +50,23 @@ const SubmissionsTableCards = (0, _mui.withStyles)(({
48
50
  setSelectedRecording(recording);
49
51
  setOpen(true);
50
52
  };
51
- const handleFeedbackJoin = recording => {
52
- setSelectedRecording(recording);
53
- setFeedbackOpen(true);
54
- };
55
- const attendeeUsernames = [];
56
- userData.forEach(user => {
57
- [selectedRecording?.attendees].flat().forEach(attendee => {
58
- if (user.memberId === attendee) {
59
- attendeeUsernames.push(user?.username);
60
- }
61
- });
62
- });
63
- const attendeesData = [];
64
- userData.forEach(user => {
65
- [selectedRecording?.attendees].flat().forEach(attendee => {
66
- if (user.memberId === attendee) {
67
- attendeesData.push(user);
68
- }
69
- });
70
- });
53
+ (0, _react.useEffect)(() => {
54
+ if (open && meetingRecsData) {
55
+ const attendees = [selectedRecording?.attendees].flat();
56
+ const newAttendeesData = userData.filter(user => attendees.includes(user.memberId)).map(user => {
57
+ const recordingFeedback = meetingRecsData.find(rec => rec.userId === user.memberId);
58
+ return {
59
+ ...user,
60
+ feedback: recordingFeedback ? {
61
+ ...recordingFeedback,
62
+ userId: undefined
63
+ } : {}
64
+ };
65
+ });
66
+ setAttendeesData(newAttendeesData);
67
+ }
68
+ // eslint-disable-next-line react-hooks/exhaustive-deps
69
+ }, [open, meetingRecsData]);
71
70
  const uniqueMeetingIds = [];
72
71
  const uniqueSubmissions = submissionsTableData.filter(row => {
73
72
  const meetingId = row.meetingId;
@@ -77,6 +76,10 @@ const SubmissionsTableCards = (0, _mui.withStyles)(({
77
76
  }
78
77
  return false;
79
78
  });
79
+ const handleClose = () => {
80
+ setOpen(false);
81
+ setAttendeesData([]);
82
+ };
80
83
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Box, {
81
84
  sx: {
82
85
  marginBottom: 2
@@ -89,19 +92,11 @@ const SubmissionsTableCards = (0, _mui.withStyles)(({
89
92
  className: classes.grow
90
93
  }), loading ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_LoadingCard.default, null), /*#__PURE__*/_react.default.createElement(_LoadingCard.default, null)) : uniqueSubmissions && uniqueSubmissions.length > 0 ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, uniqueSubmissions.slice(0, cardsToShow).map(row => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_SubmissionsCard.default, {
91
94
  t: t,
92
- userData: userData,
93
95
  submissionsTableData: row,
94
96
  handleView: () => handleJoin(row),
95
- handleViewFeedback: () => handleFeedbackJoin(row),
96
- selectedRecording: selectedRecording,
97
- setSelectedRecording: setSelectedRecording,
98
- open: open,
99
- handleClose: () => setOpen(false),
100
- feedbackOpen: feedbackOpen,
101
- feedbackHandleClose: () => setFeedbackOpen(false)
97
+ userData: userData
102
98
  }), /*#__PURE__*/_react.default.createElement(_RecordingDialog.default, {
103
99
  t: t,
104
- attendees: attendeeUsernames,
105
100
  attendeesData: attendeesData,
106
101
  open: open,
107
102
  row: row,
@@ -112,7 +107,7 @@ const SubmissionsTableCards = (0, _mui.withStyles)(({
112
107
  handleGradeConversation: handleGradeConversation,
113
108
  aiGrade: aiGrade,
114
109
  s3EventsUrl: s3EventsUrl,
115
- handleClose: () => setOpen(false),
110
+ handleClose: handleClose,
116
111
  emails: row?.attendees,
117
112
  meetingID: selectedRecording?.meetingId,
118
113
  meetingPrompt: selectedRecording?.meetingPrompt,
@@ -120,10 +115,10 @@ const SubmissionsTableCards = (0, _mui.withStyles)(({
120
115
  isTeacher: true,
121
116
  goToTimestamp: goToTimestamp,
122
117
  conversation: conversation,
123
- handleCreateFeedback: handleCreateFeedback
118
+ handleCreateFeedback: handleCreateFeedback,
119
+ meetingRecsData: meetingRecsData
124
120
  }), /*#__PURE__*/_react.default.createElement(_FeedbackInfoDialog.default, {
125
121
  t: t,
126
- attendees: attendeeUsernames,
127
122
  feedbackOpen: feedbackOpen,
128
123
  handleCreateFeedback: handleCreateFeedback,
129
124
  feedbackHandleClose: () => setFeedbackOpen(false),
@@ -167,6 +162,7 @@ SubmissionsTableCards.propTypes = {
167
162
  })),
168
163
  classes: _propTypes.default.object.isRequired,
169
164
  propsPageChange: _propTypes.default.func,
170
- propsRowChange: _propTypes.default.func
165
+ propsRowChange: _propTypes.default.func,
166
+ attendeesData: _propTypes.default.array
171
167
  };
172
168
  var _default = exports.default = SubmissionsTableCards;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nualang/nualang-ui-components",
3
- "version": "0.1.1172",
3
+ "version": "0.1.1174",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist",
@@ -41,6 +41,7 @@
41
41
  "easymde": "2.18.0",
42
42
  "emoji-mart": "5.5.2",
43
43
  "export-to-csv": "^1.3.0",
44
+ "file-saver": "^2.0.5",
44
45
  "formik": "^2.2.9",
45
46
  "fs": "^0.0.1-security",
46
47
  "immutability-helper": "^3.0",
@@ -48,6 +49,7 @@
48
49
  "json-2-csv": "^5.5.1",
49
50
  "jsonlint": "^1.6.3",
50
51
  "jsonrepair": "^3.6.0",
52
+ "jszip": "^3.10.1",
51
53
  "luxon": "^3.3.0",
52
54
  "moment": "^2.29.4",
53
55
  "n2words": "^1.21.0",