Adjusted types, environment vars, load env vars from Cloudflare (?), sync iframe updates [not working]
This commit is contained in:
parent
198109a919
commit
6cf1c2511b
|
|
@ -1,5 +1,5 @@
|
||||||
import { BaseBoxShapeUtil, TLBaseShape } from "tldraw"
|
import { BaseBoxShapeUtil, TLBaseShape } from "tldraw"
|
||||||
import { useCallback, useState } from "react"
|
import { useCallback, useState, useEffect } from "react"
|
||||||
//import Embed from "react-embed"
|
//import Embed from "react-embed"
|
||||||
|
|
||||||
export type IEmbedShape = TLBaseShape<
|
export type IEmbedShape = TLBaseShape<
|
||||||
|
|
@ -9,7 +9,7 @@ export type IEmbedShape = TLBaseShape<
|
||||||
h: number
|
h: number
|
||||||
url: string | null
|
url: string | null
|
||||||
interactionState?: {
|
interactionState?: {
|
||||||
scrollPosition?: { x: number; y: number }
|
scrollPosition: { x: number; y: number }
|
||||||
currentTime?: number // for videos
|
currentTime?: number // for videos
|
||||||
// other state you want to sync
|
// other state you want to sync
|
||||||
}
|
}
|
||||||
|
|
@ -133,12 +133,26 @@ export class EmbedShape extends BaseBoxShapeUtil<IEmbedShape> {
|
||||||
</g>
|
</g>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
component(shape: IEmbedShape) {
|
component(shape: IEmbedShape) {
|
||||||
const [inputUrl, setInputUrl] = useState(shape.props.url || "")
|
const [inputUrl, setInputUrl] = useState(shape.props.url || "")
|
||||||
const [error, setError] = useState("")
|
const [error, setError] = useState("")
|
||||||
const [copyStatus, setCopyStatus] = useState(false)
|
const [copyStatus, setCopyStatus] = useState(false)
|
||||||
|
|
||||||
|
// Add an effect to handle incoming sync updates
|
||||||
|
useEffect((): void => {
|
||||||
|
if (shape.props.interactionState?.scrollPosition) {
|
||||||
|
const iframe = document.querySelector("iframe")
|
||||||
|
if (iframe?.contentWindow) {
|
||||||
|
// Dispatch custom event to iframe
|
||||||
|
iframe.contentWindow.dispatchEvent(
|
||||||
|
new CustomEvent("syncScroll", {
|
||||||
|
detail: shape.props.interactionState.scrollPosition,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [shape.props.interactionState?.scrollPosition])
|
||||||
|
|
||||||
const handleSubmit = useCallback(
|
const handleSubmit = useCallback(
|
||||||
(e: React.FormEvent) => {
|
(e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
@ -327,11 +341,36 @@ export class EmbedShape extends BaseBoxShapeUtil<IEmbedShape> {
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
referrerPolicy="no-referrer"
|
referrerPolicy="no-referrer"
|
||||||
onLoad={(e) => {
|
onLoad={(e) => {
|
||||||
// Add message listener for iframe communication
|
const iframe = e.currentTarget as HTMLIFrameElement
|
||||||
|
|
||||||
|
// Inject scroll monitoring script
|
||||||
|
const script = `
|
||||||
|
window.addEventListener('scroll', () => {
|
||||||
|
window.parent.postMessage({
|
||||||
|
type: 'scroll',
|
||||||
|
scrollPosition: {
|
||||||
|
x: window.scrollX,
|
||||||
|
y: window.scrollY
|
||||||
|
}
|
||||||
|
}, '*');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Listen for scroll updates from other users
|
||||||
|
window.addEventListener('syncScroll', (e) => {
|
||||||
|
window.scrollTo(e.detail.x, e.detail.y);
|
||||||
|
});
|
||||||
|
`
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
iframe.contentWindow?.eval(script as string)
|
||||||
|
|
||||||
|
// Listen for messages from iframe
|
||||||
window.addEventListener("message", (event) => {
|
window.addEventListener("message", (event) => {
|
||||||
const iframe = e.currentTarget as HTMLIFrameElement
|
|
||||||
if (event.source === iframe.contentWindow) {
|
if (event.source === iframe.contentWindow) {
|
||||||
handleIframeInteraction(event.data)
|
handleIframeInteraction({
|
||||||
|
...shape.props.interactionState,
|
||||||
|
scrollPosition: event.data.scrollPosition,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -36,15 +36,10 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const apiKey = import.meta.env["VITE_DAILY_API_KEY"]
|
const response = await fetch("/api/create-room", {
|
||||||
console.log("API Key available:", !!apiKey)
|
|
||||||
if (!apiKey) throw new Error("Daily API key is missing")
|
|
||||||
|
|
||||||
const response = await fetch("https://api.daily.co/v1/rooms", {
|
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${apiKey.trim()}`,
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,11 @@
|
||||||
/// <reference types="@cloudflare/workers-types" />
|
/// <reference types="@cloudflare/workers-types" />
|
||||||
|
|
||||||
export interface Environment {
|
export interface Environment {
|
||||||
TLDRAW_BUCKET: R2Bucket
|
TLDRAW_BUCKET: R2Bucket
|
||||||
TLDRAW_DURABLE_OBJECT: DurableObjectNamespace
|
TLDRAW_DURABLE_OBJECT: DurableObjectNamespace
|
||||||
DAILY_API_KEY: string;
|
DAILY_API_KEY: string
|
||||||
DAILY_DOMAIN: string;
|
VITE_DAILY_API_KEY: string
|
||||||
}
|
VITE_DAILY_DOMAIN: string
|
||||||
|
VITE_GOOGLE_CLIENT_ID: string
|
||||||
|
VITE_GOOGLE_MAPS_API_KEY: string
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ const { preflight, corsify } = cors({
|
||||||
maxAge: 86400,
|
maxAge: 86400,
|
||||||
credentials: true,
|
credentials: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const router = AutoRouter<IRequest, [env: Environment, ctx: ExecutionContext]>({
|
const router = AutoRouter<IRequest, [env: Environment, ctx: ExecutionContext]>({
|
||||||
before: [preflight],
|
before: [preflight],
|
||||||
finally: [
|
finally: [
|
||||||
|
|
@ -124,61 +125,43 @@ const router = AutoRouter<IRequest, [env: Environment, ctx: ExecutionContext]>({
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
.post("/daily/rooms", async (request, env) => {
|
.post("/api/create-room", async (request) => {
|
||||||
try {
|
try {
|
||||||
const { name, properties } = (await request.json()) as {
|
// Replace with your actual video chat service API call
|
||||||
name: string
|
const room = await createVideoRoom()
|
||||||
properties: Record<string, unknown>
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a room using Daily.co API
|
|
||||||
const dailyResponse = await fetch("https://api.daily.co/v1/rooms", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `Bearer ${env.DAILY_API_KEY}`,
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
name,
|
|
||||||
properties,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
const dailyData = await dailyResponse.json()
|
|
||||||
|
|
||||||
if (!dailyResponse.ok) {
|
|
||||||
return new Response(
|
|
||||||
JSON.stringify({
|
|
||||||
message:
|
|
||||||
(dailyData as any).info || "Failed to create Daily.co room",
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
status: 400,
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
url: `https://${env.DAILY_DOMAIN}/${(dailyData as any).name}`,
|
url: room.url,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Access-Control-Allow-Origin": "*", // Configure appropriately for production
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return new Response(
|
return new Response(JSON.stringify({ error: "Failed to create room" }), {
|
||||||
JSON.stringify({
|
status: 500,
|
||||||
message: error instanceof Error ? error.message : "Unknown error",
|
headers: {
|
||||||
}),
|
"Content-Type": "application/json",
|
||||||
{
|
"Access-Control-Allow-Origin": "*",
|
||||||
status: 500,
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
},
|
},
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Handle OPTIONS for CORS
|
||||||
|
.options("/api/create-room", () => {
|
||||||
|
return new Response(null, {
|
||||||
|
headers: {
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
"Access-Control-Allow-Methods": "POST",
|
||||||
|
"Access-Control-Allow-Headers": "Content-Type",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
// export our router for cloudflare
|
// export our router for cloudflare
|
||||||
export default router
|
export default router
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue