SHARE_PAGE_COMPONENT.md
Overview
The SharePage component is a comprehensive full-page interface that manages shared assistant access with authentication, access control, and collaborative features. It provides the main user experience for accessing shared AI assistants with different permission levels and states.
Purpose
- Shared Assistant Access: Main interface for accessing shared AI assistants
- Access Control Management: Enforces permission-based access with multiple authorization levels
- Authentication Integration: Handles user login state and Firebase authentication
- Tool Configuration: Manages dynamic tool enabling/disabling for shared sessions
- Assistant Duplication: Allows users to create personal copies of shared assistants
Key Features
Authentication States
- not-logged-in: Anonymous user access (if permitted)
- receiver: Authenticated user with access permissions
- admin: Assistant creator with full management rights
Access Control Types
- Private: Only creator access
- Domain-based: Users from specific email domains
- Link-based: Anyone with the link
- Public: Open access
UI States
- Loading: Initial authentication and permission checking
- Access Denied: Permission-based rejection with helpful messaging
- Welcome: Initial assistant introduction before chat begins
- Main Chat: Full chat interface with sidebar and artifact support
Component Interface
interface SharePageProps {
config: ConfigProps;
}
// Key destructured properties from config:
{
name, // Assistant display name
avatar, // Assistant avatar URL
assistantId, // Unique assistant identifier
accessControl, // Permission configuration
adminEmail, // Creator's email
senderName, // Creator's display name
initialMessage, // Welcome message
initialInstructions,// Assistant instructions
initialDocuments, // Attached documents
tools, // Available tools array
toolConfigs, // Tool configuration objects
templateId // Template identifier
}
Core Functionality
1. Authentication Management
// Firebase auth state listener
useEffect(() => {
const unsubscribe = FirebaseService.onAuthStateChange((user) => {
setCurrentUser(user);
setIsAuthInitialized(true);
});
return () => unsubscribe();
}, []);
// User state determination
if (currentUser) {
setUserState(currentUser.email === adminEmail ? 'admin' : 'receiver');
} else {
setUserState('not-logged-in');
}
2. Access Control Logic
// Access validation
const accessGranted = checkAccess(localAccessControl, currentUser, adminEmail);
setHasAccess(accessGranted);
// Usage tracking (only once per session)
if (accessGranted && !hasIncrementedUsageRef.current && assistantId) {
FirebaseService.incrementAssistantUsage(assistantId);
hasIncrementedUsageRef.current = true;
}
3. Tool Configuration Persistence
// Session-based tool state management
const handleToolsChange = useCallback((updatedTools: string[]) => {
setActiveTools(updatedTools);
// Save to sessionStorage for persistence
if (assistantId) {
sessionStorage.setItem(`assistant_tools_${assistantId}`, JSON.stringify(updatedTools));
}
}, [assistantId]);
// Restore tools on component mount
useEffect(() => {
if (assistantId) {
const savedTools = sessionStorage.getItem(`assistant_tools_${assistantId}`);
if (savedTools) {
setActiveTools(JSON.parse(savedTools));
}
}
}, [assistantId]);
4. Assistant Duplication
// Create personal copy of shared assistant
const handleDuplication = async () => {
const duplicateData = createDuplicateConfig({
assistantId,
templateId,
name,
avatar,
ownerEmail: currentUser.email || '',
initialMessage,
initialInstructions,
tools: activeTools,
toolConfigs,
initialDocuments: initialDocuments || [],
accessControl: { type: 'private' } // Always private for copies
}, currentUser.uid, currentUser.email || '');
const newAssistantId = await FirebaseService.createAssistant(duplicateData);
if (newAssistantId) {
window.location.href = `/assistant/${newAssistantId}`;
}
};
5. Sharing Settings Management
// Admin-only access control updates
const handleAccessChange = useCallback(async (newAccessControl: AccessControl) => {
if (userState !== 'admin' || !assistantId) {
toast({
title: "Not authorized",
description: "Only the assistant's creator can change sharing settings.",
variant: "destructive"
});
return;
}
await FirebaseService.updateAssistant(assistantId, {
accessControl: newAccessControl
});
setLocalAccessControl(newAccessControl);
}, [userState, assistantId, toast]);
UI Components Integration
Main Layout Structure
return (
<ArtifactProvider assistantId={assistantId}>
<TooltipProvider delayDuration={100}>
<div className="flex min-h-screen bg-gray-50">
{/* Aurora background animation */}
<Aurora
colorStops={["#FF9966", "#FFD93D", "#FF6B6B"]}
blend={0.9}
amplitude={0.8}
speed={0.3}
/>
<SidebarProvider defaultOpen={false}>
<AppSidebar {...sidebarProps} />
<main className="flex-1 overflow-hidden">
{/* Header with sharing status */}
<div className="flex items-center justify-between p-4 border-b">
<SidebarTrigger />
<h1>{name || 'Messages'}</h1>
<SharingStatus
accessControl={localAccessControl}
isEditable={userState === 'admin'}
onAccessChange={handleAccessChange}
/>
<ArtifactToggleButton tools={activeTools} />
</div>
{/* Chat interface with artifacts */}
<ChatWithArtifacts sharedProps={sharedProps} />
</main>
</SidebarProvider>
</div>
</TooltipProvider>
</ArtifactProvider>
);
Access Denied UI
const AccessDeniedContent = () => {
const message = getAccessDeniedMessage(localAccessControl, !!currentUser, adminEmail);
return (
<Card className="max-w-xl w-full shadow-lg">
<CardHeader className="text-center">
<Avatar className="h-28 w-28">
<AvatarImage src={avatar} alt={name} />
<AvatarFallback>
<Shield className="h-12 w-12 text-destructive" />
</AvatarFallback>
</Avatar>
<h2>Access Denied</h2>
<p>Cannot access '{name}'</p>
</CardHeader>
<CardContent>
<p>{message}</p>
<Button asChild>
<Link href="/"><Home /> Go Home</Link>
</Button>
</CardContent>
</Card>
);
};
State Management
Key State Variables
const [accepted, setAccepted] = useState(false); // Welcome acceptance
const [userState, setUserState] = useState('not-logged-in'); // User role
const [currentUser, setCurrentUser] = useState<User | null>(null); // Firebase user
const [isAuthInitialized, setIsAuthInitialized] = useState(false); // Auth ready
const [showLoginDialog, setShowLoginDialog] = useState(false); // Login modal
const [hasAccess, setHasAccess] = useState<boolean | null>(null); // Permission state
const [localAccessControl, setLocalAccessControl] = useState<AccessControl>(); // Sharing config
const [activeTools, setActiveTools] = useState<string[]>(tools || []); // Tool selection
Conditional Rendering Logic
// Loading state (waiting for auth + access check)
if (hasAccess === null) {
return <LoadingSpinner />;
}
// Access denied state
if (hasAccess === false) {
return <AccessDeniedContent />;
}
// Welcome screen (before chat begins)
if (!accepted) {
return <WelcomeMessage onAccept={() => setAccepted(true)} />;
}
// Main chat interface
return <ChatInterface />;
Dependencies
External Libraries
- Firebase: Authentication and data persistence
- Lucide React: Icon components
- Next.js: Routing and Link components
Internal Components
EmissaryOptimized: Core chat functionalityAppSidebar: Navigation and tool configurationChatWithArtifacts: Chat interface with artifact displaySharingStatus: Access control management UIWelcomeMessage: Initial assistant introductionLoginDialog: Authentication modal
Utility Functions
checkAccess(): Permission validation logicgetAccessDeniedMessage(): Context-aware error messagingcreateDuplicateConfig(): Assistant duplication logic
Usage Examples
Basic Shared Assistant Access
// Page component receiving config from server
export default function SharedAssistantPage({ assistantConfig }) {
return <SharePage config={assistantConfig} />;
}
Integration with Next.js Dynamic Routes
// pages/assistant/[assistantId]/page.tsx
export default async function AssistantPage({ params }) {
const config = await getAssistantConfig(params.assistantId);
if (!config) {
return <NotFound />;
}
return <SharePage config={config} />;
}
Security Considerations
- Access Control Validation: Always validates permissions on both client and server
- Usage Tracking: Increments usage counters only once per authorized session
- Admin-Only Operations: Restricts sharing settings changes to assistant creators
- Session Persistence: Safely stores tool preferences without exposing sensitive data
- Authentication State: Properly handles auth initialization and user state changes
Performance Optimizations
- Memoized Props: Uses
useMemofor expensive prop calculations - Callback Optimization:
useCallbackfor event handlers to prevent re-renders - Conditional Rendering: Efficient state-based UI switching
- Session Storage: Persists tool configurations without server requests
- Single Auth Listener: Prevents multiple Firebase auth subscriptions
Error Handling
- Authentication Errors: Graceful handling of Firebase auth failures
- Access Control Updates: Toast notifications for permission errors
- Usage Tracking: Non-critical error logging without blocking UX
- Tool Configuration: Fallback to defaults if session storage fails
- Assistant Duplication: User-friendly error messages for creation failures
Testing Considerations
- Authentication States: Mock Firebase auth for different user types
- Access Control: Test all permission combinations
- Tool Configuration: Verify session storage persistence
- UI States: Test loading, denied, welcome, and main interfaces
- Assistant Duplication: Mock FirebaseService methods
- Error Scenarios: Test network failures and invalid configurations