mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-10-10 07:36:09 +08:00
added quote rating
This commit is contained in:
parent
166b6c10e7
commit
db3d25c7ef
7 changed files with 422 additions and 2 deletions
|
@ -129,6 +129,7 @@ const refactoredSrc = [
|
|||
|
||||
"./src/js/popups/custom-text-popup.js",
|
||||
"./src/js/popups/quote-search-popup.js",
|
||||
"./src/js/popups/rate-quote-popup.js",
|
||||
"./src/js/popups/version-popup.js",
|
||||
"./src/js/popups/support-popup.js",
|
||||
"./src/js/popups/custom-word-amount-popup.js",
|
||||
|
|
|
@ -54,6 +54,7 @@ export async function initSnapshot() {
|
|||
started: 0,
|
||||
completed: 0,
|
||||
},
|
||||
quoteRatings: undefined,
|
||||
};
|
||||
let snap = defaultSnap;
|
||||
try {
|
||||
|
@ -70,6 +71,7 @@ export async function initSnapshot() {
|
|||
started: userData.startedTests,
|
||||
completed: userData.completedTests,
|
||||
};
|
||||
snap.quoteRatings = userData.quoteRatings;
|
||||
snap.favouriteThemes =
|
||||
userData.favouriteThemes === undefined ? [] : userData.favouriteThemes;
|
||||
try {
|
||||
|
|
203
src/js/popups/rate-quote-popup.js
Normal file
203
src/js/popups/rate-quote-popup.js
Normal file
|
@ -0,0 +1,203 @@
|
|||
import * as DB from "./db";
|
||||
import * as Loader from "./loader";
|
||||
import * as Notifications from "./notifications";
|
||||
import axiosInstance from "./axios-instance";
|
||||
|
||||
let rating = 0;
|
||||
|
||||
let currentQuote = null;
|
||||
let quoteStats = null;
|
||||
|
||||
function reset() {
|
||||
$(`#rateQuotePopup .quote .text`).text("-");
|
||||
$(`#rateQuotePopup .quote .source .val`).text("-");
|
||||
$(`#rateQuotePopup .quote .id .val`).text("-");
|
||||
$(`#rateQuotePopup .quote .length .val`).text("-");
|
||||
$("#rateQuotePopup .ratingCount .val").text("-");
|
||||
$("#rateQuotePopup .ratingAverage .val").text("-");
|
||||
}
|
||||
|
||||
export function show(quote) {
|
||||
if ($("#rateQuotePopupWrapper").hasClass("hidden")) {
|
||||
reset();
|
||||
|
||||
currentQuote = quote;
|
||||
rating = 0;
|
||||
let alreadyRated = DB.getSnapshot().quoteRatings?.[currentQuote.language]?.[
|
||||
currentQuote.id
|
||||
];
|
||||
if (alreadyRated) {
|
||||
rating = alreadyRated;
|
||||
}
|
||||
refreshStars();
|
||||
updateData();
|
||||
$("#rateQuotePopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 0)
|
||||
.removeClass("hidden")
|
||||
.animate({ opacity: 1 }, 125);
|
||||
}
|
||||
}
|
||||
|
||||
function hide() {
|
||||
if (!$("#rateQuotePopupWrapper").hasClass("hidden")) {
|
||||
$("#rateQuotePopupWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
.animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
100,
|
||||
(e) => {
|
||||
$("#rateQuotePopupWrapper").addClass("hidden");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function refreshStars(force) {
|
||||
let limit = force ? parseInt(force) : rating;
|
||||
$(`#rateQuotePopup .star`).removeClass("active");
|
||||
for (let i = 1; i <= limit; i++) {
|
||||
$(`#rateQuotePopup .star[rating=${i}]`).addClass("active");
|
||||
}
|
||||
}
|
||||
|
||||
function updateData() {
|
||||
let lengthDesc;
|
||||
if (currentQuote.group == 0) {
|
||||
lengthDesc = "short";
|
||||
} else if (currentQuote.group == 1) {
|
||||
lengthDesc = "medium";
|
||||
} else if (currentQuote.group == 2) {
|
||||
lengthDesc = "long";
|
||||
} else if (currentQuote.group == 3) {
|
||||
lengthDesc = "thicc";
|
||||
}
|
||||
$(`#rateQuotePopup .quote .text`).text(currentQuote.text);
|
||||
$(`#rateQuotePopup .quote .source .val`).text(currentQuote.source);
|
||||
$(`#rateQuotePopup .quote .id .val`).text(currentQuote.id);
|
||||
$(`#rateQuotePopup .quote .length .val`).text(lengthDesc);
|
||||
updateRatingStats();
|
||||
}
|
||||
|
||||
export async function getQuoteStats(quote) {
|
||||
if (quote) currentQuote = quote;
|
||||
let response;
|
||||
try {
|
||||
response = await axiosInstance.get("/quote-ratings/get", {
|
||||
params: { quoteId: currentQuote.id, language: currentQuote.language },
|
||||
});
|
||||
} catch (e) {
|
||||
Loader.hide();
|
||||
let msg = e?.response?.data?.message ?? e.message;
|
||||
Notifications.add("Failed to get quote ratings: " + msg, -1);
|
||||
return;
|
||||
}
|
||||
Loader.hide();
|
||||
if (response.status !== 200) {
|
||||
Notifications.add(response.data.message);
|
||||
} else {
|
||||
quoteStats = response.data;
|
||||
if (quoteStats) {
|
||||
quoteStats.average = (
|
||||
Math.round((quoteStats.totalRating / quoteStats.ratings) * 10) / 10
|
||||
).toFixed(1);
|
||||
}
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export function clearQuoteStats() {
|
||||
quoteStats = undefined;
|
||||
}
|
||||
|
||||
async function updateRatingStats() {
|
||||
if (quoteStats === null) await getQuoteStats();
|
||||
if (quoteStats === undefined) {
|
||||
$("#rateQuotePopup .ratingCount .val").text("0");
|
||||
$("#rateQuotePopup .ratingAverage .val").text("-");
|
||||
} else {
|
||||
$("#rateQuotePopup .ratingCount .val").text(quoteStats.ratings);
|
||||
$("#rateQuotePopup .ratingAverage .val").text(quoteStats.average);
|
||||
}
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (rating == 0) {
|
||||
Notifications.add("Please select a rating");
|
||||
return;
|
||||
}
|
||||
hide();
|
||||
let response;
|
||||
try {
|
||||
response = await axiosInstance.post("/quote-ratings/submit", {
|
||||
quoteId: currentQuote.id,
|
||||
rating: rating,
|
||||
language: currentQuote.language,
|
||||
});
|
||||
} catch (e) {
|
||||
Loader.hide();
|
||||
let msg = e?.response?.data?.message ?? e.message;
|
||||
Notifications.add("Failed to submit quote rating: " + msg, -1);
|
||||
return;
|
||||
}
|
||||
Loader.hide();
|
||||
if (response.status !== 200) {
|
||||
Notifications.add(response.data.message);
|
||||
} else {
|
||||
let quoteRatings = DB.getSnapshot().quoteRatings;
|
||||
if (quoteRatings?.[currentQuote.language]?.[currentQuote.id]) {
|
||||
let oldRating = quoteRatings[currentQuote.language][currentQuote.id];
|
||||
let diff = rating - oldRating;
|
||||
quoteStats.totalRating += diff;
|
||||
|
||||
quoteRatings[currentQuote.language][currentQuote.id] = rating;
|
||||
Notifications.add("Rating updated", 1);
|
||||
} else {
|
||||
if (quoteRatings === undefined) quoteRatings = {};
|
||||
if (quoteRatings[currentQuote.language] === undefined)
|
||||
quoteRatings[currentQuote.language] = {};
|
||||
if (quoteRatings[currentQuote.language][currentQuote.id] == undefined)
|
||||
quoteRatings[currentQuote.language][currentQuote.id] = undefined;
|
||||
quoteRatings[currentQuote.language][currentQuote.id] = rating;
|
||||
quoteStats = {
|
||||
ratings: 1,
|
||||
totalRating: parseInt(rating),
|
||||
quoteId: currentQuote.id,
|
||||
language: currentQuote.language,
|
||||
};
|
||||
Notifications.add("Rating submitted", 1);
|
||||
}
|
||||
quoteStats.average = (
|
||||
Math.round((quoteStats.totalRating / quoteStats.ratings) * 10) / 10
|
||||
).toFixed(1);
|
||||
$(".pageTest #result #rateQuoteButton .rating").text(quoteStats.average);
|
||||
}
|
||||
}
|
||||
|
||||
$("#rateQuotePopupWrapper").click((e) => {
|
||||
if ($(e.target).attr("id") === "rateQuotePopupWrapper") {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#rateQuotePopup .stars .star").hover((e) => {
|
||||
let ratingHover = $(e.currentTarget).attr("rating");
|
||||
refreshStars(ratingHover);
|
||||
});
|
||||
|
||||
$("#rateQuotePopup .stars .star").click((e) => {
|
||||
let ratingHover = $(e.currentTarget).attr("rating");
|
||||
rating = ratingHover;
|
||||
});
|
||||
|
||||
$("#rateQuotePopup .stars .star").mouseout((e) => {
|
||||
$(`#rateQuotePopup .star`).removeClass("active");
|
||||
refreshStars();
|
||||
});
|
||||
|
||||
$("#rateQuotePopup .submitButton").click((e) => {
|
||||
submit();
|
||||
});
|
|
@ -35,6 +35,7 @@ import * as TodayTracker from "./today-tracker";
|
|||
import * as WeakSpot from "./weak-spot";
|
||||
import * as Wordset from "./wordset";
|
||||
import * as ChallengeContoller from "./challenge-controller";
|
||||
import * as RateQuotePopup from "./rate-quote-popup";
|
||||
|
||||
let glarsesMode = false;
|
||||
|
||||
|
@ -707,6 +708,7 @@ export async function init() {
|
|||
rq.text = rq.text.replace(/( *(\r\n|\r|\n) *)/g, "\n ");
|
||||
rq.text = rq.text.replace(/…/g, "...");
|
||||
rq.text = rq.text.trim();
|
||||
rq.language = Config.language.replace(/_\d*k$/g, "");
|
||||
|
||||
setRandomQuote(rq);
|
||||
|
||||
|
@ -849,6 +851,7 @@ export function restart(
|
|||
$("#showWordHistoryButton").removeClass("loaded");
|
||||
TestUI.focusWords();
|
||||
Funbox.resetMemoryTimer();
|
||||
RateQuotePopup.clearQuoteStats();
|
||||
|
||||
TestUI.reset();
|
||||
|
||||
|
@ -1586,6 +1589,17 @@ export async function finish(difficultyFailed = false) {
|
|||
) {
|
||||
if (firebase.auth().currentUser != null) {
|
||||
completedEvent.uid = firebase.auth().currentUser.uid;
|
||||
|
||||
let quoteStats = await RateQuotePopup.getQuoteStats(randomQuote);
|
||||
if (quoteStats !== null) {
|
||||
$(".pageTest #result #rateQuoteButton .rating").text(
|
||||
quoteStats.average
|
||||
);
|
||||
} else {
|
||||
$(".pageTest #result #rateQuoteButton .rating").text("");
|
||||
}
|
||||
$(".pageTest #result #rateQuoteButton").removeClass("hidden");
|
||||
|
||||
//check local pb
|
||||
AccountButton.loading(true);
|
||||
let dontShowCrown = false;
|
||||
|
@ -1857,6 +1871,7 @@ export async function finish(difficultyFailed = false) {
|
|||
});
|
||||
});
|
||||
} else {
|
||||
$(".pageTest #result #rateQuoteButton").addClass("hidden");
|
||||
try {
|
||||
firebase.analytics().logEvent("testCompletedNoLogin", completedEvent);
|
||||
} catch (e) {
|
||||
|
|
|
@ -18,6 +18,7 @@ import * as TestStats from "./test-stats";
|
|||
import * as Misc from "./misc";
|
||||
import * as TestUI from "./test-ui";
|
||||
import * as ChallengeController from "./challenge-controller";
|
||||
import * as RateQuotePopup from "./rate-quote-popup";
|
||||
|
||||
export let currentWordElementIndex = 0;
|
||||
export let resultVisible = false;
|
||||
|
@ -934,6 +935,10 @@ $(".pageTest #copyWordsListButton").click(async (event) => {
|
|||
}
|
||||
});
|
||||
|
||||
$(".pageTest #rateQuoteButton").click(async (event) => {
|
||||
RateQuotePopup.show(TestLogic.randomQuote);
|
||||
});
|
||||
|
||||
$(".pageTest #toggleBurstHeatmap").click(async (event) => {
|
||||
UpdateConfig.setBurstHeatmap(!Config.burstHeatmap);
|
||||
});
|
||||
|
|
|
@ -713,6 +713,114 @@ label.checkbox {
|
|||
}
|
||||
}
|
||||
|
||||
#rateQuotePopupWrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 5rem 0;
|
||||
|
||||
#rateQuotePopup {
|
||||
color: var(--sub-color);
|
||||
background: var(--bg-color);
|
||||
border-radius: var(--roundness);
|
||||
padding: 2rem;
|
||||
display: grid;
|
||||
gap: 2rem;
|
||||
width: 1000px;
|
||||
|
||||
display: grid;
|
||||
grid-template-areas: "ratingStats ratingStats submitButton" "spacer spacer spacer" "quote quote quote";
|
||||
grid-template-columns: auto 1fr;
|
||||
|
||||
color: var(--text-color);
|
||||
|
||||
.spacer {
|
||||
grid-area: spacer;
|
||||
grid-column: 1/4;
|
||||
width: 100%;
|
||||
height: 0.1rem;
|
||||
border-radius: var(--roundness);
|
||||
background: var(--sub-color);
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.submitButton {
|
||||
font-size: 2rem;
|
||||
grid-area: submitButton;
|
||||
color: var(--sub-color);
|
||||
&:hover {
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
|
||||
.top {
|
||||
color: var(--sub-color);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.ratingStats {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
grid-area: ratingStats;
|
||||
.top {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.val {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.quote {
|
||||
display: grid;
|
||||
grid-area: quote;
|
||||
gap: 1rem;
|
||||
grid-template-areas:
|
||||
"text text text"
|
||||
"id length source";
|
||||
grid-template-columns: 1fr 1fr 3fr;
|
||||
.text {
|
||||
grid-area: text;
|
||||
}
|
||||
.id {
|
||||
grid-area: id;
|
||||
}
|
||||
.length {
|
||||
grid-area: length;
|
||||
}
|
||||
.source {
|
||||
grid-area: source;
|
||||
}
|
||||
}
|
||||
|
||||
.stars {
|
||||
display: grid;
|
||||
color: var(--sub-color);
|
||||
font-size: 2rem;
|
||||
grid-template-columns: auto auto auto auto auto;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.star {
|
||||
transition: 0.125s;
|
||||
}
|
||||
i {
|
||||
pointer-events: none;
|
||||
}
|
||||
.star.active {
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#simplePopupWrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -2129,6 +2237,7 @@ key {
|
|||
color: var(--sub-color);
|
||||
font-size: 1rem;
|
||||
line-height: 1rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
|
@ -2146,6 +2255,10 @@ key {
|
|||
margin-left: 0.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.source #rateQuoteButton {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
// .infoAndTags {
|
||||
|
|
|
@ -137,6 +137,75 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="rateQuotePopupWrapper" class="hidden">
|
||||
<div id="rateQuotePopup" quoteId="">
|
||||
<div class="quote">
|
||||
<div class="text">-</div>
|
||||
<div class="id">
|
||||
<div class="top">id</div>
|
||||
<div class="val">-</div>
|
||||
</div>
|
||||
<div class="length">
|
||||
<div class="top">length</div>
|
||||
<div class="val">-</div>
|
||||
</div>
|
||||
<div class="source">
|
||||
<div class="top">source</div>
|
||||
<div class="val">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="ratingStats">
|
||||
<div class="ratingCount">
|
||||
<div class="top">ratings</div>
|
||||
<div class="val">-</div>
|
||||
</div>
|
||||
<div class="ratingAverage">
|
||||
<div class="top">average</div>
|
||||
<div class="val">-</div>
|
||||
</div>
|
||||
<div class="starsWrapper">
|
||||
<div class="top">your rating</div>
|
||||
<div class="stars">
|
||||
<div class="star active" rating="1">
|
||||
<i class="fas fa-fw fa-star"></i>
|
||||
</div>
|
||||
<div class="star active" rating="2">
|
||||
<i class="fas fa-fw fa-star"></i>
|
||||
</div>
|
||||
<div class="star active" rating="3">
|
||||
<i class="fas fa-fw fa-star"></i>
|
||||
</div>
|
||||
<div class="star" rating="4">
|
||||
<i class="fas fa-fw fa-star"></i>
|
||||
</div>
|
||||
<div class="star" rating="5">
|
||||
<i class="fas fa-fw fa-star"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="button rate1">
|
||||
<i class="fas fa-star"></i>
|
||||
<i class="far fa-star"></i>
|
||||
<i class="far fa-star"></i>
|
||||
</div>
|
||||
<div class="button rate2">
|
||||
<i class="fas fa-star"></i>
|
||||
<i class="fas fa-star"></i>
|
||||
<i class="far fa-star"></i>
|
||||
</div>
|
||||
<div class="button rate3">
|
||||
<i class="fas fa-star"></i>
|
||||
<i class="fas fa-star"></i>
|
||||
<i class="fas fa-star"></i>
|
||||
</div> -->
|
||||
<div class="icon-button submitButton">
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="settingsImportWrapper" class="hidden">
|
||||
<div id="settingsImport" action="">
|
||||
<input type="text" />
|
||||
|
@ -1498,7 +1567,7 @@
|
|||
<div class="group flat consistency">
|
||||
<div class="top">consistency</div>
|
||||
<div class="bottom" aria-label="" data-balloon-pos="up">
|
||||
-
|
||||
2 -
|
||||
</div>
|
||||
</div>
|
||||
<div class="group time">
|
||||
|
@ -1512,7 +1581,19 @@
|
|||
<!-- </div> -->
|
||||
|
||||
<div class="group source hidden">
|
||||
<div class="top">source</div>
|
||||
<div class="top">
|
||||
source
|
||||
<span
|
||||
id="rateQuoteButton"
|
||||
class="icon-button hidden"
|
||||
aria-label="Rate quote"
|
||||
data-balloon-pos="up"
|
||||
style="display: inline-block"
|
||||
>
|
||||
<i class="far fa-star"></i>
|
||||
<span class="rating"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="bottom">-</div>
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue