@nualang/nualang-ui-components 0.1.1386 → 0.1.1387

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.
@@ -296,6 +296,7 @@ function PhrasesEditor(props) {
296
296
  type: "include",
297
297
  ids: new Set()
298
298
  });
299
+ const selectedRows = Array.from(selectionModel.ids);
299
300
  const [spreadsheetPhrases, setSpreadsheetPhrases] = useState(Object.keys(phrases).length > 0 ? phrases : [rowTemplate]);
300
301
  const isRowEmpty = row => {
301
302
  let rowEmpty = true;
@@ -366,8 +367,6 @@ function PhrasesEditor(props) {
366
367
  addRow,
367
368
  isDirty,
368
369
  hasTrailingEmptyRow,
369
- selectedRow,
370
- deleteSelectedRow,
371
370
  processRowUpdate
372
371
  } = useSpreadsheetState({
373
372
  rowTemplate,
@@ -439,6 +438,15 @@ function PhrasesEditor(props) {
439
438
  console.error(error);
440
439
  }
441
440
  };
441
+ const deleteSelectedRows = () => {
442
+ if (selectedRows.length === 0) return;
443
+ const updatedRows = rows.filter(r => !selectionModel.ids.has(r.id));
444
+ handleSpreadsheetSaveChanges(phrases, formatRowsToPhrases(updatedRows));
445
+ setSelectionModel({
446
+ type: "include",
447
+ ids: new Set()
448
+ });
449
+ };
442
450
  return /*#__PURE__*/_jsxs(Box, {
443
451
  className: classes.centeredContainer,
444
452
  children: [isCreator && mode === Modes.SPREADSHEET && /*#__PURE__*/_jsx(Box, {
@@ -449,9 +457,9 @@ function PhrasesEditor(props) {
449
457
  children: /*#__PURE__*/_jsx(DefaultButton, {
450
458
  variant: "contained",
451
459
  size: "small",
452
- onClick: deleteSelectedRow,
460
+ onClick: deleteSelectedRows,
453
461
  endIcon: /*#__PURE__*/_jsx(DeleteIcon, {}),
454
- disabled: !Number.isInteger(selectedRow),
462
+ disabled: selectedRows.length === 0,
455
463
  children: t("delete_selected_row")
456
464
  })
457
465
  }), isMember && !isCreator && /*#__PURE__*/_jsx(NormalModeComponent, {
@@ -521,7 +529,9 @@ function PhrasesEditor(props) {
521
529
  isDirty: isDirty,
522
530
  hasTrailingEmptyRow: hasTrailingEmptyRow,
523
531
  hasNonEmptyRows: hasNonEmptyRows,
524
- processRowUpdate: processRowUpdate
532
+ processRowUpdate: processRowUpdate,
533
+ selectionModel: selectionModel,
534
+ onRowSelectionModelChange: setSelectionModel
525
535
  }) : /*#__PURE__*/_jsx(EmptyPhraseList, {
526
536
  t: t,
527
537
  siteLanguage: siteLanguage,
@@ -4,7 +4,7 @@ import * as Yup from "yup";
4
4
  import Tooltip from "@mui/material/Tooltip";
5
5
  import ChipInput from "../../../../Forms/ChipInput/ChipInput";
6
6
  import { domainPattern } from "../../../../utils/index";
7
- import { containsInvalidSymbols } from "../../../../utils/index";
7
+ import { containsInvalidSymbols, containsInvalidCollaboratorSymbols } from "../../../../utils/index";
8
8
  import HelpIcon from "@mui/icons-material/Help";
9
9
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
10
10
  function ClassroomSettings({
@@ -396,6 +396,6 @@ ClassroomSettings.validationSchema = Yup.object().shape({
396
396
  otherwise: () => Yup.string().nullable()
397
397
  }),
398
398
  allowedDomains: Yup.array(Yup.string().test("noSpecialChars", "no_special_characters", value => !containsInvalidSymbols(value)).matches(domainPattern, "Must be a valid domain e.g 'schooldomain.com'")).nullable(),
399
- collaborators: Yup.array(Yup.string().test("noSpecialChars", "no_special_characters", value => !containsInvalidSymbols(value))).nullable()
399
+ collaborators: Yup.array(Yup.string().test("noSpecialChars", "no_special_characters", value => !containsInvalidCollaboratorSymbols(value))).nullable()
400
400
  });
401
401
  export default ClassroomSettings;
@@ -4,7 +4,7 @@ import * as Yup from "yup";
4
4
  import Tooltip from "@mui/material/Tooltip";
5
5
  import ChipInput from "../../../../Forms/ChipInput/ChipInput";
6
6
  import { domainPattern } from "../../../../utils/index";
7
- import { containsInvalidSymbols } from "../../../../utils/index";
7
+ import { containsInvalidSymbols, containsInvalidCollaboratorSymbols } from "../../../../utils/index";
8
8
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
9
9
  function CourseSettings({
10
10
  t,
@@ -250,7 +250,7 @@ CourseSettings.validationSchema = Yup.object().shape({
250
250
  otherwise: () => Yup.string().nullable()
251
251
  }),
252
252
  allowedDomains: Yup.array(Yup.string().test("noSpecialChars", "no_special_characters", value => !containsInvalidSymbols(value)).matches(domainPattern, "Must be a valid domain e.g 'schooldomain.com'")).nullable(),
253
- collaborators: Yup.array(Yup.string().test("noSpecialChars", "no_special_characters", value => !containsInvalidSymbols(value))).nullable(),
253
+ collaborators: Yup.array(Yup.string().test("noSpecialChars", "no_special_characters", value => !containsInvalidCollaboratorSymbols(value))).nullable(),
254
254
  isShareable: Yup.string().required("required"),
255
255
  duplicated: Yup.bool()
256
256
  });
@@ -1,4 +1,4 @@
1
- import { useState, useEffect } from "react";
1
+ import { useState, useEffect, useRef } from "react";
2
2
  import { Drawer, List, ListSubheader, ListItemText, ListItemButton, ListItemIcon, IconButton, Tooltip } from "@mui/material";
3
3
  import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
4
4
  import { useTheme } from "@mui/material/styles";
@@ -25,10 +25,15 @@ function StudentAnswerDrawer({
25
25
  const theme = useTheme();
26
26
  const [selectedIndex, setSelectedIndex] = useState();
27
27
  const isSmallScreen = useMediaQuery("(max-width:959px)");
28
+ const committedAnswerRef = useRef(null);
29
+ const handleContinueRef = useRef(handleContinue);
30
+ useEffect(() => {
31
+ handleContinueRef.current = handleContinue;
32
+ });
28
33
  useEffect(() => {
29
34
  if (isTimeUp) {
30
35
  setIsAnswered(true);
31
- handleContinue();
36
+ handleContinueRef.current(committedAnswerRef.current);
32
37
  }
33
38
  }, [isTimeUp]);
34
39
  useEffect(() => {
@@ -41,6 +46,7 @@ function StudentAnswerDrawer({
41
46
  setSelectedIndex(i);
42
47
  setCurrentAnswer(value);
43
48
  setIsAnswered(true);
49
+ committedAnswerRef.current = value;
44
50
  }
45
51
  };
46
52
  const listItemIconStyle = {
@@ -1,4 +1,4 @@
1
- import { useEffect } from "react";
1
+ import { useEffect, useRef } from "react";
2
2
  import Button from "@mui/material/Button";
3
3
  import Grid from "@mui/material/Grid";
4
4
  import { makeStyles } from "tss-react/mui";
@@ -33,9 +33,13 @@ function ExerciseBottomBar({
33
33
  const {
34
34
  classes
35
35
  } = useStyles();
36
+ const handleSubmitRef = useRef(handleSubmit);
37
+ useEffect(() => {
38
+ handleSubmitRef.current = handleSubmit;
39
+ });
36
40
  useEffect(() => {
37
41
  if (isTimeUp) {
38
- handleSubmit();
42
+ handleSubmitRef.current();
39
43
  setIsAnswered(true);
40
44
  }
41
45
  }, [isTimeUp]);
@@ -120,7 +120,8 @@ function OverflowMenu({
120
120
  handleUploadVideo,
121
121
  isTeacher,
122
122
  video,
123
- setVideo
123
+ setVideo,
124
+ handleCloseMenu
124
125
  }) {
125
126
  const [isShareDrawerOpen, setIsShareDrawerOpen] = useState(false);
126
127
  const [isUploadVideoOpen, setIsUploadVideoOpen] = useState(false);
@@ -245,7 +246,10 @@ function OverflowMenu({
245
246
  title: courseName,
246
247
  url: window.location.href,
247
248
  open: isShareDrawerOpen,
248
- handleClose: () => setIsShareDrawerOpen(false),
249
+ handleClose: () => {
250
+ setIsShareDrawerOpen(false);
251
+ handleCloseMenu();
252
+ },
249
253
  subscription: subscription,
250
254
  trackRecommendedEvent: trackRecommendedEvent,
251
255
  itemId: courseId,
@@ -933,7 +937,8 @@ function Course({
933
937
  handleUploadVideo: handleUploadVideo,
934
938
  isTeacher: !isStudent,
935
939
  video: video,
936
- setVideo: setVideo
940
+ setVideo: setVideo,
941
+ handleCloseMenu: handleCloseMenu
937
942
  }), /*#__PURE__*/_jsx(UpgradeSubscription, {
938
943
  t: t,
939
944
  open: isUpgradeSubscriptionOpen,
@@ -24,6 +24,16 @@ export const containsInvalidSymbols = input => {
24
24
  }
25
25
  return false;
26
26
  };
27
+
28
+ // Same as containsInvalidSymbols but allows underscores
29
+ export const containsInvalidCollaboratorSymbols = input => {
30
+ const invalidChars = /[`#^*\[\];\\|<>\/~]/; // !()@,.'$%&+={}?:"_ allowed
31
+
32
+ if (invalidChars.test(input)) {
33
+ return true;
34
+ }
35
+ return false;
36
+ };
27
37
  export const removeExtraWhiteSpaces = (str = "") => str.replace(/\s+/g, " ").trim();
28
38
  export const removeAllSymbols = (str = "") => {
29
39
  const removedEmojis = removeEmojis(str);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nualang/nualang-ui-components",
3
- "version": "0.1.1386",
3
+ "version": "0.1.1387",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -101,7 +101,7 @@
101
101
  "@mui/system": "^7.0.2",
102
102
  "@mui/x-date-pickers": "^8.27.2",
103
103
  "@nualang/eslint-config-nualang": "0.2.0-alpha-5",
104
- "@nualang/nualang-api-and-queries": "^1.1.42",
104
+ "@nualang/nualang-api-and-queries": "^1.1.50",
105
105
  "@react-theming/storybook-addon": "^1.1.10",
106
106
  "@storybook/addon-docs": "^10.0.2",
107
107
  "@storybook/addon-links": "^10.0.2",