Skip to content

Commit 1ae9064

Browse files
Merge pull request #4528 from OneCommunityGlobal/aswin-fix-expand-all
Sireesha taking over Aswin - Fix Expand/Collapse All functionality
2 parents d570bc8 + 7cfed3a commit 1ae9064

3 files changed

Lines changed: 129 additions & 108 deletions

File tree

src/actions/bmdashboard/lessonsAction.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,20 @@ export const setLessons = payload => {
4545
};
4646
};
4747

48+
// A valid MongoDB ObjectId is a 24-character hex string. Lesson author/project
49+
// fields sometimes hold display names (e.g. "James", "project 1") instead of
50+
// real references; skip those so we don't fire doomed 404/500/400 requests.
51+
const isObjectId = id => typeof id === 'string' && /^[0-9a-fA-F]{24}$/.test(id);
52+
4853
export const fetchBMLessons = () => {
4954
return async dispatch => {
5055
try {
5156
const response = await axios.get(ENDPOINTS.BM_LESSONS);
5257
const lessons = response.data;
53-
const authorIds = [...new Set(lessons.map(lesson => lesson.author))];
54-
const projectIds = [...new Set(lessons.map(lesson => lesson.relatedProject))];
58+
const authorIds = [...new Set(lessons.map(lesson => lesson.author).filter(isObjectId))];
59+
const projectIds = [
60+
...new Set(lessons.map(lesson => lesson.relatedProject).filter(isObjectId)),
61+
];
5562

5663
// Keep the more robust approach from honglin-lesson-list-buttons branch
5764
const [authorProfiles, projectDetails] = await Promise.all([
@@ -129,10 +136,11 @@ export const fetchSingleBMLesson = lessonId => {
129136
const response = await axios.get(url);
130137
const lesson = response.data;
131138

132-
// Fetch user profile and project details concurrently
139+
// Fetch user profile and project details concurrently, but only when the
140+
// stored values are real ObjectIds (not display names like "project 1").
133141
const [projectDetails, userProfile] = await Promise.all([
134-
dispatch(fetchProjectById(lesson.relatedProject)),
135-
dispatch(getUserProfile(lesson.author)),
142+
isObjectId(lesson.relatedProject) ? dispatch(fetchProjectById(lesson.relatedProject)) : null,
143+
isObjectId(lesson.author) ? dispatch(getUserProfile(lesson.author)) : null,
136144
]);
137145

138146
// Update the lesson with author and project details

src/components/BMDashboard/LessonList/LessonCard.jsx

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ function LessonCard({ filteredLessons, onEditLessonSummary, onDeliteLessonCard,
1313
const darkMode = useSelector(state => state.theme.darkMode);
1414
const maxSummaryLength = 1500;
1515
const [expandedCards, setExpandedCards] = useState([]);
16-
const auth = useSelector(state => state.auth);
17-
const currentUserId = auth.user.userid;
1816
const [editableLessonId, setEditableLessonId] = useState(null);
1917
const [editableLessonSummary, setEditableLessonSummary] = useState('');
2018
const [validationError, setValidationError] = useState('');
2119
const [showDeletePopup, setShowDeletePopup] = useState(false);
2220
const [lessonToDeleteId, setLessonToDeleteId] = useState(null);
21+
22+
const auth = useSelector(state => state.auth);
23+
const currentUserId = auth.user.userid;
2324
const lessons = useSelector(state => state.lessons.lessons);
2425

2526
const getLikeStatus = lessonId => {
@@ -52,22 +53,19 @@ function LessonCard({ filteredLessons, onEditLessonSummary, onDeliteLessonCard,
5253
};
5354

5455
const toggleCardExpansion = lessonId => {
55-
setExpandedCards(prevExpandedCards => {
56-
if (prevExpandedCards.includes(lessonId)) {
57-
// Collapse the clicked card
58-
return prevExpandedCards.filter(id => id !== lessonId);
59-
}
60-
// Expand the clicked card
61-
return [...prevExpandedCards, lessonId];
62-
});
56+
setExpandedCards(prev =>
57+
prev.includes(lessonId) ? prev.filter(id => id !== lessonId) : [...prev, lessonId],
58+
);
6359
};
60+
6461
const expandAll = () => {
6562
setExpandedCards(filteredLessons.map(lesson => lesson._id));
6663
};
6764

6865
const collapseAll = () => {
6966
setExpandedCards([]);
7067
};
68+
7169
const handleDeletePopup = lessonId => {
7270
setShowDeletePopup(!showDeletePopup);
7371
setLessonToDeleteId(lessonId);
@@ -79,58 +77,57 @@ function LessonCard({ filteredLessons, onEditLessonSummary, onDeliteLessonCard,
7977

8078
const lessonCards = (filteredLessons || []).map(lesson => {
8179
const { isLiked, totalLikes } = getLikeStatus(lesson._id);
80+
8281
return (
83-
<Card
84-
key={`${lesson._id} + ${lesson.title} `}
85-
className={`${styles.lessonCard} ${darkMode ? styles.darkCard : ''}`}
86-
>
82+
<Card key={lesson._id} className={styles.lessonCard}>
8783
<Card.Header
8884
onClick={() => toggleCardExpansion(lesson._id)}
8985
style={{ cursor: 'pointer' }}
90-
className={`${styles.lessonCardHeader}`}
86+
className={styles.lessonCardHeader}
9187
>
92-
<Nav className={`${styles.lessonCardNav}`}>
93-
<div className={`${styles.navTitleAndDate}`}>
88+
<Nav className={styles.lessonCardNav}>
89+
<div className={styles.navTitleAndDate}>
9490
<Nav.Item className={`${styles.lessonCardNavItem} ${styles.navItemTitle}`}>
9591
{lesson.title}
9692
</Nav.Item>
9793
<Nav.Item className={`${styles.lessonCardNavItem} nav-item-date`}>
9894
Date: {formatDateAndTime(lesson.date)}
9995
</Nav.Item>
10096
</div>
97+
10198
<div>
102-
<Nav.Item className={`${styles.lessonCardTag}`}>
103-
{lesson.tags &&
104-
lesson.tags.length > 0 &&
105-
lesson.tags.map((tag, index) => (
99+
<Nav.Item className={styles.lessonCardTag}>
100+
{lesson.tags?.length > 0 &&
101+
lesson.tags.map(tag => (
106102
<span
107-
key={`tag-in-header-${tag}-${lesson._id}-${index}`}
103+
key={`tag-in-header-${tag}-${lesson._id}`}
108104
className={`text-muted ${styles.tagItem}`}
109105
>
110-
{`#${tag}`}
106+
#{tag}
111107
</span>
112108
))}
113109
</Nav.Item>
114110
</div>
115111
</Nav>
116112
</Card.Header>
113+
117114
{expandedCards.includes(lesson._id) && (
118115
<>
119-
<Card.Body className={`${styles.scrollableCardBody}`}>
120-
<Card.Text className={`${styles.cardTagAndFile}`}>
116+
<Card.Body className={styles.scrollableCardBody}>
117+
<Card.Text className={styles.cardTagAndFile}>
121118
Tags:{' '}
122-
{lesson.tags &&
123-
lesson.tags.length > 0 &&
124-
lesson.tags.map((tag, index) => (
119+
{lesson.tags?.length > 0 &&
120+
lesson.tags.map(tag => (
125121
<span
126-
key={`tag-in-body-${tag}-${lesson._id}-${index}`}
122+
key={`tag-in-body-${tag}-${lesson._id}`}
127123
className={`text-muted ${styles.tagItem}`}
128124
>
129-
{`#${tag}`}
125+
#{tag}
130126
</span>
131127
))}
132128
</Card.Text>
133-
<Card.Text className={`${styles.lessonSummary}`}>
129+
130+
<Card.Text className={styles.lessonSummary}>
134131
{editableLessonId === lesson._id ? (
135132
<>
136133
<textarea
@@ -139,7 +136,7 @@ function LessonCard({ filteredLessons, onEditLessonSummary, onDeliteLessonCard,
139136
onChange={e => setEditableLessonSummary(e.target.value)}
140137
/>
141138
{validationError && (
142-
<span className={`${styles.validationError}`}>{validationError}</span>
139+
<span className={styles.validationError}>{validationError}</span>
143140
)}
144141
<button type="submit" onClick={() => handleSaveEdit(lesson._id)}>
145142
Save
@@ -152,27 +149,29 @@ function LessonCard({ filteredLessons, onEditLessonSummary, onDeliteLessonCard,
152149
<span>
153150
{ReactHtmlParser(
154151
(lesson?.content || '').length > maxSummaryLength
155-
? `${(lesson?.content || '').slice(0, maxSummaryLength)}...`
152+
? `${lesson.content.slice(0, maxSummaryLength)}...`
156153
: lesson?.content || '',
157154
)}
158155
</span>
159156
)}
160157
</Card.Text>
161158

162-
<Card.Text className={`${styles.cardTagAndFile}`}>
163-
File: <span className={`${styles.lessonFile}`}>file</span>
159+
<Card.Text className={styles.cardTagAndFile}>
160+
File: <span className={styles.lessonFile}>file</span>
164161
</Card.Text>
165162
</Card.Body>
163+
166164
<Card.Footer className={`${styles.lessonCardFooter} text-muted`}>
167165
<div>
168-
<span className={`${styles.footerItemsAuthorAndFrom}`}>
166+
<span className={styles.footerItemsAuthorAndFrom}>
169167
Author: {lesson.author?.name || 'Unknown'}
170168
</span>
171-
<span className={`${styles.footerItemsAuthorAndFrom}`}>
169+
<span className={styles.footerItemsAuthorAndFrom}>
172170
From: {lesson.relatedProject?.name || 'Unknown Project'}
173171
</span>
174172
</div>
175-
<div className={`${styles.lessonCardFooterItems}`}>
173+
174+
<div className={styles.lessonCardFooterItems}>
176175
{currentUserId === lesson.author?.id && (
177176
<div>
178177
<button
@@ -183,23 +182,22 @@ function LessonCard({ filteredLessons, onEditLessonSummary, onDeliteLessonCard,
183182
Edit
184183
</button>
185184
<button
186-
onClick={() => handleDeletePopup(lesson._id)}
187185
className="text-muted"
188186
type="button"
187+
onClick={() => handleDeletePopup(lesson._id)}
189188
>
190189
Delete
191190
</button>
192191
</div>
193192
)}
193+
194194
<div>
195195
<span
196196
role="button"
197197
tabIndex="0"
198198
onClick={() => handleLikeCount(lesson._id, currentUserId)}
199199
onKeyDown={e => {
200-
if (e.key === 'Enter') {
201-
handleLikeCount(lesson._id, currentUserId);
202-
}
200+
if (e.key === 'Enter') handleLikeCount(lesson._id, currentUserId);
203201
}}
204202
style={{ outline: 'none' }}
205203
>
@@ -250,12 +248,14 @@ function LessonCard({ filteredLessons, onEditLessonSummary, onDeliteLessonCard,
250248
Collapse All
251249
</button>
252250
</div>
251+
253252
<DeleteLessonCardPopUp
254253
open={showDeletePopup}
255254
setDeletePopup={setShowDeletePopup}
256255
deleteLesson={onDeliteLessonCard}
257256
lessonId={lessonToDeleteId}
258257
/>
258+
259259
{lessonCards}
260260
</div>
261261
);

0 commit comments

Comments
 (0)