Skip to content

Commit

Permalink
feat(DELETE ENTRY): Delete functionality, Modal setup
Browse files Browse the repository at this point in the history
  • Loading branch information
Bonitoflakes committed May 1, 2023
1 parent 2145e7f commit 0648dae
Show file tree
Hide file tree
Showing 9 changed files with 432 additions and 216 deletions.
21 changes: 13 additions & 8 deletions src/components/tracker-entry/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const generateBill = (id: number, billable: boolean) => {
return div;
};

export const generateDate = (startDate: string, endDate: string, date: string) => {
export const generateDate = (date: string, startDate: string, endDate: string) => {
const div = createElement("div", { class: ["date-time-wrapper"] });

const startTime = createElement("input", {
Expand All @@ -94,20 +94,21 @@ export const generateDate = (startDate: string, endDate: string, date: string) =

const hyphen = createElement("span", { class: ["time-divider"] }, "-");

(startTime as HTMLInputElement).value = startDate ?? "01:20";
(endTime as HTMLInputElement).value = endDate ?? "10:40";
(startTime as HTMLInputElement).value = startDate ?? "Dev Messed up";
(endTime as HTMLInputElement).value = endDate ?? "Dev Messed up";

const tagImg = createElement("img", { src: calendarGray, alt: "" });
const dateImg = createElement("img", { src: calendarGray, alt: "" });
const dateInput = createElement("input", {
type: "date",
class: ["native-date-picker"],
}) as HTMLInputElement;
dateInput.value = date;
const tagBtn = createElement("button", { class: ["timetracker-recorder__date-button"] });
tagBtn.append(tagImg, dateInput);
const dateButton = createElement("button", { class: ["timetracker-recorder__date-button"] });
dateButton.append(dateImg, dateInput);

div.append(startTime, hyphen, endTime, tagBtn);
return div;
div.append(startTime, hyphen, endTime, dateButton);

return [div, startTime, endTime, dateButton, dateInput];
};

export const generatePlayButton = () => {
Expand All @@ -131,3 +132,7 @@ export const generateStopwatch = (time: number[]) => {
const stopwatch = createElement("div", { class: ["tracker-entry__stopwatch"] }, `${hrs}:${mins}:${secs}`);
return stopwatch;
};

export const generateLine = () => {
return createElement("div", { class: ["line"] });
};
161 changes: 161 additions & 0 deletions src/components/tracker-entry/helpers_OTHERS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { generateToast } from "@components";
import { Store } from "@store";
import { $, createElement } from "@utils";
import closeWhite from "@assets/close-white.svg";

export const handleTimeArrowKeys = (e: KeyboardEvent) => {
const input = e.currentTarget as HTMLInputElement;
if (e.key === "ArrowUp") {
let [hrs, mins] = getHoursAndMins(input.value);
mins++;

if (mins >= 60) {
hrs++;
mins = 0;
}

if (hrs >= 24) {
hrs = 0;
}

const hrs_string = hrs.toString().padStart(2, "0");
const mins_string = mins.toString().padStart(2, "0");
input.value = `${hrs_string}:${mins_string}`;
}
if (e.key === "ArrowDown") {
let [hrs, mins] = getHoursAndMins(input.value);

mins--;

if (mins < 0) {
hrs--;
mins = 59;
}

if (hrs < 0) {
hrs = 23;
}

const hrs_string = hrs.toString().padStart(2, "0");
const mins_string = mins.toString().padStart(2, "0");
input.value = `${hrs_string}:${mins_string}`;
}
};

// Function to get hours and minutes from the time input value
export const getHoursAndMins = (value: string) => {
// TODO: Add validation for numbers only, length <=5 && >3
const hrs = Number(value.split(":").join("").slice(0, 2));
const mins = Number(value.split(":").join("").slice(-2));
return [hrs, mins];
};

export const findEntry = (id: number) => {
const entry = Store.entries.find(({ id: e_id }) => id === e_id);
if (!entry) throw new Error("Entry not found!!, please check the ID");

return entry;
};

export const createDropdown = () => {
const dropdown = createElement("div", { class: ["menu-dropdown"] });
const duplicateOption = createElement("button", { class: ["option", "option--duplicate"] }, "Duplicate");
const deleteOption = createElement("button", { class: ["option", "option--delete"] }, "Delete");

dropdown.append(duplicateOption, deleteOption);
return [dropdown, duplicateOption, deleteOption];
};

export const createDeleteModal = (id: number) => {
const modal = createElement("div", { class: ["modal"] });
const modalContent = createElement("div", { class: ["modal-content"] });
const modalHeader = createElement("div", { class: ["modal-header"] });
const modalTitle = createElement("h1", { class: ["modal-title"] }, "Delete");
const closeButton = createElement("button", { class: ["modal-button--close"] });
const closeIconImg = createElement("img", { src: closeWhite, class: ["modal-close__img"] });
const modalBody = createElement("div", { class: ["modal-body"] });
const modalBodyText = createElement(
"p",
{ class: ["modal-body__text"] },
"Are you sure you want to delete this entry?"
);
const modalFooter = createElement("div", { class: ["modal-footer"] });
const cancelButton = createElement("a", { class: ["modal-button--cancel"], href: "#" }, "Cancel");
const deleteButton = createElement("button", { class: ["modal-button--delete"] }, "Delete");

closeButton.appendChild(closeIconImg);
modalHeader.append(modalTitle, closeButton);

modalBody.appendChild(modalBodyText);

modalFooter.appendChild(cancelButton);
modalFooter.appendChild(deleteButton);

modalContent.append(modalHeader, modalBody, modalFooter);
modal.append(modalContent);
document.body.append(modal);

// EventListeners
cancelButton.addEventListener("click", removeModal);
closeButton.addEventListener("click", removeModal);
deleteButton.addEventListener("click", () => deleteEntry(id));

return modal;
};

export const focusModal = (e: KeyboardEvent) => {
const modal = $("modal");
const focusableElements = 'button, a, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
const focusableContent = modal.querySelectorAll(focusableElements);
const firstFocusableElement = focusableContent[0] as HTMLElement;
const lastFocusableElement = focusableContent[focusableContent.length - 1] as HTMLElement;

if (e.key === "Escape") {
removeModal();
document.removeEventListener("keydown", focusModal);
}

const isTabPressed = e.key === "Tab";

if (!isTabPressed) return;

if (e.shiftKey) {
// if shift key pressed for shift + tab combination
if (document.activeElement === firstFocusableElement) {
lastFocusableElement.focus(); // add focus for the last focusable element
e.preventDefault();
}
return;
}

// if tab key is pressed
if (document.activeElement === lastFocusableElement) {
// if focused has reached to last focusable element then focus first focusable element after pressing tab
firstFocusableElement.focus(); // add focus for the first focusable element
e.preventDefault();
}
};

export function removeModal() {
const modal = $("modal");
const dropdown = $("menu-dropdown");
const modalContent = $("modal-content");

modalContent.classList.add("fadeOutUpBig");
Promise.all(modalContent.getAnimations().map((animation) => animation.finished)).then(() => modal.remove());
dropdown.remove();
document.removeEventListener("keydown", focusModal);
}

// TODO: Add more logic... Actual deletion requires ID to be passed along.
const deleteEntry = (id: number) => {
removeModal();

// delete entry from Store;
Store.entries.splice(
Store.entries.findIndex((entry) => entry.id === id),
1
);

generateToast("Entry deleted successfully.", true);
};
3 changes: 3 additions & 0 deletions src/components/tracker-entry/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { Store, subscribe } from "@store";
import { generateTrackerEntry } from "./trackerEntry";

subscribe(Store.entries, generateTrackerEntry);

export { generateTrackerEntry };
Loading

0 comments on commit 0648dae

Please sign in to comment.