Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 10 additions & 40 deletions dev/app/components/EmbeddedWidgetComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
"use client";

import { useEffect, useRef, useState } from "react";

import { AirbyteEmbeddedWidget, WidgetEvent } from "@/src/EmbeddedWidget";
import styles from "../page.module.css";

// Debug logging to check if AirbyteEmbeddedWidget is available
console.log("AirbyteEmbeddedWidget imported:", Boolean(AirbyteEmbeddedWidget));

interface EmbeddedWidgetComponentProps {
onEvent?: (event: WidgetEvent) => void;
Expand All @@ -21,43 +16,25 @@ export function EmbeddedWidgetComponent({ onEvent, className }: EmbeddedWidgetCo

useEffect(() => {
let isMounted = true;

const initializeWidget = async () => {
if (initialized) {
return;
}

if (initialized) return;
try {
const response = await fetch("/api/widget_token");
const data = await response.json();

// Check if component is still mounted after async operations
if (!isMounted) {
return;
}

console.log("Token response:", data);

if (!data.token) {
console.error("Token response:", data);
throw new Error("Missing token in response");
}

if (!isMounted) return;
if (!data.token) throw new Error("Missing token in response");
try {
widgetRef.current = new AirbyteEmbeddedWidget({
token: data.token,
onEvent: (event: WidgetEvent) => {
if (onEvent) {
onEvent(event);
}
onEvent?.(event);
fetch("/api/embedded_response", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(event),
}).catch((err) => console.error("Error sending event data:", err));
},
});

if (isMounted) {
setInitialized(true);
setLoading(false);
Expand All @@ -72,32 +49,25 @@ export function EmbeddedWidgetComponent({ onEvent, className }: EmbeddedWidgetCo
}
}
};

// Reset initialized state on each mount to handle StrictMode remounting
setInitialized(false);

// Execute initialization
initializeWidget();

return () => {
isMounted = false;
};
}, [onEvent]);

const handleOpenWidget = () => {
if (widgetRef.current) {
widgetRef.current.open();
}
widgetRef.current?.open();
};

return (
<div className={styles.widgetComponentWrapper}>
{loading && <div className={styles.loading}>Loading widget...</div>}
{error && <div className={styles.error}>Error: {error}</div>}
<div className="flex flex-col items-center gap-4">
{loading && <div className="text-gray-600 text-base">Loading widget...</div>}
{error && <div className="text-red-600 text-base p-4 bg-red-100 rounded border border-red-200">Error: {error}</div>}
{initialized && (
<button
<button
onClick={handleOpenWidget}
className={`${styles.widgetButton} ${className || ""}`}
className={`px-6 py-3 text-base font-medium text-white bg-indigo-600 rounded-md shadow hover:bg-indigo-700 active:bg-indigo-800 transition-colors duration-200 ${className || ""}`}
>
Open Airbyte
</button>
Expand Down
5 changes: 5 additions & 0 deletions dev/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import "tailwindcss";

@tailwind base;
@tailwind components;
@tailwind utilities;
5 changes: 4 additions & 1 deletion dev/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "./globals.css";
import type { Metadata } from "next";

export const metadata: Metadata = {
Expand All @@ -11,7 +12,9 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body>{children}</body>
<body className="min-h-screen text-black">
{children}
</body>
</html>
);
}
76 changes: 51 additions & 25 deletions dev/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,73 @@
"use client";

import { EmbeddedWidgetComponent } from "./components/EmbeddedWidgetComponent";
import styles from "./page.module.css";

export default function Home() {
const handleWidgetEvent = (event: any) => {
console.log("Widget event handled in Home component:", event);
};

return (
<div className={styles.container}>
<header className={styles.header}>
<h1 className={styles.heading}>Airbyte Embedded Widget</h1>
<div className="min-h-screen bg-gradient-to-br from-indigo-50 via-blue-50 to-indigo-100 flex flex-col">
<header className="w-full py-10 shadow-md mb-12 border-b border-indigo-100">
<div className="max-w-2xl mx-auto flex flex-col items-center px-6">
<h1 className="text-5xl font-black text-indigo-700 tracking-tight drop-shadow-sm mb-2 text-center">
Airbyte Embedded Widget
</h1>
<p className="text-lg text-indigo-400 font-medium text-center">
A beautiful developer playground for your widget
</p>
</div>
</header>

<div className={styles.widgetContainer}>
<p className={styles.note}>Click the button below to open the Airbyte widget.</p>
<div className={styles.buttonContainer}>
<EmbeddedWidgetComponent onEvent={handleWidgetEvent} />
<main className="flex-1 flex flex-col items-center justify-center px-2 pb-12">
<div className=" p-10 rounded-3xl shadow-2xl w-full max-w-lg text-center mb-12 border border-indigo-100 transition-all duration-300">
<p className="text-base opacity-90 mb-8 text-gray-700">
Click the button below to open the Airbyte widget.
</p>
<div className="flex justify-center mt-2">
<EmbeddedWidgetComponent onEvent={handleWidgetEvent} />
</div>
</div>
</div>

<div className={styles.envContainer}>
<h2 className={styles.headingSmall}>Environment Variables:</h2>
<EnvVar label="NEXT_PUBLIC_WORKSPACE_ID" value={process.env.NEXT_PUBLIC_WORKSPACE_ID} />
<EnvVar label="NEXT_PUBLIC_CLIENT_ID" value={process.env.NEXT_PUBLIC_CLIENT_ID} />
<EnvVar
label="NEXT_PUBLIC_CLIENT_SECRET"
value={process.env.NEXT_PUBLIC_CLIENT_SECRET ? "******" : "Not set"}
/>
<EnvVar label="NEXT_PUBLIC_BASE_URL" value={process.env.NEXT_PUBLIC_BASE_URL} />
<p className={styles.envNote}>
Note: Environment variables must be prefixed with <code>NEXT_PUBLIC_</code> to be visible on the client side.
</p>
</div>
<div className="w-full max-w-lg border border-indigo-100 p-8 rounded-2xl bg-white/90 shadow-lg">
<h2 className="text-xl font-bold mb-6 text-indigo-700 flex items-center gap-2">
<span className="inline-block w-3 h-3 bg-indigo-400 rounded-full animate-pulse" />
Environment Variables
</h2>
<div className="space-y-3 mb-4">
<EnvVar
label="NEXT_PUBLIC_WORKSPACE_ID"
value={process.env.NEXT_PUBLIC_WORKSPACE_ID}
/>
<EnvVar label="NEXT_PUBLIC_CLIENT_ID" value={process.env.NEXT_PUBLIC_CLIENT_ID} />
<EnvVar
label="NEXT_PUBLIC_CLIENT_SECRET"
value={process.env.NEXT_PUBLIC_CLIENT_SECRET ? "******" : "Not set"}
/>
<EnvVar label="NEXT_PUBLIC_BASE_URL" value={process.env.NEXT_PUBLIC_BASE_URL} />
</div>
<p className="mt-3 text-xs text-gray-500 text-left">
<span className="font-semibold text-indigo-500">Note:</span> Environment variables must be prefixed with{" "}
<code className="bg-indigo-50 px-1 rounded text-indigo-700">NEXT_PUBLIC_</code> to be visible on the client side.
</p>
</div>
</main>
</div>
);
}

function EnvVar({ label, value }: { label: string; value: string | undefined }) {
function EnvVar({
label,
value,
}: {
label: string;
value: string | undefined;
}) {
return (
<div>
<b>{label}:</b> {value || "Not set"}
<div className="flex items-center justify-between bg-indigo-50/80 px-4 py-2 rounded-lg text-base border border-indigo-100">
<span className="font-semibold text-indigo-800 tracking-wide">{label}:</span>
<span className="ml-3 text-gray-700 font-mono break-all">{value || "Not set"}</span>
</div>
);
}
4 changes: 4 additions & 0 deletions dev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@
"react-dom": "^18"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.10",
"@types/node": "^20.11.24",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.4.21",
"eslint": "^9.23.0",
"eslint-config-next": "14.2.5",
"postcss": "^8.5.6",
"tailwindcss": "^4.1.10",
"typescript": "5.8.2"
}
}
6 changes: 6 additions & 0 deletions dev/postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;
9 changes: 9 additions & 0 deletions dev/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
content: [
"./app/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@airbyte-embedded/airbyte-embedded-widget",
"version": "0.4.2",
"version": "0.4.3",
"description": "Embedded widget for Airbyte",
"type": "module",
"main": "dist/index.cjs.js",
Expand Down
Loading
Loading