Prettier format pending files

This commit is contained in:
Builder.io 2025-10-18 05:09:17 +00:00
parent 7bf4ce124d
commit db87f720a1
5 changed files with 157 additions and 53 deletions

View file

@ -115,14 +115,24 @@ export function FeedItemCard({
<div className="rounded-2xl border border-border/40 bg-background/80 p-4">
<div className="flex flex-wrap items-center justify-between gap-3 text-sm text-muted-foreground">
<div className="flex items-center gap-3">
<Button variant="ghost" size="sm" className="gap-2 pl-2 pr-3" onClick={() => onLike(item.id)}>
<Button
variant="ghost"
size="sm"
className="gap-2 pl-2 pr-3"
onClick={() => onLike(item.id)}
>
<Heart className="h-4 w-4 text-aethex-400" />
<span className="font-medium text-foreground">
{item.likes.toLocaleString()}
</span>
<span className="hidden sm:inline">Like</span>
</Button>
<Button variant="ghost" size="sm" className="gap-2 pl-2 pr-3" onClick={() => onComment(item.id)}>
<Button
variant="ghost"
size="sm"
className="gap-2 pl-2 pr-3"
onClick={() => onComment(item.id)}
>
<MessageCircle className="h-4 w-4 text-aethex-400" />
<span className="font-medium text-foreground">
{item.comments.toLocaleString()}

View file

@ -255,9 +255,15 @@ export const communityService = {
if (!error) {
return (Array.isArray(data) ? data : []) as CommunityPost[];
}
console.warn("Supabase getPosts relational select failed:", (error as any)?.message || error);
console.warn(
"Supabase getPosts relational select failed:",
(error as any)?.message || error,
);
} catch (e) {
console.warn("Supabase getPosts relational select threw:", (e as any)?.message || e);
console.warn(
"Supabase getPosts relational select threw:",
(e as any)?.message || e,
);
}
// 2) Fallback to simple posts select, then hydrate author profiles manually
@ -269,7 +275,9 @@ export const communityService = {
.order("created_at", { ascending: false })
.limit(limit);
if (!postsErr && Array.isArray(posts) && posts.length) {
const authorIds = Array.from(new Set(posts.map((p: any) => p.author_id).filter(Boolean)));
const authorIds = Array.from(
new Set(posts.map((p: any) => p.author_id).filter(Boolean)),
);
let profilesById: Record<string, any> = {};
if (authorIds.length) {
const { data: profiles, error: profErr } = await supabase
@ -278,20 +286,39 @@ export const communityService = {
.in("id", authorIds);
if (!profErr && Array.isArray(profiles)) {
profilesById = Object.fromEntries(
profiles.map((u: any) => [u.id, { username: u.username, full_name: u.full_name, avatar_url: u.avatar_url }]),
profiles.map((u: any) => [
u.id,
{
username: u.username,
full_name: u.full_name,
avatar_url: u.avatar_url,
},
]),
);
}
}
return posts.map((p: any) => ({ ...p, user_profiles: profilesById[p.author_id] || null })) as CommunityPost[];
return posts.map((p: any) => ({
...p,
user_profiles: profilesById[p.author_id] || null,
})) as CommunityPost[];
}
if (postsErr) console.warn("Supabase getPosts simple select failed:", (postsErr as any)?.message || postsErr);
if (postsErr)
console.warn(
"Supabase getPosts simple select failed:",
(postsErr as any)?.message || postsErr,
);
} catch (e2) {
console.warn("Supabase getPosts simple select threw:", (e2 as any)?.message || e2);
console.warn(
"Supabase getPosts simple select threw:",
(e2 as any)?.message || e2,
);
}
// 3) Final fallback to API if available
try {
const resp = await fetch(`/api/posts?limit=${encodeURIComponent(String(limit))}`);
const resp = await fetch(
`/api/posts?limit=${encodeURIComponent(String(limit))}`,
);
if (resp.ok) {
const ct = resp.headers.get("content-type") || "";
if (ct.includes("application/json") || ct.includes("json")) {
@ -299,13 +326,24 @@ export const communityService = {
return (Array.isArray(payload) ? payload : []) as CommunityPost[];
} else {
const text = await resp.text();
console.warn("API fallback returned non-JSON content-type:", ct, text.slice(0, 120));
console.warn(
"API fallback returned non-JSON content-type:",
ct,
text.slice(0, 120),
);
}
} else {
console.warn("API fallback /api/posts not ok:", resp.status, resp.statusText);
console.warn(
"API fallback /api/posts not ok:",
resp.status,
resp.statusText,
);
}
} catch (apiErr) {
console.error("API fallback for getPosts failed:", (apiErr as any)?.message || apiErr);
console.error(
"API fallback for getPosts failed:",
(apiErr as any)?.message || apiErr,
);
}
// Return actual empty array (no demo/mocks)
@ -364,11 +402,14 @@ export const communityService = {
async likePost(postId: string, userId: string): Promise<number | null> {
try {
const resp = await fetch(`/api/community/posts/${encodeURIComponent(postId)}/like`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ user_id: userId }),
});
const resp = await fetch(
`/api/community/posts/${encodeURIComponent(postId)}/like`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ user_id: userId }),
},
);
if (resp.ok) {
const json = await resp.json();
return typeof json?.likes === "number" ? json.likes : null;
@ -379,11 +420,14 @@ export const communityService = {
async unlikePost(postId: string, userId: string): Promise<number | null> {
try {
const resp = await fetch(`/api/community/posts/${encodeURIComponent(postId)}/unlike`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ user_id: userId }),
});
const resp = await fetch(
`/api/community/posts/${encodeURIComponent(postId)}/unlike`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ user_id: userId }),
},
);
if (resp.ok) {
const json = await resp.json();
return typeof json?.likes === "number" ? json.likes : null;
@ -394,7 +438,9 @@ export const communityService = {
async listComments(postId: string): Promise<any[]> {
try {
const resp = await fetch(`/api/community/posts/${encodeURIComponent(postId)}/comments`);
const resp = await fetch(
`/api/community/posts/${encodeURIComponent(postId)}/comments`,
);
if (!resp.ok) return [];
return await resp.json();
} catch {
@ -402,12 +448,19 @@ export const communityService = {
}
},
async addComment(postId: string, userId: string, content: string): Promise<any | null> {
const resp = await fetch(`/api/community/posts/${encodeURIComponent(postId)}/comments`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ user_id: userId, content }),
});
async addComment(
postId: string,
userId: string,
content: string,
): Promise<any | null> {
const resp = await fetch(
`/api/community/posts/${encodeURIComponent(postId)}/comments`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ user_id: userId, content }),
},
);
if (!resp.ok) return null;
return await resp.json();
},

