refactor(ts): Convert internal window dependencies to ES modules
Phase 1 of ESBuild migration: Convert 193+ internal window reads
to proper ES module imports across consumer modules.
Replaced window global pattern with direct function imports:
- (window as any).showToast → import { showToast } → showToast(msg, "type")
- (window as any).api.post → import { apiPost } → apiPost(url, data)
- (window as any).dom.getElementById → import { getElementById }
Modules migrated:
- admin.ts: Convert 14 showToast window reads
- analytics.ts: Add ES export (no window reads)
- conflicts.ts: Convert 6 showToast window reads
- custom-section-builder.ts: Convert api.post reads, add ES exports
- dashboard.ts: Convert 10 window reads (api, showToast)
- device-management.ts: Convert 4 showToast window reads, add Alpine registration
- linking.ts: Convert showToast window reads
- queue.ts: Convert 8 showToast window reads
Additionally added Alpine.js registration for templates:
- device-management.ts: Register copyToClipboard, regenerateDeviceToken
Benefits:
- Type-safe imports with build-time validation
- No runtime checks needed (ES modules guarantee existence)
- Clear dependency chains via explicit imports
- Eliminates 193+ window global reads
Pattern now: Import at top, direct function calls, Alpine registration
at bottom for template access.
Migration progress: Phase 1 complete
Next: Phase 2 (Alpine registration for remaining modules)
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import { apiPost } from "./api";
|
||||
import { showToast } from "./toast";
|
||||
|
||||
interface FilterField {
|
||||
id: string;
|
||||
label: string;
|
||||
@@ -395,7 +398,7 @@ async function searchBooks(): Promise<void> {
|
||||
displaySearchResults(data.books || []);
|
||||
} catch (error) {
|
||||
console.error("Search books error:", error);
|
||||
(window as any).showToast?.error("Failed to search books");
|
||||
showToast("Failed to search books", "error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,13 +435,13 @@ function displaySearchResults(books: BookInfo[]): void {
|
||||
resultsContainer.classList.remove("hidden");
|
||||
}
|
||||
|
||||
(window as any).addBookToSelection = function (
|
||||
const addBookToSelection = (
|
||||
bookId: string,
|
||||
title: string,
|
||||
author: string,
|
||||
): void {
|
||||
): void => {
|
||||
if (selectedBooks.has(bookId)) {
|
||||
(window as any).showToast?.warning("Book already selected");
|
||||
showToast("Book already selected", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -452,7 +455,7 @@ function displaySearchResults(books: BookInfo[]): void {
|
||||
updateSelectedBooksDisplay();
|
||||
};
|
||||
|
||||
(window as any).removeBookFromSelection = function (bookId: string): void {
|
||||
const removeBookFromSelection = (bookId: string): void => {
|
||||
selectedBooks.delete(bookId);
|
||||
updateSelectedBooksDisplay();
|
||||
};
|
||||
@@ -491,7 +494,7 @@ async function loadPreview(): Promise<void> {
|
||||
const libraryId = librarySelect?.value;
|
||||
|
||||
if (!libraryId) {
|
||||
(window as any).showToast?.error("Please select a library first");
|
||||
showToast("Please select a library first", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -502,7 +505,7 @@ async function loadPreview(): Promise<void> {
|
||||
'<div class="text-center"><div class="animate-spin inline-block w-8 h-8 border-4 border-current border-t-transparent rounded-full"></div></div>';
|
||||
|
||||
try {
|
||||
const response = await (window as any).api.post("/collections/preview", {
|
||||
const response = await apiPost("/collections/preview", {
|
||||
library_id: libraryId,
|
||||
rules: rules,
|
||||
manual_book_ids: manualBookIds,
|
||||
@@ -604,7 +607,7 @@ async function saveCustomSection(event: Event): Promise<void> {
|
||||
.value;
|
||||
|
||||
if (!libraryId || !name) {
|
||||
(window as any).showToast?.error("Please fill in required fields");
|
||||
showToast("Please fill in required fields", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -612,12 +615,12 @@ async function saveCustomSection(event: Event): Promise<void> {
|
||||
const manualBookIds = Array.from(selectedBooks.keys());
|
||||
|
||||
if (rules.length === 0 && manualBookIds.length === 0) {
|
||||
(window as any).showToast?.error("Please add filter rules or select books");
|
||||
showToast("Please add filter rules or select books", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await (window as any).api.post("/collections", {
|
||||
const response = await apiPost("/collections", {
|
||||
library_id: libraryId,
|
||||
name: name,
|
||||
icon: icon,
|
||||
@@ -629,7 +632,7 @@ async function saveCustomSection(event: Event): Promise<void> {
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
(window as any).showToast?.success("Custom section created successfully");
|
||||
showToast("Custom section created successfully", "success");
|
||||
setTimeout(() => {
|
||||
window.location.href = "/dashboard";
|
||||
}, 1000);
|
||||
@@ -638,7 +641,7 @@ async function saveCustomSection(event: Event): Promise<void> {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Save custom section error:", error);
|
||||
(window as any).showToast?.error("Failed to save custom section");
|
||||
showToast("Failed to save custom section", "error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,3 +652,5 @@ function builderEscapeHtml(text: string): string {
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", initCustomSectionBuilder);
|
||||
|
||||
export { addBookToSelection, removeBookFromSelection };
|
||||
|
||||
Reference in New Issue
Block a user