e.stopPropagation()}
+ onClick={(e) => e.stopPropagation()}
>
diff --git a/src/components/ProfileHead.jsx b/src/components/ProfileHead.jsx
index ec13223..ec8675a 100644
--- a/src/components/ProfileHead.jsx
+++ b/src/components/ProfileHead.jsx
@@ -5,7 +5,7 @@ import axios from "axios";
import classNames from "classnames";
import toast from "react-hot-toast";
import { useSelector, useDispatch } from "react-redux";
-import { Select } from "antd";
+import { Button, Checkbox, Modal, Select } from "antd";
import { standards } from "../components/Options";
import { server } from "../main";
import "../styles/login.scss";
@@ -14,12 +14,12 @@ import { getChapters } from "../actions/chapterAction";
import { getTopics } from "../actions/topicAction";
import Loading from "../pages/Loading";
import ViewChapTop from "./ViewChapTop";
-
-
+import { getSubtopics } from "../actions/subtopicAction";
+import _ from 'lodash';
function debounce(func, delay) {
let timeoutId;
- return function(...args) {
+ return function (...args) {
if (timeoutId) {
clearTimeout(timeoutId);
}
@@ -29,9 +29,7 @@ function debounce(func, delay) {
};
}
-
-
-const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
+const ProfileHead = ({ selectedQuestion, setSelectedQuestion, toBottom }) => {
const [questions, setQuestions] = useState([]);
const [userTodayQuestions, setUserTodayQuestions] = useState("");
const [userRank, setUserRank] = useState("");
@@ -41,8 +39,8 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
const [myTodayQuestions, setTodayMyQuestions] = useState("");
const [selectedStandard, setSelectedStandard] = useState("");
const [selectedSubject, setSelectedSubject] = useState("");
- const [selectedChapter, setSelectedChapter] = useState("");
- const [selectedTopic, setSelectedTopic] = useState("");
+ const [selectedChapter, setSelectedChapter] = useState([]);
+ const [selectedTopic, setSelectedTopic] = useState([]);
// eslint-disable-next-line no-unused-vars
const [subjects, setSubjects] = useState([]);
// eslint-disable-next-line no-unused-vars
@@ -53,6 +51,7 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
const [myChapters, setMyChapters] = useState([]);
// eslint-disable-next-line no-unused-vars
const [topics, setTopics] = useState([]);
+ const [subTopics, setSubtopics] = useState([]);
// eslint-disable-next-line no-unused-vars
const [myTopics, setMyTopics] = useState([]);
const [activeTabIndex, setActiveTabIndex] = useState(0);
@@ -64,7 +63,6 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
const [myCurrentPage, setMyCurrentPage] = useState(1);
const [myTotalPages, setMyTotalPages] = useState(1);
const [totalQuestions, setTotalQuestions] = useState(0);
- // const [MyTotalQuestions, setMyTotalQuestions] = useState(0);
const [questionsLength, setQuestionsLength] = useState(0);
const [fixedTotalQuestions, setFixedTotalQuestions] = useState(0);
const [fixedMyTotalQuestions, setFixedTotalMyQuestions] = useState(0);
@@ -72,34 +70,139 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
const [searchMyQuery, setSearchMyQuery] = useState("");
const questionsPerPage = 50;
const [inputValue, setInputValue] = useState('');
- // eslint-disable-next-line no-unused-vars
+ const [selectedSubtopics, setSelectedSubtopics] = useState([]);
+ const [isSubtopicsLoading, setIsSubtopicsLoading] = useState(false);
const [myInputValue, setMyInputValue] = useState('');
- const inputRef = useRef(null);
- const myInputRef = useRef(null);
+ const inputRef = useRef(null);
+ const myInputRef = useRef(null);
const dispatch = useDispatch();
-
-
-
const { subjectList } = useSelector((state) => state.getSubject);
const { chapterList } = useSelector((state) => state.getChapter);
const { topicList } = useSelector((state) => state.getTopic);
+ const { subtopics } = useSelector((state) => state.getSubtopic);
+ const [selectAllAllQuestions, setSelectAllAllQuestions] = useState(false);
+ const [selectAllMyQuestions, setSelectAllMyQuestions] = useState(false);
+ const [selectedQuestions, setSelectedQuestions] = useState({});
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [areQuestionsSelected, setAreQuestionsSelected] = useState(false);
+ const [selectedTopic1, setSelectedTopic1] = useState([]);
+ const [selectedSubtopics1, setSelectedSubtopics1] = useState([]);
+
+ useEffect(() => {
+ const anySelected = Object.values(selectedQuestions).some(Boolean);
+ setAreQuestionsSelected(anySelected);
+ }, [selectedQuestions]);
useEffect(() => {
if (selectedStandard) {
dispatch(getSubjects(selectedStandard));
}
+ }, [dispatch, selectedStandard]);
+ useEffect(() => {
if (selectedSubject && selectedStandard) {
dispatch(getChapters(selectedSubject, selectedStandard));
}
- if (selectedSubject && selectedStandard && selectedChapter) {
- dispatch(getTopics(selectedSubject, selectedStandard, selectedChapter));
- }
- }, [dispatch, selectedStandard, selectedSubject, selectedChapter]);
+ }, [dispatch, selectedSubject, selectedStandard]);
+ useEffect(() => {
+ const fetchTopics = async () => {
+ if (selectedSubject && selectedStandard && selectedChapter.length > 0) {
+ try {
+ const chapterNames = selectedChapter.join(','); // Convert array to comma-separated string
+ const response = await dispatch(getTopics(selectedSubject, selectedStandard, chapterNames));
- const { user } = useSelector((state) => state.user);
+ if (response && response.payload) {
+ setTopics(response.payload);
+ selectedTopic1(response.payload)
- const isAdmin = user?.role === "admin";
+ }
+ } catch (error) {
+ console.error('Error fetching topics:', error);
+ }
+ }
+ };
+ fetchTopics();
+ }, [dispatch, selectedSubject, selectedStandard, selectedChapter]);
+ useEffect(() => {
+ const fetchSubtopics = async () => {
+ if (
+ selectedSubject &&
+ selectedStandard &&
+ selectedChapter.length > 0 &&
+ (selectedTopic.length > 0)
+ ) {
+ setIsSubtopicsLoading(true);
+ try {
+
+ const response = await dispatch(
+ getSubtopics(
+ selectedSubject,
+ selectedStandard,
+ selectedChapter.join(","), // Convert chapter array to comma-separated string
+ selectedTopic.join(",")
+ )
+ );
+
+ if (response && response.payload) {
+ const fetchedSubtopics = response.payload;
+ setSubtopics(fetchedSubtopics);
+ setSelectedSubtopics1([]); // Clear previously selected subtopics
+ } else {
+ setSubtopics([]);
+ setSelectedSubtopics1([]);
+ }
+ } catch (error) {
+ console.error("Error fetching subtopics:", error);
+ setSubtopics([]);
+ setSelectedSubtopics1([]);
+ } finally {
+ setIsSubtopicsLoading(false);
+ }
+ } else {
+ setSubtopics([]);
+ setSelectedSubtopics1([]);
+ }
+ };
+
+ fetchSubtopics();
+ }, [dispatch, selectedSubject, selectedStandard, selectedChapter, selectedTopic, selectedTopic1]);
+ useEffect(() => {
+ const fetchSubtopicsForTopic1 = async () => {
+ if (
+ selectedSubject &&
+ selectedStandard &&
+ selectedChapter.length > 0 &&
+ selectedTopic1.length > 0
+ ) {
+ setIsSubtopicsLoading(true);
+ try {
+ const response = await dispatch(
+ getSubtopics(
+ selectedSubject,
+ selectedStandard,
+ selectedChapter.join(","),
+ selectedTopic1.join(",")
+ )
+ );
+ if (response && response.payload) {
+ setSelectedSubtopics1(response.payload);
+ } else {
+ setSelectedSubtopics1([]);
+ }
+ } catch (error) {
+ console.error("Error fetching subtopics for topic1:", error);
+ setSelectedSubtopics1([]);
+ } finally {
+ setIsSubtopicsLoading(false);
+ }
+ } else {
+ setSelectedSubtopics1([]);
+ }
+ };
+ fetchSubtopicsForTopic1();
+ }, [dispatch, selectedSubject, selectedStandard, selectedChapter, selectedTopic1]);
+ const { user } = useSelector((state) => state.user);
+ const isAdmin = user?.role === "admin";
useEffect(() => {
if (activeTabIndex === 0) {
fetchQuestions(
@@ -107,6 +210,9 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
selectedSubject,
selectedChapter,
selectedTopic,
+ selectedSubtopics,
+ selectedSubtopics1,
+ selectedTopic1,
selectedUser,
searchKeyword,
);
@@ -116,6 +222,7 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
selectedSubject,
selectedChapter,
selectedTopic,
+ selectedSubtopics,
searchMyQuery
);
}
@@ -124,34 +231,41 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
selectedSubject,
selectedChapter,
selectedTopic,
+ selectedSubtopics,
+ selectedSubtopics1,
+ selectedTopic1,
activeTabIndex,
selectedUser,
searchKeyword,
searchMyQuery
]);
-
const fetchQuestions = async (
standard,
subject,
chapter,
topic,
- createdBy,
+ subtopic,
limit,
page
) => {
setLoading(true);
+
try {
+ const params = {
+ standard,
+ subject,
+ chapter,
+ topic,
+ subtopic,
+ limit,
+ page,
+ search: searchKeyword,
+ };
+
+
+
const response = await axios.get(`${server}/api/get/question`, {
- params: {
- standard: selectedStandard,
- subject,
- chapter,
- topic,
- createdBy,
- limit: questionsPerPage,
- page,
- search: searchKeyword,
- },
+ params,
withCredentials: true,
});
@@ -161,6 +275,7 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
setUserTodayQuestions(response.data?.todaysQuestionsCount);
setUserRank(response.data?.userRank);
setTopperUser(response.data?.topperUser);
+
const totalQuestions = response.data.totalQuestions || 0;
setTotalQuestions(totalQuestions);
setTotalPages(Math.ceil(totalQuestions / limit));
@@ -168,14 +283,66 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
setQuestions([]);
}
} catch (error) {
- console.error(error);
- toast.error(error.message);
+ console.error("Error fetching questions:", error);
+
+ if (error.response && error.response.data && error.response.data.message) {
+ toast.error(error.response.data.message);
+ } else {
+ toast.error("Failed to fetch questions. Please try again.");
+ }
} finally {
setLoading(false);
}
};
+ const fetchTotalQuestionsDebounced = useCallback(
+ _.debounce(async (
+ standard,
+ subject,
+ chapter,
+ topic,
+ subtopic,
+ createdBy,
+ search,
+ mySearch
+ ) => {
+ try {
+ const response = await axios.get(`${server}/api/get/totalquestion`, {
+ params: {
+ standard,
+ subject,
+ chapter,
+ topic,
+ subtopic,
+ createdBy,
+ search,
+ mySearch,
+ },
+ withCredentials: true,
+ });
+
+ if (response.data.success) {
+ const fixedMyTotalQuestions = response.data.totalMyQuestions || 0;
+ setFixedTotalMyQuestions(fixedMyTotalQuestions);
+ const fixedTotalQuestions = response.data.fixedTotalQuestions || 0;
+ setFixedTotalQuestions(fixedTotalQuestions);
+ setTotalQuestions(response.data.totalQuestions);
+ setQuestionsLength(response.data.totalMyQuestions);
+ setTotalPages(
+ Math.ceil(response.data.totalQuestions / questionsPerPage)
+ );
- const fetchUserQuestions = async (standard, subject, chapter, topic, limit, page) => {
+ setMyTotalPages(
+ Math.ceil(response.data.totalMyQuestions / questionsPerPage)
+ );
+ }
+ } catch (error) {
+ console.error(error);
+ toast.error("Failed to fetch total questions count");
+ }
+ }, 500),
+ []
+ );
+ const fetchUserQuestions = async (standard, subject, chapter, topicList, subtopic, limit, page) => {
setLoading(true);
try {
const response = await axios.get(`${server}/api/get/myquestion`, {
@@ -184,9 +351,10 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
subject,
chapter,
topicList,
+ subtopic,
limit: questionsPerPage,
page,
- search: searchMyQuery,
+ search: searchMyQuery,
},
withCredentials: true,
});
@@ -208,8 +376,6 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
setLoading(false);
}
};
-
-
const fetchUsers = async () => {
try {
if (isAdmin) {
@@ -226,54 +392,6 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
console.error(error);
}
};
-
-
-
- const fetchTotalQuestions = async (
- standard,
- subject,
- chapter,
- topic,
- createdBy,
- search,
- mySearch
- ) => {
- try {
- const response = await axios.get(`${server}/api/get/totalquestion`, {
- params: {
- standard,
- subject,
- chapter,
- topic,
- createdBy,
- search,
- mySearch,
- },
- withCredentials: true,
- });
-
- if (response.data.success) {
- const fixedMyTotalQuestions = response.data.totalMyQuestions || 0;
- setFixedTotalMyQuestions(fixedMyTotalQuestions);
- const fixedTotalQuestions = response.data.fixedTotalQuestions || 0;
- setFixedTotalQuestions(fixedTotalQuestions);
- setTotalQuestions(response.data.totalQuestions);
- setQuestionsLength(response.data.questionsLength);
- setTotalPages(
- Math.ceil(response.data.totalQuestions / questionsPerPage)
- );
-
- setMyTotalPages(
- Math.ceil(response.data.questionsLength / questionsPerPage)
- );
- }
- } catch (error) {
- console.error(error);
- toast.error("Failed to fetch total questions count");
- }
- };
-
-
useEffect(() => {
fetchUsers(
selectedStandard,
@@ -290,12 +408,11 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
selectedTopic,
searchKeyword
]);
-
const handleResetFilters = () => {
setSelectedSubject("");
- setSelectedChapter("");
- setSelectedTopic("");
- setSelectedStandard("")
+ setSelectedChapter([]);
+ setSelectedTopic([]);
+ setSelectedStandard([])
setSubjects([]);
setChapters([]);
@@ -314,46 +431,47 @@ const ProfileHead = ({ setSelectedQuestion, toBottom }) => {
setInputValue("");
setMyInputValue("")
setCurrentPage(1);
- setMyCurrentPage(1)
+ setMyCurrentPage(1);
+ };
+ const handleTabChange = (index) => {
+ setSelectedStandard("")
+ setSelectedQuestion(null);
+ setActiveTabIndex(index);
+ setCurrentPage(1);
+ setMyCurrentPage(1);
+ setSelectedSubject("");
+ setSelectedChapter([]);
+ setSelectedTopic([]);
+ setSubjects([]);
+ setChapters([]);
+ setTopics([]);
+ setMySubjects([]);
+ setMyChapters([]);
+ setMyTopics([]);
+ setQuestions([]);
+ setSelectedUser(null);
+ setMyQuestions([]);
+ setMyRank("");
+ setUserRank("");
+ setUserTodayQuestions("");
+ setTodayMyQuestions("");
+ setSearchMyQuery("");
+ setSearchKeyword("");
+ setInputValue("");
+ setMyInputValue("");
+ setSelectedTopic1([]);
+ setSelectedSubtopics1([])
};
-
-const handleTabChange = (index) => {
- setSelectedStandard("")
- setSelectedQuestion(null);
- setActiveTabIndex(index);
- setCurrentPage(1);
- setMyCurrentPage(1);
- setSelectedSubject("");
- setSelectedChapter("");
- setSelectedTopic("");
- setSubjects([]);
- setChapters([]);
- setTopics([]);
- setMySubjects([]);
- setMyChapters([]);
- setMyTopics([]);
- setQuestions([]);
- setSelectedUser(null);
- setMyQuestions([]);
- setMyRank("");
- setUserRank("");
- setUserTodayQuestions("");
- setTodayMyQuestions("");
- setSearchMyQuery("");
- setSearchKeyword("");
- setInputValue("");
- setMyInputValue("")
-};
useEffect(() => {
if (!isAdmin) {
setActiveTabIndex(1);
}
}, [isAdmin]);
-
useEffect(() => {
setSelectedSubject("");
- setSelectedChapter("");
- setSelectedTopic("");
+ setSelectedChapter([]);
+ setSelectedTopic([]);
+ setSelectedSubtopics([])
setSelectedUser("");
setSubjects([]);
setChapters([]);
@@ -369,38 +487,42 @@ const handleTabChange = (index) => {
setSearchKeyword('')
setCurrentPage(1);
setMyCurrentPage(1)
+ setSelectedTopic1([]);
+ setSelectedSubtopics1([]);
}, [user]);
-
const filteredQuestions = questions.filter(
(question) =>
(!selectedSubject || question.subject === selectedSubject) &&
(!selectedUser || question.createdBy === selectedUser)
);
-
const filteredMyQuestions = myQuestions.filter((question) => {
if (!selectedSubject) return true;
return question.subject === selectedSubject;
});
-
const handleUserChange = (value) => {
setSelectedUser(value);
setUserRank("");
setUserTodayQuestions("");
-
- };
+ setSelectedTopic([]);
+ setSelectedSubtopics([])
- useEffect(() => {
- fetchTotalQuestions(selectedStandard, selectedSubject, selectedChapter, selectedTopic, selectedUser, searchKeyword, searchMyQuery);
+ };
+ useEffect(() => {
+ fetchTotalQuestionsDebounced(
+ selectedStandard,
+ selectedSubject,
+ selectedChapter,
+ selectedTopic,
+ selectedSubtopics,
+ selectedUser,
+ searchKeyword,
+ searchMyQuery
+ );
});
-
-
-
-
const handleQuestionClick = (question) => {
setSelectedQuestion(question);
toBottom();
};
-
const handleNextPage = () => {
if (activeTabIndex === 0) {
if (currentPage < totalPages) {
@@ -411,6 +533,7 @@ const handleTabChange = (index) => {
selectedSubject,
selectedChapter,
selectedTopic,
+ selectedSubtopics,
selectedUser,
questionsPerPage,
newPage
@@ -425,13 +548,13 @@ const handleTabChange = (index) => {
selectedSubject,
selectedChapter,
selectedTopic,
+ selectedSubtopics,
questionsPerPage,
newPage
);
}
}
};
-
const handlePrevPage = () => {
if (activeTabIndex === 0) {
if (currentPage > 1) {
@@ -442,6 +565,7 @@ const handleTabChange = (index) => {
selectedSubject,
selectedChapter,
selectedTopic,
+ selectedSubtopics,
selectedUser,
questionsPerPage,
newPage
@@ -456,84 +580,267 @@ const handleTabChange = (index) => {
selectedSubject,
selectedChapter,
selectedTopic,
+ selectedSubtopics,
questionsPerPage,
newPage
);
}
}
};
-
const handleSearch = useCallback(
debounce((keyword) => {
- setCurrentPage(1);
+ setCurrentPage(1);
setSearchKeyword(keyword);
if (inputRef.current) {
- inputRef.current.focus();
+ inputRef.current.focus();
}
- fetchQuestions(keyword);
- }, 300),
+ fetchQuestions(keyword);
+ }, 300),
[]
);
-
const handleSearchChange = (e) => {
setCurrentPage(1);
- const value = e.target.value;
+ const value = e.target.value;
setInputValue(value);
if (value === '') {
resetSearchResults();
} else if (value.endsWith(' ') || value.endsWith('\n')) {
- const trimmedValue = value.trim();
+ const trimmedValue = value.trim();
handleSearch(trimmedValue);
}
};
const handleSearchClick = () => {
handleSearch(inputValue.trim());
};
- const resetSearchResults = () => {
+ const resetSearchResults = () => {
setSearchKeyword('');
setInputValue('');
- };
-
-
- const handleMySearch = useCallback(
+ };
+ const handleMySearch = useCallback(
debounce((keyword) => {
setMyCurrentPage(1);
setSearchMyQuery(keyword);
if (myInputRef.current) {
- myInputRef.current.focus();
+ myInputRef.current.focus();
}
- fetchUserQuestions(keyword);
- }, 300),
+ fetchUserQuestions(keyword);
+ }, 300),
[]
);
const handleMySearcChange = (e) => {
setMyCurrentPage(1);
- const value = e.target.value;
+ const value = e.target.value;
setMyInputValue(value);
-// setSearchMyQuery(e.target.value)
+ // setSearchMyQuery(e.target.value)
if (value === '') {
-
+
resetMySearchResults();
} else if (value.endsWith(' ') || value.endsWith('\n')) {
- const trimmedValue = value.trim();
+ const trimmedValue = value.trim();
handleMySearch(trimmedValue);
}
}
const resetMySearchResults = () => {
setSearchMyQuery('');
- setMyInputValue('');
+ setMyInputValue('');
};
const handleMySearchClick = () => {
fetchUserQuestions(handleMySearch)
}
+ const renderSubtopicSelectors = (subtopics, level) => {
+ if (!subtopics || subtopics.length === 0) {
+ return null; // Return early if there are no subtopics
+ }
+
+ return (
+
+
+
+ {/* Topic Selection */}
+ {subtopics.length > 0 && (
+
+
+ );
+ };
+ const handleSelectAllAllQuestions = () => {
+ if (filteredQuestions.length === 0) return;
+ const newSelectedQuestions = !selectAllAllQuestions ? {} : {};
+ if (!selectAllAllQuestions) {
+ filteredQuestions.forEach(question => {
+ newSelectedQuestions[question._id] = true;
+ });
+ }
+ setSelectedQuestions(newSelectedQuestions);
+ setSelectAllAllQuestions(!selectAllAllQuestions);
+ };
+ const handleSelectAllMyQuestions = () => {
+ if (filteredMyQuestions.length === 0) return;
+ const newSelectedQuestions = !selectAllMyQuestions ? {} : {};
+ if (!selectAllMyQuestions) {
+ filteredMyQuestions.forEach(question => {
+ newSelectedQuestions[question._id] = true;
+ });
+ }
+ setSelectedQuestions(newSelectedQuestions);
+ setSelectAllMyQuestions(!selectAllMyQuestions);
+ };
+ const handleSelectQuestion = (questionId) => {
+ const newSelectedQuestions = { ...selectedQuestions };
+ if (newSelectedQuestions[questionId]) {
+ delete newSelectedQuestions[questionId];
+ } else {
+ newSelectedQuestions[questionId] = true;
+ }
+ setSelectedQuestions(newSelectedQuestions);
+ };
+ const handleEditClick = (question) => {
+ if (areQuestionsSelected) {
+ setIsModalOpen(true);
+ }
+ };
+
+ const handleModalOk = async () => {
+ const questionIdsArray = Object.keys(selectedQuestions).filter((key) => selectedQuestions[key] === true);
+
+ // Ensure at least one question is selected
+ if (questionIdsArray.length === 0) {
+ toast.error('Please select at least one question.');
+ return;
+ }
+
+ // Get the last selected topic (new topic) and the first selected topic (selected topic to keep)
+ const newTopic = selectedTopic1.length > 0 ? selectedTopic1[selectedTopic1.length - 1] : '';
+ const selectedTopicToKeep = selectedTopic.length > 0 ? selectedTopic[0] : '';
+
+ try {
+ // Prepare the payload with selected question IDs
+ let payload = {
+ questionIds: questionIdsArray
+ };
+
+ // Case 1: Add a new topic if no previously selected topic exists
+ if (newTopic && !selectedTopicToKeep) {
+ payload = {
+ ...payload,
+ topic: newTopic // Add the new topic
+ };
+ console.log("Adding new topic:", payload);
+ }
+
+ // Case 2: Replace the selected topic with the new one if both exist
+ if (newTopic && selectedTopicToKeep) {
+ payload = {
+ ...payload,
+ topic: newTopic, // Replace old topic with the new one
+ selectedTopic: selectedTopicToKeep // Send the selected topic for replacement
+ };
+ console.log("Replacing the old topic with new topic:", payload);
+ }
+
+ // Case 3: Retain the selected topic if no new topic is provided
+ if (selectedTopicToKeep && !newTopic) {
+ payload = {
+ ...payload,
+ topic: selectedTopicToKeep // Retain the selected topic
+ };
+ console.log("Retaining selected topic:", payload);
+ }
+
+ // Send the request to the backend
+ const response = await axios.put(`${server}/api/updatequestiontopic`, payload);
+
+ // Handle successful response
+ toast.success(response.data.message || 'Questions updated successfully.');
+
+ // Reset modal and selections
+ setIsModalOpen(false);
+ setSelectedQuestions({});
+ setSelectedTopic1([]); // Clear the topics
+
+ } catch (error) {
+ const errorMessage = error.response?.data?.message || 'An error occurred while updating questions.';
+ toast.error(errorMessage);
+ console.error('Error updating questions:', errorMessage);
+ }
+ };
+
+
+
+ const handleModalCancel = () => {
+ setIsModalOpen(false);
+ };
+ const handleTopicChange = (value) => {
+ setSelectedTopic1(value);
+ setSelectedSubtopics1([]);
+ };
+
+ useEffect(() => {
+ setSelectedTopic1(selectedTopic);
+ setSelectedSubtopics1(selectedSubtopics)
+ }, [selectedTopic, selectedSubtopics]);
+ const renderSubtopicSelector = (subtopics, level = 1) => {
+ if (!subtopics || subtopics.length === 0) {
+ return null; // Return early if there are no subtopics
+ }
+
+ return (
+
+
+
+
+
+ );
+ };
+
+
return (
<>
-
+
@@ -606,8 +913,9 @@ const handleTabChange = (index) => {
onChange={(value) => {
setSelectedStandard(value);
setSelectedSubject("");
- setSelectedChapter("");
- setSelectedTopic("");
+ setSelectedChapter([]);
+ setSelectedTopic([]);
+ setSelectedSubtopics([])
setSelectedQuestion(null);
setCurrentPage(1)
setMyCurrentPage(1)
@@ -630,8 +938,9 @@ const handleTabChange = (index) => {
value={selectedSubject}
onChange={(value) => {
setSelectedSubject(value);
- setSelectedChapter("");
- setSelectedTopic("");
+ setSelectedChapter([]);
+ setSelectedTopic([]);
+ setSelectedSubtopics([])
setSelectedQuestion(null);
setCurrentPage(1)
setMyCurrentPage(1)
@@ -651,66 +960,88 @@ const handleTabChange = (index) => {
-
-
+
+
+
+ {isSubtopicsLoading && (
+
+
+
+ )}
+
+ {selectedTopic.length > 0 && !isSubtopicsLoading && (
+ renderSubtopicSelectors(subtopics, 0)
+ )}
+
{subjectList && chapterList && topicList ? (
-
-
- {isAdmin && (
+
+
+ {isAdmin && (
+
+ classNames(
+ "w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-blue-700",
+ "ring-white ring-opacity-60 ring-offset-2 ring-offset-blue-400 focus:outline-none focus:ring-2",
+ selected
+ ? "bg-white shadow"
+ : "text-blue-100 hover:bg-white/[0.12] hover:text-white"
+ )
+ }
+ >
+ All Questions
+
+ )}
classNames(
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-blue-700",
@@ -721,262 +1052,341 @@ const handleTabChange = (index) => {
)
}
>
- All Questions
+ My Questions
- )}
-
- classNames(
- "w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-blue-700",
- "ring-white ring-opacity-60 ring-offset-2 ring-offset-blue-400 focus:outline-none focus:ring-2",
- selected
- ? "bg-white shadow"
- : "text-blue-100 hover:bg-white/[0.12] hover:text-white"
- )
- }
- >
- My Questions
-
-
-
-
- {selectedUser && (
-
- )}
- {selectedUser && userRank && (
-
- )}
-
- {activeTabIndex === 0 && (
-
- )}
-
- {activeTabIndex === 1 && (
-
- )}
-
-
- {isAdmin && (
-
+
+
+ {selectedUser && (
+
+ )}
+ {selectedUser && userRank && (
+
+ )}
+
+ {activeTabIndex === 0 && (
+
+ )}
+
+ {activeTabIndex === 1 && (
+
+ )}
+
+ {isAdmin && (
+
+
+ {loading ? (
+
+ ) : (
+ <>
+
+
+ Total Questions: {totalQuestions}
+
+
+
+ {totalQuestions > 0 && filteredQuestions.length > 0 ? (
+ <>
+ {selectedTopic.length > 0 && (
+
+ 0 &&
+ filteredQuestions.every(question => selectedQuestions[question._id])}
+ onChange={handleSelectAllAllQuestions}
+ >
+ Select All
+
+
+
+ )}
+
+
+ {selectedTopic ? (
+ filteredQuestions.map((question, index) => (
+
handleQuestionClick(question)}
+ className="cursor-pointer text-gray-900 p-2 flex items-start space-x-4"
+ >
+ {selectedTopic.length > 0 && (
+
handleSelectQuestion(question._id)}
+ onClick={(e) => e.stopPropagation()}
+ />
+ )}
+
+
+ Q. {(currentPage - 1) * questionsPerPage + index + 1}
+
+
+
+
+ ))
+ ) : (
+
+ Please select a topic to view questions.
+
+ )}
+ >
+ ) : (
+
+ No questions available.
+
+ )}
+ >
+ )}
+
+
+
+
+
+ {totalQuestions === 0 ? "0 / " : `${currentPage} / `}
+
+
+ {totalQuestions === 0 ? "0" : totalPages}
+
+
+
+
+
+ )}
+ {activeTabIndex === 1 ? (
+
+
+
+
+ ) : null}
+
{loading ? (
) : (
<>
+
- Total Questions: {totalQuestions}
+ Total Questions: {fixedMyTotalQuestions}
-
- {totalQuestions === 0 ? (
-
- No questions found.
-
+
+ {fixedMyTotalQuestions === 0 ? (
+
No questions found.
) : (
- filteredQuestions.map((question, index) => (
-
handleQuestionClick(question)}
- className="cursor-pointer text-gray-900 p-2 "
- >
-
- Q.
- {(currentPage - 1) * questionsPerPage + index + 1}
-
-
-
- ))
+ <>
+ {selectedTopic.length > 0 && (
+
+ 0 &&
+ filteredMyQuestions.every(question => selectedQuestions[question._id])}
+ onChange={handleSelectAllMyQuestions}
+ >
+ Select All
+
+
+
+ )}
+
+
+ {filteredMyQuestions.map((question, index) => (
+
handleQuestionClick(question)}
+ className="cursor-pointer text-gray-900 p-2 flex items-start space-x-4"
+ >
+ {selectedTopic.length > 0 && (
+ handleSelectQuestion(question._id)}
+ onClick={(e) => e.stopPropagation()}
+ />
+ )}
+
+ Q. {(myCurrentPage - 1) * questionsPerPage + index + 1}
+
+
+
+ ))}
+ >
)}
>
)}
+
+ {/* Pagination Controls */}
- {totalQuestions === 0 ? "0 / " : `${currentPage} / `}
+ {fixedMyTotalQuestions === 0 ? "0 / " : `${myCurrentPage} / `}
- {totalQuestions === 0 ? "0" : totalPages}
+ {fixedMyTotalQuestions === 0 ? "0" : myTotalPages}
-
- )}
-
- {activeTabIndex === 1 ? (
-
-
-
-
- ) : null}
-
-
-
- {loading ? (
-
- ) : (
- <>
-
- Total Questions: {questionsLength}
-
-
- {questionsLength === 0 ? (
-
- No questions found.
-
- ) : (
- filteredMyQuestions.map((question, index) => (
-
handleQuestionClick(question)}
- className="cursor-pointer text-gray-900 p-2"
- >
-
- Q.{" "}
- {(myCurrentPage - 1) * questionsPerPage + index + 1}
-
-
-
- ))
- )}
- >
- )}
-
-
-
-
-
- {questionsLength === 0 ? "0 / " : `${myCurrentPage} / `}
-
-
- {questionsLength === 0 ? "0" : myTotalPages}
-
-
-
-
-
-
-
-
- ) : (
+
+
+ ) : (
Loading...
)}
+
+
+
+
+
+
+ {renderSubtopicSelector(subtopics)}
+ {isSubtopicsLoading && (
+
+
+
+ )}
+
+
+
>
);
};
@@ -984,6 +1394,7 @@ const handleTabChange = (index) => {
ProfileHead.propTypes = {
setSelectedQuestion: PropTypes.func.isRequired,
toBottom: PropTypes.func.isRequired,
+ selectedQuestion: PropTypes.func.isRequired
};
export default ProfileHead;
diff --git a/src/pages/CreateQuestion.jsx b/src/pages/CreateQuestion.jsx
index 697b03a..c3ce349 100644
--- a/src/pages/CreateQuestion.jsx
+++ b/src/pages/CreateQuestion.jsx
@@ -189,39 +189,53 @@ const CreateQuestion = () => {
);
-
-
useEffect(() => {
+ // Fetch subjects when the standard changes
if (standard) {
dispatch(getSubjects(standard));
}
- if (subject && standard) {
+
+ // Fetch chapters when both standard and subject are selected
+ if (standard && subject) {
dispatch(getChapters(subject, standard));
}
+
+ // Function to fetch topics for selected chapters
const fetchTopics = async () => {
- if (subject && standard && chapter) {
- let allTopics = []; // To store all topics from selected chapters
- for (const chap of chapter) {
- const response = await dispatch(getTopics(subject, standard, chap));
- allTopics = [...allTopics, ...response.topic]; // Combine topics from all chapters
+ if (standard && subject && chapter && chapter.length > 0) {
+ const chapterNames = chapter.join(','); // Join chapter names with commas
+
+ try {
+ const response = await dispatch(getTopics(subject, standard, chapterNames));
+ if (response && response.payload && response.payload.success) {
+ // Assuming you have some logic to handle the fetched topics
+ // e.g., setting them in local state or using Redux state
}
- }
- };
+ } catch (error) {
+ console.error('Error fetching topics:', error);
+ }
+ }
+ };
- fetchTopics();
- if (subject && standard && chapter && topic) {
+ // Fetch topics based on the selected chapters
+ fetchTopics();
+
+ // Fetch subtopics only when all criteria are met
+ if (standard && subject && chapter && chapter.length > 0 && topic && topic.length > 0) {
setIsSubtopicsLoading(true);
dispatch(getSubtopics(subject, standard, chapter, topic))
- .then(() => {
+ .then((response) => {
setIsSubtopicsLoading(false);
})
- .catch(() => {
+ .catch((error) => {
+ console.error('Error fetching subtopics:', error);
setIsSubtopicsLoading(false);
});
} else {
setIsSubtopicsLoading(false);
}
}, [dispatch, standard, subject, chapter, topic]);
+
const uploadImageToS3 = async (file, signedUrl) => {
const response = await fetch(signedUrl, {
diff --git a/src/pages/Profile.jsx b/src/pages/Profile.jsx
index 975b7ef..afc84bc 100644
--- a/src/pages/Profile.jsx
+++ b/src/pages/Profile.jsx
@@ -288,7 +288,7 @@ const Profile = () => {
return (
-
+
{selectedQuestion ? (
@@ -358,18 +358,20 @@ const Profile = () => {
Class: {selectedQuestion.standard}
Subject: {selectedQuestion.subject}
-
Chapter: {selectedQuestion.chapter.join(", ")}
+
Chapter: {selectedQuestion?.chapter?.join(", ")}
Topics: {selectedQuestion && selectedQuestion.topics ? selectedQuestion.topics.join(", ") : "No topics available"}
Level: {selectedQuestion.level}
- Subtopics:{" "}
- {selectedQuestion.subtopics.length > 0
- ? selectedQuestion.subtopics.join(", ")
- : "N/A"}
-
+ Subtopics:{" "}
+ {selectedQuestion && selectedQuestion.subtopics
+ ? selectedQuestion.subtopics.length > 0
+ ? selectedQuestion.subtopics.join(", ")
+ : "No subtopics"
+ : "N/A"}
+
Nested Subtopic: {selectedQuestion.nestedSubTopic || "N/A"}