x
This commit is contained in:
parent
9f98c853db
commit
3cb78a90d8
3 changed files with 162 additions and 83 deletions
137
index.html
137
index.html
|
|
@ -417,34 +417,27 @@ function smartCopyShare(proposalId, proposalText) {
|
|||
|
||||
// Create or get user in DB
|
||||
async function createUser(user) {
|
||||
try {
|
||||
console.log("Creating user:", user); // Log the user data
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/users`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: user.id,
|
||||
name: user.name
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
console.error("User creation API error:", errorData);
|
||||
throw new Error('Failed to create user');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log("User creation successful:", data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error creating user:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
try {
|
||||
console.log("Creating user:", user);
|
||||
|
||||
const data = await fetchWithErrorHandling(`${API_BASE_URL}/users`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: user.id,
|
||||
name: user.name
|
||||
})
|
||||
});
|
||||
|
||||
console.log("User creation successful:", data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('Error creating user:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Animation for successful post
|
||||
function animatePostSuccess() {
|
||||
|
|
@ -543,28 +536,58 @@ function smartCopyShare(proposalId, proposalText) {
|
|||
}, 500);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
async function fetchWithErrorHandling(url, options = {}) {
|
||||
try {
|
||||
// Add mode: 'cors' explicitly to ensure CORS is respected
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
mode: 'cors',
|
||||
credentials: 'same-origin'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
// Try to parse error message from response
|
||||
let errorData;
|
||||
try {
|
||||
errorData = await response.json();
|
||||
} catch (e) {
|
||||
errorData = { error: `HTTP error: ${response.status} ${response.statusText}` };
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
errorData.error ||
|
||||
errorData.message ||
|
||||
`Request failed with status ${response.status}`
|
||||
);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error(`Fetch error for ${url}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch proposals from API
|
||||
async function fetchProposals() {
|
||||
try {
|
||||
// Show loading indicator
|
||||
showLoadingIndicator();
|
||||
|
||||
const sortSelect = document.getElementById('sort-select');
|
||||
const sortBy = sortSelect ? sortSelect.value : 'newest';
|
||||
const response = await fetch(`${API_BASE_URL}/proposals?sortBy=${sortBy}&userId=${currentUser.id}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch proposals');
|
||||
}
|
||||
|
||||
const proposals = await response.json();
|
||||
renderProposals(proposals);
|
||||
} catch (error) {
|
||||
console.error('Error fetching proposals:', error);
|
||||
showErrorMessage('Oops! Failed to load petitions. Parliament might be censoring us already!');
|
||||
}
|
||||
}
|
||||
try {
|
||||
// Show loading indicator
|
||||
showLoadingIndicator();
|
||||
|
||||
const sortSelect = document.getElementById('sort-select');
|
||||
const sortBy = sortSelect ? sortSelect.value : 'newest';
|
||||
|
||||
const data = await fetchWithErrorHandling(
|
||||
`${API_BASE_URL}/proposals?sortBy=${sortBy}&userId=${currentUser.id}`
|
||||
);
|
||||
|
||||
renderProposals(data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching proposals:', error);
|
||||
showErrorMessage('Oops! Failed to load petitions. Try refreshing the page.');
|
||||
}
|
||||
}
|
||||
|
||||
// Handle voting
|
||||
async function handleVote(proposalId, voteType) {
|
||||
|
|
@ -760,7 +783,7 @@ async function submitVoteToServer(proposalId, voteType, isPetition = false, peti
|
|||
voteData.petitionDetails = petitionDetails;
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/votes`, {
|
||||
const response = await fetchWithErrorHandling(`${API_BASE_URL}/votes`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
|
@ -1117,7 +1140,7 @@ uploadIcon.style.marginRight = '8px';
|
|||
const trending = Math.random() > 0.8; // Randomly mark some as trending
|
||||
|
||||
// Create the proposal first
|
||||
const createResponse = await fetch(`${API_BASE_URL}/proposals`, {
|
||||
const createResponse = await fetchWithErrorHandling(`${API_BASE_URL}/proposals`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
|
@ -1466,7 +1489,7 @@ uploadIcon.style.marginRight = '8px';
|
|||
showToastMessage('Loading petition...', '#11cc77');
|
||||
|
||||
// Fetch the specific proposal
|
||||
const response = await fetch(`${API_BASE_URL}/proposals?userId=${currentUser.id}`);
|
||||
const response = await fetchWithErrorHandling(`${API_BASE_URL}/proposals?userId=${currentUser.id}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch proposal');
|
||||
|
|
@ -1761,7 +1784,7 @@ async function loadModalComments(proposalId) {
|
|||
|
||||
try {
|
||||
// Include the current user ID to get their votes
|
||||
const response = await fetch(`${API_BASE_URL}/comments?proposalId=${proposalId}&userId=${currentUser.id}`);
|
||||
const response = await fetchWithErrorHandling(`${API_BASE_URL}/comments?proposalId=${proposalId}&userId=${currentUser.id}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch comments');
|
||||
|
|
@ -1880,7 +1903,7 @@ async function handleCommentVote(commentId, voteType) {
|
|||
|
||||
// Submit vote to server
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/comment-votes`, {
|
||||
const response = await fetchWithErrorHandling(`${API_BASE_URL}/comment-votes`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
|
@ -1938,7 +1961,7 @@ async function loadComments(proposalId) {
|
|||
|
||||
try {
|
||||
// Include the current user ID to get their votes
|
||||
const response = await fetch(`${API_BASE_URL}/comments?proposalId=${proposalId}&userId=${currentUser.id}`);
|
||||
const response = await fetchWithErrorHandling(`${API_BASE_URL}/comments?proposalId=${proposalId}&userId=${currentUser.id}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch comments');
|
||||
|
|
@ -2028,7 +2051,7 @@ async function submitComment(proposalId, form) {
|
|||
submitButton.disabled = true;
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/comments`, {
|
||||
const response = await fetchWithErrorHandling(`${API_BASE_URL}/comments`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
|
@ -2342,7 +2365,7 @@ function updateCommentCount(proposalId) {
|
|||
const commentsToggle = document.getElementById(`comments-toggle-${proposalId}`);
|
||||
if (!commentsToggle) return;
|
||||
|
||||
fetch(`${API_BASE_URL}/comments?proposalId=${proposalId}`)
|
||||
fetchWithErrorHandling(`${API_BASE_URL}/comments?proposalId=${proposalId}`)
|
||||
.then(response => response.json())
|
||||
.then(comments => {
|
||||
const commentCount = comments.length;
|
||||
|
|
@ -2360,7 +2383,7 @@ function loadComments(proposalId) {
|
|||
|
||||
commentsList.innerHTML = '<div class="comments-loading">Loading comments...</div>';
|
||||
|
||||
fetch(`${API_BASE_URL}/comments?proposalId=${proposalId}`)
|
||||
fetchWithErrorHandling(`${API_BASE_URL}/comments?proposalId=${proposalId}`)
|
||||
.then(response => response.json())
|
||||
.then(comments => {
|
||||
if (comments.length === 0) {
|
||||
|
|
@ -2389,7 +2412,7 @@ function loadComments(proposalId) {
|
|||
|
||||
// Update submitComment function to handle promises
|
||||
function submitComment(proposalId, commentText) {
|
||||
return fetch(`${API_BASE_URL}/comments`, {
|
||||
return fetchWithErrorHandling(`${API_BASE_URL}/comments`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
|
|
|||
102
worker.js
102
worker.js
|
|
@ -1,3 +1,38 @@
|
|||
// Define CORS headers - These need to be applied to *all* responses
|
||||
const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
'Access-Control-Max-Age': '86400', // 24 hours
|
||||
};
|
||||
|
||||
// Handle OPTIONS request for CORS preflight
|
||||
function handleOptions() {
|
||||
return new Response(null, {
|
||||
headers: corsHeaders
|
||||
});
|
||||
}
|
||||
|
||||
// Helper to create standardized responses with CORS headers
|
||||
function createResponse(body, status = 200, cacheDuration = 60*60*24) {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
...corsHeaders // Make sure CORS headers are added to every response
|
||||
};
|
||||
|
||||
if (cacheDuration > 0) {
|
||||
headers['Cache-Control'] = `public, max-age=${cacheDuration}`;
|
||||
headers['CDN-Cache-Control'] = `public, max-age=${cacheDuration}`;
|
||||
} else {
|
||||
headers['Cache-Control'] = 'no-store';
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify(body), {
|
||||
status,
|
||||
headers
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
async fetch(request, env, ctx) {
|
||||
try {
|
||||
|
|
@ -13,7 +48,10 @@ export default {
|
|||
// Check if the hostname is valid
|
||||
if (!validHostnames.includes(url.hostname)) {
|
||||
console.error(`Unexpected hostname: ${url.hostname}`);
|
||||
return new Response('Invalid hostname', { status: 400 });
|
||||
return new Response('Invalid hostname', {
|
||||
status: 400,
|
||||
headers: corsHeaders // Add CORS headers even to error responses
|
||||
});
|
||||
}
|
||||
|
||||
const path = url.pathname;
|
||||
|
|
@ -22,17 +60,11 @@ export default {
|
|||
console.log(`Processing request: ${url.toString()}`);
|
||||
console.log(`User-Agent: ${request.headers.get('User-Agent')}`);
|
||||
|
||||
// Handle CORS preflight requests first
|
||||
// Handle CORS preflight requests first - this is critical
|
||||
if (request.method === 'OPTIONS') {
|
||||
return handleOptions();
|
||||
}
|
||||
|
||||
// // Check if this is an API request (starts with /api/)
|
||||
// if (!path.startsWith('/api/')) {
|
||||
// // For non-API routes, pass through to Cloudflare Pages
|
||||
// return fetch(request);
|
||||
// }
|
||||
|
||||
// For GET requests, try to serve from cache first
|
||||
if (request.method === "GET") {
|
||||
// Create a cache key from the request URL
|
||||
|
|
@ -69,7 +101,10 @@ export default {
|
|||
|
||||
if (!response.ok) {
|
||||
console.error('Failed to fetch styles.css', response.status, response.statusText);
|
||||
return new Response('CSS File Not Found', { status: 404 });
|
||||
return new Response('CSS File Not Found', {
|
||||
status: 404,
|
||||
headers: corsHeaders // Add CORS headers
|
||||
});
|
||||
}
|
||||
|
||||
// Get the CSS content
|
||||
|
|
@ -96,7 +131,10 @@ export default {
|
|||
return cssResponse;
|
||||
} catch (error) {
|
||||
console.error('Error fetching styles.css:', error);
|
||||
return new Response('Internal Server Error', { status: 500 });
|
||||
return new Response('Internal Server Error', {
|
||||
status: 500,
|
||||
headers: corsHeaders // Add CORS headers
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -252,22 +290,36 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Critical error in request handling:', error);
|
||||
return new Response(JSON.stringify({
|
||||
error: 'Internal Server Error',
|
||||
details: error.message
|
||||
}), {
|
||||
status: 500,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...corsHeaders // Add CORS headers to error responses too
|
||||
}
|
||||
});
|
||||
}
|
||||
// If no other handler catches the request, return a 404
|
||||
return createResponse({
|
||||
error: 'Not found',
|
||||
path,
|
||||
method: request.method,
|
||||
availableRoutes: [
|
||||
{ path: '/api/health', method: 'GET', description: 'Check system health' },
|
||||
{ path: '/api/proposals', method: 'GET', description: 'Get proposals' },
|
||||
{ path: '/api/proposals/:id', method: 'GET', description: 'Get a single proposal by ID' },
|
||||
{ path: '/api/proposals/:id', method: 'PUT', description: 'Update proposal' },
|
||||
{ path: '/api/votes', method: 'POST', description: 'Create/update vote' },
|
||||
{ path: '/api/users', method: 'POST', description: 'Create/get user' },
|
||||
{ path: '/api/petition-stats', method: 'GET', description: 'Get petition statistics' }
|
||||
]
|
||||
}, 404);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Critical error in request handling:', error);
|
||||
return new Response(JSON.stringify({
|
||||
error: 'Internal Server Error',
|
||||
details: error.message
|
||||
}), {
|
||||
status: 500,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...corsHeaders // Add CORS headers to error responses too
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@ bucket_name = "memes"
|
|||
[vars]
|
||||
ENVIRONMENT = "production"
|
||||
|
||||
# Routes (if using workers.dev)
|
||||
# Routes - Ensure ALL routes are properly configured
|
||||
[[routes]]
|
||||
pattern = "theradicalparty.com/api/*"
|
||||
zone_name = "theradicalparty.com"
|
||||
|
||||
[[routes]]
|
||||
pattern = "radical.omar-c29.workers.dev/*"
|
||||
zone_name = "radical.omar-c29.workers.dev"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue