All files / src/common/hooks useEmailAlias.ts

94.11% Statements 80/85
86.95% Branches 20/23
100% Functions 5/5
94.11% Lines 80/85

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 1071x 1x 1x 1x   1x 1x       1x 25x 25x 25x     25x 10x 10x 10x 10x 10x 10x   10x     10x 10x 10x 3x 10x   10x 10x 10x 25x     25x 25x 25x 25x 25x 25x 25x 25x 11x 8x 11x 25x 25x 25x 25x   3x     3x 3x 25x 25x     25x 25x     25x 2x   1x 1x       2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 25x     25x 2x 1x 1x 1x 25x   25x 25x 25x 25x 25x 25x 25x 25x 25x  
import { supabase } from '@common/services/supabaseClient';
import { userService } from '@common/services/user/UserService';
import { useLogger } from '@common/utils/logger/useLogger';
import { queryKeyFactory } from '@common/utils/queryKeyFactory';
import { User } from '@supabase/supabase-js';
import { useQuery } from '@tanstack/react-query';
import { useCallback, useEffect, useState } from 'react';
 
type AppUser = User | null;
 
export function useEmailAlias() {
  const log = useLogger('useEmailAlias');
  const [user, setUser] = useState<AppUser>(null);
  const [copied, setCopied] = useState<boolean>(false);
 
  // Fetch the current user when the component mounts
  useEffect(() => {
    const fetchUser = async () => {
      const {
        data: { user },
      } = await supabase.auth.getUser();
      setUser(user);
    };
 
    fetchUser();
 
    // Set up auth state listener
    const {
      data: { subscription },
    } = supabase.auth.onAuthStateChange((_event: string, session) => {
      setUser(session?.user || null);
    });
 
    return () => {
      subscription?.unsubscribe();
    };
  }, []);
 
  // Use React Query to fetch email alias with proper caching
  const {
    data: aliasResult = { email: '', error: null },
    isLoading: loading,
    error: queryError,
    refetch,
  } = useQuery({
    queryKey: queryKeyFactory.user.emailAlias(user?.id),
    queryFn: async () => {
      const result = await userService.getEmailAlias();
      return result;
    },
    enabled: !!user, // Only fetch when user is authenticated
    staleTime: 5 * 60 * 1000, // 5 minutes - email alias doesn't change often
    gcTime: 30 * 60 * 1000, // 30 minutes
    retry: (failureCount, error) => {
      // Don't retry if user is not authenticated
      if (error?.message?.includes('Auth session missing')) {
        return false;
      }
      return failureCount < 2;
    },
    retryDelay: (attemptIndex) => Math.min(1000 * Math.pow(2, attemptIndex), 5000),
  });
 
  // Convert query error to string
  const error = queryError ? 'Failed to load email alias' : null;
  const emailAlias = aliasResult.email || '';
 
  // Copy email alias to clipboard
  const copyToClipboard = useCallback(async () => {
    if (!emailAlias) return false;
 
    try {
      await navigator.clipboard.writeText(emailAlias);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
      return true;
    } catch (err) {
      log.error(
        'Failed to copy email alias',
        {
          action: 'copy_email_alias',
          metadata: { emailAlias },
        },
        err instanceof Error ? err : new Error(String(err))
      );
      return false;
    }
  }, [emailAlias, log]);
 
  // Create refresh function that uses React Query's refetch
  const refresh = useCallback(() => {
    if (user) {
      return refetch();
    }
    return Promise.resolve();
  }, [user, refetch]);
 
  return {
    emailAlias,
    loading,
    error,
    copied,
    copyToClipboard,
    refresh,
  };
}