Connect frontend to API and display events
This commit is contained in:
+10
-6
@@ -1,21 +1,25 @@
|
||||
import Fastify from "fastify";
|
||||
import { pool } from "./db/index.js";
|
||||
import { calendarRoutes } from "./modules/calendar/routes.js";
|
||||
import cors from "@fastify/cors";
|
||||
import { pool } from "./db";
|
||||
import { calendarRoutes } from "./modules/calendar/routes";
|
||||
|
||||
const app = Fastify();
|
||||
|
||||
await app.register(cors, {
|
||||
origin: true,
|
||||
});
|
||||
|
||||
pool
|
||||
.query("SELECT NOW()")
|
||||
.then((res) => console.log("DB connected:", res.rows[0]))
|
||||
.catch((err) => console.error("DB connection failed:", err));
|
||||
|
||||
app.register(calendarRoutes);
|
||||
|
||||
app.get("/health", async () => {
|
||||
return { ok: true };
|
||||
});
|
||||
|
||||
app.register(calendarRoutes);
|
||||
|
||||
app.listen({ port: 3000, host: "0.0.0.0" }).then(() => {
|
||||
console.log("API running on port 3000");
|
||||
});
|
||||
|
||||
});
|
||||
+32
-135
@@ -1,145 +1,42 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import { useEffect, useState } from "react";
|
||||
import { getEvents } from "./lib/api";
|
||||
|
||||
const supabase = createClient(
|
||||
import.meta.env.VITE_SUPABASE_URL,
|
||||
import.meta.env.VITE_SUPABASE_ANON_KEY
|
||||
)
|
||||
type Event = {
|
||||
id: string;
|
||||
title: string;
|
||||
starts_at: string;
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [events, setEvents] = useState<any[]>([])
|
||||
const [user, setUser] = useState<any>(null)
|
||||
const [profile, setProfile] = useState<any>(null)
|
||||
const [status, setStatus] = useState('loading...')
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
export default function CalendarPage() {
|
||||
const [events, setEvents] = useState<Event[]>([]);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
void loadEvents()
|
||||
void loadSession()
|
||||
}, [])
|
||||
|
||||
async function loadEvents() {
|
||||
const { data, error } = await supabase
|
||||
.from('events')
|
||||
.select('*')
|
||||
.order('created_at', { ascending: false })
|
||||
|
||||
if (error) {
|
||||
setError(error.message)
|
||||
setStatus('error loading events')
|
||||
return
|
||||
}
|
||||
|
||||
setEvents(data || [])
|
||||
setStatus('ready')
|
||||
}
|
||||
|
||||
async function loadSession() {
|
||||
const { data, error } = await supabase.auth.getUser()
|
||||
|
||||
if (error) {
|
||||
setError(error.message)
|
||||
return
|
||||
}
|
||||
|
||||
setUser(data.user ?? null)
|
||||
|
||||
if (data.user) {
|
||||
const { data: profileData, error: profileError } = await supabase
|
||||
.from('profiles')
|
||||
.select('*')
|
||||
.eq('id', data.user.id)
|
||||
.maybeSingle()
|
||||
|
||||
if (profileError) {
|
||||
setError(profileError.message)
|
||||
return
|
||||
}
|
||||
|
||||
setProfile(profileData)
|
||||
}
|
||||
}
|
||||
|
||||
async function signIn() {
|
||||
setError(null)
|
||||
|
||||
const { data, error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password,
|
||||
})
|
||||
|
||||
if (error) {
|
||||
setError(error.message)
|
||||
console.error('signIn error:', error)
|
||||
return
|
||||
}
|
||||
|
||||
console.log('signIn data:', data)
|
||||
setUser(data.user ?? null)
|
||||
|
||||
if (data.user) {
|
||||
const { data: profileData, error: profileError } = await supabase
|
||||
.from('profiles')
|
||||
.select('*')
|
||||
.eq('id', data.user.id)
|
||||
.maybeSingle()
|
||||
|
||||
if (profileError) {
|
||||
setError(profileError.message)
|
||||
console.error('profile error:', profileError)
|
||||
return
|
||||
}
|
||||
|
||||
setProfile(profileData)
|
||||
}
|
||||
}
|
||||
|
||||
async function signOut() {
|
||||
await supabase.auth.signOut()
|
||||
setUser(null)
|
||||
setProfile(null)
|
||||
}
|
||||
getEvents()
|
||||
.then((data) => {
|
||||
console.log("Fetched events:", data);
|
||||
setEvents(data);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Fetch failed:", err);
|
||||
setError(String(err));
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div style={{ padding: 20, color: 'white' }}>
|
||||
<h1>Supabase Test</h1>
|
||||
<p>Status: {status}</p>
|
||||
<div style={{ padding: "20px" }}>
|
||||
<h1>Events</h1>
|
||||
|
||||
{!user ? (
|
||||
<div>
|
||||
<h2>Sign In</h2>
|
||||
<input
|
||||
placeholder="Email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
style={{ display: 'block', marginBottom: 12 }}
|
||||
/>
|
||||
<input
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
style={{ display: 'block', marginBottom: 12 }}
|
||||
/>
|
||||
<button onClick={signIn}>Sign In</button>
|
||||
{error && <p>Error: {error}</p>}
|
||||
|
||||
<p>Event count: {events.length}</p>
|
||||
|
||||
{events.map((event) => (
|
||||
<div key={event.id}>
|
||||
<strong>{event.title}</strong>
|
||||
<div>{new Date(event.starts_at).toLocaleString()}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<h2>Signed In</h2>
|
||||
<p>{user.email}</p>
|
||||
<button onClick={signOut}>Sign Out</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && <p style={{ color: 'red' }}>{error}</p>}
|
||||
|
||||
<h2>Profile</h2>
|
||||
<pre>{JSON.stringify(profile, null, 2)}</pre>
|
||||
|
||||
<h2>Events</h2>
|
||||
<pre>{JSON.stringify(events, null, 2)}</pre>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
+4
-21
@@ -1,26 +1,9 @@
|
||||
import type { CalendarEvent } from '../types/calendar'
|
||||
|
||||
const API_BASE = 'http://localhost:8787'
|
||||
|
||||
export async function fetchPublicEvents(params: {
|
||||
from: string
|
||||
to: string
|
||||
calendarId?: string
|
||||
resourceId?: string
|
||||
}): Promise<CalendarEvent[]> {
|
||||
const search = new URLSearchParams({
|
||||
from: params.from,
|
||||
to: params.to,
|
||||
})
|
||||
|
||||
if (params.calendarId) search.set('calendarId', params.calendarId)
|
||||
if (params.resourceId) search.set('resourceId', params.resourceId)
|
||||
|
||||
const res = await fetch(`${API_BASE}/v1/public/events?${search.toString()}`)
|
||||
export async function getEvents() {
|
||||
const res = await fetch("http://localhost:3000/events");
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to fetch events: ${res.status}`)
|
||||
throw new Error("Failed to fetch events");
|
||||
}
|
||||
|
||||
return res.json() as Promise<CalendarEvent[]>
|
||||
return res.json();
|
||||
}
|
||||
Reference in New Issue
Block a user