diff --git a/components/CollaboratorFacepile.js b/components/CollaboratorFacepile.js
new file mode 100644
index 0000000..5439c61
--- /dev/null
+++ b/components/CollaboratorFacepile.js
@@ -0,0 +1,133 @@
+import { useState, useEffect } from 'react';
+
+export default function CollaboratorFacepile({ collectionId, creatorEmail }) {
+ const [collaborators, setCollaborators] = useState([]);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ if (collectionId) {
+ fetchCollaborators();
+ }
+ }, [collectionId]);
+
+ const fetchCollaborators = async () => {
+ try {
+ const response = await fetch(`/api/collections/${collectionId}/permissions`, {
+ headers: {
+ 'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
+ }
+ });
+
+ if (response.ok) {
+ const data = await response.json();
+ setCollaborators(data.permissions || []);
+ }
+ } catch (error) {
+ console.error('Error fetching collaborators:', error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ if (loading) {
+ return (
+
+
+ Crafted by {creatorEmail}
+
+
+
+ );
+ }
+
+ // Include creator and active collaborators
+ const allUsers = [
+ { email: creatorEmail, role: 'owner', status: 'active' },
+ ...collaborators.filter(c => c.status === 'active')
+ ];
+
+ const visibleUsers = allUsers.slice(0, 4); // Show max 4 faces
+ const remainingCount = Math.max(0, allUsers.length - 4);
+
+ const getRoleColor = (role) => {
+ switch (role) {
+ case 'owner': return 'bg-purple-600';
+ case 'editor': return 'bg-blue-600';
+ case 'viewer': return 'bg-green-600';
+ default: return 'bg-gray-600';
+ }
+ };
+
+ const getRoleLabel = (role) => {
+ switch (role) {
+ case 'owner': return 'Owner';
+ case 'editor': return 'Collaborator';
+ case 'viewer': return 'Viewer';
+ default: return 'Member';
+ }
+ };
+
+ return (
+
+
+ Crafted by {creatorEmail}
+ {allUsers.length > 1 && (
+
+ & {allUsers.length - 1} other{allUsers.length > 2 ? 's' : ''}
+
+ )}
+
+
+ {allUsers.length > 1 && (
+
+ {visibleUsers.map((user, index) => (
+
+
+ {user.email ? user.email.charAt(0).toUpperCase() : '?'}
+
+
+ {/* Tooltip */}
+
+
+
{user.email}
+
{getRoleLabel(user.role)}
+ {/* Arrow */}
+
+
+
+
+ ))}
+
+ {remainingCount > 0 && (
+
+
+ +{remainingCount}
+
+
+ {/* Tooltip for remaining users */}
+
+
+
{remainingCount} more collaborator{remainingCount > 1 ? 's' : ''}
+ {allUsers.slice(4).map((user, index) => (
+
+ {user.email} ({getRoleLabel(user.role)})
+
+ ))}
+ {/* Arrow */}
+
+
+
+
+ )}
+
+ )}
+
+ );
+}
\ No newline at end of file
diff --git a/pages/api/favorites.js b/pages/api/favorites.js
index 8d5bd6c..c941fa8 100644
--- a/pages/api/favorites.js
+++ b/pages/api/favorites.js
@@ -33,7 +33,7 @@ export default async function handler(req, res) {
// Get user's favorites
const { type } = req.query; // Optional filter by type
- let query = sql`
+ const result = await sql`
SELECT uf.*,
CASE
WHEN uf.item_type = 'collection' THEN c.name
@@ -45,27 +45,9 @@ export default async function handler(req, res) {
LEFT JOIN cards ON uf.item_type = 'card' AND uf.item_id = cards.id
LEFT JOIN decks d ON uf.item_type = 'deck' AND uf.item_id = d.id
WHERE uf.user_id = ${user.userId}
+ ${type ? sql`AND uf.item_type = ${type}` : sql``}
+ ORDER BY uf.created_at DESC
`;
-
- if (type) {
- query = sql`
- SELECT uf.*,
- CASE
- WHEN uf.item_type = 'collection' THEN c.name
- WHEN uf.item_type = 'card' THEN cards.name
- WHEN uf.item_type = 'deck' THEN d.name
- END as item_name
- FROM user_favorites uf
- LEFT JOIN collections c ON uf.item_type = 'collection' AND uf.item_id = c.id
- LEFT JOIN cards ON uf.item_type = 'card' AND uf.item_id = cards.id
- LEFT JOIN decks d ON uf.item_type = 'deck' AND uf.item_id = d.id
- WHERE uf.user_id = ${user.userId} AND uf.item_type = ${type}
- `;
- }
-
- query = sql`${query} ORDER BY uf.created_at DESC`;
-
- const result = await query;
res.status(200).json({
favorites: result.rows
diff --git a/pages/collection/[id].js b/pages/collection/[id].js
index 739f114..fa8f695 100644
--- a/pages/collection/[id].js
+++ b/pages/collection/[id].js
@@ -1,9 +1,9 @@
import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
import Link from 'next/link';
-import CollaborationManager from '../../components/CollaborationManager';
import UploadImageModal from '../../components/UploadImageModal';
import ShareModal from '../../components/ShareModal';
+import CollaboratorFacepile from '../../components/CollaboratorFacepile';
import Layout from '../../components/Layout';
export default function CollectionView() {
@@ -385,17 +385,10 @@ export default function CollectionView() {
{/* Creator and Stats */}
-
-
Crafted by
-
-
-
- {collection.creator_email?.charAt(0).toUpperCase()}
-
-
-
{collection.creator_email}
-
-
+
Cards: {cards.length}
Cost: ${collection.totalValue || '0'}
@@ -644,14 +637,7 @@ export default function CollectionView() {
)}
- {/* Collaboration Manager */}
-
-
-
+
{/* Upload Image Modal */}