Skip to content

Commit ec3a51a

Browse files
committed
Refactor views into modular components and add JS view controllers
1 parent f0dac53 commit ec3a51a

20 files changed

+1069
-1417
lines changed

public/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
<!-- Initial loading overlay -->
2828
<div id="initial-loading-overlay" style="position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: var(--background-color, #ffffff); z-index: 9999; transition: opacity 150ms ease-in-out;"></div>
2929

30+
<div class="offline-notification" id="offline-notification">
31+
You are currently offline. Some features may be limited.
32+
</div>
3033
<script>
3134
// Remove the loading overlay once the router has initialized
3235
window.addEventListener('route-changed', () => {

public/js/deps.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
// Import and re-export spa-router
10-
export { Router, transitions, renderer, componentLoader } from 'https://esm.sh/@profullstack/spa-router@1.8.4';
10+
export { Router, transitions, renderer, componentLoader } from 'https://esm.sh/@profullstack/spa-router@1.9.0';
1111

1212
// Import and re-export state-manager
1313
export { createStore, StoreConnector } from 'https://esm.sh/@profullstack/[email protected]';

public/js/views/api-keys.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* Initialize the API keys page
3+
*/
4+
function initApiKeysPage() {
5+
// Check if user is logged in
6+
const apiKey = localStorage.getItem('api_key') || new URLSearchParams(window.location.search).get('api_key');
7+
8+
if (!apiKey) {
9+
document.getElementById('api-key-container').style.display = 'none';
10+
document.getElementById('login-prompt').style.display = 'block';
11+
} else {
12+
document.getElementById('api-key-container').style.display = 'block';
13+
document.getElementById('login-prompt').style.display = 'none';
14+
}
15+
16+
// Set up tab switching
17+
const tabButtons = document.querySelectorAll('.tab-button');
18+
tabButtons.forEach(button => {
19+
button.addEventListener('click', () => {
20+
console.log('Tab button clicked:', button.dataset.tab);
21+
22+
// Remove active class from all buttons
23+
tabButtons.forEach(btn => btn.classList.remove('active'));
24+
25+
// Add active class to clicked button
26+
button.classList.add('active');
27+
28+
// Hide all tab content
29+
document.querySelectorAll('.tab-content').forEach(tab => {
30+
tab.style.display = 'none';
31+
});
32+
33+
// Show selected tab content
34+
const tabId = button.dataset.tab;
35+
const tabContent = document.getElementById(`${tabId}-tab`);
36+
37+
if (tabContent) {
38+
tabContent.style.display = 'block';
39+
console.log('Tab content displayed:', tabId);
40+
} else {
41+
console.error('Tab content not found:', tabId);
42+
}
43+
});
44+
});
45+
46+
// Force refresh of the API key manager component
47+
setTimeout(() => {
48+
const apiKeyManager = document.querySelector('api-key-manager');
49+
if (apiKeyManager) {
50+
// Try to force a re-render
51+
apiKeyManager.render();
52+
53+
// Also try to reload the API keys
54+
if (typeof apiKeyManager._loadApiKeys === 'function') {
55+
apiKeyManager._loadApiKeys();
56+
}
57+
58+
console.log('API key manager refreshed');
59+
} else {
60+
console.error('API key manager component not found');
61+
62+
// Try to create it dynamically if it doesn't exist
63+
const container = document.getElementById('api-key-container');
64+
if (container) {
65+
console.log('Creating API key manager component dynamically');
66+
const apiKeyManagerElement = document.createElement('api-key-manager');
67+
container.innerHTML = '';
68+
container.appendChild(apiKeyManagerElement);
69+
}
70+
}
71+
}, 500);
72+
}
73+
74+
// Initialize the page when the DOM is loaded
75+
document.addEventListener('DOMContentLoaded', initApiKeysPage);
76+
77+
// Also initialize on spa-transition-end event for SPA router
78+
document.addEventListener('spa-transition-end', initApiKeysPage);

public/js/views/dashboard.js

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
import { ApiClient } from '../api-client.js';
2+
3+
/**
4+
* Initialize the dashboard page
5+
*/
6+
function initDashboard() {
7+
console.log('Initializing dashboard...');
8+
9+
// Check if user is logged in
10+
const apiKey = localStorage.getItem('api_key');
11+
const jwtToken = localStorage.getItem('jwt_token');
12+
13+
console.log('API key exists:', !!apiKey);
14+
console.log('JWT token exists:', !!jwtToken);
15+
console.log('JWT token length:', jwtToken ? jwtToken.length : 0);
16+
17+
if (!apiKey && !jwtToken) {
18+
console.log('No authentication found, redirecting to login page');
19+
// Redirect to login page
20+
window.router.navigate('/login');
21+
return;
22+
}
23+
24+
// Check if user has an active subscription
25+
const userJson = localStorage.getItem('user');
26+
let user = null;
27+
28+
if (userJson) {
29+
try {
30+
user = JSON.parse(userJson);
31+
} catch (e) {
32+
console.error('Error parsing user JSON:', e);
33+
}
34+
}
35+
36+
// Verify subscription status
37+
const hasActiveSubscription = user &&
38+
user.subscription &&
39+
user.subscription.status === 'active';
40+
41+
if (!hasActiveSubscription) {
42+
// Redirect to subscription page
43+
alert('You need an active subscription to access the dashboard.');
44+
window.router.navigate('/subscription');
45+
return;
46+
}
47+
48+
// Set up tab switching
49+
const tabButtons = document.querySelectorAll('.tab-button');
50+
tabButtons.forEach(button => {
51+
button.addEventListener('click', () => {
52+
// Remove active class from all buttons
53+
tabButtons.forEach(btn => btn.classList.remove('active'));
54+
55+
// Add active class to clicked button
56+
button.classList.add('active');
57+
58+
// Hide all tab content
59+
document.querySelectorAll('.tab-content').forEach(tab => {
60+
tab.style.display = 'none';
61+
});
62+
63+
// Show selected tab content
64+
const tabId = button.dataset.tab;
65+
document.getElementById(`${tabId}-tab`).style.display = 'block';
66+
67+
// If history tab is selected, refresh the document history
68+
if (tabId === 'history') {
69+
// Get the document-history component and refresh it
70+
const historyComponent = document.querySelector('document-history');
71+
if (historyComponent) {
72+
console.log('Refreshing document history...');
73+
historyComponent.loadHistory();
74+
} else {
75+
console.error('Document history component not found');
76+
}
77+
}
78+
});
79+
});
80+
81+
// Set up document type change handler
82+
const documentTypeSelect = document.getElementById('document-type');
83+
documentTypeSelect.addEventListener('change', () => {
84+
// Hide all options containers
85+
document.querySelectorAll('.options-container').forEach(container => {
86+
container.style.display = 'none';
87+
});
88+
89+
// Show options container for selected document type
90+
const documentType = documentTypeSelect.value;
91+
const optionsContainer = document.getElementById(`${documentType}-options`);
92+
if (optionsContainer) {
93+
optionsContainer.style.display = 'block';
94+
}
95+
96+
// Update filename extension
97+
updateFilenameExtension(documentType);
98+
});
99+
100+
// Set up convert button
101+
const convertButton = document.getElementById('convert-button');
102+
if (convertButton) {
103+
console.log('Found convert button, adding click event listener');
104+
convertButton.addEventListener('click', convertDocument);
105+
} else {
106+
console.error('Convert button not found in the DOM');
107+
}
108+
109+
// Initialize filename with default extension
110+
updateFilenameExtension(documentTypeSelect.value);
111+
112+
console.log('Dashboard initialization complete');
113+
}
114+
115+
/**
116+
* Update the filename extension based on the selected document type
117+
* @param {string} documentType - The selected document type
118+
*/
119+
function updateFilenameExtension(documentType) {
120+
const filenameInput = document.getElementById('filename');
121+
const currentFilename = filenameInput.value || 'document';
122+
123+
// Remove any existing extension
124+
const baseFilename = currentFilename.replace(/\.\w+$/, '');
125+
126+
// Add new extension based on document type
127+
const extensions = {
128+
pdf: '.pdf',
129+
doc: '.doc',
130+
excel: '.xlsx',
131+
ppt: '.pptx',
132+
epub: '.epub',
133+
markdown: '.md'
134+
};
135+
136+
filenameInput.value = baseFilename + (extensions[documentType] || '');
137+
}
138+
139+
/**
140+
* Convert the document based on the selected options
141+
*/
142+
async function convertDocument() {
143+
console.log('Convert button clicked');
144+
try {
145+
// Get form values
146+
const html = document.getElementById('html-input').value;
147+
console.log('HTML content length:', html ? html.length : 0);
148+
if (!html) {
149+
alert('Please enter HTML content');
150+
return;
151+
}
152+
153+
const documentType = document.getElementById('document-type').value;
154+
const filename = document.getElementById('filename').value;
155+
const storeDocument = document.getElementById('store-document').checked;
156+
console.log('Converting document:', { documentType, filename, storeDocument });
157+
158+
// Show loading state
159+
const convertButton = document.getElementById('convert-button');
160+
const originalButtonText = convertButton.textContent;
161+
convertButton.textContent = 'Converting...';
162+
convertButton.disabled = true;
163+
164+
// Prepare request data based on document type
165+
let result;
166+
console.log('Preparing to convert document type:', documentType);
167+
168+
switch (documentType) {
169+
case 'pdf':
170+
console.log('Converting to PDF');
171+
const pdfFormat = document.getElementById('pdf-format').value;
172+
const pdfOrientation = document.getElementById('pdf-orientation').value;
173+
const pdfOptions = {
174+
format: pdfFormat,
175+
orientation: pdfOrientation
176+
};
177+
console.log('PDF options:', pdfOptions);
178+
179+
console.log('Calling ApiClient.htmlToPdf...');
180+
result = await ApiClient.htmlToPdf(html, pdfOptions, filename, storeDocument);
181+
console.log('PDF conversion successful');
182+
break;
183+
184+
case 'doc':
185+
result = await ApiClient.htmlToDoc(html, filename, storeDocument);
186+
break;
187+
188+
case 'excel':
189+
const sheetName = document.getElementById('excel-sheet').value || 'Sheet1';
190+
result = await ApiClient.htmlToExcel(html, filename, sheetName, storeDocument);
191+
break;
192+
193+
case 'ppt':
194+
const title = document.getElementById('ppt-title').value || 'Presentation';
195+
result = await ApiClient.htmlToPpt(html, filename, title, storeDocument);
196+
break;
197+
198+
case 'epub':
199+
const epubTitle = document.getElementById('epub-title').value || '';
200+
const epubAuthor = document.getElementById('epub-author').value || '';
201+
result = await ApiClient.htmlToEpub(html, filename, epubTitle, epubAuthor, '', storeDocument);
202+
break;
203+
204+
case 'markdown':
205+
const markdown = await ApiClient.htmlToMarkdown(html);
206+
// For markdown, we'll create a blob and download it
207+
const markdownBlob = new Blob([markdown], { type: 'text/markdown' });
208+
ApiClient.downloadBlob(markdownBlob, filename);
209+
210+
// Reset button state
211+
convertButton.textContent = originalButtonText;
212+
convertButton.disabled = false;
213+
214+
// Refresh document history if we're storing documents
215+
if (storeDocument) {
216+
refreshDocumentHistory();
217+
}
218+
219+
return;
220+
}
221+
222+
// Download the result
223+
ApiClient.downloadBlob(result, filename);
224+
225+
// Reset button state
226+
convertButton.textContent = originalButtonText;
227+
convertButton.disabled = false;
228+
229+
// Refresh document history if we're storing documents
230+
if (storeDocument) {
231+
refreshDocumentHistory();
232+
}
233+
} catch (error) {
234+
console.error('Error converting document:', error);
235+
console.error('Error stack:', error.stack);
236+
console.error('Error type:', error.constructor.name);
237+
console.error('Error message:', error.message);
238+
239+
// Show detailed error message
240+
alert('Error converting document: ' + error.message);
241+
242+
// Reset button state
243+
const convertButton = document.getElementById('convert-button');
244+
convertButton.textContent = 'Convert Document';
245+
convertButton.disabled = false;
246+
}
247+
}
248+
249+
/**
250+
* Refresh the document history component
251+
*/
252+
function refreshDocumentHistory() {
253+
// Get the document-history component and refresh it
254+
const historyComponent = document.querySelector('document-history');
255+
if (historyComponent) {
256+
historyComponent.loadHistory();
257+
}
258+
}
259+
260+
// Load the document-history component and initialize the dashboard
261+
import('../components/document-history.js')
262+
.then(() => {
263+
console.log('Document history component loaded successfully');
264+
// Initialize the dashboard after the component is loaded
265+
initDashboard();
266+
})
267+
.catch(error => {
268+
console.error('Error loading document history component:', error);
269+
// Still initialize the dashboard even if component fails to load
270+
initDashboard();
271+
});

0 commit comments

Comments
 (0)