feat: add weather widget to user portal below navbar
This commit is contained in:
@@ -42,6 +42,16 @@ export async function GET() {
|
|||||||
[userId]
|
[userId]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Get weather
|
||||||
|
let weather = undefined;
|
||||||
|
try {
|
||||||
|
const weatherRes = await fetch('http://localhost:3000/api/weather');
|
||||||
|
if (weatherRes.ok) {
|
||||||
|
const weatherData = await weatherRes.json();
|
||||||
|
weather = weatherData.data;
|
||||||
|
}
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
reservations,
|
reservations,
|
||||||
coupons,
|
coupons,
|
||||||
@@ -49,6 +59,7 @@ export async function GET() {
|
|||||||
benefits: benefits.map((b: { text: string }) => b.text),
|
benefits: benefits.map((b: { text: string }) => b.text),
|
||||||
wifiPassword,
|
wifiPassword,
|
||||||
trips,
|
trips,
|
||||||
|
weather,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if ((error as Error).message === 'Unauthorized') {
|
if ((error as Error).message === 'Unauthorized') {
|
||||||
|
|||||||
+36
-1
@@ -20,10 +20,16 @@ interface Message {
|
|||||||
created_at: string;
|
created_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Weather {
|
||||||
|
current: { celsius: number; fahrenheit: number; summary: string; windspeed: number; weathercode: number };
|
||||||
|
today: { maxC: number; minC: number; maxF: number; minF: number; summary: string; weathercode: number };
|
||||||
|
}
|
||||||
|
|
||||||
interface PortalData {
|
interface PortalData {
|
||||||
trips: Trip[];
|
trips: Trip[];
|
||||||
wifiPassword: string;
|
wifiPassword: string;
|
||||||
messages: Message[];
|
messages: Message[];
|
||||||
|
weather?: Weather;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gold = '#E8A849';
|
const gold = '#E8A849';
|
||||||
@@ -123,10 +129,39 @@ export default function UserPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<main style={{ padding: '2rem', maxWidth: '64rem', margin: '0 auto' }}>
|
<main style={{ padding: '2rem', maxWidth: '64rem', margin: '0 auto' }}>
|
||||||
<h1 style={{ fontSize: 'clamp(28px, 4vw, 42px)', fontWeight: 400, fontStyle: 'italic', color: navy, margin: '0 0 2rem' }}>
|
<h1 style={{ fontSize: 'clamp(28px, 4vw, 42px)', fontWeight: 400, fontStyle: 'italic', color: navy, margin: '0 0 1.5rem' }}>
|
||||||
Your Portal
|
Your Portal
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
{/* Weather Widget - Always visible below navbar */}
|
||||||
|
{data.weather && (
|
||||||
|
<div style={{ background: 'linear-gradient(135deg, #010D1E 0%, #1a2a3a 100%)', borderRadius: '16px', padding: '1.25rem 1.5rem', marginBottom: '2rem', display: 'flex', alignItems: 'center', gap: '2rem', flexWrap: 'wrap', boxShadow: '0 4px 16px rgba(1,13,30,0.2)' }}>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
||||||
|
<div style={{ fontSize: '48px' }}>
|
||||||
|
{data.weather.current.weathercode <= 1 ? '☀️' : data.weather.current.weathercode === 2 ? '⛅' : data.weather.current.weathercode === 3 ? '☁️' : data.weather.current.weathercode >= 51 && data.weather.current.weathercode <= 55 ? '🌧️' : data.weather.current.weathercode >= 61 ? '🌧️' : '☀️'}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div style={{ fontSize: '28px', fontWeight: 600, color: '#fff' }}>{data.weather.current.celsius}°C</div>
|
||||||
|
<div style={{ fontSize: '13px', color: 'rgba(255,255,255,0.7)' }}>{data.weather.current.summary}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', gap: '2rem', flex: 1, justifyContent: 'flex-end', flexWrap: 'wrap' }}>
|
||||||
|
<div style={{ textAlign: 'center' }}>
|
||||||
|
<div style={{ fontSize: '11px', color: 'rgba(255,255,255,0.6)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>High</div>
|
||||||
|
<div style={{ fontSize: '20px', fontWeight: 500, color: '#E8A849' }}>{data.weather.today.maxC}°</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ textAlign: 'center' }}>
|
||||||
|
<div style={{ fontSize: '11px', color: 'rgba(255,255,255,0.6)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>Low</div>
|
||||||
|
<div style={{ fontSize: '20px', fontWeight: 500, color: '#88b4e8' }}>{data.weather.today.minC}°</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ textAlign: 'center' }}>
|
||||||
|
<div style={{ fontSize: '11px', color: 'rgba(255,255,255,0.6)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>Wind</div>
|
||||||
|
<div style={{ fontSize: '16px', color: '#fff' }}>{data.weather.current.windspeed} km/h</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Welcome Message - Show on reservation day */}
|
{/* Welcome Message - Show on reservation day */}
|
||||||
{activeTrip && (
|
{activeTrip && (
|
||||||
<Section title="Welcome!" highlight>
|
<Section title="Welcome!" highlight>
|
||||||
|
|||||||
Reference in New Issue
Block a user