- Add comprehensive analytics components with export functionality - Implement territory management with manager performance tracking - Add seatmap components for venue layout management - Create customer management features with modal interface - Add advanced hooks for dashboard flags and territory data - Implement seat selection and venue management utilities - Add type definitions for ticketing and seatmap systems 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
203 lines
5.6 KiB
TypeScript
203 lines
5.6 KiB
TypeScript
// Firebase Authentication Context for Black Canyon Tickets React Rebuild
|
|
// This is a mock authentication context for learning purposes only
|
|
|
|
import React, { createContext, useContext, useEffect, useState } from 'react';
|
|
|
|
import {
|
|
onAuthStateChanged,
|
|
signOut,
|
|
signInWithEmailAndPassword,
|
|
GoogleAuthProvider,
|
|
signInWithPopup,
|
|
createUserWithEmailAndPassword
|
|
} from 'firebase/auth';
|
|
|
|
import { auth } from '@/lib/firebase';
|
|
import type { User} from '@/types/auth';
|
|
import { MOCK_USERS, ROLE_PERMISSIONS } from '@/types/auth';
|
|
|
|
import type {
|
|
User as FirebaseUser} from 'firebase/auth';
|
|
|
|
interface FirebaseAuthContextType {
|
|
// Authentication state
|
|
user: User | null;
|
|
firebaseUser: FirebaseUser | null;
|
|
loading: boolean;
|
|
|
|
// Authentication methods
|
|
signInEmail: (email: string, password: string) => Promise<void>;
|
|
signInGoogle: () => Promise<void>;
|
|
signUpEmail: (email: string, password: string) => Promise<void>;
|
|
signOut: () => Promise<void>;
|
|
|
|
// Utility methods
|
|
hasRole: (role: User['role'] | User['role'][]) => boolean;
|
|
hasPermission: (permission: string) => boolean;
|
|
}
|
|
|
|
const FirebaseAuthContext = createContext<FirebaseAuthContextType | null>(null);
|
|
|
|
// Google Auth Provider setup
|
|
const googleProvider = new GoogleAuthProvider();
|
|
googleProvider.setCustomParameters({
|
|
prompt: 'select_account'
|
|
});
|
|
|
|
export const FirebaseAuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
const [user, setUser] = useState<User | null>(null);
|
|
const [firebaseUser, setFirebaseUser] = useState<FirebaseUser | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
// Map Firebase user to our User type using mock data
|
|
const mapFirebaseUserToUser = (firebaseUser: FirebaseUser): User => {
|
|
// In a real app, this would fetch user data from Firestore
|
|
// For learning purposes, we'll use mock data based on email
|
|
const mockUser = MOCK_USERS[firebaseUser.email || ''] || MOCK_USERS['organizer@example.com'];
|
|
|
|
if (!mockUser) {
|
|
throw new Error('Mock user not found');
|
|
}
|
|
|
|
// Filter out problematic photo URLs that cause 404 errors
|
|
const getValidAvatar = (photoURL: string | null, fallback?: string): string | undefined => {
|
|
if (!photoURL) return fallback;
|
|
|
|
// Block known problematic Unsplash URLs
|
|
if (photoURL.includes('photo-1494790108755-2616b612b786')) {
|
|
return fallback;
|
|
}
|
|
|
|
// Add other URL validations if needed
|
|
return photoURL;
|
|
};
|
|
|
|
return {
|
|
...mockUser,
|
|
id: firebaseUser.uid,
|
|
email: firebaseUser.email || mockUser.email,
|
|
name: firebaseUser.displayName || mockUser.name,
|
|
avatar: getValidAvatar(firebaseUser.photoURL, mockUser.avatar),
|
|
metadata: {
|
|
...mockUser.metadata,
|
|
lastLogin: new Date().toISOString(),
|
|
emailVerified: firebaseUser.emailVerified,
|
|
},
|
|
};
|
|
};
|
|
|
|
// Listen for authentication state changes
|
|
useEffect(() => {
|
|
const unsubscribe = onAuthStateChanged(auth, (firebaseUser) => {
|
|
setFirebaseUser(firebaseUser);
|
|
|
|
if (firebaseUser) {
|
|
const mappedUser = mapFirebaseUserToUser(firebaseUser);
|
|
setUser(mappedUser);
|
|
} else {
|
|
setUser(null);
|
|
}
|
|
|
|
setLoading(false);
|
|
});
|
|
|
|
return () => unsubscribe();
|
|
}, []);
|
|
|
|
// Sign in with email and password
|
|
const signInEmail = async (email: string, password: string): Promise<void> => {
|
|
setLoading(true);
|
|
try {
|
|
await signInWithEmailAndPassword(auth, email, password);
|
|
} catch (error) {
|
|
setLoading(false);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
// Sign in with Google
|
|
const signInGoogle = async (): Promise<void> => {
|
|
setLoading(true);
|
|
try {
|
|
await signInWithPopup(auth, googleProvider);
|
|
} catch (error) {
|
|
setLoading(false);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
// Sign up with email and password
|
|
const signUpEmail = async (email: string, password: string): Promise<void> => {
|
|
setLoading(true);
|
|
try {
|
|
await createUserWithEmailAndPassword(auth, email, password);
|
|
} catch (error) {
|
|
setLoading(false);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
// Sign out
|
|
const handleSignOut = async (): Promise<void> => {
|
|
setLoading(true);
|
|
try {
|
|
await signOut(auth);
|
|
} catch (error) {
|
|
setLoading(false);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
// Check if user has specific role(s)
|
|
const hasRole = (role: User['role'] | User['role'][]): boolean => {
|
|
if (!user) {return false;}
|
|
if (Array.isArray(role)) {
|
|
return role.includes(user.role);
|
|
}
|
|
return user.role === role;
|
|
};
|
|
|
|
// Check if user has specific permission
|
|
const hasPermission = (permission: string): boolean => {
|
|
if (!user) {return false;}
|
|
const userPermissions = ROLE_PERMISSIONS[user.role] || [];
|
|
|
|
// Check for wildcard permissions (admin:* grants all admin permissions)
|
|
return userPermissions.some(userPerm => {
|
|
if (userPerm.endsWith(':*')) {
|
|
const prefix = userPerm.slice(0, -1); // Remove the '*'
|
|
return permission.startsWith(prefix);
|
|
}
|
|
return userPerm === permission;
|
|
});
|
|
};
|
|
|
|
const value: FirebaseAuthContextType = {
|
|
user,
|
|
firebaseUser,
|
|
loading,
|
|
signInEmail,
|
|
signInGoogle,
|
|
signUpEmail,
|
|
signOut: handleSignOut,
|
|
hasRole,
|
|
hasPermission,
|
|
};
|
|
|
|
return (
|
|
<FirebaseAuthContext.Provider value={value}>
|
|
{children}
|
|
</FirebaseAuthContext.Provider>
|
|
);
|
|
};
|
|
|
|
// Custom hook to use Firebase Auth context
|
|
export const useFirebaseAuth = (): FirebaseAuthContextType => {
|
|
const context = useContext(FirebaseAuthContext);
|
|
if (!context) {
|
|
throw new Error('useFirebaseAuth must be used within a FirebaseAuthProvider');
|
|
}
|
|
return context;
|
|
};
|
|
|
|
export default FirebaseAuthContext; |