Skip to content

Commit a72a7ca

Browse files
authored
Fix pgflow-demo slow loading time (#128)
* chore: add static and runtime configurations, implement skeleton loading, and update auth handling - Set dynamic to 'force-static' for specific pages to optimize static rendering - Set runtime to 'edge' for sign-in and sign-up pages for edge functions - Introduce SkeletonTable and Skeleton components for improved loading states - Update header-auth and website-analyzer-form to manage user state with useEffect - Enhance example links component to fetch login status asynchronously - Minor UI adjustments for sign-in, sign-up, and homepage components to handle loading and auth states * refactor: move data loading logic outside useEffect to prevent race conditions - Extracted the data fetching and initialization code from the initial useEffect - Ensured data is loaded after subscription setup to avoid race conditions - Maintained existing state updates and loading state management - Improved code clarity and separation of concerns in the component * chore: update environment variables and configure GitHub OAuth provider - Added GITHUB_OAUTH_CLIENT_ID and GITHUB_OAUTH_CLIENT_SECRET to environment example - Enabled GitHub external auth in the configuration with environment variable references - Updated redirect URI for OAuth callback to localhost - Minor formatting adjustments in environment and config files * chore: add scripts for managing local Supabase instance in playground package - Introduced start-supabase, stop-supabase, and restart-supabase scripts for easier local development - Updated package.json with commands to start, stop, and restart Supabase - Included a script to serve functions and generate TypeScript types for database schema * chore: update script references and commands in package.json and add a new helper script Refactored package.json to replace npx commands with local script invocations for better consistency and control. Added a new executable script for managing Supabase environment variables and commands, improving developer experience and script maintainability. * feat: enhance auth pages with loading states, improve user feedback, and add logging - Added isLoading state to sign-in and sign-up forms for better UX during async actions - Disabled inputs and buttons during loading to prevent duplicate submissions - Updated GithubButton to support external loading state and show spinner - Implemented useEffect in sign-up page to process searchParams and display messages - Added console logs in auth callback route for debugging code exchange process - Enhanced header-auth component with auth state change logging for better monitoring - Updated supabase config with explicit redirect URL and additional redirect URLs for OAuth - Refactored submit-button to show spinner during pending state - Overall improvements for user feedback, debugging, and code consistency * fix: prevent default form submission and handle loading state in auth components - Added e.preventDefault() to form onSubmit handler in sign-in page - Updated GithubButton to reset loading state on error handling - Ensures consistent loading state management across authentication UI components * style: improve layout and UI consistency across components - Add relative positioning to main container for layout stability - Extend footer to be fixed at bottom with background and backdrop blur - Adjust sidebar styling with consistent border and opacity states - Enhance border and overflow styles in flow run details component - Update analysis UI container with background and margin for better spacing
1 parent 6183d6f commit a72a7ca

File tree

22 files changed

+339
-143
lines changed

22 files changed

+339
-143
lines changed

examples/playground/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
# https://app.supabase.com/project/_/settings/api
33
NEXT_PUBLIC_SUPABASE_URL="http://127.0.0.1:54321"
44
NEXT_PUBLIC_SUPABASE_ANON_KEY="your key here"
5+
GITHUB_OAUTH_CLIEND_ID=
6+
GITHUB_OAUTH_CLIENT_SECRET=

examples/playground/app/(auth-pages)/forgot-password/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { Label } from "@/components/ui/label";
66
import Link from "next/link";
77
import { SmtpMessage } from "../smtp-message";
88

9+
export const dynamic = 'force-static';
10+
911
export default async function ForgotPassword(props: {
1012
searchParams: Promise<Message>;
1113
}) {

examples/playground/app/(auth-pages)/sign-in/page.tsx

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use client';
2+
export const runtime = 'edge';
23

34
import { signInAction } from '@/app/actions';
45
import { FormMessage, Message } from '@/components/form-message';
@@ -17,6 +18,7 @@ export default function Login({
1718
searchParams: Promise<Message>;
1819
}) {
1920
const [message, setMessage] = useState<Message | null>(null);
21+
const [isLoading, setIsLoading] = useState(false);
2022
const router = useRouter();
2123

2224
// After successful login, redirect to home page
@@ -54,7 +56,10 @@ export default function Login({
5456
}, [router, searchParams]);
5557

5658
return (
57-
<form className="flex flex-col min-w-64 max-w-64 mx-auto">
59+
<form className="flex flex-col min-w-64 max-w-64 mx-auto" onSubmit={(e) => {
60+
e.preventDefault();
61+
setIsLoading(true);
62+
}}>
5863
<h1 className="text-2xl font-medium">Sign in</h1>
5964
<p className="text-sm text-foreground">
6065
Don't have an account?{' '}
@@ -63,8 +68,18 @@ export default function Login({
6368
</Link>
6469
</p>
6570
<div className="flex flex-col gap-2 [&>input]:mb-3 mt-8">
71+
<GithubButton
72+
onLoadingChange={setIsLoading}
73+
disabled={isLoading}
74+
className="h-12 text-base"
75+
/>
76+
<div className="relative flex py-4 items-center">
77+
<div className="flex-grow border-t border-muted"></div>
78+
<span className="flex-shrink mx-4 text-muted-foreground text-sm">Or continue with email</span>
79+
<div className="flex-grow border-t border-muted"></div>
80+
</div>
6681
<Label htmlFor="email">Email</Label>
67-
<Input name="email" placeholder="you@example.com" required />
82+
<Input name="email" placeholder="you@example.com" required disabled={isLoading} />
6883
<div className="flex justify-between items-center">
6984
<Label htmlFor="password">Password</Label>
7085
<Link
@@ -79,16 +94,15 @@ export default function Login({
7994
name="password"
8095
placeholder="Your password"
8196
required
97+
disabled={isLoading}
8298
/>
83-
<SubmitButton pendingText="Signing In..." formAction={signInAction}>
84-
Sign in
99+
<SubmitButton
100+
pendingText="Signing In..."
101+
formAction={signInAction}
102+
disabled={isLoading}
103+
>
104+
Sign in with email
85105
</SubmitButton>
86-
<div className="relative flex py-4 items-center">
87-
<div className="flex-grow border-t border-muted"></div>
88-
<span className="flex-shrink mx-4 text-muted-foreground text-sm">Or</span>
89-
<div className="flex-grow border-t border-muted"></div>
90-
</div>
91-
<GithubButton />
92106
<FormMessage message={message} />
93107
</div>
94108
</form>

examples/playground/app/(auth-pages)/sign-up/page.tsx

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,45 @@
1+
'use client';
2+
export const runtime = 'edge';
3+
14
import { signUpAction } from "@/app/actions";
25
import { FormMessage, Message } from "@/components/form-message";
36
import { GithubButton } from "@/components/github-button";
47
import { SubmitButton } from "@/components/submit-button";
58
import { Input } from "@/components/ui/input";
69
import { Label } from "@/components/ui/label";
710
import Link from "next/link";
11+
import { useState, useEffect } from 'react';
812

9-
export default async function Signup(props: {
13+
export default function Signup(props: {
1014
searchParams: Promise<Message>;
1115
}) {
12-
const searchParams = await props.searchParams;
13-
if ("message" in searchParams) {
16+
const [message, setMessage] = useState<Message | null>(null);
17+
const [isLoading, setIsLoading] = useState(false);
18+
19+
useEffect(() => {
20+
const processSearchParams = async () => {
21+
try {
22+
const resolvedParams = await props.searchParams;
23+
setMessage(resolvedParams);
24+
} catch (error) {
25+
console.error('Error processing searchParams:', error);
26+
}
27+
};
28+
29+
processSearchParams();
30+
}, [props.searchParams]);
31+
32+
if (message && "message" in message) {
1433
return (
1534
<div className="w-full flex-1 flex items-center h-screen sm:max-w-md justify-center gap-2 p-4">
16-
<FormMessage message={searchParams} />
35+
<FormMessage message={message} />
1736
</div>
1837
);
1938
}
2039

2140
return (
2241
<>
23-
<form className="flex flex-col min-w-64 max-w-64 mx-auto">
42+
<form className="flex flex-col min-w-64 max-w-64 mx-auto" onSubmit={() => setIsLoading(true)}>
2443
<h1 className="text-2xl font-medium">Sign up</h1>
2544
<p className="text-sm text text-foreground">
2645
Already have an account?{" "}
@@ -29,26 +48,36 @@ export default async function Signup(props: {
2948
</Link>
3049
</p>
3150
<div className="flex flex-col gap-2 [&>input]:mb-3 mt-8">
51+
<GithubButton
52+
onLoadingChange={setIsLoading}
53+
disabled={isLoading}
54+
className="h-12 text-base"
55+
text="Sign up with GitHub"
56+
/>
57+
<div className="relative flex py-4 items-center">
58+
<div className="flex-grow border-t border-muted"></div>
59+
<span className="flex-shrink mx-4 text-muted-foreground text-sm">Or sign up with email</span>
60+
<div className="flex-grow border-t border-muted"></div>
61+
</div>
3262
<Label htmlFor="email">Email</Label>
33-
<Input name="email" placeholder="you@example.com" required />
63+
<Input name="email" placeholder="you@example.com" required disabled={isLoading} />
3464
<Label htmlFor="password">Password</Label>
3565
<Input
3666
type="password"
3767
name="password"
3868
placeholder="Your password"
3969
minLength={6}
4070
required
71+
disabled={isLoading}
4172
/>
42-
<SubmitButton formAction={signUpAction} pendingText="Signing up...">
43-
Sign up
73+
<SubmitButton
74+
formAction={signUpAction}
75+
pendingText="Signing up..."
76+
disabled={isLoading}
77+
>
78+
Sign up with email
4479
</SubmitButton>
45-
<div className="relative flex py-4 items-center">
46-
<div className="flex-grow border-t border-muted"></div>
47-
<span className="flex-shrink mx-4 text-muted-foreground text-sm">Or</span>
48-
<div className="flex-grow border-t border-muted"></div>
49-
</div>
50-
<GithubButton />
51-
<FormMessage message={searchParams} />
80+
<FormMessage message={message} />
5281
</div>
5382
</form>
5483
</>

examples/playground/app/auth/callback/route.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@ export async function GET(request: Request) {
1010
const origin = requestUrl.origin;
1111
const redirectTo = requestUrl.searchParams.get('redirect_to')?.toString();
1212

13+
console.log('Auth callback - code:', code);
14+
console.log('Auth callback - origin:', origin);
15+
console.log('Auth callback - redirectTo:', redirectTo);
16+
1317
if (code) {
1418
const supabase = await createClient();
15-
await supabase.auth.exchangeCodeForSession(code);
19+
const { data, error } = await supabase.auth.exchangeCodeForSession(code);
20+
console.log('Exchange code result - data:', data);
21+
console.log('Exchange code result - error:', error);
1622
}
1723

1824
if (redirectTo) {

examples/playground/app/layout.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default function RootLayout({
4848
disableTransitionOnChange
4949
>
5050
<LoadingStateProvider>
51-
<main className="min-h-screen flex flex-col items-center">
51+
<main className="min-h-screen flex flex-col items-center relative">
5252
<div className="flex-1 w-full flex flex-col items-center">
5353
<nav className="w-full flex justify-center border-b border-b-foreground/10 h-14">
5454
<div className="w-full max-w-5xl flex justify-between items-center p-1 px-5 text-sm">
@@ -115,11 +115,11 @@ export default function RootLayout({
115115
</div>
116116
</div>
117117
</nav>
118-
<div className="flex flex-col max-w-5xl p-3 pt-0 w-full">
118+
<div className="flex flex-col max-w-5xl p-3 pt-0 w-full flex-1 pb-20">
119119
{children}
120120
</div>
121121

122-
<footer className="w-full flex items-center justify-center border-t mx-auto text-center text-xs gap-8 py-16">
122+
<footer className="w-full flex items-center justify-center border-t mx-auto text-center text-xs gap-8 py-4 fixed bottom-0 bg-background/95 backdrop-blur-sm z-50">
123123
<p>
124124
Powered by{' '}
125125
<a

examples/playground/app/page.tsx

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,29 @@
11
import Hero from '@/components/hero';
22
import WebsiteAnalyzerForm from '@/components/website-analyzer-form';
33
import AuthRedirectHandler from '@/components/auth-redirect-handler';
4-
import { createClient } from '@/utils/supabase/server';
54
import ExampleLinks from '@/components/example-links';
65

7-
export default async function Home() {
8-
const supabase = await createClient();
9-
const {
10-
data: { user },
11-
} = await supabase.auth.getUser();
12-
const isLoggedIn = !!user;
6+
export const runtime = 'edge';
7+
8+
export default function Home() {
139

1410
return (
1511
<>
1612
<main className="flex-1 flex flex-col gap-6 px-4">
1713
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
18-
<WebsiteAnalyzerForm isLoggedIn={isLoggedIn} />
14+
<WebsiteAnalyzerForm />
1915
<div>
2016
<h2 className="text-2xl font-medium mb-4">How it works</h2>
2117
<p className="text-foreground/80">
2218
Enter a URL in the form to analyze a website. Our tool will scrape
2319
it then use AI to summarize it and extract tags.
2420
</p>
25-
{!isLoggedIn && (
26-
<div className="mt-4 p-4 bg-yellow-50 border border-yellow-200 rounded-md">
27-
<p className="text-yellow-800">
28-
You'll need to sign in to analyze websites. When you click the
29-
button, you'll be redirected to the sign-in page.
30-
</p>
31-
</div>
32-
)}
3321

3422
<div className="mt-6">
3523
<h3 className="text-lg font-medium mb-2">
3624
Example Websites to Analyze
3725
</h3>
38-
<ExampleLinks isLoggedIn={isLoggedIn} />
26+
<ExampleLinks />
3927
</div>
4028
</div>
4129
</div>

examples/playground/app/websites/page.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Input } from '@/components/ui/input';
88
import { FormMessage } from '@/components/form-message';
99
import { SubmitButton } from '@/components/submit-button';
1010
import { useRouter } from 'next/navigation';
11+
import { SkeletonTable } from '@/components/skeleton-table';
1112

1213
type WebsiteRow = Database['public']['Tables']['websites']['Row'];
1314

@@ -139,7 +140,9 @@ export default function Page() {
139140

140141
<div>
141142
<h2 className="text-2xl font-medium mb-4">Your Websites</h2>
142-
{websites && websites.length > 0 ? (
143+
{websites === null ? (
144+
<SkeletonTable />
145+
) : websites.length > 0 ? (
143146
<div className="border rounded-lg shadow-sm">
144147
<div className="overflow-x-auto">
145148
<table className="w-full">

examples/playground/app/websites/runs/[run_id]/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ function RunPageContent() {
3232
{/* Debug panel: Technical details - first on mobile, right side on desktop */}
3333
<div className="w-full lg:w-[35%] xl:w-[30%] order-first lg:order-last mb-6 lg:mb-0">
3434
<div
35-
className={`relative lg:fixed lg:top-16 lg:bottom-4 lg:right-4 w-full lg:w-[calc(35%-2rem)] xl:w-[calc(30%-2rem)] overflow-hidden flex flex-col transition-all duration-300 group border hover:shadow-lg
35+
className={`relative lg:fixed lg:top-16 lg:bottom-20 lg:right-4 w-full lg:w-[calc(35%-2rem)] xl:w-[calc(30%-2rem)] overflow-hidden flex flex-col transition-all duration-300 group rounded-lg hover:shadow-sm z-10
3636
${isPinned
37-
? "opacity-100 border-solid border-foreground/30"
38-
: "opacity-50 hover:opacity-100 cursor-pointer border-dashed border-foreground/20 hover:border-solid"
37+
? "opacity-100 border border-solid border-muted/30"
38+
: "opacity-50 hover:opacity-100 cursor-pointer border border-dashed border-muted/20 hover:border-solid"
3939
}`}
4040
>
4141
{/* Pin button for keeping sidebar visible - moved to right side */}

examples/playground/components/example-links.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
'use client';
22

33
import { useRouter } from 'next/navigation';
4-
import { useTransition } from 'react';
4+
import { useTransition, useEffect, useState } from 'react';
55
import { createClient } from '@/utils/supabase/client';
66
import { exampleLinks } from '@/lib/example-links';
77
import { useLoadingState } from './loading-state-provider';
88

9-
export default function ExampleLinks({ isLoggedIn }: { isLoggedIn: boolean }) {
9+
export default function ExampleLinks() {
1010
const [isPending, startTransition] = useTransition();
11+
const [isLoggedIn, setIsLoggedIn] = useState<boolean | null>(null);
1112
const router = useRouter();
1213
const supabase = createClient();
1314
const { setLoading } = useLoadingState();
1415

16+
useEffect(() => {
17+
supabase.auth.getUser().then(({ data }) => {
18+
setIsLoggedIn(!!data.user);
19+
});
20+
}, []);
21+
1522
// Function to handle example link clicks
1623
const handleExampleClick = (e: React.MouseEvent<HTMLAnchorElement>, url: string) => {
1724
if (isPending) {

0 commit comments

Comments
 (0)