Copy Code
Copy Code
DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Codeforces Profile Analyzer</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
import axios from "axios";
return apiClient;
};
useEffect(() => {
if (parentData) {
setData([axisTitle, ...getData(parentData)]);
}
}, [parentData, getData, axisTitle]);
.react-calendar-heatmap rect:hover {
stroke: #555;
stroke-width: 1px;
}
.react-calendar-heatmap .color-empty {
fill: #eeeeee;
}
.react-calendar-heatmap .color-1 {
fill: #8cc665;
}
.react-calendar-heatmap .color-2 {
fill: #44a340;
}
.react-calendar-heatmap .color-3 {
fill: #1e6823;
}
import { useEffect, useState } from "react";
import CalendarHeatmap from "react-calendar-heatmap";
import moment from "moment";
import "./index.css";
import ReactTooltip from "react-tooltip";
useEffect(() => {
if (year) {
const start_date = moment(`01-01-${year}`).toDate();
const end_date = moment(`12-31-${year}`).toDate();
setStartDate(start_date);
setEndDate(end_date);
} else {
setStartDate(moment(new Date()).subtract(1, "years").toDate());
setEndDate(new Date());
}
}, [year]);
useEffect(() => {
if (parentData) {
setData(getData(parentData));
}
}, [parentData, getData]);
return data ? (
<>
<CalendarHeatmap
startDate={startDate}
endDate={endDate}
values={data}
classForValue={(value) => {
if (!value || value < 1) {
return "color-empty";
}
return `color-${value.count}`;
}}
showWeekdayLabels={true}
tooltipDataAttrs={(value) => {
if (value.date) {
return {
"data-tip": `${
value.numberOfSubmissions || 0
} submissions on ${moment(value.date).format("DD/MM/YYYY")}`,
};
}
}}
/>
<ReactTooltip />
</>
) : (
<></>
);
};
.MuiTableCell-head {
color: #ffffff !important;
}
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";
import Link from "@mui/material/Link";
import "./ContestTable.css";
useEffect(() => {
const sortedData = _.sortBy(parentData, ["ratingUpdateTimeSeconds"]);
if (sortedData.length > 0) {
last = moment.unix(sortedData[0].ratingUpdateTimeSeconds);
}
let step;
setHAxisTicks(temp);
// console.log(moment().subtract(1, "months").startOf("month").format("MMM"));
}, [parentData]);
useEffect(() => {
if (parentData) {
setData([axisTitle, ...getData(parentData)]);
}
}, [parentData, getData, axisTitle]);
const options = {
curveType: "function",
legend: { position: "bottom" },
hAxis: { ticks: hAxisTicks },
pointSize: 8,
};
return data ? (
<Chart
chartType="LineChart"
width="100%"
height="350px"
data={data}
options={options}
/>
) : null;
};
useEffect(() => {
if (parentData) {
const tempData = getData(parentData);
// sort nested array by index 1 item
tempData
.sort((a, b) => {
if (a[1] < b[1]) {
return -1;
} else if (a[1] > b[1]) {
return 1;
} else {
return 0;
}
})
.reverse();
setData([axisTitle, ...tempData]);
}
}, [parentData, getData, axisTitle]);
return data ? (
<Chart
height={400}
chartType="PieChart"
options={{ pieSliceText: "none" }}
data={data}
/>
) : (
<></>
);
};
if (!tried.has(name)) {
tried.add(name);
}
});
return {
tried: tried.size,
solved: solved.size,
unsolved: tried.size - solved.size,
};
};
data?.forEach((value) => {
const name = value?.problem?.name;
const verdict = value?.verdict;
if (!solved.has(name) && verdict === "OK") {
solved.add(name);
}
if (!tried.has(name)) {
tried.add(name);
triedMap[name] = value;
}
});
tried.forEach((name) => {
if (!solved.has(name)) {
const value = triedMap[name];
console.log(value);
arr.push({
name: `${contestId}-${problemIndex}`,
link: `https://codeforces.com/contest/${contestId}/problem/$
{problemIndex}`,
});
}
});
return arr;
};
return arr;
};
return arr;
};
return arr;
};
return arr;
};
return options;
}
return [
{ label: "Choose year" },
{ label: `${currentYear}`, value: `${currentYear}` },
];
};
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
const n = problemList.length;
const index = getRandomInt(n);
return problemList[index];
};
.main-container {
padding: 10px;
}
.app-heading {
text-align: center;
font-family: Arial, Helvetica, sans-serif;
}
.handle-input {
min-width: 200px;
padding: 8px;
outline: none;
}
.submit-button {
margin-left: 10px;
padding: 8px;
cursor: pointer;
border-radius: 5px;
background-color: #1769aa;
color: #ffffff;
border: 0;
font-size: 16px;
}
.error-message {
color: red;
}
.section-container {
padding: 10px;
padding-top: 2px;
background-color: white;
box-sizing: border-box;
margin: 20px 0;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2),
0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.unsolved-problems-container {
display: flex;
gap: 12px;
padding: 5px 10px;
flex-wrap: wrap;
}
a {
text-decoration: none;
color: blue;
}
.problemCardWrapper {
display: flex;
justify-content: center;
padding: 10px 0;
}
.problemCard {
padding: 20px;
cursor: pointer;
font-size: 18px;
display: flex;
gap: 20px;
}
.problemCard:hover {
background-color: lightgray;
}
import { useEffect, useState } from "react";
import apiClient from "./apis/apiClient";
import BarChart from "./components/BarChart";
import CalendarHeatMap from "./components/CalendarHeatMap";
import PieChart from "./components/PieChart";
import LineChart from "./components/LineChart";
import {
getProblemRatingDistribution,
getProblemTagDistribution,
getDataForCalendarHeatmap,
getContestRatingChanges,
getProblemsCount,
getUnsolvedProblems,
getYearsOptions,
getRandomProblem,
} from "./utils";
import "./App.css";
return d;
};
useEffect(() => {
if (data) {
setProblemsCount(getProblemsCount(data));
setUnsolvedProblemsList(getUnsolvedProblems(data));
setYearOptions(getYearsOptions(data));
}
}, [data]);
useEffect(() => {
getProblemList();
}, []);
useEffect(() => {
console.log("Problem list: ", problemList);
const randomProblem = getRandomProblem(problemList);
setProblem(randomProblem);
console.log("Random problem: ", randomProblem);
}, [problemList]);
let s = value.site;
if (!value.site) {
s = site
.split("_")
.map((txt) => txt.charAt(0).toUpperCase() + txt.slice(1))
.join("");
}
t = new Date(value.end_time);
const end_date = `${makeTwoDigit(t.getDate())}-${makeTwoDigit(
t.getMonth() + 1
)}-${t.getFullYear()}`;
const end_time = `${makeTwoDigit(t.getHours())}:${makeTwoDigit(
t.getMinutes()
)}`;
value = {
...value,
duration: d,
site: s,
start_date: start_date,
start_time: start_time,
end_date: end_date,
end_time: end_time,
};
return value;
});
setContestsList(data);
};
useEffect(() => {
fetchContestsList();
}, []);
return (
<div className="problemCardWrapper">
<div
className="problemCard"
onClick={() => {
window.location = link;
}}
>
<span>
{problem?.contestId}-{problem?.index}
</span>
<span>{problem.name}</span>
<span>{problem.rating}</span>
</div>
</div>
);
};
return (
<>
<div className="main-container">
<h2 className="app-heading">Codeforces Profile Analyzer</h2>
<input
className="handle-input"
type="text"
onChange={(e) => setUsername(e.target.value)}
placeholder="Enter codeforces handle"
/>
<button className="submit-button" onClick={fetchUserInfo}>
Search
</button>
{loading ? (
<Container
sx={{
display: "flex",
justifyContent: "center",
paddingTop: "200px",
}}
>
<ReactLoading type="spin" color="#000000" height={60} width={60} />
</Container>
) : (
data && (
<div style={{ marginTop: 20 }}>
<div className="section-container">
<h3>Solved Problem's Rating Distribution</h3>
<BarChart
getData={getProblemRatingDistribution}
data={data}
axisTitle={["Problem Rating", "Solved Count"]}
/>
</div>
<div className="section-container">
<h3>Solved Problem's Tags Distribution</h3>
<PieChart
getData={getProblemTagDistribution}
data={data}
axisTitle={["Problem Tag", "Solved Count"]}
/>
</div>
<div className="section-container">
<h3>User contest rating change</h3>
<LineChart
data={contestData}
getData={getContestRatingChanges}
axisTitle={["Time", "Rating"]}
/>
</div>
<div className="section-container">
<h3>Stats</h3>
{unsolvedProblemsList.length && (
<div className="section-container">
<h3>Unsolved Problems</h3>
<div className="unsolved-problems-container">
{unsolvedProblemsList.map((value) => (
<p>
<a href={value.link} target="_blank">
{value.name}
</a>
</p>
))}
</div>
</div>
)}
<div className="section-container">
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<h3>User Activity Heat Map</h3>
<div
style={{
width: 180,
}}
>
<Select
options={yearOptions}
onChange={(option) => {
setYear(option);
}}
value={year}
/>
</div>
</div>
<CalendarHeatMap
getData={getDataForCalendarHeatmap}
data={data}
year={year.value}
/>
</div>
<div className="section-container">
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<h3>Random problem</h3>
<button
className="submit-button"
onClick={() => {
setProblem(getRandomProblem(problemList));
}}
>
Search Problem
</button>
</div>
{displayProblem(problem)}
</div>
<div className="section-container">
<h3>Current or Upcoming Contests</h3>
<ToastContainer />
</>
);
};
body {
background-color: #f5f5f5;
}
body::-webkit-scrollbar {
background: white;
width: 8px;
}
body::-webkit-scrollbar-thumb {
background: rgb(118, 118, 118);
border-radius: 4px;
}
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";