@nualang/nualang-ui-components 0.1.1430 → 0.1.1431
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.
- package/dist/Cards/Bot/Bot.js +2 -12
- package/dist/Cards/Course/Course.js +2 -15
- package/dist/Cards/Roleplay/Roleplay.js +2 -12
- package/dist/Cards/Topic/Topic.js +2 -12
- package/dist/Dialogs/FindChatbotDialog/FindChatbotDialog.js +17 -68
- package/dist/Dialogs/FindCoursesDialog/FindCoursesDialog.js +8 -45
- package/dist/Dialogs/FindScenarioDialog/FindScenarioDialog.js +17 -68
- package/dist/Dialogs/FindTopicsDialog/FindTopicsDialog.js +19 -175
- package/dist/Dialogs/QuickCreateChatbotDialog/QuickCreateChatbotDialog.js +2 -1
- package/dist/Dialogs/SearchFilters/SearchFilters.js +147 -75
- package/dist/Dialogs/SearchFilters/SearchFilters.test.js +65 -0
- package/dist/Forms/Settings/Tabs/General/General.js +2 -1
- package/dist/Forms/UpdateBot/UpdateBot.js +4 -2
- package/dist/Forms/UpdateClassroom/UpdateClassroom.js +8 -4
- package/dist/Forms/UpdateCourse/UpdateCourse.js +6 -3
- package/dist/Forms/UpdateGroup/UpdateGroup.js +4 -2
- package/dist/Forms/UpdatePhraseList/UpdatePhraseList.js +14 -3
- package/dist/Forms/UpdateRoleplay/UpdateRoleplay.js +4 -2
- package/dist/Forms/UpdateTopic/UpdateTopic.js +6 -3
- package/dist/Misc/StickyBar/StickyBar.js +64 -0
- package/dist/Misc/StickyBar/StickyBar.test.js +62 -0
- package/dist/Misc/StickyBar/package.json +6 -0
- package/dist/Navigation/Header/Header.js +1 -0
- package/dist/Navigation/ResponsiveTabs/ResponsiveTabs.js +37 -7
- package/package.json +1 -1
package/dist/Cards/Bot/Bot.js
CHANGED
|
@@ -135,12 +135,7 @@ function Bot({
|
|
|
135
135
|
children: [/*#__PURE__*/_jsx(CardTop, {
|
|
136
136
|
children: /*#__PURE__*/_jsx(Skeleton, {
|
|
137
137
|
variant: "rectangular",
|
|
138
|
-
sx:
|
|
139
|
-
...classes.media,
|
|
140
|
-
...(compact ? {
|
|
141
|
-
paddingTop: "40%"
|
|
142
|
-
} : {})
|
|
143
|
-
}
|
|
138
|
+
sx: classes.media
|
|
144
139
|
})
|
|
145
140
|
}), /*#__PURE__*/_jsx(CardHeader, {
|
|
146
141
|
action: /*#__PURE__*/_jsx(IconButton, {
|
|
@@ -199,12 +194,7 @@ function Bot({
|
|
|
199
194
|
onClick: selectBot,
|
|
200
195
|
role: "link",
|
|
201
196
|
children: [/*#__PURE__*/_jsx(ProgressiveCardMedia, {
|
|
202
|
-
sx:
|
|
203
|
-
...classes.media,
|
|
204
|
-
...(compact ? {
|
|
205
|
-
paddingTop: "40%"
|
|
206
|
-
} : {})
|
|
207
|
-
},
|
|
197
|
+
sx: classes.media,
|
|
208
198
|
highQualitySrc: visible || !pictureXs ? cardPicture || picture || PlaceholderImages.bot : null,
|
|
209
199
|
lowQualitySrc: pictureXs,
|
|
210
200
|
title: botName,
|
|
@@ -297,13 +297,7 @@ CourseDifficulty.propTypes = {
|
|
|
297
297
|
difficulty: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
|
|
298
298
|
compact: PropTypes.bool
|
|
299
299
|
};
|
|
300
|
-
|
|
301
|
-
// Keep compact cards' media at 16:9 even though it makes the card a little
|
|
302
|
-
// taller than the old 40% (2.5:1) crop - matches how the picture actually
|
|
303
|
-
// looks everywhere else it's shown.
|
|
304
|
-
const COMPACT_MEDIA_ASPECT_RATIO = "56.25%";
|
|
305
300
|
function CourseCardMedia({
|
|
306
|
-
compact,
|
|
307
301
|
visible,
|
|
308
302
|
cardPicture,
|
|
309
303
|
picture,
|
|
@@ -311,10 +305,7 @@ function CourseCardMedia({
|
|
|
311
305
|
placeholderRef
|
|
312
306
|
}) {
|
|
313
307
|
return /*#__PURE__*/_jsx(ProgressiveCardMedia, {
|
|
314
|
-
sx:
|
|
315
|
-
...classes.media,
|
|
316
|
-
paddingTop: COMPACT_MEDIA_ASPECT_RATIO
|
|
317
|
-
} : classes.media,
|
|
308
|
+
sx: classes.media,
|
|
318
309
|
highQualitySrc: visible || !pictureXs ? cardPicture || picture || PlaceholderImages.course : null,
|
|
319
310
|
lowQualitySrc: pictureXs,
|
|
320
311
|
placeholderRef: placeholderRef
|
|
@@ -373,10 +364,7 @@ function CompactCourseLoading() {
|
|
|
373
364
|
children: [/*#__PURE__*/_jsx(CardTop, {
|
|
374
365
|
children: /*#__PURE__*/_jsx(Skeleton, {
|
|
375
366
|
variant: "rectangular",
|
|
376
|
-
sx:
|
|
377
|
-
...classes.media,
|
|
378
|
-
paddingTop: COMPACT_MEDIA_ASPECT_RATIO
|
|
379
|
-
}
|
|
367
|
+
sx: classes.media
|
|
380
368
|
})
|
|
381
369
|
}), /*#__PURE__*/_jsx(CardHeader, {
|
|
382
370
|
title: /*#__PURE__*/_jsx(Skeleton, {
|
|
@@ -698,7 +686,6 @@ function CourseCard({
|
|
|
698
686
|
role: "link",
|
|
699
687
|
"aria-label": `${checked ? t("selected") : t("select")} ${courseName}`,
|
|
700
688
|
children: /*#__PURE__*/_jsx(CourseCardMedia, {
|
|
701
|
-
compact: true,
|
|
702
689
|
visible: visible,
|
|
703
690
|
cardPicture: cardPicture,
|
|
704
691
|
picture: picture,
|
|
@@ -135,12 +135,7 @@ function Roleplay({
|
|
|
135
135
|
children: [/*#__PURE__*/_jsx(CardTop, {
|
|
136
136
|
children: /*#__PURE__*/_jsx(Skeleton, {
|
|
137
137
|
variant: "rectangular",
|
|
138
|
-
sx:
|
|
139
|
-
...classes.media,
|
|
140
|
-
...(compact ? {
|
|
141
|
-
paddingTop: "40%"
|
|
142
|
-
} : {})
|
|
143
|
-
}
|
|
138
|
+
sx: classes.media
|
|
144
139
|
})
|
|
145
140
|
}), /*#__PURE__*/_jsx(CardHeader, {
|
|
146
141
|
action: /*#__PURE__*/_jsx(IconButton, {
|
|
@@ -199,12 +194,7 @@ function Roleplay({
|
|
|
199
194
|
role: "link",
|
|
200
195
|
"aria-label": "Card Image",
|
|
201
196
|
children: [/*#__PURE__*/_jsx(ProgressiveCardMedia, {
|
|
202
|
-
sx:
|
|
203
|
-
...classes.media,
|
|
204
|
-
...(compact ? {
|
|
205
|
-
paddingTop: "40%"
|
|
206
|
-
} : {})
|
|
207
|
-
},
|
|
197
|
+
sx: classes.media,
|
|
208
198
|
highQualitySrc: visible || !pictureXs ? cardPicture || picture || PlaceholderImages.roleplay : null,
|
|
209
199
|
lowQualitySrc: pictureXs,
|
|
210
200
|
placeholderRef: placeholderRef,
|
|
@@ -38,12 +38,7 @@ function Topic({
|
|
|
38
38
|
children: [/*#__PURE__*/_jsx(CardTop, {
|
|
39
39
|
children: /*#__PURE__*/_jsx(Skeleton, {
|
|
40
40
|
variant: "rectangular",
|
|
41
|
-
sx:
|
|
42
|
-
...classes.media,
|
|
43
|
-
...(compact ? {
|
|
44
|
-
paddingTop: "40%"
|
|
45
|
-
} : {})
|
|
46
|
-
}
|
|
41
|
+
sx: classes.media
|
|
47
42
|
})
|
|
48
43
|
}), /*#__PURE__*/_jsx(CardHeader, {
|
|
49
44
|
title: /*#__PURE__*/_jsx(Skeleton, {
|
|
@@ -94,12 +89,7 @@ function Topic({
|
|
|
94
89
|
disabled: disableActions,
|
|
95
90
|
role: "link",
|
|
96
91
|
children: /*#__PURE__*/_jsx(ProgressiveCardMedia, {
|
|
97
|
-
sx:
|
|
98
|
-
...classes.media,
|
|
99
|
-
...(compact ? {
|
|
100
|
-
paddingTop: "40%"
|
|
101
|
-
} : {})
|
|
102
|
-
},
|
|
92
|
+
sx: classes.media,
|
|
103
93
|
highQualitySrc: visible || !pictureXs ? cardPicture || picture || PlaceholderImages.topic : null,
|
|
104
94
|
lowQualitySrc: pictureXs,
|
|
105
95
|
title: topicName,
|
|
@@ -16,7 +16,7 @@ import CloseIcon from "@mui/icons-material/Close";
|
|
|
16
16
|
import AddIcon from "@mui/icons-material/Add";
|
|
17
17
|
import Bots from "../../Lists/Bots/Bots";
|
|
18
18
|
import PlaceholderImages from "../../utils/placeholder-images/index";
|
|
19
|
-
import { SearchFilters, Transition } from "../SearchFilters/SearchFilters";
|
|
19
|
+
import { SearchFilters, Transition, applyFilters, useSearchFilters } from "../SearchFilters/SearchFilters";
|
|
20
20
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
21
21
|
export default function FindChatbotDialog({
|
|
22
22
|
open,
|
|
@@ -43,11 +43,11 @@ export default function FindChatbotDialog({
|
|
|
43
43
|
// Restricted users are always kept on the library tab, regardless of state.
|
|
44
44
|
const effectiveTab = isCommunityAccessRestricted ? 0 : tab;
|
|
45
45
|
const [selectedBotIds, setSelectedBotIds] = useState([]);
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
});
|
|
46
|
+
const {
|
|
47
|
+
filters,
|
|
48
|
+
resetFilters,
|
|
49
|
+
filterProps
|
|
50
|
+
} = useSearchFilters();
|
|
51
51
|
const allChatbots = [...libraryChatbots, ...communityChatbots];
|
|
52
52
|
const selectedChatbots = allChatbots.filter(bot => selectedBotIds.includes(bot.botId)).filter((bot, index, arr) => arr.findIndex(b => b.botId === bot.botId) === index).map(bot => ({
|
|
53
53
|
...bot,
|
|
@@ -56,16 +56,6 @@ export default function FindChatbotDialog({
|
|
|
56
56
|
const handleToggle = botId => {
|
|
57
57
|
setSelectedBotIds(prev => prev.includes(botId) ? prev.filter(id => id !== botId) : [...prev, botId]);
|
|
58
58
|
};
|
|
59
|
-
const handleFilterChange = event => {
|
|
60
|
-
const {
|
|
61
|
-
name,
|
|
62
|
-
value
|
|
63
|
-
} = event.target;
|
|
64
|
-
setFilters(prev => ({
|
|
65
|
-
...prev,
|
|
66
|
-
[name]: value
|
|
67
|
-
}));
|
|
68
|
-
};
|
|
69
59
|
const handleAdd = () => {
|
|
70
60
|
onAddChatbots(selectedChatbots);
|
|
71
61
|
reset();
|
|
@@ -73,11 +63,7 @@ export default function FindChatbotDialog({
|
|
|
73
63
|
};
|
|
74
64
|
const reset = () => {
|
|
75
65
|
setSelectedBotIds([]);
|
|
76
|
-
|
|
77
|
-
setFilters({
|
|
78
|
-
difficulty: "all",
|
|
79
|
-
sort: "newest"
|
|
80
|
-
});
|
|
66
|
+
resetFilters();
|
|
81
67
|
setTab(0);
|
|
82
68
|
};
|
|
83
69
|
const handleDialogClose = () => {
|
|
@@ -101,37 +87,14 @@ export default function FindChatbotDialog({
|
|
|
101
87
|
const handleTabChange = (_, v) => {
|
|
102
88
|
if (isCommunityAccessRestricted) return;
|
|
103
89
|
setTab(v);
|
|
104
|
-
|
|
105
|
-
setFilters({
|
|
106
|
-
difficulty: "all",
|
|
107
|
-
sort: "newest"
|
|
108
|
-
});
|
|
90
|
+
resetFilters();
|
|
109
91
|
if (scrollRef.current) scrollRef.current.scrollTop = 0;
|
|
110
92
|
};
|
|
111
|
-
const
|
|
112
|
-
if (!search.trim()) return chatbots;
|
|
113
|
-
const q = search.toLowerCase();
|
|
114
|
-
return chatbots.filter(bot => bot.botName?.toLowerCase().includes(q) || bot.description?.toLowerCase().includes(q) || bot.createdByName?.toLowerCase().includes(q));
|
|
115
|
-
};
|
|
116
|
-
const applyCommunityFilters = chatbots => {
|
|
117
|
-
let result = filterChatbots(chatbots);
|
|
118
|
-
if (filters.difficulty && filters.difficulty !== "all") {
|
|
119
|
-
result = result.filter(bot => bot.difficulty === filters.difficulty);
|
|
120
|
-
}
|
|
121
|
-
if (filters.sort === "newest") {
|
|
122
|
-
result = [...result].sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0));
|
|
123
|
-
} else if (filters.sort === "oldest") {
|
|
124
|
-
result = [...result].sort((a, b) => new Date(a.createdAt || 0) - new Date(b.createdAt || 0));
|
|
125
|
-
} else {
|
|
126
|
-
result = [...result].sort((a, b) => (b.exerciseStartTotal || 0) - (a.exerciseStartTotal || 0));
|
|
127
|
-
}
|
|
128
|
-
return result;
|
|
129
|
-
};
|
|
130
|
-
const currentChatbots = effectiveTab === 0 ? filterChatbots(libraryChatbots) : applyCommunityFilters(communityChatbots);
|
|
93
|
+
const currentChatbots = applyFilters(effectiveTab === 0 ? libraryChatbots : communityChatbots, filters, "botName");
|
|
131
94
|
const isLoading = effectiveTab === 0 ? isLoadingLibrary : isLoadingCommunity;
|
|
132
|
-
const
|
|
95
|
+
const libraryLabel = t("add_own_exercise_message", {
|
|
133
96
|
exerciseName: t("chatbots").toLowerCase()
|
|
134
|
-
})
|
|
97
|
+
});
|
|
135
98
|
const addButtonLabel = selectedBotIds.length > 0 ? `${t("add_chatbots")} (${selectedBotIds.length})` : t("add_chatbots");
|
|
136
99
|
return /*#__PURE__*/_jsxs(Dialog, {
|
|
137
100
|
open: open,
|
|
@@ -190,24 +153,10 @@ export default function FindChatbotDialog({
|
|
|
190
153
|
disabled: isCommunityAccessRestricted
|
|
191
154
|
})]
|
|
192
155
|
})
|
|
193
|
-
}),
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
xs: 0,
|
|
198
|
-
md: 1.5
|
|
199
|
-
},
|
|
200
|
-
borderBottom: 1,
|
|
201
|
-
borderColor: "divider"
|
|
202
|
-
},
|
|
203
|
-
children: /*#__PURE__*/_jsx(SearchFilters, {
|
|
204
|
-
t: t,
|
|
205
|
-
difficulty: filters.difficulty,
|
|
206
|
-
handleFilterChange: handleFilterChange,
|
|
207
|
-
sort: filters.sort,
|
|
208
|
-
search: search,
|
|
209
|
-
setSearch: setSearch
|
|
210
|
-
})
|
|
156
|
+
}), /*#__PURE__*/_jsx(SearchFilters, {
|
|
157
|
+
t: t,
|
|
158
|
+
...filterProps,
|
|
159
|
+
dataCyPrefix: "find-chatbots"
|
|
211
160
|
}), /*#__PURE__*/_jsx(Box, {
|
|
212
161
|
ref: scrollRef,
|
|
213
162
|
sx: {
|
|
@@ -229,13 +178,13 @@ export default function FindChatbotDialog({
|
|
|
229
178
|
children: t("no_chatbots_found") || "No chatbots found"
|
|
230
179
|
})
|
|
231
180
|
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
232
|
-
children: [/*#__PURE__*/_jsx(Typography, {
|
|
181
|
+
children: [effectiveTab === 0 && /*#__PURE__*/_jsx(Typography, {
|
|
233
182
|
color: "text.secondary",
|
|
234
183
|
sx: {
|
|
235
184
|
display: "block",
|
|
236
185
|
mb: 2
|
|
237
186
|
},
|
|
238
|
-
children:
|
|
187
|
+
children: libraryLabel
|
|
239
188
|
}), /*#__PURE__*/_jsx(Bots, {
|
|
240
189
|
t: t,
|
|
241
190
|
bots: currentChatbots,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useEffect, useMemo, useRef
|
|
1
|
+
import { useState, useEffect, useMemo, useRef } from "react";
|
|
2
2
|
import { useInView } from "react-intersection-observer";
|
|
3
3
|
import { courses as courseQuerys, ReactQuery } from "@nualang/nualang-api-and-queries/Queries";
|
|
4
4
|
import { getCourses } from "@nualang/nualang-api-and-queries/APIs/Courses";
|
|
@@ -7,7 +7,6 @@ import AppBar from "@mui/material/AppBar";
|
|
|
7
7
|
import Toolbar from "@mui/material/Toolbar";
|
|
8
8
|
import IconButton from "@mui/material/IconButton";
|
|
9
9
|
import Typography from "@mui/material/Typography";
|
|
10
|
-
import Slide from "@mui/material/Slide";
|
|
11
10
|
import Box from "@mui/material/Box";
|
|
12
11
|
import Tabs from "@mui/material/Tabs";
|
|
13
12
|
import Tab from "@mui/material/Tab";
|
|
@@ -26,6 +25,7 @@ import SortBySelector from "../../Forms/SortBySelector/SortBySelector";
|
|
|
26
25
|
import useDebounce from "../../hooks/useDebounce";
|
|
27
26
|
import useHorizontalScroll from "../../hooks/useHorizontalScroll";
|
|
28
27
|
import PlaceholderImages from "../../utils/placeholder-images/index";
|
|
28
|
+
import { DIFFICULTIES, SORT_BY_OPTIONS, Transition, sortItems } from "../SearchFilters/SearchFilters";
|
|
29
29
|
|
|
30
30
|
// The Community tab wraps into a grid, same as Topics.jsx's compact cards in
|
|
31
31
|
// FindTopicsDialog. My library keeps horizontal scrolling rows (below) so
|
|
@@ -46,29 +46,14 @@ const courseGridSx = {
|
|
|
46
46
|
const {
|
|
47
47
|
useInfiniteQuery
|
|
48
48
|
} = ReactQuery;
|
|
49
|
-
|
|
50
|
-
// Same CEFR codes FindTopicsDialog's community difficulty filter uses.
|
|
51
|
-
const DIFFICULTIES = ["A1", "A2", "B1", "B2", "C1", "C2"];
|
|
52
49
|
const LIBRARY_PAGE_SIZE = 12;
|
|
53
50
|
const nextLibraryPageParam = lastPage => lastPage.LastEvaluatedKey?.page || lastPage.LastEvaluatedKey?.courseId ? lastPage.LastEvaluatedKey : undefined;
|
|
54
|
-
const SORT_BY_OPTIONS = {
|
|
55
|
-
popular: "popular",
|
|
56
|
-
newest: "newest",
|
|
57
|
-
oldest: "oldest"
|
|
58
|
-
};
|
|
59
51
|
const DEFAULT_FILTERS = {
|
|
60
52
|
learnLang: "all",
|
|
61
53
|
forLang: "all",
|
|
62
54
|
difficulty: "all",
|
|
63
55
|
sort: "popular"
|
|
64
56
|
};
|
|
65
|
-
const Transition = /*#__PURE__*/forwardRef(function Transition(props, ref) {
|
|
66
|
-
return /*#__PURE__*/_jsx(Slide, {
|
|
67
|
-
direction: "up",
|
|
68
|
-
ref: ref,
|
|
69
|
-
...props
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
57
|
function CourseFilters({
|
|
73
58
|
t,
|
|
74
59
|
search,
|
|
@@ -202,7 +187,7 @@ function CourseFilters({
|
|
|
202
187
|
children: t("all") || "All"
|
|
203
188
|
}), DIFFICULTIES.map(d => /*#__PURE__*/_jsx(MenuItem, {
|
|
204
189
|
value: d,
|
|
205
|
-
children: d
|
|
190
|
+
children: t(d) || d
|
|
206
191
|
}, d))]
|
|
207
192
|
}), /*#__PURE__*/_jsx(SortBySelector, {
|
|
208
193
|
id: "course-sort",
|
|
@@ -560,15 +545,7 @@ export default function FindCoursesDialog({
|
|
|
560
545
|
}
|
|
561
546
|
return true;
|
|
562
547
|
});
|
|
563
|
-
|
|
564
|
-
if (filters.sort === "newest") {
|
|
565
|
-
sorted.sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0));
|
|
566
|
-
} else if (filters.sort === "oldest") {
|
|
567
|
-
sorted.sort((a, b) => new Date(a.createdAt || 0) - new Date(b.createdAt || 0));
|
|
568
|
-
} else {
|
|
569
|
-
sorted.sort((a, b) => (b.exerciseStartTotal || 0) - (a.exerciseStartTotal || 0));
|
|
570
|
-
}
|
|
571
|
-
return sorted;
|
|
548
|
+
return sortItems(filtered, filters.sort);
|
|
572
549
|
}, [learnCoursesQuery.data, groupCoursesQuery.data, groupCoursesQuery.isSuccess, filters.learnLang, filters.forLang, filters.difficulty, search, filters.sort]);
|
|
573
550
|
const libraryCreatedCourses = useMemo(() => (teachCoursesQuery.data?.pages || []).flatMap(page => page.Items || []), [teachCoursesQuery.data]);
|
|
574
551
|
const communityCoursesQuery = courseQuerys.useCommunityCourses(async queryFilters => {
|
|
@@ -807,18 +784,11 @@ export default function FindCoursesDialog({
|
|
|
807
784
|
isLoadingMore: learnCoursesQuery.isFetchingNextPage,
|
|
808
785
|
resetKey: librarySortResetKey
|
|
809
786
|
})]
|
|
810
|
-
}) : isLoadingCommunity ? /*#__PURE__*/
|
|
787
|
+
}) : isLoadingCommunity ? /*#__PURE__*/_jsx(Box, {
|
|
811
788
|
sx: {
|
|
812
789
|
p: 3
|
|
813
790
|
},
|
|
814
|
-
children:
|
|
815
|
-
variant: "text",
|
|
816
|
-
width: 220,
|
|
817
|
-
height: 28,
|
|
818
|
-
sx: {
|
|
819
|
-
mb: 2
|
|
820
|
-
}
|
|
821
|
-
}), /*#__PURE__*/_jsx(Box, {
|
|
791
|
+
children: /*#__PURE__*/_jsx(Box, {
|
|
822
792
|
sx: courseGridSx,
|
|
823
793
|
children: Array.from({
|
|
824
794
|
length: 10
|
|
@@ -826,7 +796,7 @@ export default function FindCoursesDialog({
|
|
|
826
796
|
t: t,
|
|
827
797
|
compact: true
|
|
828
798
|
}, i))
|
|
829
|
-
})
|
|
799
|
+
})
|
|
830
800
|
}) : isCommunityEmpty ? /*#__PURE__*/_jsx(Box, {
|
|
831
801
|
display: "flex",
|
|
832
802
|
justifyContent: "center",
|
|
@@ -839,14 +809,7 @@ export default function FindCoursesDialog({
|
|
|
839
809
|
sx: {
|
|
840
810
|
p: 3
|
|
841
811
|
},
|
|
842
|
-
children: [/*#__PURE__*/_jsx(Typography, {
|
|
843
|
-
variant: "body2",
|
|
844
|
-
color: "text.secondary",
|
|
845
|
-
sx: {
|
|
846
|
-
mb: 2
|
|
847
|
-
},
|
|
848
|
-
children: t("courses_shared_by_other_teachers") || "Courses shared by other teachers"
|
|
849
|
-
}), communityCourses.length === 0 ? /*#__PURE__*/_jsx(Typography, {
|
|
812
|
+
children: [communityCourses.length === 0 ? /*#__PURE__*/_jsx(Typography, {
|
|
850
813
|
variant: "body2",
|
|
851
814
|
color: "text.secondary",
|
|
852
815
|
children: t("no_community_courses_match") || "No courses match these filters"
|
|
@@ -4,7 +4,7 @@ import { Dialog, AppBar, Toolbar, IconButton, Typography, Box, Tabs, Tab, Avatar
|
|
|
4
4
|
import { Close as CloseIcon, Add as AddIcon } from "@mui/icons-material";
|
|
5
5
|
import Roleplays from "../../Lists/Roleplays/Roleplays";
|
|
6
6
|
import PlaceholderImages from "../../utils/placeholder-images/index";
|
|
7
|
-
import { SearchFilters, Transition } from "../SearchFilters/SearchFilters";
|
|
7
|
+
import { SearchFilters, Transition, applyFilters, useSearchFilters } from "../SearchFilters/SearchFilters";
|
|
8
8
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
9
9
|
export default function FindScenarioDialog({
|
|
10
10
|
open,
|
|
@@ -31,11 +31,11 @@ export default function FindScenarioDialog({
|
|
|
31
31
|
// Restricted users are always kept on the library tab, regardless of state.
|
|
32
32
|
const effectiveTab = isCommunityAccessRestricted ? 0 : tab;
|
|
33
33
|
const [selectedRoleplayIds, setSelectedRoleplayIds] = useState([]);
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
34
|
+
const {
|
|
35
|
+
filters,
|
|
36
|
+
resetFilters,
|
|
37
|
+
filterProps
|
|
38
|
+
} = useSearchFilters();
|
|
39
39
|
const allScenarios = [...libraryScenarios, ...communityScenarios];
|
|
40
40
|
const selectedScenarios = allScenarios.filter(roleplay => selectedRoleplayIds.includes(roleplay.roleplayId)).filter((roleplay, index, arr) => arr.findIndex(r => r.roleplayId === roleplay.roleplayId) === index).map(roleplay => ({
|
|
41
41
|
...roleplay,
|
|
@@ -44,16 +44,6 @@ export default function FindScenarioDialog({
|
|
|
44
44
|
const handleToggle = roleplayId => {
|
|
45
45
|
setSelectedRoleplayIds(prev => prev.includes(roleplayId) ? prev.filter(id => id !== roleplayId) : [...prev, roleplayId]);
|
|
46
46
|
};
|
|
47
|
-
const handleFilterChange = event => {
|
|
48
|
-
const {
|
|
49
|
-
name,
|
|
50
|
-
value
|
|
51
|
-
} = event.target;
|
|
52
|
-
setFilters(prev => ({
|
|
53
|
-
...prev,
|
|
54
|
-
[name]: value
|
|
55
|
-
}));
|
|
56
|
-
};
|
|
57
47
|
const handleAdd = () => {
|
|
58
48
|
onAddScenarios(selectedScenarios);
|
|
59
49
|
reset();
|
|
@@ -61,11 +51,7 @@ export default function FindScenarioDialog({
|
|
|
61
51
|
};
|
|
62
52
|
const reset = () => {
|
|
63
53
|
setSelectedRoleplayIds([]);
|
|
64
|
-
|
|
65
|
-
setFilters({
|
|
66
|
-
difficulty: "all",
|
|
67
|
-
sort: "newest"
|
|
68
|
-
});
|
|
54
|
+
resetFilters();
|
|
69
55
|
setTab(0);
|
|
70
56
|
};
|
|
71
57
|
const handleDialogClose = () => {
|
|
@@ -89,37 +75,14 @@ export default function FindScenarioDialog({
|
|
|
89
75
|
const handleTabChange = (_, v) => {
|
|
90
76
|
if (isCommunityAccessRestricted) return;
|
|
91
77
|
setTab(v);
|
|
92
|
-
|
|
93
|
-
setFilters({
|
|
94
|
-
difficulty: "all",
|
|
95
|
-
sort: "newest"
|
|
96
|
-
});
|
|
78
|
+
resetFilters();
|
|
97
79
|
if (scrollRef.current) scrollRef.current.scrollTop = 0;
|
|
98
80
|
};
|
|
99
|
-
const
|
|
100
|
-
if (!search.trim()) return scenarios;
|
|
101
|
-
const q = search.toLowerCase();
|
|
102
|
-
return scenarios.filter(roleplay => roleplay.roleplayName?.toLowerCase().includes(q) || roleplay.description?.toLowerCase().includes(q) || roleplay.createdByName?.toLowerCase().includes(q));
|
|
103
|
-
};
|
|
104
|
-
const applyCommunityFilters = scenarios => {
|
|
105
|
-
let result = filterScenarios(scenarios);
|
|
106
|
-
if (filters.difficulty && filters.difficulty !== "all") {
|
|
107
|
-
result = result.filter(roleplay => roleplay.difficulty === filters.difficulty);
|
|
108
|
-
}
|
|
109
|
-
if (filters.sort === "newest") {
|
|
110
|
-
result = [...result].sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0));
|
|
111
|
-
} else if (filters.sort === "oldest") {
|
|
112
|
-
result = [...result].sort((a, b) => new Date(a.createdAt || 0) - new Date(b.createdAt || 0));
|
|
113
|
-
} else {
|
|
114
|
-
result = [...result].sort((a, b) => (b.exerciseStartTotal || 0) - (a.exerciseStartTotal || 0));
|
|
115
|
-
}
|
|
116
|
-
return result;
|
|
117
|
-
};
|
|
118
|
-
const currentScenarios = effectiveTab === 0 ? filterScenarios(libraryScenarios) : applyCommunityFilters(communityScenarios);
|
|
81
|
+
const currentScenarios = applyFilters(effectiveTab === 0 ? libraryScenarios : communityScenarios, filters, "roleplayName");
|
|
119
82
|
const isLoading = effectiveTab === 0 ? isLoadingLibrary : isLoadingCommunity;
|
|
120
|
-
const
|
|
83
|
+
const libraryLabel = t("add_own_exercise_message", {
|
|
121
84
|
exerciseName: t("scenarios").toLowerCase()
|
|
122
|
-
})
|
|
85
|
+
});
|
|
123
86
|
const addButtonLabel = selectedRoleplayIds.length > 0 ? `${t("add_scenarios")} (${selectedRoleplayIds.length})` : t("add_scenarios");
|
|
124
87
|
return /*#__PURE__*/_jsxs(Dialog, {
|
|
125
88
|
open: open,
|
|
@@ -178,24 +141,10 @@ export default function FindScenarioDialog({
|
|
|
178
141
|
disabled: isCommunityAccessRestricted
|
|
179
142
|
})]
|
|
180
143
|
})
|
|
181
|
-
}),
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
xs: 0,
|
|
186
|
-
md: 1.5
|
|
187
|
-
},
|
|
188
|
-
borderBottom: 1,
|
|
189
|
-
borderColor: "divider"
|
|
190
|
-
},
|
|
191
|
-
children: /*#__PURE__*/_jsx(SearchFilters, {
|
|
192
|
-
t: t,
|
|
193
|
-
difficulty: filters.difficulty,
|
|
194
|
-
handleFilterChange: handleFilterChange,
|
|
195
|
-
sort: filters.sort,
|
|
196
|
-
search: search,
|
|
197
|
-
setSearch: setSearch
|
|
198
|
-
})
|
|
144
|
+
}), /*#__PURE__*/_jsx(SearchFilters, {
|
|
145
|
+
t: t,
|
|
146
|
+
...filterProps,
|
|
147
|
+
dataCyPrefix: "find-scenarios"
|
|
199
148
|
}), /*#__PURE__*/_jsx(Box, {
|
|
200
149
|
ref: scrollRef,
|
|
201
150
|
sx: {
|
|
@@ -217,13 +166,13 @@ export default function FindScenarioDialog({
|
|
|
217
166
|
children: t("no_scenarios_found") || "No scenarios found"
|
|
218
167
|
})
|
|
219
168
|
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
220
|
-
children: [/*#__PURE__*/_jsx(Typography, {
|
|
169
|
+
children: [effectiveTab === 0 && /*#__PURE__*/_jsx(Typography, {
|
|
221
170
|
color: "text.secondary",
|
|
222
171
|
sx: {
|
|
223
172
|
display: "block",
|
|
224
173
|
mb: 2
|
|
225
174
|
},
|
|
226
|
-
children:
|
|
175
|
+
children: libraryLabel
|
|
227
176
|
}), /*#__PURE__*/_jsx(Roleplays, {
|
|
228
177
|
t: t,
|
|
229
178
|
roleplays: currentScenarios,
|