VIBN Frontend for Coolify deployment

This commit is contained in:
2026-02-15 19:25:52 -08:00
commit 40bf8428cd
398 changed files with 76513 additions and 0 deletions

View File

@@ -0,0 +1,190 @@
"use client";
import { useState, useEffect } from 'react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { auth } from '@/lib/firebase/config';
import { toast } from 'sonner';
import { Users, UserPlus, Crown, Mail } from 'lucide-react';
import { useParams } from 'next/navigation';
interface WorkspaceUser {
id: string;
email: string;
displayName: string;
role: 'owner' | 'admin' | 'member';
joinedAt: any;
lastActive: any;
}
export default function UsersPage() {
const params = useParams();
const workspace = params.workspace as string;
const [users, setUsers] = useState<WorkspaceUser[]>([]);
const [loading, setLoading] = useState(true);
const [currentUser, setCurrentUser] = useState<WorkspaceUser | null>(null);
useEffect(() => {
loadUsers();
}, []);
const loadUsers = async () => {
try {
const user = auth.currentUser;
if (!user) return;
const token = await user.getIdToken();
const response = await fetch(`/api/workspace/${workspace}/users`, {
headers: {
'Authorization': `Bearer ${token}`,
},
});
if (response.ok) {
const data = await response.json();
setUsers(data.users);
setCurrentUser(data.currentUser);
}
} catch (error) {
console.error('Error loading users:', error);
toast.error('Failed to load workspace users');
} finally {
setLoading(false);
}
};
const getRoleBadgeColor = (role: string) => {
switch (role) {
case 'owner':
return 'bg-purple-500/10 text-purple-600 border-purple-500/20';
case 'admin':
return 'bg-blue-500/10 text-blue-600 border-blue-500/20';
default:
return 'bg-gray-500/10 text-gray-600 border-gray-500/20';
}
};
return (
<div className="flex h-full flex-col overflow-auto">
<div className="flex-1 p-8 space-y-8 max-w-6xl">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-4xl font-bold mb-2">Team Members</h1>
<p className="text-muted-foreground text-lg">
Manage workspace access and team collaboration
</p>
</div>
<Button disabled>
<UserPlus className="mr-2 h-4 w-4" />
Invite User
</Button>
</div>
{/* Current User Info */}
{currentUser && (
<Card className="border-primary/50 bg-primary/5">
<CardHeader>
<CardTitle className="text-base flex items-center gap-2">
<Crown className="h-4 w-4" />
Your Account
</CardTitle>
</CardHeader>
<CardContent>
<div className="flex items-center justify-between">
<div>
<p className="font-medium">{currentUser.displayName || 'Unknown'}</p>
<p className="text-sm text-muted-foreground">{currentUser.email}</p>
</div>
<div className={`px-3 py-1 rounded-full text-xs font-medium border ${getRoleBadgeColor(currentUser.role)}`}>
{currentUser.role}
</div>
</div>
</CardContent>
</Card>
)}
{/* Users List */}
{loading ? (
<Card>
<CardContent className="pt-6">
<p className="text-center text-muted-foreground">Loading team members...</p>
</CardContent>
</Card>
) : users.length === 0 ? (
<Card>
<CardContent className="pt-6 text-center space-y-4">
<div className="flex justify-center">
<div className="h-16 w-16 rounded-full bg-muted flex items-center justify-center">
<Users className="h-8 w-8 text-muted-foreground" />
</div>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">No team members yet</h3>
<p className="text-sm text-muted-foreground mb-4">
Invite team members to collaborate on projects in this workspace
</p>
<Button disabled>
<UserPlus className="mr-2 h-4 w-4" />
Invite Your First Team Member
</Button>
</div>
</CardContent>
</Card>
) : (
<div className="space-y-3">
{users.map((user) => (
<Card key={user.id}>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<div className="h-12 w-12 rounded-full bg-primary/10 flex items-center justify-center">
<Mail className="h-5 w-5 text-primary" />
</div>
<div>
<p className="font-medium">{user.displayName || 'Unknown'}</p>
<p className="text-sm text-muted-foreground">{user.email}</p>
{user.lastActive && (
<p className="text-xs text-muted-foreground mt-1">
Last active: {new Date(user.lastActive._seconds * 1000).toLocaleDateString()}
</p>
)}
</div>
</div>
<div className="flex items-center gap-3">
<div className={`px-3 py-1 rounded-full text-xs font-medium border ${getRoleBadgeColor(user.role)}`}>
{user.role}
</div>
</div>
</div>
</CardContent>
</Card>
))}
</div>
)}
{/* Info Card */}
<Card className="border-blue-500/20 bg-blue-500/5">
<CardHeader>
<CardTitle className="text-base">Team Collaboration (Coming Soon)</CardTitle>
</CardHeader>
<CardContent className="space-y-2 text-sm text-muted-foreground">
<p>
<strong>👥 Team Workspaces:</strong> Invite team members to collaborate on projects together.
</p>
<p>
<strong>🔐 Role-Based Access:</strong> Control what team members can see and do with flexible permissions.
</p>
<p>
<strong>💬 Shared Context:</strong> All team members can access shared AI chat history and project documentation.
</p>
<p className="text-xs italic pt-2">
This feature is currently in development. Check back soon!
</p>
</CardContent>
</Card>
</div>
</div>
);
}