View file

@ -133,7 +133,13 @@ export default function Feed() {
} finally {
setIsLoading(false);
}
}, [aethexSocialService, communityService, mapPostsToFeedItems, toast, user?.id]);
}, [
aethexSocialService,
communityService,
mapPostsToFeedItems,
toast,
user?.id,
]);
useEffect(() => {
fetchFeed();
@ -246,10 +252,16 @@ export default function Feed() {
const content = prompt("Add a comment:")?.trim();
if (!content) return;
try {
const created = await communityService.addComment(postId, user.id, content);
const created = await communityService.addComment(
postId,
user.id,
content,
);
if (created) {
setItems((prev) =>
prev.map((it) => (it.id === postId ? { ...it, comments: it.comments + 1 } : it)),
prev.map((it) =>
it.id === postId ? { ...it, comments: it.comments + 1 } : it,
),
);
}
} catch (e) {

View file

@ -58,7 +58,10 @@ const ProfilePassport = () => {
(AethexUserProfile & { email?: string | null }) | null
>(null);
const [achievements, setAchievements] = useState<AethexAchievement[]>([]);
const [followStats, setFollowStats] = useState<{ followers: number; following: number }>({ followers: 0, following: 0 });
const [followStats, setFollowStats] = useState<{
followers: number;
following: number;
}>({ followers: 0, following: 0 });
const [degree, setDegree] = useState<string>("");
const [projects, setProjects] = useState<ProjectPreview[]>([]);
const [interests, setInterests] = useState<string[]>([]);
@ -266,7 +269,11 @@ const ProfilePassport = () => {
aethexSocialService.getFollowing(resolvedId),
aethexSocialService.getFollowers(resolvedId),
]);
if (!cancelled) setFollowStats({ following: followingIds.length, followers: followerIds.length });
if (!cancelled)
setFollowStats({
following: followingIds.length,
followers: followerIds.length,
});
} catch {}
try {
const me = user?.id || null;
@ -276,9 +283,13 @@ const ProfilePassport = () => {
if (first.has(resolvedId)) setDegree("1st");
else {
const secondLists = await Promise.all(
Array.from(first).slice(0, 50).map((id) => aethexSocialService.getConnections(id)),
Array.from(first)
.slice(0, 50)
.map((id) => aethexSocialService.getConnections(id)),
);
const second = new Set(
secondLists.flat().map((c: any) => c.connection_id),
);
const second = new Set(secondLists.flat().map((c: any) => c.connection_id));
setDegree(second.has(resolvedId) ? "2nd" : "3rd+");
}
} else if (me && resolvedId && me === resolvedId) {
@ -547,14 +558,22 @@ const ProfilePassport = () => {
)}
</div>
<div className="flex flex-wrap gap-2 text-sm text-slate-300">
<Badge variant="outline" className="border-slate-700/70 bg-slate-900/40">
<Badge
variant="outline"
className="border-slate-700/70 bg-slate-900/40"
>
Followers: {followStats.followers}
</Badge>
<Badge variant="outline" className="border-slate-700/70 bg-slate-900/40">
<Badge
variant="outline"
className="border-slate-700/70 bg-slate-900/40"
>
Following: {followStats.following}
</Badge>
{degree && (
<Badge className="bg-aethex-500/20 text-aethex-100">{degree} degree</Badge>
<Badge className="bg-aethex-500/20 text-aethex-100">
{degree} degree
</Badge>
)}
{profile.github_url && (
<Button

View file

@ -911,14 +911,19 @@ export function createServer() {
.from("community_post_likes")
.select("post_id", { count: "exact", head: true })
.eq("post_id", postId);
const count = (c as any)?.length ? (c as any).length : (c as any)?.count || null;
const count = (c as any)?.length
? (c as any).length
: (c as any)?.count || null;
if (typeof count === "number") {
await adminSupabase
.from("community_posts")
.update({ likes_count: count })
.eq("id", postId);
}
return res.json({ ok: true, likes: typeof count === "number" ? count : undefined });
return res.json({
ok: true,
likes: typeof count === "number" ? count : undefined,
});
} catch (e: any) {
return res.status(500).json({ error: e?.message || String(e) });
}
@ -939,14 +944,19 @@ export function createServer() {
.from("community_post_likes")
.select("post_id", { count: "exact", head: true })
.eq("post_id", postId);
const count = (c as any)?.length ? (c as any).length : (c as any)?.count || null;
const count = (c as any)?.length
? (c as any).length
: (c as any)?.count || null;
if (typeof count === "number") {
await adminSupabase
.from("community_posts")
.update({ likes_count: count })
.eq("id", postId);
}
return res.json({ ok: true, likes: typeof count === "number" ? count : undefined });
return res.json({
ok: true,
likes: typeof count === "number" ? count : undefined,
});
} catch (e: any) {
return res.status(500).json({ error: e?.message || String(e) });
}
@ -958,7 +968,9 @@ export function createServer() {
try {
const { data, error } = await adminSupabase
.from("community_comments")
.select("*, user_profiles:user_id ( id, full_name, username, avatar_url )")
.select(
"*, user_profiles:user_id ( id, full_name, username, avatar_url )",
)
.eq("post_id", postId)
.order("created_at", { ascending: true });
if (error) return res.status(500).json({ error: error.message });
@ -1077,14 +1089,12 @@ export function createServer() {
title: string,
message?: string,
) => {
await adminSupabase
.from("notifications")
.insert({
user_id: userId,
type: "info",
title,
message: message || null,
});
await adminSupabase.from("notifications").insert({
user_id: userId,
type: "info",
title,
message: message || null,
});
};
// Notify explicit targets