supabase client tool

This commit is contained in:
2025-04-01 17:45:12 +08:00
parent c0649ce10f
commit 1978e0224e
3 changed files with 134 additions and 7 deletions

View File

@@ -1,11 +1,12 @@
"use client";
import { useEffect, useState } from 'react';
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
import type { Database } from '@/types/supabase';
import { Select } from './Select';
import { getSupabaseClient } from '../../utils/supabase';
import { AuthChangeEvent, Session } from '@supabase/supabase-js';
type Team = Database['public']['Tables']['teams']['Row'];
type Team = Database['limq']['Tables']['teams']['Row'];
interface TeamSelectorProps {
value?: string;
@@ -17,8 +18,6 @@ export function TeamSelector({ value, onChange, className }: TeamSelectorProps)
const [teams, setTeams] = useState<Team[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const supabase = createClientComponentClient<Database>();
useEffect(() => {
let isMounted = true;
@@ -31,6 +30,8 @@ export function TeamSelector({ value, onChange, className }: TeamSelectorProps)
setError(null);
try {
const supabase = getSupabaseClient();
// 获取用户的团队成员关系
console.log('Fetching team memberships for user:', userId);
const { data: memberships, error: membershipError } = await supabase
@@ -84,8 +85,10 @@ export function TeamSelector({ value, onChange, className }: TeamSelectorProps)
}
};
const supabase = getSupabaseClient();
// 设置认证状态监听器
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
const { data: { subscription } } = supabase.auth.onAuthStateChange((event: AuthChangeEvent, session: Session | null) => {
console.log('Auth state changed:', event, session?.user);
if (event === 'SIGNED_IN' && session?.user?.id) {
fetchTeams(session.user.id);
@@ -96,7 +99,7 @@ export function TeamSelector({ value, onChange, className }: TeamSelectorProps)
});
// 初始检查session
supabase.auth.getSession().then(({ data: { session } }) => {
supabase.auth.getSession().then(({ data: { session } }: { data: { session: Session | null } }) => {
console.log('Initial session check:', session?.user);
if (session?.user?.id) {
fetchTeams(session.user.id);
@@ -107,7 +110,7 @@ export function TeamSelector({ value, onChange, className }: TeamSelectorProps)
isMounted = false;
subscription.unsubscribe();
};
}, [supabase]);
}, []);
if (loading) {
return <div className="animate-pulse h-10 bg-gray-200 rounded-md dark:bg-gray-700" />;

59
app/utils/supabase.ts Normal file
View File

@@ -0,0 +1,59 @@
import { createClient, SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@/types/supabase";
let supabase: SupabaseClient<Database> | null = null;
// 简单的存储适配器使用localStorage
const storageAdapter = {
getItem: async (key: string) => {
try {
const item = localStorage.getItem(key);
return item;
} catch (error) {
console.error("Storage get error:", error);
return null;
}
},
setItem: async (key: string, value: string) => {
try {
localStorage.setItem(key, value);
} catch (error) {
console.error("Storage set error:", error);
}
},
removeItem: async (key: string) => {
try {
localStorage.removeItem(key);
} catch (error) {
console.error("Storage remove error:", error);
}
},
};
export const getSupabaseClient = (): SupabaseClient<Database> => {
if (!supabase) {
if (!process.env.NEXT_PUBLIC_SUPABASE_URL || !process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY) {
throw new Error('Missing Supabase environment variables');
}
supabase = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
{
db: { schema: "limq" },
auth: {
storage: storageAdapter,
persistSession: true,
autoRefreshToken: true,
},
}
);
}
return supabase;
};
export const clearSupabaseInstance = () => {
supabase = null;
};

View File

@@ -78,4 +78,69 @@ export interface Database {
[_ in never]: never
}
}
limq: {
Tables: {
teams: {
Row: {
id: string
name: string
description: string | null
avatar_url: string | null
attributes: Json | null
created_at: string
updated_at: string
deleted_at: string | null
}
Insert: {
id?: string
name: string
description?: string | null
avatar_url?: string | null
attributes?: Json | null
created_at?: string
updated_at?: string
deleted_at?: string | null
}
Update: {
id?: string
name?: string
description?: string | null
avatar_url?: string | null
attributes?: Json | null
created_at?: string
updated_at?: string
deleted_at?: string | null
}
}
team_membership: {
Row: {
id: string
team_id: string
user_id: string
role: string
created_at: string
updated_at: string
deleted_at: string | null
}
Insert: {
id?: string
team_id: string
user_id: string
role: string
created_at?: string
updated_at?: string
deleted_at?: string | null
}
Update: {
id?: string
team_id?: string
user_id?: string
role?: string
created_at?: string
updated_at?: string
deleted_at?: string | null
}
}
}
}
}