diff --git a/index.html b/index.html index 54e7484..71cee80 100644 --- a/index.html +++ b/index.html @@ -640,8 +640,14 @@ async function safeFetch(url, options = {}) { clearTimeout(timeoutId); // Check for successful response - if (!response.ok) { - const errorText = await response.text(); + if (response.status < 200 || response.status >= 300) { + let errorText; + try { + const errorData = await response.json(); + errorText = errorData.error || JSON.stringify(errorData); + } catch (e) { + errorText = await response.text(); + } // Check if this is a Cloudflare error if (errorText.includes('Cloudflare') || errorText.includes('cf-error')) { @@ -663,7 +669,12 @@ async function safeFetch(url, options = {}) { throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`); } - return await response.json(); + try { + return await response.json(); + } catch (jsonError) { + console.error('Error parsing JSON response:', jsonError); + throw new Error('Invalid response format from server'); + } } catch (error) { console.error('Fetch Error:', { message: error.message, @@ -692,7 +703,7 @@ async function safeFetch(url, options = {}) { const sortBy = sortSelect ? sortSelect.value : 'newest'; // Log the full request URL and parameters - const requestUrl = `${API_BASE_URL}/proposals?sortBy=${sortBy}&userId=${currentUser.id}`; + const requestUrl = `${API_BASE_URL}/proposals?sortBy=${sortBy}&userId=${currentUser?.id || 'anonymous'}`; console.log('Fetching proposals from:', requestUrl); console.log('Current user:', currentUser); @@ -711,13 +722,35 @@ async function safeFetch(url, options = {}) { console.log('Response headers:', Object.fromEntries(response.headers.entries())); if (!response.ok) { - const errorText = await response.text(); - console.error('Error response:', errorText); + let errorText; + try { + const errorData = await response.json(); + console.error('Error response JSON:', errorData); + errorText = errorData.error || errorData.details?.message || JSON.stringify(errorData); + } catch (e) { + errorText = await response.text(); + console.error('Error response text:', errorText); + } throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`); } - const data = await response.json(); - console.log('Proposals data:', data); + let data; + try { + data = await response.json(); + } catch (jsonError) { + console.error('Error parsing JSON response:', jsonError); + throw new Error('Invalid JSON response from server'); + } + + console.log('Proposals data received:', { + count: data?.data?.length || 0, + pagination: data?.pagination + }); + + if (!data || !data.data || !Array.isArray(data.data)) { + console.error('Invalid data structure:', data); + throw new Error('Invalid data structure received from server'); + } renderProposals(data); } catch (error) { @@ -2259,34 +2292,49 @@ async function submitComment(proposalId, commentText) { console.log(`Submitting comment for proposal ${proposalId}: ${commentText.substring(0, 20)}...`); - return safeFetch(`${API_BASE_URL}/comments`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - proposalId: proposalId, - userId: currentUser.id, - commentText: commentText - }) - }) - .then(response => { - if (!response.ok) { - throw new Error('Failed to post comment'); + try { + const response = await fetch(`${API_BASE_URL}/comments`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + proposalId: proposalId, + userId: currentUser.id, + commentText: commentText + }) + }); + + console.log("Comment submission response status:", response.status); + + if (response.status >= 200 && response.status < 300) { + // Successfully created comment + const data = await response.json(); + console.log("Comment created successfully:", data); + + loadComments(proposalId); + updateCommentCount(proposalId); + showToastMessage('Comment posted!', '#11cc77'); + return data; + } else { + // Server returned an error + let errorMessage; + try { + const errorData = await response.json(); + errorMessage = errorData.error || 'Unknown server error'; + } catch (e) { + errorMessage = await response.text() || 'Failed to post comment'; + } + + console.error('Error posting comment:', errorMessage); + showToastMessage('Failed to post comment', '#ff0099'); + throw new Error(errorMessage); } - return response.json(); - }) - .then(data => { - loadComments(proposalId); - updateCommentCount(proposalId); - showToastMessage('Comment posted!', '#11cc77'); - return data; - }) - .catch(error => { - console.error('Error posting comment:', error); + } catch (error) { + console.error('Network or processing error:', error); showToastMessage('Failed to post comment', '#ff0099'); throw error; - }); + } } // Function to check if comment input is not empty diff --git a/worker.js b/worker.js index 96ca891..aa5eb8d 100644 --- a/worker.js +++ b/worker.js @@ -31,6 +31,8 @@ function createResponse(body, status = 200, cacheDuration = 60*60*24) { headers['Cache-Control'] = 'no-store'; } + // Create a standard Response object + // This ensures properties like 'ok' are properly set based on status code return new Response(JSON.stringify(body), { status, headers @@ -1033,6 +1035,9 @@ async function getProposals(request, env) { MAX_PAGE_SIZE ); const offset = (page - 1) * limit; + const sortBy = url.searchParams.get('sortBy') || 'newest'; + + console.log(`Getting proposals with sorting: ${sortBy}`); // Define the base query let query = ` @@ -1045,26 +1050,44 @@ async function getProposals(request, env) { (SELECT COUNT(DISTINCT pd.user_id) FROM petition_details pd WHERE pd.proposal_id = p.id AND pd.verified = 1) as verified_petitioners FROM proposals p JOIN users u ON p.author_id = u.id - ORDER BY p.timestamp DESC `; + // Add sorting + if (sortBy === 'newest') { + query += ` ORDER BY p.timestamp DESC`; + } else if (sortBy === 'oldest') { + query += ` ORDER BY p.timestamp ASC`; + } else if (sortBy === 'popular') { + query += ` ORDER BY upvotes DESC, p.timestamp DESC`; + } else if (sortBy === 'controversial') { + query += ` ORDER BY (upvotes + downvotes) DESC, ABS(upvotes - downvotes) ASC, p.timestamp DESC`; + } else { + // Default to newest + query += ` ORDER BY p.timestamp DESC`; + } + // Add pagination query += ` LIMIT ? OFFSET ?`; + console.log(`Executing query with pagination: limit=${limit}, offset=${offset}`); + // Execute the query const proposals = await env.DB.prepare(query).bind(limit, offset).all(); + console.log(`Retrieved ${proposals.results?.length || 0} proposals`); + // Add pagination info to response return createResponse({ data: proposals.results, pagination: { page, limit, - total: proposals.results.length, - hasMore: proposals.results.length === limit + total: proposals.results?.length || 0, + hasMore: proposals.results?.length === limit } }); } catch (error) { + console.error('Error retrieving proposals:', error); return createResponse({ error: 'Failed to retrieve proposals', details: logError(error, { action: 'get_proposals' })