mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2024-09-20 23:36:37 +08:00
refactor(edit tag): use new modal system
This commit is contained in:
parent
f47340b301
commit
4220c54de2
|
@ -791,15 +791,14 @@
|
|||
<div class="quotes"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tagsWrapper" class="popupWrapper hidden" tabindex="-1">
|
||||
<div id="tagsEdit" action="" tagid="">
|
||||
<form>
|
||||
<div class="title"></div>
|
||||
<input type="text" title="tag" />
|
||||
<button type="submit"></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<dialog id="editTagModal" class="modalWrapper hidden">
|
||||
<form class="modal">
|
||||
<div class="title"></div>
|
||||
<input type="text" title="tag" />
|
||||
<div class="text"></div>
|
||||
<button type="submit"></button>
|
||||
</form>
|
||||
</dialog>
|
||||
<dialog id="streakHourOffsetModal" class="modalWrapper hidden">
|
||||
<div class="modal">
|
||||
<div class="title">Set streak hour offset</div>
|
||||
|
|
|
@ -1469,6 +1469,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
#editTagModal {
|
||||
.modal {
|
||||
max-width: 450px;
|
||||
}
|
||||
}
|
||||
|
||||
#streakHourOffsetModal {
|
||||
.modal {
|
||||
max-width: 500px;
|
||||
|
@ -1493,9 +1499,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
#tagsWrapper,
|
||||
#newResultFilterPresetPopupWrapper {
|
||||
#tagsEdit,
|
||||
#newResultFilterPresetPopup {
|
||||
max-height: 90vh;
|
||||
background: var(--bg-color);
|
||||
|
@ -1511,12 +1515,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
#tagsEdit form,
|
||||
#presetEdit form {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
#editProfileModal {
|
||||
.modal {
|
||||
max-width: 600px;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as DB from "../../db";
|
||||
import * as EditTagsPopup from "../../popups/edit-tags-popup";
|
||||
import * as EditTagsPopup from "../../modals/edit-tag";
|
||||
import * as ModesNotice from "../../elements/modes-notice";
|
||||
import * as TagController from "../../controllers/tag-controller";
|
||||
import Config from "../../config";
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as ShareCustomThemeModal from "../modals/share-custom-theme";
|
|||
import * as CookiesModal from "../modals/cookies";
|
||||
import * as StreakHourOffsetModal from "../modals/streak-hour-offset";
|
||||
import * as EditPresetPopup from "../modals/edit-preset";
|
||||
import * as EditTagPopup from "../modals/edit-tag";
|
||||
|
||||
import * as Notifications from "../elements/notifications";
|
||||
|
||||
|
@ -69,3 +70,64 @@ settingsPage
|
|||
EditPresetPopup.show("remove", presetid, name);
|
||||
}
|
||||
});
|
||||
|
||||
settingsPage?.querySelector(".section.tags")?.addEventListener("click", (e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
if (target.classList.contains("addTagButton")) {
|
||||
EditTagPopup.show("add");
|
||||
} else if (target.classList.contains("editButton")) {
|
||||
const tagid = target.parentElement?.getAttribute("data-id");
|
||||
const name = target.parentElement?.getAttribute("data-display");
|
||||
if (
|
||||
tagid === undefined ||
|
||||
name === undefined ||
|
||||
tagid === "" ||
|
||||
name === "" ||
|
||||
tagid === null ||
|
||||
name === null
|
||||
) {
|
||||
Notifications.add(
|
||||
"Failed to edit tag: Could not find tag id or name",
|
||||
-1
|
||||
);
|
||||
return;
|
||||
}
|
||||
EditTagPopup.show("edit", tagid, name);
|
||||
} else if (target.classList.contains("clearPbButton")) {
|
||||
const tagid = target.parentElement?.getAttribute("data-id");
|
||||
const name = target.parentElement?.getAttribute("data-display");
|
||||
if (
|
||||
tagid === undefined ||
|
||||
name === undefined ||
|
||||
tagid === "" ||
|
||||
name === "" ||
|
||||
tagid === null ||
|
||||
name === null
|
||||
) {
|
||||
Notifications.add(
|
||||
"Failed to clear tag PB: Could not find tag id or name",
|
||||
-1
|
||||
);
|
||||
return;
|
||||
}
|
||||
EditTagPopup.show("clearPb", tagid, name);
|
||||
} else if (target.classList.contains("removeButton")) {
|
||||
const tagid = target.parentElement?.getAttribute("data-id");
|
||||
const name = target.parentElement?.getAttribute("data-display");
|
||||
if (
|
||||
tagid === undefined ||
|
||||
name === undefined ||
|
||||
tagid === "" ||
|
||||
name === "" ||
|
||||
tagid === null ||
|
||||
name === null
|
||||
) {
|
||||
Notifications.add(
|
||||
"Failed to remove tag: Could not find tag id or name",
|
||||
-1
|
||||
);
|
||||
return;
|
||||
}
|
||||
EditTagPopup.show("remove", tagid, name);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -30,7 +30,6 @@ import "./controllers/route-controller";
|
|||
import "./pages/about";
|
||||
import "./elements/scroll-to-top";
|
||||
import "./popups/mobile-test-config-popup";
|
||||
import "./popups/edit-tags-popup";
|
||||
import "./popups/google-sign-up-popup";
|
||||
import "./popups/result-tags-popup";
|
||||
import * as Account from "./pages/account";
|
||||
|
|
171
frontend/src/ts/modals/edit-tag.ts
Normal file
171
frontend/src/ts/modals/edit-tag.ts
Normal file
|
@ -0,0 +1,171 @@
|
|||
import Ape from "../ape";
|
||||
import * as DB from "../db";
|
||||
import * as Notifications from "../elements/notifications";
|
||||
import * as Loader from "../elements/loader";
|
||||
import * as Settings from "../pages/settings";
|
||||
import * as ConnectionState from "../states/connection";
|
||||
import AnimatedModal from "../utils/animated-modal";
|
||||
|
||||
export function show(action: string, id?: string, name?: string): void {
|
||||
if (!ConnectionState.get()) {
|
||||
Notifications.add("You are offline", 0, {
|
||||
duration: 2,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
void modal.show({
|
||||
focusFirstInput: true,
|
||||
beforeAnimation: async () => {
|
||||
$("#editTagModal .modal .text").addClass("hidden");
|
||||
if (action === "add") {
|
||||
$("#editTagModal .modal").attr("data-action", "add");
|
||||
$("#editTagModal .modal .title").html("Add new tag");
|
||||
$("#editTagModal .modal button").html(`add`);
|
||||
$("#editTagModal .modal input").val("");
|
||||
$("#editTagModal .modal input").removeClass("hidden");
|
||||
} else if (action === "edit" && id !== undefined && name !== undefined) {
|
||||
$("#editTagModal .modal").attr("data-action", "edit");
|
||||
$("#editTagModal .modal").attr("data-tag-id", id);
|
||||
$("#editTagModal .modal .title").html("Edit tag");
|
||||
$("#editTagModal .modal button").html(`save`);
|
||||
$("#editTagModal .modal input").val(name);
|
||||
$("#editTagModal .modal input").removeClass("hidden");
|
||||
} else if (
|
||||
action === "remove" &&
|
||||
id !== undefined &&
|
||||
name !== undefined
|
||||
) {
|
||||
$("#editTagModal .modal").attr("data-action", "remove");
|
||||
$("#editTagModal .modal").attr("data-tag-id", id);
|
||||
$("#editTagModal .modal .title").html("Delete tag");
|
||||
$("#editTagModal .modal .text").removeClass("hidden");
|
||||
$("#editTagModal .modal .text").html(
|
||||
`Are you sure you want to delete tag ${name}?`
|
||||
);
|
||||
$("#editTagModal .modal button").html(`delete`);
|
||||
$("#editTagModal .modal input").addClass("hidden");
|
||||
} else if (
|
||||
action === "clearPb" &&
|
||||
id !== undefined &&
|
||||
name !== undefined
|
||||
) {
|
||||
$("#editTagModal .modal").attr("data-action", "clearPb");
|
||||
$("#editTagModal .modal").attr("data-tag-id", id);
|
||||
$("#editTagModal .modal .title").html("Clear personal bests");
|
||||
$("#editTagModal .modal .text").removeClass("hidden");
|
||||
$("#editTagModal .modal .text").html(
|
||||
`Are you sure you want to clear personal bests for tag ${name}?`
|
||||
);
|
||||
$("#editTagModal .modal button").html(`clear`);
|
||||
$("#editTagModal .modal input").addClass("hidden");
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function hide(): void {
|
||||
void modal.hide();
|
||||
}
|
||||
|
||||
async function apply(): Promise<void> {
|
||||
const action = $("#editTagModal .modal").attr("data-action");
|
||||
const propTagName = $("#editTagModal .modal input").val() as string;
|
||||
const tagName = propTagName.replaceAll(" ", "_");
|
||||
const tagId = $("#editTagModal .modal").attr("data-tag-id") as string;
|
||||
|
||||
hide();
|
||||
Loader.show();
|
||||
|
||||
if (action === "add") {
|
||||
const response = await Ape.users.createTag(tagName);
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add(
|
||||
"Failed to add tag: " + response.message.replace(tagName, propTagName),
|
||||
-1
|
||||
);
|
||||
} else {
|
||||
if (response.data === null) {
|
||||
Notifications.add("Tag was added but data returned was null", -1);
|
||||
Loader.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
Notifications.add("Tag added", 1);
|
||||
DB.getSnapshot()?.tags?.push({
|
||||
display: propTagName,
|
||||
name: response.data.name,
|
||||
_id: response.data._id,
|
||||
personalBests: {
|
||||
time: {},
|
||||
words: {},
|
||||
quote: {},
|
||||
zen: {},
|
||||
custom: {},
|
||||
},
|
||||
});
|
||||
void Settings.update();
|
||||
}
|
||||
} else if (action === "edit") {
|
||||
const response = await Ape.users.editTag(tagId, tagName);
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add("Failed to edit tag: " + response.message, -1);
|
||||
} else {
|
||||
Notifications.add("Tag updated", 1);
|
||||
DB.getSnapshot()?.tags?.forEach((tag) => {
|
||||
if (tag._id === tagId) {
|
||||
tag.name = tagName;
|
||||
tag.display = propTagName;
|
||||
}
|
||||
});
|
||||
void Settings.update();
|
||||
}
|
||||
} else if (action === "remove") {
|
||||
const response = await Ape.users.deleteTag(tagId);
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add("Failed to remove tag: " + response.message, -1);
|
||||
} else {
|
||||
Notifications.add("Tag removed", 1);
|
||||
DB.getSnapshot()?.tags?.forEach((tag, index: number) => {
|
||||
if (tag._id === tagId) {
|
||||
DB.getSnapshot()?.tags?.splice(index, 1);
|
||||
}
|
||||
});
|
||||
void Settings.update();
|
||||
}
|
||||
} else if (action === "clearPb") {
|
||||
const response = await Ape.users.deleteTagPersonalBest(tagId);
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add("Failed to clear tag pb: " + response.message, -1);
|
||||
} else {
|
||||
Notifications.add("Tag PB cleared", 1);
|
||||
DB.getSnapshot()?.tags?.forEach((tag) => {
|
||||
if (tag._id === tagId) {
|
||||
tag.personalBests = {
|
||||
time: {},
|
||||
words: {},
|
||||
quote: {},
|
||||
zen: {},
|
||||
custom: {},
|
||||
};
|
||||
}
|
||||
});
|
||||
void Settings.update();
|
||||
}
|
||||
}
|
||||
Loader.hide();
|
||||
}
|
||||
|
||||
const modal = new AnimatedModal({
|
||||
dialogId: "editTagModal",
|
||||
setup: (modalEl): void => {
|
||||
modalEl.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
void apply();
|
||||
});
|
||||
},
|
||||
});
|
|
@ -1,229 +0,0 @@
|
|||
import Ape from "../ape";
|
||||
import * as DB from "../db";
|
||||
import * as Notifications from "../elements/notifications";
|
||||
import * as Loader from "../elements/loader";
|
||||
import * as Settings from "../pages/settings";
|
||||
import * as ConnectionState from "../states/connection";
|
||||
import * as Skeleton from "../utils/skeleton";
|
||||
import { isPopupVisible } from "../utils/misc";
|
||||
|
||||
const wrapperId = "tagsWrapper";
|
||||
|
||||
export function show(action: string, id?: string, name?: string): void {
|
||||
if (!ConnectionState.get()) {
|
||||
Notifications.add("You are offline", 0, {
|
||||
duration: 2,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Skeleton.append(wrapperId, "popups");
|
||||
|
||||
if (action === "add") {
|
||||
$("#tagsWrapper #tagsEdit").attr("action", "add");
|
||||
$("#tagsWrapper #tagsEdit .title").html("Add new tag");
|
||||
$("#tagsWrapper #tagsEdit button").html(`add`);
|
||||
$("#tagsWrapper #tagsEdit input").val("");
|
||||
$("#tagsWrapper #tagsEdit input").removeClass("hidden");
|
||||
} else if (action === "edit" && id !== undefined && name !== undefined) {
|
||||
$("#tagsWrapper #tagsEdit").attr("action", "edit");
|
||||
$("#tagsWrapper #tagsEdit").attr("tagid", id);
|
||||
$("#tagsWrapper #tagsEdit .title").html("Edit tag name");
|
||||
$("#tagsWrapper #tagsEdit button").html(`save`);
|
||||
$("#tagsWrapper #tagsEdit input").val(name);
|
||||
$("#tagsWrapper #tagsEdit input").removeClass("hidden");
|
||||
} else if (action === "remove" && id !== undefined && name !== undefined) {
|
||||
$("#tagsWrapper #tagsEdit").attr("action", "remove");
|
||||
$("#tagsWrapper #tagsEdit").attr("tagid", id);
|
||||
$("#tagsWrapper #tagsEdit .title").html("Delete tag " + name);
|
||||
$("#tagsWrapper #tagsEdit button").html(`delete`);
|
||||
$("#tagsWrapper #tagsEdit input").addClass("hidden");
|
||||
} else if (action === "clearPb" && id !== undefined && name !== undefined) {
|
||||
$("#tagsWrapper #tagsEdit").attr("action", "clearPb");
|
||||
$("#tagsWrapper #tagsEdit").attr("tagid", id);
|
||||
$("#tagsWrapper #tagsEdit .title").html("Clear PB for tag " + name);
|
||||
$("#tagsWrapper #tagsEdit button").html(`clear`);
|
||||
$("#tagsWrapper #tagsEdit input").addClass("hidden");
|
||||
}
|
||||
|
||||
if (!isPopupVisible(wrapperId)) {
|
||||
$("#tagsWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 0)
|
||||
.removeClass("hidden")
|
||||
.animate({ opacity: 1 }, 125, () => {
|
||||
const input = $("#tagsWrapper #tagsEdit input");
|
||||
if (!input.hasClass("hidden")) {
|
||||
$("#tagsWrapper #tagsEdit input").trigger("focus");
|
||||
} else {
|
||||
$("#tagsWrapper").trigger("focus");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function hide(): void {
|
||||
if (isPopupVisible(wrapperId)) {
|
||||
$("#tagsWrapper #tagsEdit").attr("action", "");
|
||||
$("#tagsWrapper #tagsEdit").attr("tagid", "");
|
||||
$("#tagsWrapper")
|
||||
.stop(true, true)
|
||||
.css("opacity", 1)
|
||||
.animate(
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
125,
|
||||
() => {
|
||||
$("#tagsWrapper").addClass("hidden");
|
||||
Skeleton.remove(wrapperId);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function apply(): Promise<void> {
|
||||
const action = $("#tagsWrapper #tagsEdit").attr("action");
|
||||
const propTagName = $("#tagsWrapper #tagsEdit input").val() as string;
|
||||
const tagName = propTagName.replaceAll(" ", "_");
|
||||
const tagId = $("#tagsWrapper #tagsEdit").attr("tagid") as string;
|
||||
|
||||
hide();
|
||||
Loader.show();
|
||||
|
||||
if (action === "add") {
|
||||
const response = await Ape.users.createTag(tagName);
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add(
|
||||
"Failed to add tag: " + response.message.replace(tagName, propTagName),
|
||||
-1
|
||||
);
|
||||
} else {
|
||||
if (response.data === null) {
|
||||
Notifications.add("Tag was added but data returned was null", -1);
|
||||
Loader.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
Notifications.add("Tag added", 1);
|
||||
DB.getSnapshot()?.tags?.push({
|
||||
display: propTagName,
|
||||
name: response.data.name,
|
||||
_id: response.data._id,
|
||||
personalBests: {
|
||||
time: {},
|
||||
words: {},
|
||||
quote: {},
|
||||
zen: {},
|
||||
custom: {},
|
||||
},
|
||||
});
|
||||
void Settings.update();
|
||||
}
|
||||
} else if (action === "edit") {
|
||||
const response = await Ape.users.editTag(tagId, tagName);
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add("Failed to edit tag: " + response.message, -1);
|
||||
} else {
|
||||
Notifications.add("Tag updated", 1);
|
||||
DB.getSnapshot()?.tags?.forEach((tag) => {
|
||||
if (tag._id === tagId) {
|
||||
tag.name = tagName;
|
||||
tag.display = propTagName;
|
||||
}
|
||||
});
|
||||
void Settings.update();
|
||||
}
|
||||
} else if (action === "remove") {
|
||||
const response = await Ape.users.deleteTag(tagId);
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add("Failed to remove tag: " + response.message, -1);
|
||||
} else {
|
||||
Notifications.add("Tag removed", 1);
|
||||
DB.getSnapshot()?.tags?.forEach((tag, index: number) => {
|
||||
if (tag._id === tagId) {
|
||||
DB.getSnapshot()?.tags?.splice(index, 1);
|
||||
}
|
||||
});
|
||||
void Settings.update();
|
||||
}
|
||||
} else if (action === "clearPb") {
|
||||
const response = await Ape.users.deleteTagPersonalBest(tagId);
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add("Failed to clear tag pb: " + response.message, -1);
|
||||
} else {
|
||||
Notifications.add("Tag PB cleared", 1);
|
||||
DB.getSnapshot()?.tags?.forEach((tag) => {
|
||||
if (tag._id === tagId) {
|
||||
tag.personalBests = {
|
||||
time: {},
|
||||
words: {},
|
||||
quote: {},
|
||||
zen: {},
|
||||
custom: {},
|
||||
};
|
||||
}
|
||||
});
|
||||
void Settings.update();
|
||||
}
|
||||
}
|
||||
Loader.hide();
|
||||
}
|
||||
|
||||
$("#tagsWrapper").on("click", (e) => {
|
||||
if ($(e.target).attr("id") === "tagsWrapper") {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#tagsWrapper #tagsEdit form").on("submit", (e) => {
|
||||
e.preventDefault();
|
||||
void apply();
|
||||
});
|
||||
|
||||
$(".pageSettings .section.tags").on("click", ".addTagButton", () => {
|
||||
show("add");
|
||||
});
|
||||
|
||||
$(".pageSettings .section.tags").on(
|
||||
"click",
|
||||
".tagsList .tag .editButton",
|
||||
(e) => {
|
||||
const tagid = $(e.currentTarget).parent(".tag").attr("data-id");
|
||||
const name = $(e.currentTarget).parent(".tag").attr("data-display");
|
||||
show("edit", tagid, name);
|
||||
}
|
||||
);
|
||||
|
||||
$(".pageSettings .section.tags").on(
|
||||
"click",
|
||||
".tagsList .tag .clearPbButton",
|
||||
(e) => {
|
||||
const tagid = $(e.currentTarget).parent(".tag").attr("data-id");
|
||||
const name = $(e.currentTarget).parent(".tag").attr("data-display");
|
||||
show("clearPb", tagid, name);
|
||||
}
|
||||
);
|
||||
|
||||
$(".pageSettings .section.tags").on(
|
||||
"click",
|
||||
".tagsList .tag .removeButton",
|
||||
(e) => {
|
||||
const tagid = $(e.currentTarget).parent(".tag").attr("data-id");
|
||||
const name = $(e.currentTarget).parent(".tag").attr("data-display");
|
||||
show("remove", tagid, name);
|
||||
}
|
||||
);
|
||||
|
||||
$(document).on("keydown", (event) => {
|
||||
if (event.key === "Escape" && isPopupVisible(wrapperId)) {
|
||||
hide();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
Skeleton.save(wrapperId);
|
Loading…
Reference in a new issue