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:
2026-03-08 01:14:35 -05:00
parent 149d14f5eb
commit 9947a12f09
8 changed files with 93 additions and 169 deletions
+13 -20
View File
@@ -1,3 +1,5 @@
import { Alpine } from "./alpine";
import { showToast } from "./toast";
// Device Management - Token copy and regeneration
// Procedural style with proper types (no OOP)
@@ -29,17 +31,11 @@ function copyToClipboard(text: string, label: string): void {
navigator.clipboard
.writeText(text)
.then(() => {
const toast = (window as any).showToast;
if (toast) {
toast.success(`${label} copied to clipboard`);
}
showToast(`${label} copied to clipboard`, "success");
})
.catch((err: unknown) => {
console.error("Failed to copy:", err);
const toast = (window as any).showToast;
if (toast) {
toast.error("Failed to copy to clipboard");
}
showToast("Failed to copy to clipboard", "error");
});
}
@@ -75,21 +71,16 @@ function regenerateDeviceToken(deviceId: string, event: Event): void {
return response.json() as Promise<RegenerateTokenResponse>;
})
.then((_data: RegenerateTokenResponse) => {
const toast = (window as any).showToast;
if (toast) {
toast.success(
"Token regenerated successfully - update your device config",
);
}
showToast(
"Token regenerated successfully - update your device config",
"success",
);
// Reload page to show new token
setTimeout(() => location.reload(), 1500);
})
.catch((error: unknown) => {
console.error("Error:", error);
const toast = (window as any).showToast;
if (toast) {
toast.error("Failed to regenerate token");
}
showToast("Failed to regenerate token", "error");
if (btn) {
btn.disabled = false;
btn.innerHTML = originalText;
@@ -98,5 +89,7 @@ function regenerateDeviceToken(deviceId: string, event: Event): void {
}
// Export functions for global access (called from template onclick attributes)
window.copyToClipboard = copyToClipboard;
window.regenerateDeviceToken = regenerateDeviceToken;
Alpine.global("devices", {
copyToClipboard,
regenerateDeviceToken,
});