updates
This commit is contained in:
parent
fc47823714
commit
2f7f26e4fd
109
nginx-host.conf
109
nginx-host.conf
@ -28,7 +28,65 @@ server {
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # from certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # from certbot
|
||||
|
||||
# === Proxy all traffic to your Node app ===
|
||||
# === Proxy for direct image requests from Wren API ===
|
||||
location ~* ^/images/(.*)$ {
|
||||
proxy_pass https://www.wren.co/images/$1;
|
||||
proxy_ssl_server_name on;
|
||||
proxy_set_header Host www.wren.co;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_buffers 16 4k;
|
||||
proxy_buffer_size 2k;
|
||||
|
||||
# Add CORS headers for images
|
||||
add_header Access-Control-Allow-Origin '*' always;
|
||||
add_header Access-Control-Allow-Methods 'GET, OPTIONS' always;
|
||||
add_header Access-Control-Allow-Headers 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always;
|
||||
|
||||
# Cache control for images
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800";
|
||||
|
||||
# Handle OPTIONS requests for CORS preflight
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header Access-Control-Allow-Origin '*';
|
||||
add_header Access-Control-Allow-Methods 'GET, OPTIONS';
|
||||
add_header Access-Control-Allow-Headers 'Origin, X-Requested-With, Content-Type, Accept, Authorization';
|
||||
add_header Access-Control-Max-Age 1728000;
|
||||
add_header Content-Type 'text/plain charset=UTF-8';
|
||||
add_header Content-Length 0;
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
# === Proxy for Wren API requests ===
|
||||
location /api/wren/ {
|
||||
proxy_pass https://www.wren.co/api/;
|
||||
proxy_ssl_server_name on;
|
||||
proxy_set_header Host www.wren.co;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Add CORS headers for API requests
|
||||
add_header Access-Control-Allow-Origin '*' always;
|
||||
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS' always;
|
||||
add_header Access-Control-Allow-Headers 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always;
|
||||
|
||||
# Handle OPTIONS requests for CORS preflight
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header Access-Control-Allow-Origin '*';
|
||||
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
|
||||
add_header Access-Control-Allow-Headers 'Origin, X-Requested-With, Content-Type, Accept, Authorization';
|
||||
add_header Access-Control-Max-Age 1728000;
|
||||
add_header Content-Type 'text/plain charset=UTF-8';
|
||||
add_header Content-Length 0;
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
# === Proxy all other traffic to your Node app ===
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3800;
|
||||
proxy_http_version 1.1;
|
||||
@ -38,10 +96,55 @@ server {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# increase timeouts if your app sometimes takes longer to respond:
|
||||
proxy_read_timeout 90;
|
||||
|
||||
# Add CORS headers for all responses
|
||||
add_header Access-Control-Allow-Origin '*' always;
|
||||
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS' always;
|
||||
add_header Access-Control-Allow-Headers 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always;
|
||||
|
||||
# Increase timeouts for potentially slow API calls
|
||||
proxy_read_timeout 120;
|
||||
proxy_connect_timeout 120;
|
||||
proxy_send_timeout 120;
|
||||
}
|
||||
|
||||
# === Additional common settings ===
|
||||
|
||||
# Increase client body size for file uploads if needed
|
||||
client_max_body_size 10M;
|
||||
|
||||
# Enable compression for better performance
|
||||
gzip on;
|
||||
gzip_comp_level 5;
|
||||
gzip_min_length 256;
|
||||
gzip_proxied any;
|
||||
gzip_vary on;
|
||||
gzip_types
|
||||
application/atom+xml
|
||||
application/javascript
|
||||
application/json
|
||||
application/ld+json
|
||||
application/manifest+json
|
||||
application/rss+xml
|
||||
application/vnd.geo+json
|
||||
application/vnd.ms-fontobject
|
||||
application/x-font-ttf
|
||||
application/x-web-app-manifest+json
|
||||
application/xhtml+xml
|
||||
application/xml
|
||||
font/opentype
|
||||
image/bmp
|
||||
image/svg+xml
|
||||
image/x-icon
|
||||
text/cache-manifest
|
||||
text/css
|
||||
text/plain
|
||||
text/vcard
|
||||
text/vnd.rim.location.xloc
|
||||
text/vtt
|
||||
text/x-component
|
||||
text/x-cross-domain-policy;
|
||||
|
||||
# Optional: serve static assets directly if you ever add any here
|
||||
# location /static/ {
|
||||
# root /var/www/puffinoffset.com;
|
||||
|
||||
35
nginx.conf
35
nginx.conf
@ -13,15 +13,38 @@ server {
|
||||
gzip_proxied expired no-cache no-store private auth;
|
||||
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
# Forward all requests to index.html for SPA routing
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Cache static assets
|
||||
# Add CORS headers for static assets including images
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, no-transform";
|
||||
add_header Access-Control-Allow-Origin * always;
|
||||
add_header Access-Control-Allow-Methods 'GET, OPTIONS' always;
|
||||
add_header Access-Control-Allow-Headers 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# Forward all requests to index.html for SPA routing
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
|
||||
# Add CORS headers for all responses
|
||||
add_header Access-Control-Allow-Origin * always;
|
||||
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS' always;
|
||||
add_header Access-Control-Allow-Headers 'Origin, X-Requested-With, Content-Type, Accept, Authorization' always;
|
||||
}
|
||||
|
||||
# Respond to preflighted CORS requests
|
||||
location /api/ {
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header Access-Control-Allow-Origin * always;
|
||||
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS' always;
|
||||
add_header Access-Control-Allow-Headers 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always;
|
||||
add_header Access-Control-Max-Age 1728000;
|
||||
add_header Content-Type 'text/plain charset=UTF-8';
|
||||
add_header Content-Length 0;
|
||||
return 204;
|
||||
}
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Don't cache HTML
|
||||
|
||||
@ -160,19 +160,16 @@ export async function createOffsetOrder(
|
||||
console.error('[wrenClient] Cannot create order - missing API token');
|
||||
throw new Error('Carbon offset service is currently unavailable. Please contact support.');
|
||||
}
|
||||
|
||||
// Always use portfolio ID 2 for Community Tree Planting as seen in the tutorial
|
||||
const actualPortfolioId = 2;
|
||||
|
||||
console.log(`[wrenClient] Creating offset order: portfolio=${actualPortfolioId}, tons=${tons}, dryRun=${dryRun}`);
|
||||
console.log(`[wrenClient] Creating offset order: portfolio=${portfolioId}, tons=${tons}, dryRun=${dryRun}`);
|
||||
|
||||
const api = createApiClient();
|
||||
// Removed the /api prefix to match the working example
|
||||
const response = await api.post('/offset-orders', {
|
||||
// Using exactly the format shown in the API tutorial
|
||||
portfolioId: actualPortfolioId, // Force using ID 2 as in the tutorial
|
||||
portfolioId, // Use the provided portfolio ID instead of hardcoding
|
||||
tons,
|
||||
dryRun: true // Always use dryRun mode for testing
|
||||
dryRun // Use the provided dryRun parameter
|
||||
});
|
||||
|
||||
// Add detailed response logging
|
||||
|
||||
@ -64,19 +64,34 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr
|
||||
fetchPortfolio();
|
||||
}, []);
|
||||
|
||||
const [portfolios, setPortfolios] = useState<Portfolio[]>([]);
|
||||
const [selectedPortfolioId, setSelectedPortfolioId] = useState<number | null>(null);
|
||||
|
||||
const fetchPortfolio = async () => {
|
||||
try {
|
||||
const portfolios = await getPortfolios();
|
||||
const puffinPortfolio = portfolios.find(p =>
|
||||
const allPortfolios = await getPortfolios();
|
||||
|
||||
// Check if portfolios were returned
|
||||
if (!allPortfolios || allPortfolios.length === 0) {
|
||||
throw new Error('No portfolios available');
|
||||
}
|
||||
|
||||
setPortfolios(allPortfolios);
|
||||
|
||||
// Set default portfolio - prefer one with "puffin" in the name, otherwise first one
|
||||
const puffinPortfolio = allPortfolios.find(p =>
|
||||
p.name.toLowerCase().includes('puffin') ||
|
||||
p.name.toLowerCase().includes('maritime')
|
||||
);
|
||||
|
||||
if (!puffinPortfolio) {
|
||||
throw new Error('Portfolio not found');
|
||||
if (puffinPortfolio) {
|
||||
setPortfolio(puffinPortfolio);
|
||||
setSelectedPortfolioId(puffinPortfolio.id);
|
||||
} else {
|
||||
// Default to first portfolio if no puffin portfolio found
|
||||
setPortfolio(allPortfolios[0]);
|
||||
setSelectedPortfolioId(allPortfolios[0].id);
|
||||
}
|
||||
|
||||
setPortfolio(puffinPortfolio);
|
||||
} catch (err) {
|
||||
setError('Failed to fetch portfolio information. Please try again.');
|
||||
} finally {
|
||||
@ -84,6 +99,15 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr
|
||||
}
|
||||
};
|
||||
|
||||
// Handle portfolio selection change
|
||||
const handlePortfolioChange = (portfolioId: number) => {
|
||||
const selected = portfolios.find(p => p.id === portfolioId);
|
||||
if (selected) {
|
||||
setPortfolio(selected);
|
||||
setSelectedPortfolioId(portfolioId);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOffsetOrder = async () => {
|
||||
if (!portfolio) return;
|
||||
|
||||
@ -287,6 +311,28 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr
|
||||
</div>
|
||||
) : portfolio ? (
|
||||
<>
|
||||
{portfolios.length > 1 && (
|
||||
<div className="mb-8">
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Select Carbon Offset Portfolio
|
||||
</label>
|
||||
<select
|
||||
value={selectedPortfolioId || ''}
|
||||
onChange={(e) => handlePortfolioChange(Number(e.target.value))}
|
||||
className="block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"
|
||||
>
|
||||
{portfolios.map((p) => (
|
||||
<option key={p.id} value={p.id}>
|
||||
{p.name} - {formatCurrency(p.pricePerTon, getCurrencyByCode(currency))} per ton
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<p className="mt-2 text-sm text-gray-500">
|
||||
Select which portfolio of climate projects you'd like to support.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="bg-white border rounded-lg p-6 mb-8">
|
||||
<h3 className="text-xl font-semibold text-gray-900 mb-4">
|
||||
{portfolio.name}
|
||||
@ -396,4 +442,4 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user