- {username == ""
+ {isLoggingOut
+ ? `Till next time, ${username} ...`
+ : username == ""
? "Wake up, Neo..."
: `Welcome, ${username}!`}
@@ -68,7 +93,7 @@ const NavBar = ({ message, timer = 0 }) => {
);
};
-NavBar.propTypes = {
+Header.propTypes = {
message: propTypes.shape({
username: propTypes.string.isRequired,
isLoading: propTypes.bool.isRequired,
@@ -78,6 +103,7 @@ NavBar.propTypes = {
wasCookieSent: propTypes.bool.isRequired,
}),
timer: propTypes.number,
+ isLoggingOut: propTypes.bool
};
-export default NavBar;
+export default Header;
diff --git a/src/components/LogOut.js b/src/components/LogOut.js
new file mode 100644
index 0000000..8490caf
--- /dev/null
+++ b/src/components/LogOut.js
@@ -0,0 +1,24 @@
+import React from "react";
+import { LogOutButton } from "../styles/logout-button";
+import propTypes from "prop-types";
+
+const LogOut = ({ handleLogOutClick }) => {
+ const handleLogout = () => {
+ //Called when LogOut button is clicked
+ handleLogOutClick();
+ };
+
+ return (
+
+
+ LogOut
+
+
+ );
+};
+
+LogOut.propTypes = {
+ handleLogOutClick: propTypes.func,
+};
+
+export default LogOut;
diff --git a/src/components/NotAcQuestionsTable.js b/src/components/NotAcQuestionsTable.js
new file mode 100644
index 0000000..af6d4e1
--- /dev/null
+++ b/src/components/NotAcQuestionsTable.js
@@ -0,0 +1,254 @@
+import React from "react";
+import propTypes, { array } from "prop-types";
+
+import {
+ TableContainer,
+ Table,
+ TBody,
+ THead,
+ Tr,
+ Th,
+ Td,
+} from "../styles/table";
+import { Scrollable } from "../styles/scrollbar";
+import { ShuffleButton } from "../styles/shufflestyle";
+import { useTable, usePagination } from "react-table";
+
+function PaginationTable({ columns, data, onShuffle_var }) {
+ const {
+ getTableProps,
+ getTableBodyProps,
+ headerGroups,
+ prepareRow,
+ page,
+ canPreviousPage,
+ canNextPage,
+ pageOptions,
+ pageCount,
+ gotoPage,
+ nextPage,
+ previousPage,
+ setPageSize,
+ state: { pageIndex, pageSize },
+ } = useTable(
+ {
+ columns,
+ data,
+ initialState: { pageIndex: 0 },
+ },
+ usePagination
+ );
+
+ return (
+ <>
+
+ {" "}
+ {" "}
+ {" "}
+ {" "}
+
+ Page{" "}
+
+ {pageIndex + 1} of {pageOptions.length}
+ {" "}
+ | Go to page:{" "}
+ {
+ const page = e.target.value
+ ? Number(e.target.value) - 1
+ : 0;
+ gotoPage(page);
+ }}
+ style={{ width: "50px",
+ background: "#000000",
+ color: "#FFFF00", }}
+ />
+ {" "}
+
+
+
+
+
+ {headerGroups.map((headerGroup) => (
+
+ {headerGroup.headers.map((column) => (
+
+ {(() => {
+ switch (column.Header) {
+ case "Title":
+ console.log(column.Header);
+ return (
+
+ Pick one Random Question
+ )
+ }
+ })()}
+ {column.render("Header")}
+ |
+ ))}
+
+ ))}
+
+
+ {/* */}
+ {/* */}
+
+ {page.map((row, i) => {
+ prepareRow(row);
+ return (
+
+ {row.cells.map((cell) => {
+ return (
+ |
+ {cell.render("Cell")}
+ |
+ );
+ })}
+
+ );
+ })}
+
+ {/* */}
+
+ >
+ );
+}
+
+const NotAcQuestionsTable = ({ data, onShuffle }) => {
+ console.log("DATA:", data);
+ console.log(typeof shuffle_image);
+
+ //extracting useful information
+ const useful_data = [];
+ data["stat_status_pairs"].map((que, index) => {
+ if (!(que["status"] === "notac")) {
+ //if not notac then return null
+ return null;
+ }
+ useful_data.push({
+ href: "https://leetcode.com/problems/"+que["stat"]["question__title_slug"],
+ ques_id: que["stat"]["frontend_question_id"],
+ ques_title: que["stat"]["question__title"],
+ level:
+ que["difficulty"]["level"] == 1
+ ? "Easy"
+ : que["difficulty"]["level"] == 2
+ ? "Medium"
+ : "Hard",
+ status: "Not-AC",
+ paid: que["paid_only"] === true ? "Premium" : "Free",
+ });
+ });
+ console.log(useful_data);
+
+ //defining column names and attributes
+ const columns = React.useMemo(
+ () => [
+ {
+ width: 9,
+ minWidth: 9,
+ Header: "ID",
+ accessor: "ques_id",
+ },
+ {
+ width: 55,
+ Header: "Title",
+ minWidth: 55,
+ id: "link",
+ accessor: d => d.href,
+ Cell: ({ row }) => {row.original.ques_title}
+ },
+ {
+ width: 12,
+ minWidth: 12,
+ Header: "Level",
+ accessor: "level",
+ },
+ {
+ width: 12,
+ minWidth: 12,
+ Header: "Status",
+ accessor: "status",
+ },
+ {
+ width: 12,
+ minWidth: 12,
+ Header: "Paid",
+ accessor: "paid",
+ },
+ ],
+ []
+ );
+
+
+ return (
+
+
+
+ );
+};
+
+NotAcQuestionsTable.propTypes = {
+ data: propTypes.shape({
+ stat_status_pairs: propTypes.arrayOf(
+ propTypes.shape({
+ difficulty: propTypes.shape({ level: propTypes.number }),
+ stat: propTypes.shape({
+ question__title: propTypes.string,
+ question__title_slug: propTypes.string,
+ }),
+ level: propTypes.number,
+ status: propTypes.string,
+ })
+ ),
+ }),
+ onShuffle: propTypes.func,
+};
+
+export default NotAcQuestionsTable;
diff --git a/src/components/Popup.js b/src/components/Popup.js
new file mode 100644
index 0000000..1f104e1
--- /dev/null
+++ b/src/components/Popup.js
@@ -0,0 +1,174 @@
+import React from "react";
+import {
+ TableContainer,
+ Table,
+ TBody,
+ THead,
+ Tr,
+ Th,
+ Td,
+} from "../styles/table";
+import propTypes from "prop-types";
+import { AddRemoveButton } from "../styles/add-remove-button";
+
+function Popup({ popup, setPopup, data, warningMessage="" }) {
+ console.log(popup);
+ return (
+
+ {
+ warningMessage !== ""
+ ?
+ {warningMessage}
+
setPopup(false)} style={{fontSize: "18px", padding: "1px 10px 1px 10px", marginRight: "0px", position: "absolute", right: "0", top: "1px"}}>
+ X
+
+
+ :
+
setPopup(false)}
+ >
+ x
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | ID |
+ Title |
+ Level |
+ Status |
+ Paid |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | {data["stat"]["frontend_question_id"]} |
+
+
+ {data["stat"]["question__title"]}
+
+ |
+
+ {data["difficulty"]["level"] == 1
+ ? "Easy"
+ : data["difficulty"]["level"] == 2
+ ? "Medium"
+ : "Hard"}
+ |
+
+ {data["status"] === "ac"
+ ? "AC"
+ : data["status"] === "notac"
+ ? "Not-AC"
+ : "Not-Attempted"}
+ |
+
+ {data["paid_only"] === true
+ ? "Premium"
+ : "Free"}
+ |
+
+
+
+
+
+ }
+
+ );
+}
+
+Popup.propTypes = {
+ popup: propTypes.bool,
+ setPopup: propTypes.func,
+ data: propTypes.shape({
+ stat_status_pairs: propTypes.arrayOf(
+ propTypes.shape({
+ difficulty: propTypes.shape({ level: propTypes.number }),
+ stat: propTypes.shape({
+ question__title: propTypes.string,
+ question__title_slug: propTypes.string,
+ }),
+ level: propTypes.number,
+ status: propTypes.string,
+ })
+ ),
+ }),
+ warningMessage: propTypes.string,
+}
+
+export default Popup;
diff --git a/src/components/QuestionsTable.js b/src/components/QuestionsTable.js
index aae7758..0300d8f 100644
--- a/src/components/QuestionsTable.js
+++ b/src/components/QuestionsTable.js
@@ -1,6 +1,5 @@
import React from "react";
import propTypes, { array } from "prop-types";
-
import {
TableContainer,
Table,
@@ -10,67 +9,329 @@ import {
Th,
Td,
} from "../styles/table";
+import { Scrollable } from "../styles/scrollbar";
+import { ShuffleButton } from "../styles/shufflestyle";
+
+//import shuffle_image from "../static/images/icon.png";
+//import { Link } from 'react-router';
+import { useTable, usePagination } from "react-table";
+function PaginationTable({ columns, data, onShuffle_var }) {
+ const {
+ getTableProps,
+ getTableBodyProps,
+ headerGroups,
+ prepareRow,
+ page,
+ canPreviousPage,
+ canNextPage,
+ pageOptions,
+ pageCount,
+ gotoPage,
+ nextPage,
+ previousPage,
+ setPageSize,
+ state: { pageIndex, pageSize },
+ } = useTable(
+ {
+ columns,
+ data,
+ initialState: { pageIndex: 0 },
+ },
+ usePagination
+ );
+
+ return (
+ <>
+
+ {" "}
+ {" "}
+ {" "}
+ {" "}
+
+ Page{" "}
+
+ {pageIndex + 1} of {pageOptions.length}
+ {" "}
+ | Go to page:{" "}
+ {
+ const page = e.target.value
+ ? Number(e.target.value) - 1
+ : 0;
+ gotoPage(page);
+ }}
+ style={{ width: "50px",
+ background: "#000000",
+ color: "#FFFF00", }}
+ />
+ {" "}
+
+
+
+
+
+ {headerGroups.map((headerGroup) => (
+
+ {headerGroup.headers.map((column) => (
+
+ {(() => {
+ switch (column.Header) {
+ case "Title":
+ console.log(column.Header);
+ return (
+
+ Pick one Random Question
+ )
+ }
+ })()}
+ {column.render("Header")}
+ |
+ ))}
+
+ ))}
+
+
+ {/* */}
+ {/* */}
+
+ {page.map((row, i) => {
+ prepareRow(row);
+ return (
+
+ {row.cells.map((cell) => {
+ return (
+ |
+ {cell.render("Cell")}
+ |
+ );
+ })}
+
+ );
+ })}
+
+ {/* */}
+
+ >
+ );
+}
-const QuestionsTable = ({ data }) => {
+function QuestionsTable({ data, onShuffle }) {
console.log("DATA:", data);
+ console.log(typeof shuffle_image);
+
+ //extracting useful information
+ const useful_data = [];
+ data["stat_status_pairs"].map((que, index) => {
+ useful_data.push({
+ href: "https://leetcode.com/problems/"+que["stat"]["question__title_slug"],
+ ques_id: que["stat"]["frontend_question_id"],
+ ques_title: que["stat"]["question__title"],
+ level:
+ que["difficulty"]["level"] == 1
+ ? "Easy"
+ : que["difficulty"]["level"] == 2
+ ? "Medium"
+ : "Hard",
+ status:
+ que["status"] === "ac"
+ ? "AC"
+ : que["status"] === "notac"
+ ? "Not-AC"
+ : "Not-Attempted",
+ paid: que["paid_only"] === true ? "Premium" : "Free",
+ });
+ });
+ //console.log(useful_data);
+
+ //defining column names and attributes
+ const columns = React.useMemo(
+ () => [
+ {
+ width: 9,
+ minWidth: 9,
+ Header: "ID",
+ accessor: "ques_id",
+ },
+ {
+ width: 55,
+ Header: "Title",
+ minWidth: 55,
+ id: "link",
+ accessor: d => d.href,
+ Cell: ({ row }) => {row.original.ques_title}
+ },
+ {
+ width: 12,
+ minWidth: 12,
+ Header: "Level",
+ accessor: "level",
+ },
+ {
+ width: 12,
+ minWidth: 12,
+ Header: "Status",
+ accessor: "status",
+ },
+ {
+ width: 12,
+ minWidth: 12,
+ Header: "Paid",
+ accessor: "paid",
+ },
+ ],
+ []
+ );
+
return (
+ <>
-
-
-
-
-
+ {/*
+
+ {/* added new column for "question_id" */}{/*
+
+
+
+
+
- | Title |
+ ID |
+ */}
+ {/*
+
+ Pick one Random Problem
+ */}{/*}
+
+
+ Pick one Random Question
+
+ Title
+ |
Level |
- Status |
+ Status |
+ Paid |
-
-
-
-
-
-
-
-
- {data["stat_status_pairs"].map((que, index) => {
- return (
-
- |
-
- {que["stat"]["question__title"]}
-
- |
-
- {que["difficulty"]["level"] == 1
- ? "Easy"
- : que["difficulty"]["level"] == 2
- ? "Medium"
- : "Hard"}
- |
-
- {que["status"] === "ac"
- ? "AC"
- : que["status"] === "notac"
- ? "Not-AC"
- : "Not-Attempted"}
- |
-
- );
- })}
-
-
+ */}
+ {/* */}
+ {/* */}
+ {/*
+ {data["stat_status_pairs"].map((que, index) => {
+ return (
+
+ |
+ {que["stat"]["frontend_question_id"]}
+ |
+
+
+ {que["stat"]["question__title"]}
+
+ |
+
+ {que["difficulty"]["level"] == 1
+ ? "Easy"
+ : que["difficulty"]["level"] == 2
+ ? "Medium"
+ : "Hard"}
+ |
+
+ {que["status"] === "ac"
+ ? "AC"
+ : que["status"] === "notac"
+ ? "Not-AC"
+ : "Not-Attempted"}
+ |
+
+ {que["paid_only"] === true
+ ? "Premium"
+ : "Free"}
+ |
+
+ );
+ })}
+ */}
+
+ {/* */}
+ >
);
-};
+}
QuestionsTable.propTypes = {
data: propTypes.shape({
@@ -86,6 +347,7 @@ QuestionsTable.propTypes = {
})
),
}),
+ onShuffle: propTypes.func,
};
export default QuestionsTable;
diff --git a/src/components/TableContent.js b/src/components/TableContent.js
new file mode 100644
index 0000000..6dca9e8
--- /dev/null
+++ b/src/components/TableContent.js
@@ -0,0 +1,71 @@
+import React, { useEffect } from "react";
+import QuestionsTable from "./QuestionsTable";
+import AttemptedQuestionsTable from "./AttemptedQuestionsTable";
+import AcQuestionsTable from "./AcQuestionsTable";
+import NotAcQuestionsTable from "./NotAcQuestionsTable";
+import propTypes from "prop-types";
+import VirtualContestTable from './VirtualContestTable';
+
+const TableContent = ({ data, category, onShuffle, virtualContestQuestions, setVirtualContestQuestions, setResponse }) => {
+ // This component checks the category and returns the corresponding component accordingly
+
+ switch (category) {
+ case "All Questions":
+ return ;
+
+ case "Attempted":
+ return (
+
+ );
+
+ case "Accepted":
+ return ;
+
+ case "Not Accepted":
+ return ;
+
+ case "Virtual Contest":
+ return ;
+
+ default:
+ return null;
+ }
+};
+
+TableContent.propTypes = {
+ data: propTypes.shape({
+ stat_status_pairs: propTypes.arrayOf(
+ propTypes.shape({
+ difficulty: propTypes.shape({ level: propTypes.number }),
+ stat: propTypes.shape({
+ question__title: propTypes.string,
+ question__title_slug: propTypes.string,
+ }),
+ level: propTypes.number,
+ status: propTypes.string,
+ })
+ ),
+ }),
+ category: propTypes.string,
+ onShuffle: propTypes.func,
+ virtualContestQuestions: propTypes.arrayOf(
+ propTypes.shape({
+ difficulty: propTypes.shape({ level: propTypes.number }),
+ stat: propTypes.shape({
+ question__title: propTypes.string,
+ question__title_slug: propTypes.string,
+ }),
+ level: propTypes.number,
+ status: propTypes.string,
+ })
+ ),
+ setVirtualContestQuestions: propTypes.func,
+ setResponse: propTypes.func,
+};
+
+export default TableContent;
diff --git a/src/components/VirtualContest.js b/src/components/VirtualContest.js
new file mode 100644
index 0000000..a379906
--- /dev/null
+++ b/src/components/VirtualContest.js
@@ -0,0 +1,244 @@
+import React, { useEffect, useState } from "react";
+import propTypes from "prop-types";
+import { AddRemoveButton } from '../styles/add-remove-button'
+import 'regenerator-runtime';
+import emitUserDataEvent from "../helpers/EmitUserDataEvent";
+import { FaUndo } from "react-icons/fa";
+
+import {
+ TableContainer,
+ Table,
+ TBody,
+ THead,
+ Tr,
+ Th,
+ Td,
+} from "../styles/table";
+
+import { TIME_OUT_LIMIT } from "../Constants";
+import ContestSummary from "./ContestSummary";
+
+const VirtualContest = ({ data, virtualContestQuestions, setVirtualContestQuestions, setResponse }) => {
+ // console.log("DATA:", data);
+
+ const [ questionsData, setQuestionsData ] = useState(data);
+ const [ contestQuestions, setContestQuestions ] = useState(virtualContestQuestions);
+ const [ endingContest, setEndingContest ] = useState(false);
+ const [ contestEnded, setContestEnded ] = useState(false);
+ const [ fetchingData, setFetchingData ] = useState(false);
+ const [ dataFetched, setDataFetched ] = useState(false);
+
+ const handleEndButton = () => {
+ setEndingContest(true);
+ }
+
+ const handleEndContest = () => {
+ handleFetchData();
+ setContestEnded(true);
+ }
+
+ const handleCloseVirtualContest = () => {
+ setVirtualContestQuestions([]);
+ }
+
+ const handleGoBackToContest = () => {
+ setEndingContest(false);
+ }
+
+ const handleFetchData = () => {
+ setFetchingData(true);
+ emitUserDataEvent(setResponse, setQuestionsData);
+ emitUserDataEvent(setResponse);
+ }
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setFetchingData(true);
+ emitUserDataEvent(setResponse, setQuestionsData);
+ }, 1000*TIME_OUT_LIMIT );
+
+ return () => clearInterval(interval); // This represents the unmount function, in which you need to clear your interval to prevent memory leaks.
+
+ }, []);
+
+ useEffect(() => {
+ let updatedQuestionsList = [];
+ questionsData["stat_status_pairs"].forEach(que => {
+ let flag = 0;
+ virtualContestQuestions.forEach(question => {
+ if(que["stat"]["frontend_question_id"] === question["stat"]["frontend_question_id"]) {
+ flag=1;
+ console.log(que["stat"]["question__title"], que["status"])
+ }
+ });
+ if(flag === 1) {
+ updatedQuestionsList.push(que);
+ }
+ });
+ setVirtualContestQuestions(updatedQuestionsList);
+ setContestQuestions((prev) => {
+ return updatedQuestionsList;
+ });
+ setFetchingData(false);
+ setDataFetched(true);
+ const timer = setTimeout(() => {
+ setDataFetched(false);
+
+ return () => clearTimeout(timer);
+ }, 2000);
+ }, [questionsData]);
+
+ if(contestEnded) {
+ return (
+
+ Contest has ended !!
+
+
+ Close Summary
+
+
+ )
+ }
+
+ const fetchSuccess = !questionsData.shouldRunTimer;
+ const msg = (fetchSuccess)?"Status Updated Successfully!!" : "Fetching Status Failed ... ";
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ | ID |
+ Title |
+ Level |
+ Status |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {contestQuestions.map((que, index) => {
+
+ return (
+
+ |
+ {que["stat"]["frontend_question_id"]}
+ |
+
+
+ {que["stat"]["question__title"]}
+
+ |
+
+ {que["difficulty"]["level"] == 1
+ ? "Easy"
+ : que["difficulty"]["level"] == 2
+ ? "Medium"
+ : "Hard"}
+ |
+
+
+ {
+ que["status"]==="notac"
+ ?"Not AC"
+ :que["status"]==="ac"
+ ?"AC"
+ :"Not Attempted"
+ }
+
+ |
+
+ );
+ })}
+
+
+
+
+ End Virtual Contest
+
+
+
+ Fetch Status
+
+
+
+ {
+ fetchingData
+ ?
+ Fetching Status ...
+
+ :null
+ }
+
+ {
+ dataFetched && !fetchingData
+ ?
+ {msg}
+
+ :null
+ }
+
+ {
+ endingContest
+ ?
+
+ Are you sure to end the contest?
+
+ Yes
+ Go back to contest
+
+ :null
+ }
+
+ )
+}
+
+VirtualContest.propTypes = {
+ data: propTypes.shape({
+ stat_status_pairs: propTypes.arrayOf(
+ propTypes.shape({
+ difficulty: propTypes.shape({ level: propTypes.number }),
+ stat: propTypes.shape({
+ question__title: propTypes.string,
+ question__title_slug: propTypes.string,
+ }),
+ level: propTypes.number,
+ status: propTypes.string,
+ })
+ ),
+ }),
+ virtualContestQuestions: propTypes.arrayOf(
+ propTypes.shape({
+ difficulty: propTypes.shape({ level: propTypes.number }),
+ stat: propTypes.shape({
+ question__title: propTypes.string,
+ question__title_slug: propTypes.string,
+ }),
+ level: propTypes.number,
+ status: propTypes.string,
+ })
+ ),
+ setVirtualContestQuestions: propTypes.func,
+ setResponse: propTypes.func,
+};
+
+export default VirtualContest;
diff --git a/src/components/VirtualContestTable.js b/src/components/VirtualContestTable.js
new file mode 100644
index 0000000..34d1669
--- /dev/null
+++ b/src/components/VirtualContestTable.js
@@ -0,0 +1,240 @@
+import React, { useState, useEffect } from "react";
+import propTypes from "prop-types";
+import { AddRemoveButton } from '../styles/add-remove-button'
+import 'regenerator-runtime';
+import { Scrollable } from "../styles/scrollbar";
+
+import {
+ TableContainer,
+ Table,
+ TBody,
+ THead,
+ Tr,
+ Th,
+ Td,
+} from "../styles/table";
+import { CategoryButton } from "../styles/category";
+import Popup from "./Popup";
+import VirtualContest from "./VirtualContest";
+
+const VirtualContestTable = ({ data, virtualContestQuestions, setVirtualContestQuestions, setResponse }) => {
+ console.log("DATA:", data);
+
+ const [ selectedQuestions, setSelectedQuestions ] = useState([]);
+ const [ popup, setPopup ] = useState(false);
+
+ const handleStartVirtualContest = () => {
+ if(selectedQuestions.length<2 || selectedQuestions.length>5) {
+ setPopup(true);
+ return;
+ }
+ console.log("Virtual contest has started");
+ let questionsList = selectedQuestions;
+ setSelectedQuestions([]);
+ setVirtualContestQuestions(questionsList);
+ }
+
+ const handleOnClick = (que) => {
+
+ setSelectedQuestions(prevQues => {
+ let newSelectedQues = []; //new list of selected questions
+ let flag=0; //flag=1 if question in list, else 0
+ prevQues.forEach(question => {
+ if(question["stat"]["question__title_slug"] == que["stat"]["question__title_slug"]) {
+ flag = 1;
+ }
+ });
+ prevQues.forEach(question => { //add rest of the questions
+ if(question["stat"]["question__title_slug"] != que["stat"]["question__title_slug"]) {
+ newSelectedQues.push(question);
+ }
+ });
+ if(flag == 0) { //if flag=0(i.e. question not in current list) then add this question to the new list
+ newSelectedQues.push(que);
+ }
+ return newSelectedQues;
+ });
+ }
+
+ if(virtualContestQuestions.length>=2 && virtualContestQuestions.length<=5) {
+ return (
+
+ )
+ }
+
+ return (
+
+ {popup && (
+
+ )}
+
+ Start Virtual Contest
+
+
+
+
+
+
+
+
+
+
+ | ID |
+ Title |
+ Level |
+ Status |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {selectedQuestions.map((que, index) => {
+
+ //displaying the selected questions
+
+ return (
+
+ |
+ {que["stat"]["frontend_question_id"]}
+ |
+
+
+ {que["stat"]["question__title"]}
+
+ |
+
+ {que["difficulty"]["level"] == 1
+ ? "Easy"
+ : que["difficulty"]["level"] == 2
+ ? "Medium"
+ : "Hard"}
+ |
+
+ handleOnClick(que)} isRemoveButton={true} >
+ Remove
+
+ |
+
+ );
+ })}
+
+
+
+
+
+
+
+
+
+
+
+
+ {data["stat_status_pairs"].map((que, index) => {
+
+ if(que["status"] === "ac" || que["status"] === "notac" || que["paid_only"]==true) { // return null if attempted or paid
+ return null;
+ }
+
+ let isSelected = false;
+ selectedQuestions.forEach(question => {
+ if(question["stat"]["question__title_slug"] == que["stat"]["question__title_slug"]) {
+ isSelected=true;
+ }
+ });
+
+ if(isSelected) {
+ return null;
+ }
+
+ // if free and not attempted then return as a row for the table
+ return (
+
+ |
+ {que["stat"]["frontend_question_id"]}
+ |
+
+
+ {que["stat"]["question__title"]}
+
+ |
+
+ {que["difficulty"]["level"] == 1
+ ? "Easy"
+ : que["difficulty"]["level"] == 2
+ ? "Medium"
+ : "Hard"}
+ |
+
+ {/* handleOnClick(que["stat"]["question__title_slug"])} isRemoveButton={isSelected} > */}
+ handleOnClick(que)} isRemoveButton={isSelected} >
+ { (isSelected)? "Remove" : "Add" }
+
+ |
+
+ );
+ })}
+
+
+
+
+ );
+};
+
+VirtualContestTable.propTypes = {
+ data: propTypes.shape({
+ stat_status_pairs: propTypes.arrayOf(
+ propTypes.shape({
+ difficulty: propTypes.shape({ level: propTypes.number }),
+ stat: propTypes.shape({
+ question__title: propTypes.string,
+ question__title_slug: propTypes.string,
+ }),
+ level: propTypes.number,
+ status: propTypes.string,
+ })
+ ),
+ }),
+ virtualContestQuestions: propTypes.arrayOf(
+ propTypes.shape({
+ difficulty: propTypes.shape({ level: propTypes.number }),
+ stat: propTypes.shape({
+ question__title: propTypes.string,
+ question__title_slug: propTypes.string,
+ }),
+ level: propTypes.number,
+ status: propTypes.string,
+ })
+ ),
+ setVirtualContestQuestions: propTypes.func,
+ setResponse: propTypes.func,
+};
+
+export default VirtualContestTable;
diff --git a/src/helpers/EmitUserDataEvent.js b/src/helpers/EmitUserDataEvent.js
index f9170f9..b6205e3 100644
--- a/src/helpers/EmitUserDataEvent.js
+++ b/src/helpers/EmitUserDataEvent.js
@@ -1,24 +1,45 @@
import { ipcRenderer } from "electron";
+import { USER_DATA_EVENT } from "../Constants";
import getTimerValueBasedOnResponse from "./GetTimerValueBasedOnResponse";
-const emitUserDataEvent = (setResponse) => {
- ipcRenderer.send("user-data");
- ipcRenderer.on("user-data", (e, res) => {
- console.log("Client Receiver in APP:", res);
+const emitUserDataEvent = (setResponse, setQuestionsData) => {
+ ipcRenderer.send(USER_DATA_EVENT);
+ ipcRenderer.on(USER_DATA_EVENT, (e, res) => {
+ console.log("Client Receiver in APP:", res);
+ if(setQuestionsData) {
+ setQuestionsData(prev => {
+ const timerValue = getTimerValueBasedOnResponse(res.message);
+ if(timerValue === 0) {
+ return ({
+ ...res.data,
+ message: { ...res.message, isLoading: false },
+ timer: timerValue,
+ shouldRunTimer: timerValue !== 0,
+ })
+ } else {
+ return ({
+ ...prev,
+ message: { ...res.message, isLoading: false },
+ timer: timerValue,
+ shouldRunTimer: timerValue !== 0,
+ })
+ }
+ });
+ } else {
+ setResponse((prev) => {
+ const timerValue = getTimerValueBasedOnResponse(res.message);
+ return {
+ ...res,
+ message: { ...res.message, isLoading: false },
+ timer: timerValue,
+ shouldRunTimer: timerValue !== 0,
+ };
+ });
+ }
- setResponse((prev) => {
- const timerValue = getTimerValueBasedOnResponse(res.message);
- return {
- ...res,
- message: { ...res.message, isLoading: false },
- timer: timerValue,
- shouldRunTimer: timerValue !== 0,
- };
- });
-
- // Removing all listeners to this event after getting the response.
- ipcRenderer.removeAllListeners();
- });
+ // Removing all listeners to this event after getting the response.
+ ipcRenderer.removeAllListeners();
+ });
};
export default emitUserDataEvent;
diff --git a/src/static/gifs/iDontBelieveThat.gif b/src/static/gifs/iDontBelieveThat.gif
new file mode 100644
index 0000000..518255b
Binary files /dev/null and b/src/static/gifs/iDontBelieveThat.gif differ
diff --git a/src/static/gifs/iDontBelieveThat.mp4 b/src/static/gifs/iDontBelieveThat.mp4
new file mode 100644
index 0000000..966a393
Binary files /dev/null and b/src/static/gifs/iDontBelieveThat.mp4 differ
diff --git a/src/static/images/random.png b/src/static/images/random.png
new file mode 100644
index 0000000..1d004fd
Binary files /dev/null and b/src/static/images/random.png differ
diff --git a/src/styles/add-remove-button.js b/src/styles/add-remove-button.js
new file mode 100644
index 0000000..af9dbce
--- /dev/null
+++ b/src/styles/add-remove-button.js
@@ -0,0 +1,27 @@
+import styled, { css } from "styled-components";
+
+//Styled component for LogOut button
+
+export const AddRemoveButton = styled.button`
+ background: transparent;
+ border-radius: 3px;
+ border: 2px solid #ff00e0;
+ color: white;
+ font-family: "Cool Font";
+ padding: 0.25em 1em;
+ margin: 0 10px 0 10px;
+ ${(props) =>
+ props &&
+ (
+ (props.isRemoveButton &&
+ css`
+ color: #ff0000;
+ `)
+ ||
+ (props.isAddButton &&
+ css`
+ color: #39ff14;
+ `)
+ )
+ }
+`;
diff --git a/src/styles/cookie-form.js b/src/styles/cookie-form.js
index 6c19aa8..a0c82f7 100644
--- a/src/styles/cookie-form.js
+++ b/src/styles/cookie-form.js
@@ -1,6 +1,6 @@
import styled, { keyframes } from "styled-components";
import { backgroundImageProperty } from "./constants";
-import { greetingAnimation } from "./navbar";
+import { greetingAnimation } from "./header";
export const Div = styled.div`
display: flex;
@@ -12,6 +12,16 @@ export const Div = styled.div`
padding: 5px;
background-image: ${backgroundImageProperty};
`;
+export const Div1 = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-self: center;
+ width: 500px;
+ height: 500px;
+ padding: 5px;
+
+`;
export const Textarea = styled.textarea`
resize: none;
diff --git a/src/styles/footer.js b/src/styles/footer.js
new file mode 100644
index 0000000..e6a1fa9
--- /dev/null
+++ b/src/styles/footer.js
@@ -0,0 +1,18 @@
+import styled, { keyframes, css } from "styled-components";
+import { backgroundImageProperty } from "./constants";
+export const rotate = keyframes`
+0%{opacity: 0.75}
+ 30% { opacity: 1 }
+ 60% { opacity: 0.75; }
+ 100% { opacity: 0.5;
+}`;
+export const Rotate = styled.div`
+display : inline-flex;
+animation: ${rotate} 0.5s linear infinite;
+`;
+export const Div = styled.div`
+ color: #39ff14;
+ padding: 10px;
+ background-image: ${backgroundImageProperty};
+ margin-top: auto;
+`;
diff --git a/src/styles/navbar.js b/src/styles/header.js
similarity index 97%
rename from src/styles/navbar.js
rename to src/styles/header.js
index 21f8f1c..ec362df 100644
--- a/src/styles/navbar.js
+++ b/src/styles/header.js
@@ -28,6 +28,7 @@ export const Div = styled.div`
? css`
font-family: "Tetris Font";
margin: 0 0 0 10px;
+ cursor: pointer;
`
: css`
flex-basis: 20%;
diff --git a/src/styles/logout-button.js b/src/styles/logout-button.js
new file mode 100644
index 0000000..49c46b6
--- /dev/null
+++ b/src/styles/logout-button.js
@@ -0,0 +1,21 @@
+import styled, { css } from "styled-components";
+
+//Styled component for LogOut button
+
+export const LogOutButton = styled.button`
+ background: transparent;
+ border-radius: 3px;
+ border: 2px solid #ff00e0;
+ color: white;
+ font-family: "Cool Font";
+ padding: 0.25em 1em;
+ margin: 0 10px 0 10px;
+ position: absolute;
+ right: 20px;
+ ${(props) =>
+ props &&
+ props.isLogOutButton &&
+ css`
+ color: #ff0000;
+ `}
+`;
diff --git a/src/styles/scrollbar.js b/src/styles/scrollbar.js
new file mode 100644
index 0000000..b51c774
--- /dev/null
+++ b/src/styles/scrollbar.js
@@ -0,0 +1,11 @@
+import styled, { css } from "styled-components";
+
+export const Scrollable = styled.div`
+ overflow: auto;
+ ${(props) =>
+ props &&
+ props.maxHeight &&
+ css`
+ max-height: ${props.maxHeight};
+ `}
+`;
diff --git a/src/styles/shuffle_button.js b/src/styles/shuffle_button.js
new file mode 100644
index 0000000..bd4a6cd
--- /dev/null
+++ b/src/styles/shuffle_button.js
@@ -0,0 +1,32 @@
+import styled, { css } from "styled-components";
+
+export const ShuffleButton = styled.a`
+ border-bottom: 1px dashed;
+ text-decoration: none;
+ hover {
+ cursor: help;
+ position: relative;
+ }
+ span {
+ display: none;
+ }
+ hover span {
+ border: #666 2px dotted;
+ padding: 5px 20px 5px 5px;
+ display: block;
+ z-index: 100;
+ background: #e3e3e3;
+ left: 0px;
+ margin: 15px;
+ width: 300px;
+ position: absolute;
+ top: 15px;
+ text-decoration: none;
+ }
+ ${(props) =>
+ props &&
+ props.maxHeight &&
+ css`
+ max-height: ${props.maxHeight};
+ `}
+`;
diff --git a/src/styles/shufflestyle.js b/src/styles/shufflestyle.js
new file mode 100644
index 0000000..d27d2cc
--- /dev/null
+++ b/src/styles/shufflestyle.js
@@ -0,0 +1,51 @@
+import styled, { css } from "styled-components";
+export const shufflestyle = {
+ borderBottom: "1px dashed",
+
+ ":hover": {
+ cursor: "help",
+ position: "relative",
+ color: "yellow",
+ },
+ span: {
+ display: "none",
+ },
+ ":hover span": {
+ border: "#666 2px dotted",
+ padding: "5px 20px 5px 5px",
+ display: "block",
+ "z-index": "100",
+ background: "#e3e3e3",
+ left: "0px",
+ margin: "15px",
+ width: "300px",
+ position: " absolute",
+ top: "15px",
+ "text-decoration": "none",
+ },
+};
+export const ShuffleButton = styled.a`
+ href: "#";
+ border-bottom: 1px dashed;
+ text-decoration: none;
+ &:hover {
+ position: relative;
+ }
+ span {
+ display: none;
+ position: relative;
+ }
+ &:hover span {
+ border: #39ff14 2px dashed;
+ display: block;
+ z-index: 2;
+ background: black;
+ left: -300px;
+ font-size: 12px;
+ margin: 15px;
+ width: 200px;
+ position: absolute;
+ top: 0px;
+ text-decoration: none;
+ }
+`;