Directory: studios from DevConnect collectives with fallback and richer rendering
cgen-949afaa5b28449cbbe3eb492e5a4adb0
This commit is contained in:
parent
0cfc878c3e
commit
34be084b31
1 changed files with 41 additions and 9 deletions
|
|
@ -19,7 +19,8 @@ export default function Directory() {
|
||||||
const [hideAeThex, setHideAeThex] = useState(true);
|
const [hideAeThex, setHideAeThex] = useState(true);
|
||||||
type BasicDev = { id: string; name: string; avatar_url?: string | null; location?: string | null; user_type?: string | null; experience_level?: string | null };
|
type BasicDev = { id: string; name: string; avatar_url?: string | null; location?: string | null; user_type?: string | null; experience_level?: string | null };
|
||||||
const [devs, setDevs] = useState<BasicDev[]>([]);
|
const [devs, setDevs] = useState<BasicDev[]>([]);
|
||||||
const [studios, setStudios] = useState<any[]>([]);
|
type Studio = { id: string; name: string; description?: string | null; type?: string | null; is_recruiting?: boolean | null; recruiting_roles?: string[] | null; tags?: string[] | null; slug?: string | null; visibility?: string | null };
|
||||||
|
const [studios, setStudios] = useState<Studio[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const client = devconnect || supabase;
|
const client = devconnect || supabase;
|
||||||
|
|
@ -48,18 +49,31 @@ export default function Directory() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const studiosTable = client === devconnect ? "collectives" : "teams";
|
||||||
|
const mapStudio = (r: any): Studio => ({
|
||||||
|
id: String(r.id),
|
||||||
|
name: r.name,
|
||||||
|
description: r.description || null,
|
||||||
|
type: r.type || (r.visibility || null),
|
||||||
|
is_recruiting: r.is_recruiting ?? null,
|
||||||
|
recruiting_roles: r.recruiting_roles ?? null,
|
||||||
|
tags: r.tags ?? null,
|
||||||
|
slug: r.slug || null,
|
||||||
|
visibility: r.visibility || null,
|
||||||
|
});
|
||||||
|
|
||||||
client
|
client
|
||||||
.from<any>("teams" as any)
|
.from<any>(studiosTable as any)
|
||||||
.select("id,name,description,visibility,created_at")
|
.select(client === devconnect ? "id,name,description,type,is_recruiting,recruiting_roles,tags,slug,created_at" : "id,name,description,visibility,created_at")
|
||||||
.limit(200)
|
.limit(200)
|
||||||
.then(({ data, error }) => {
|
.then(({ data, error }) => {
|
||||||
if (!error && data) setStudios(data);
|
if (!error && Array.isArray(data)) setStudios(data.map(mapStudio));
|
||||||
else if (client !== supabase) {
|
else if (client !== supabase) {
|
||||||
supabase
|
supabase
|
||||||
.from<any>("teams" as any)
|
.from<any>("teams" as any)
|
||||||
.select("id,name,description,visibility,created_at")
|
.select("id,name,description,visibility,created_at")
|
||||||
.limit(200)
|
.limit(200)
|
||||||
.then(({ data: d2 }) => setStudios(d2 || []));
|
.then(({ data: d2 }) => setStudios((d2 || []).map(mapStudio)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -82,7 +96,8 @@ export default function Directory() {
|
||||||
if (!q) return true;
|
if (!q) return true;
|
||||||
return (
|
return (
|
||||||
(t.name || "").toLowerCase().includes(q) ||
|
(t.name || "").toLowerCase().includes(q) ||
|
||||||
(t.description || "").toLowerCase().includes(q)
|
(t.description || "").toLowerCase().includes(q) ||
|
||||||
|
(t.tags || []).join(" ").toLowerCase().includes(q)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}, [studios, query]);
|
}, [studios, query]);
|
||||||
|
|
@ -144,11 +159,28 @@ export default function Directory() {
|
||||||
{filteredStudios.map((t) => (
|
{filteredStudios.map((t) => (
|
||||||
<Card key={t.id} className="border-border/40 bg-card/60 backdrop-blur">
|
<Card key={t.id} className="border-border/40 bg-card/60 backdrop-blur">
|
||||||
<CardHeader className="pb-2">
|
<CardHeader className="pb-2">
|
||||||
<CardTitle className="text-lg">{t.name}</CardTitle>
|
<div className="flex items-center justify-between gap-2">
|
||||||
{t.visibility && <CardDescription className="capitalize">{t.visibility}</CardDescription>}
|
<CardTitle className="text-lg">{t.name}</CardTitle>
|
||||||
|
{t.is_recruiting && (
|
||||||
|
<Badge className="bg-emerald-500/10 text-emerald-200 border-emerald-400/40">Recruiting</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{(t.type || t.visibility) && (
|
||||||
|
<CardDescription className="capitalize">{t.type || t.visibility}</CardDescription>
|
||||||
|
)}
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="pt-0">
|
<CardContent className="pt-0 space-y-3">
|
||||||
<p className="text-sm text-muted-foreground line-clamp-3">{t.description || ""}</p>
|
<p className="text-sm text-muted-foreground line-clamp-3">{t.description || ""}</p>
|
||||||
|
{(t.tags && t.tags.length > 0) && (
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{t.tags!.map((tag) => (
|
||||||
|
<Badge key={tag} variant="outline" className="text-xs">{tag}</Badge>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{(t.recruiting_roles && t.recruiting_roles.length > 0) && (
|
||||||
|
<div className="text-xs text-muted-foreground">Roles: {t.recruiting_roles!.join(", ")}</div>
|
||||||
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue