diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts index eb0ae29..97815f3 100644 --- a/src/hooks/useAuth.ts +++ b/src/hooks/useAuth.ts @@ -169,7 +169,7 @@ export const useAuth = () => { const syncUserProfile = async (user: User) => { try { console.log('šŸ”„ syncUserProfile: Sincronizando dados:', user.email); - // Wrapper de timeout para operaƧƵes de banco + let fetchTimeoutId: ReturnType; const fetchTimeout = new Promise((_, reject) => { fetchTimeoutId = setTimeout(() => reject(new Error('Timeout syncUserProfile fetch')), 15000); @@ -192,30 +192,95 @@ export const useAuth = () => { return; } - // Se nĆ£o existe, criar registro na tabela usuarios + // Se nĆ£o existe, criar registro completo if (!existingUser) { - let insertTimeoutId: ReturnType; - const insertTimeout = new Promise((_, reject) => { - insertTimeoutId = setTimeout(() => reject(new Error('Timeout syncUserProfile insert')), 15000); + console.log('šŸ‘¤ Novo usuĆ”rio detectado. Criando registros...'); + + let orgTimeoutId: ReturnType; + const orgTimeout = new Promise((_, reject) => { + orgTimeoutId = setTimeout(() => reject(new Error('Timeout creating org')), 15000); + }); + + // 1. Criar organização padrĆ£o + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const orgPromise = (supabase as any) + .from('organizacoes') + .insert({ + slug: `org-${user.id.slice(0, 8)}`, + nome: `Organização de ${user.user_metadata?.full_name || user.email?.split('@')[0] || 'UsuĆ”rio'}`, + status: 'ativa', + plano: 'trial' + }) + .select() + .single(); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const { data: org, error: orgError } = await Promise.race([orgPromise, orgTimeout]) as any; + clearTimeout(orgTimeoutId!); + + if (orgError) { + console.error('Erro ao criar organização:', orgError); + return; + } + + console.log('āœ… Organização criada:', org.id); + + // 2. Criar usuĆ”rio + let userTimeoutId: ReturnType; + const userTimeout = new Promise((_, reject) => { + userTimeoutId = setTimeout(() => reject(new Error('Timeout creating user')), 15000); }); // eslint-disable-next-line @typescript-eslint/no-explicit-any - const insertPromise = (supabase as any) + const userPromise = (supabase as any) .from('usuarios') .insert({ id: user.id, email: user.email!, + organizacao_id: org.id, nome: user.user_metadata?.full_name || user.user_metadata?.nome || user.email?.split('@')[0] || 'UsuĆ”rio', ativo: true }); // eslint-disable-next-line @typescript-eslint/no-explicit-any - const { error: insertError } = await Promise.race([insertPromise, insertTimeout]) as any; - clearTimeout(insertTimeoutId!); + const { error: userError } = await Promise.race([userPromise, userTimeout]) as any; + clearTimeout(userTimeoutId!); - if (insertError) { - console.error('Erro ao criar perfil do usuĆ”rio:', insertError); + if (userError) { + console.error('Erro ao criar usuĆ”rio:', userError); + return; } + + console.log('āœ… UsuĆ”rio criado'); + + // 3. Criar registro em organizacao_usuarios (CRƍTICO!) + let memTimeoutId: ReturnType; + const memTimeout = new Promise((_, reject) => { + memTimeoutId = setTimeout(() => reject(new Error('Timeout creating membership')), 15000); + }); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const memPromise = (supabase as any) + .from('organizacao_usuarios') + .insert({ + organizacao_id: org.id, + usuario_id: user.id, + role: 'owner', // Primeiro usuĆ”rio Ć© owner + ativo: true + }); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const { error: memError } = await Promise.race([memPromise, memTimeout]) as any; + clearTimeout(memTimeoutId!); + + if (memError) { + console.error('Erro ao criar membership:', memError); + return; + } + + console.log('āœ… Membership criado - UsuĆ”rio agora tem acesso!'); + } else { + console.log('āœ… UsuĆ”rio jĆ” existe:', existingUser.id); } } catch (error) { console.error('Erro/Timeout na sincronização do perfil:', error); diff --git a/src/lib/supabase.ts b/src/lib/supabase.ts index eda90e3..e6943bb 100644 --- a/src/lib/supabase.ts +++ b/src/lib/supabase.ts @@ -16,7 +16,7 @@ export const supabase = createClient(supabaseUrl, supabaseAnonKey, { autoRefreshToken: true, persistSession: true, detectSessionInUrl: true, - flowType: 'implicit' // Fallback para Implicit Flow evitando bugs do PKCE em domĆ­nios customizados + flowType: 'pkce' // PKCE Ć© mais seguro e funciona melhor com domĆ­nios customizados }, realtime: { params: { diff --git a/src/pages/AuthCallback.tsx b/src/pages/AuthCallback.tsx index 2faba9f..dc94b76 100644 --- a/src/pages/AuthCallback.tsx +++ b/src/pages/AuthCallback.tsx @@ -38,18 +38,26 @@ export const AuthCallback: React.FC = () => { clearTimeout(fallbackTimer); setStatus('success'); - // Garantir permissƵes do Super Admin - if (session.user.email === 'admtracksteel@gmail.com') { - console.log('šŸ‘‘ Super Admin detectado! Atualizando permissƵes...'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - await (supabase.from('usuarios') as any).upsert({ - id: session.user.id, - email: session.user.email, - nome: session.user.user_metadata?.full_name || 'Super Admin', - role: 'dev', - ativo: true - }); - console.log('šŸ‘‘ PermissƵes de Super Admin aplicadas!'); + // Sincronizar perfil do usuĆ”rio ANTES de redirecionar + try { + console.log('šŸ”„ Sincronizando perfil do usuĆ”rio...'); + + // Importar função de sync + const { useUserStore } = await import('../stores/useUserStore'); + + // Aguardar sincronização com timeout + let syncTimeoutId: ReturnType; + const syncTimeout = new Promise((_, reject) => { + syncTimeoutId = setTimeout(() => reject(new Error('Timeout sync')), 15000); + }); + + const syncPromise = useUserStore.getState().fetchCurrentUser(session.user.id); + await Promise.race([syncPromise, syncTimeout]); + clearTimeout(syncTimeoutId!); + + console.log('āœ… Perfil sincronizado com sucesso'); + } catch (err) { + console.error('āš ļø Erro ao sincronizar perfil (continuando mesmo assim):', err); } console.log('āœ… SessĆ£o confirmada! Redirecionando para /');