Prettier format pending files

This commit is contained in:
Builder.io 2025-09-27 23:53:05 +00:00
parent 1fdc0a40db
commit 15dbb11bcf
6 changed files with 164 additions and 45 deletions

View file

@ -53,7 +53,10 @@ export default function PostComposer({ onPosted }: { onPosted?: () => void }) {
const handlePost = async () => {
if (!user) {
toast({ title: "Sign in required", description: "Please sign in to post" });
toast({
title: "Sign in required",
description: "Please sign in to post",
});
return;
}
if (!text.trim() && !mediaFile && !mediaUrlInput.trim()) {
@ -75,15 +78,31 @@ export default function PostComposer({ onPosted }: { onPosted?: () => void }) {
}
if (mediaUrl) {
if (/\.(mp4|webm|mov)(\?.*)?$/i.test(mediaUrl) || /video\//.test(mediaFile?.type || "")) {
if (
/\.(mp4|webm|mov)(\?.*)?$/i.test(mediaUrl) ||
/video\//.test(mediaFile?.type || "")
) {
mediaType = "video";
} else if (/\.(png|jpe?g|gif|webp|svg)(\?.*)?$/i.test(mediaUrl) || /image\//.test(mediaFile?.type || "")) {
} else if (
/\.(png|jpe?g|gif|webp|svg)(\?.*)?$/i.test(mediaUrl) ||
/image\//.test(mediaFile?.type || "")
) {
mediaType = "image";
}
}
const content = JSON.stringify({ text: text.trim(), mediaUrl, mediaType });
const title = text.trim().slice(0, 80) || (mediaType === "video" ? "New video" : mediaType === "image" ? "New photo" : "Update");
const content = JSON.stringify({
text: text.trim(),
mediaUrl,
mediaType,
});
const title =
text.trim().slice(0, 80) ||
(mediaType === "video"
? "New video"
: mediaType === "image"
? "New photo"
: "Update");
await communityService.createPost({
author_id: user.id,
@ -98,7 +117,11 @@ export default function PostComposer({ onPosted }: { onPosted?: () => void }) {
reset();
onPosted?.();
} catch (e: any) {
toast({ variant: "destructive", title: "Could not post", description: e?.message || "Try again later" });
toast({
variant: "destructive",
title: "Could not post",
description: e?.message || "Try again later",
});
} finally {
setSubmitting(false);
}

View file

@ -13,8 +13,10 @@ export const aethexSocialService = {
try {
const raw = localStorage.getItem("demo_profiles");
const profiles = raw ? JSON.parse(raw) : [];
return profiles.filter((p:any)=>p.id!==userId).slice(0, limit);
} catch { return [] as any[]; }
return profiles.filter((p: any) => p.id !== userId).slice(0, limit);
} catch {
return [] as any[];
}
},
async getFollowing(userId: string): Promise<string[]> {

View file

@ -19,8 +19,7 @@ export function ensureDemoSeed() {
username: "TestSubject",
full_name: "Test Subject",
email: "testsubject@demo.local",
avatar_url:
"https://i.pravatar.cc/150?img=1",
avatar_url: "https://i.pravatar.cc/150?img=1",
bio: "Trying features, sharing experiments, and stress-testing the feed.",
managed_by: "mrpiglr@gmail.com",
},

View file

@ -257,7 +257,9 @@ export const communityService = {
const raw = localStorage.getItem("demo_posts");
const posts = raw ? JSON.parse(raw) : [];
return posts.slice(0, limit);
} catch { return []; }
} catch {
return [];
}
},
async createPost(
@ -282,12 +284,16 @@ export const communityService = {
updated_at: new Date().toISOString(),
likes_count: 0,
comments_count: 0,
user_profiles: (function(){
try{
const profiles = JSON.parse(localStorage.getItem("demo_profiles")||"[]");
return profiles.find((p:any)=>p.id===post.author_id) || null;
}catch{ return null; }
})()
user_profiles: (function () {
try {
const profiles = JSON.parse(
localStorage.getItem("demo_profiles") || "[]",
);
return profiles.find((p: any) => p.id === post.author_id) || null;
} catch {
return null;
}
})(),
};
const raw = localStorage.getItem("demo_posts");
const list = raw ? JSON.parse(raw) : [];
@ -308,8 +314,10 @@ export const communityService = {
try {
const raw = localStorage.getItem("demo_posts");
const posts = raw ? JSON.parse(raw) : [];
return posts.filter((p:any)=>p.author_id===userId);
} catch { return []; }
return posts.filter((p: any) => p.author_id === userId);
} catch {
return [];
}
},
};

View file

@ -25,8 +25,12 @@ export default function Admin() {
const { user, loading, roles } = useAuth();
const navigate = useNavigate();
const isOwner = Array.isArray(roles) && roles.includes("owner");
const demoProfiles: any[] = (function(){
try { return JSON.parse(localStorage.getItem("demo_profiles")||"[]"); } catch { return []; }
const demoProfiles: any[] = (function () {
try {
return JSON.parse(localStorage.getItem("demo_profiles") || "[]");
} catch {
return [];
}
})();
useEffect(() => {
@ -228,18 +232,28 @@ export default function Admin() {
<CardTitle className="text-lg">Demo Accounts</CardTitle>
</div>
<CardDescription>
Managed by <span className="text-foreground">mrpiglr@gmail.com</span>
Managed by{" "}
<span className="text-foreground">mrpiglr@gmail.com</span>
</CardDescription>
</CardHeader>
<CardContent className="space-y-3">
{demoProfiles.length === 0 && (
<div className="text-sm text-muted-foreground">No demo accounts seeded yet.</div>
<div className="text-sm text-muted-foreground">
No demo accounts seeded yet.
</div>
)}
{demoProfiles.map((p) => (
<div key={p.id} className="flex items-center justify-between p-2 rounded border border-border/40">
<div
key={p.id}
className="flex items-center justify-between p-2 rounded border border-border/40"
>
<div>
<div className="font-medium">{p.full_name || p.username}</div>
<div className="text-xs text-muted-foreground">{p.email}</div>
<div className="font-medium">
{p.full_name || p.username}
</div>
<div className="text-xs text-muted-foreground">
{p.email}
</div>
</div>
<Badge variant="outline">Managed</Badge>
</div>

View file

@ -33,13 +33,23 @@ interface FeedItem {
comments: number;
}
function parseContent(content: string): { text?: string; mediaUrl?: string | null; mediaType: "video" | "image" | "none" } {
function parseContent(content: string): {
text?: string;
mediaUrl?: string | null;
mediaType: "video" | "image" | "none";
} {
try {
const obj = JSON.parse(content || "{}");
return {
text: obj.text || content,
mediaUrl: obj.mediaUrl || null,
mediaType: obj.mediaType || (obj.mediaUrl ? (/(mp4|webm|mov)$/i.test(obj.mediaUrl) ? "video" : "image") : "none"),
mediaType:
obj.mediaType ||
(obj.mediaUrl
? /(mp4|webm|mov)$/i.test(obj.mediaUrl)
? "video"
: "image"
: "none"),
};
} catch {
return { text: content, mediaUrl: null, mediaType: "none" };
@ -108,7 +118,9 @@ export default function Feed() {
const sub = realtimeService.subscribeToCommunityPosts(() => load());
return () => {
try { sub.unsubscribe(); } catch {}
try {
sub.unsubscribe();
} catch {}
};
}, [user, loading]);
@ -128,7 +140,11 @@ export default function Feed() {
const url = `${location.origin}/feed#post-${id}`;
try {
if ((navigator as any).share) {
await (navigator as any).share({ title: "AeThex", text: "Check this post", url });
await (navigator as any).share({
title: "AeThex",
text: "Check this post",
url,
});
} else {
await navigator.clipboard.writeText(url);
toast({ description: "Link copied" });
@ -139,7 +155,11 @@ export default function Feed() {
if (!user && !loading) return <Navigate to="/login" replace />;
if (loading || isLoading) {
return (
<LoadingScreen message="Loading your feed..." showProgress duration={1000} />
<LoadingScreen
message="Loading your feed..."
showProgress
duration={1000}
/>
);
}
@ -156,13 +176,28 @@ export default function Feed() {
</div>
)}
{items.map((item) => (
<section id={`post-${item.id}`} key={item.id} className="snap-start h-[calc(100vh-64px)] relative flex items-center justify-center">
<section
id={`post-${item.id}`}
key={item.id}
className="snap-start h-[calc(100vh-64px)] relative flex items-center justify-center"
>
<Card className="w-full h-full bg-black/60 border-border/30 overflow-hidden">
<CardContent className="w-full h-full p-0 relative">
{item.mediaType === "video" && item.mediaUrl ? (
<video src={item.mediaUrl} className="w-full h-full object-cover" autoPlay loop muted={muted} playsInline />
<video
src={item.mediaUrl}
className="w-full h-full object-cover"
autoPlay
loop
muted={muted}
playsInline
/>
) : item.mediaType === "image" && item.mediaUrl ? (
<img src={item.mediaUrl} alt={item.caption || item.authorName} className="w-full h-full object-cover" />
<img
src={item.mediaUrl}
alt={item.caption || item.authorName}
className="w-full h-full object-cover"
/>
) : (
<div className="w-full h-full bg-gradient-to-br from-aethex-500/20 to-neon-blue/20" />
)}
@ -170,16 +205,38 @@ export default function Feed() {
<div className="absolute inset-0 bg-gradient-to-t from-black/50 via-black/20 to-transparent" />
<div className="absolute right-4 bottom-24 flex flex-col items-center gap-4">
<Button size="icon" variant="secondary" className="rounded-full bg-white/20 hover:bg-white/30" onClick={() => setMuted((m) => !m)}>
{muted ? <VolumeX className="h-5 w-5" /> : <Volume2 className="h-5 w-5" />}
<Button
size="icon"
variant="secondary"
className="rounded-full bg-white/20 hover:bg-white/30"
onClick={() => setMuted((m) => !m)}
>
{muted ? (
<VolumeX className="h-5 w-5" />
) : (
<Volume2 className="h-5 w-5" />
)}
</Button>
<Button size="icon" variant="secondary" className="rounded-full bg-white/20 hover:bg-white/30">
<Button
size="icon"
variant="secondary"
className="rounded-full bg-white/20 hover:bg-white/30"
>
<Heart className="h-5 w-5" />
</Button>
<Button size="icon" variant="secondary" className="rounded-full bg-white/20 hover:bg-white/30">
<Button
size="icon"
variant="secondary"
className="rounded-full bg-white/20 hover:bg-white/30"
>
<MessageCircle className="h-5 w-5" />
</Button>
<Button size="icon" variant="secondary" className="rounded-full bg-white/20 hover:bg-white/30" onClick={() => share(item.id)}>
<Button
size="icon"
variant="secondary"
className="rounded-full bg-white/20 hover:bg-white/30"
onClick={() => share(item.id)}
>
<Share2 className="h-5 w-5" />
</Button>
</div>
@ -188,20 +245,36 @@ export default function Feed() {
<div className="flex items-center gap-3">
<Avatar className="h-10 w-10">
<AvatarImage src={item.authorAvatar || undefined} />
<AvatarFallback>{item.authorName[0] || "U"}</AvatarFallback>
<AvatarFallback>
{item.authorName[0] || "U"}
</AvatarFallback>
</Avatar>
<div>
<div className="font-semibold text-white">{item.authorName}</div>
<div className="font-semibold text-white">
{item.authorName}
</div>
{item.caption && (
<div className="text-xs text-white/80 max-w-[60vw] line-clamp-2">{item.caption}</div>
<div className="text-xs text-white/80 max-w-[60vw] line-clamp-2">
{item.caption}
</div>
)}
</div>
</div>
<Button size="sm" variant={isFollowingAuthor(item.authorId) ? "outline" : "default"} onClick={() => toggleFollow(item.authorId)}>
<Button
size="sm"
variant={
isFollowingAuthor(item.authorId) ? "outline" : "default"
}
onClick={() => toggleFollow(item.authorId)}
>
{isFollowingAuthor(item.authorId) ? (
<span className="flex items-center gap-1"><UserCheck className="h-4 w-4" /> Following</span>
<span className="flex items-center gap-1">
<UserCheck className="h-4 w-4" /> Following
</span>
) : (
<span className="flex items-center gap-1"><UserPlus className="h-4 w-4" /> Follow</span>
<span className="flex items-center gap-1">
<UserPlus className="h-4 w-4" /> Follow
</span>
)}
</Button>
</div>