Prettier format pending files
This commit is contained in:
parent
d28c0e3937
commit
ef56ff44fd
8 changed files with 333 additions and 98 deletions
|
|
@ -52,7 +52,10 @@ const App = () => (
|
|||
<Route path="/dashboard" element={<Dashboard />} />
|
||||
<Route path="/admin" element={<Admin />} />
|
||||
<Route path="/network" element={<Network />} />
|
||||
<Route path="/profile" element={<Navigate to="/network" replace />} />
|
||||
<Route
|
||||
path="/profile"
|
||||
element={<Navigate to="/network" replace />}
|
||||
/>
|
||||
<Route path="/login" element={<Login />} />
|
||||
|
||||
{/* Service routes */}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ export default function Layout({ children }: LayoutProps) {
|
|||
{(() => {
|
||||
const isOwner = Array.isArray(roles) && roles.includes("owner");
|
||||
const navItems = user
|
||||
? (isOwner ? [{ name: "Admin", href: "/admin" }, ...userNavigation] : userNavigation)
|
||||
? isOwner
|
||||
? [{ name: "Admin", href: "/admin" }, ...userNavigation]
|
||||
: userNavigation
|
||||
: navigation;
|
||||
return navItems.map((item, index) => (
|
||||
<Link
|
||||
|
|
@ -93,7 +95,12 @@ export default function Layout({ children }: LayoutProps) {
|
|||
{user ? (
|
||||
// Logged in - always show Dashboard button; show avatar menu if profile exists
|
||||
<div className="flex items-center space-x-3">
|
||||
<Button asChild variant="outline" size="sm" className="hover-lift">
|
||||
<Button
|
||||
asChild
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="hover-lift"
|
||||
>
|
||||
<Link to="/dashboard">Dashboard</Link>
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm" className="hover-lift">
|
||||
|
|
@ -141,9 +148,9 @@ export default function Layout({ children }: LayoutProps) {
|
|||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link to="/dashboard" className="cursor-pointer">
|
||||
<Settings className="mr-2 h-4 w-4" />
|
||||
Settings
|
||||
</Link>
|
||||
<Settings className="mr-2 h-4 w-4" />
|
||||
Settings
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
|
|
|
|||
|
|
@ -114,7 +114,9 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||
// Auto-seed owner roles if logging in as site owner
|
||||
const ownerEmail = userProfile?.email?.toLowerCase();
|
||||
if (ownerEmail === "mrpiglr@gmail.com" && !r.includes("owner")) {
|
||||
const seeded = Array.from(new Set(["owner", "admin", "founder", ...r]));
|
||||
const seeded = Array.from(
|
||||
new Set(["owner", "admin", "founder", ...r]),
|
||||
);
|
||||
await aethexRoleService.setUserRoles(userId, seeded);
|
||||
r = seeded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ function isTableMissing(err: any): boolean {
|
|||
const msg = String(err?.message || err?.hint || err?.details || "");
|
||||
return (
|
||||
err?.code === "42P01" || // undefined_table
|
||||
msg.includes("relation \"") ||
|
||||
msg.includes('relation "') ||
|
||||
msg.includes("does not exist") ||
|
||||
msg.includes("table")
|
||||
);
|
||||
|
|
@ -86,12 +86,15 @@ export const aethexUserService = {
|
|||
email: user.email,
|
||||
} as AethexUserProfile;
|
||||
}
|
||||
const created = await mockAuth.updateProfile(user.id as any, {
|
||||
username: user.email?.split("@")[0] || "user",
|
||||
email: user.email || "",
|
||||
role: "member",
|
||||
onboarded: true,
|
||||
} as any);
|
||||
const created = await mockAuth.updateProfile(
|
||||
user.id as any,
|
||||
{
|
||||
username: user.email?.split("@")[0] || "user",
|
||||
email: user.email || "",
|
||||
role: "member",
|
||||
onboarded: true,
|
||||
} as any,
|
||||
);
|
||||
return {
|
||||
...(created as any),
|
||||
email: user.email,
|
||||
|
|
@ -123,7 +126,10 @@ export const aethexUserService = {
|
|||
if (error) {
|
||||
console.warn("Error updating profile, attempting mock fallback:", error);
|
||||
if (isTableMissing(error)) {
|
||||
const mock = await mockAuth.updateProfile(userId as any, updates as any);
|
||||
const mock = await mockAuth.updateProfile(
|
||||
userId as any,
|
||||
updates as any,
|
||||
);
|
||||
return mock as unknown as AethexUserProfile;
|
||||
}
|
||||
throw error;
|
||||
|
|
@ -162,17 +168,20 @@ export const aethexUserService = {
|
|||
if (error) {
|
||||
console.warn("Error creating profile, attempting mock fallback:", error);
|
||||
if (isTableMissing(error)) {
|
||||
const mock = await mockAuth.updateProfile(userId as any, {
|
||||
username: profileData.username || `user_${Date.now()}`,
|
||||
full_name: profileData.full_name,
|
||||
bio: profileData.bio,
|
||||
location: profileData.location,
|
||||
linkedin_url: profileData.linkedin_url as any,
|
||||
github_url: profileData.github_url as any,
|
||||
twitter_url: profileData.twitter_url as any,
|
||||
level: 1,
|
||||
total_xp: 0,
|
||||
} as any);
|
||||
const mock = await mockAuth.updateProfile(
|
||||
userId as any,
|
||||
{
|
||||
username: profileData.username || `user_${Date.now()}`,
|
||||
full_name: profileData.full_name,
|
||||
bio: profileData.bio,
|
||||
location: profileData.location,
|
||||
linkedin_url: profileData.linkedin_url as any,
|
||||
github_url: profileData.github_url as any,
|
||||
twitter_url: profileData.twitter_url as any,
|
||||
level: 1,
|
||||
total_xp: 0,
|
||||
} as any,
|
||||
);
|
||||
|
||||
return {
|
||||
...(mock as any),
|
||||
|
|
@ -206,7 +215,9 @@ export const aethexUserService = {
|
|||
interest,
|
||||
}));
|
||||
|
||||
const { error } = await supabase.from("user_interests").insert(interestRows);
|
||||
const { error } = await supabase
|
||||
.from("user_interests")
|
||||
.insert(interestRows);
|
||||
|
||||
if (error) {
|
||||
if (isTableMissing(error)) return;
|
||||
|
|
@ -283,7 +294,10 @@ export const aethexProjectService = {
|
|||
},
|
||||
|
||||
async deleteProject(projectId: string): Promise<boolean> {
|
||||
const { error } = await supabase.from("projects").delete().eq("id", projectId);
|
||||
const { error } = await supabase
|
||||
.from("projects")
|
||||
.delete()
|
||||
.eq("id", projectId);
|
||||
|
||||
if (error) {
|
||||
console.warn("Error deleting project:", error);
|
||||
|
|
@ -410,7 +424,8 @@ export const aethexAchievementService = {
|
|||
const updates: any = {};
|
||||
if ("total_xp" in (profile as any)) updates.total_xp = newTotalXP;
|
||||
if ("level" in (profile as any)) updates.level = newLevel;
|
||||
if ("loyalty_points" in (profile as any)) updates.loyalty_points = newLoyaltyPoints;
|
||||
if ("loyalty_points" in (profile as any))
|
||||
updates.loyalty_points = newLoyaltyPoints;
|
||||
|
||||
if (Object.keys(updates).length > 0) {
|
||||
await supabase.from("user_profiles").update(updates).eq("id", userId);
|
||||
|
|
@ -426,7 +441,10 @@ export const aethexAchievementService = {
|
|||
.single();
|
||||
|
||||
if (levelUpAchievement.data) {
|
||||
await this.awardAchievement(userId, (levelUpAchievement.data as any).id);
|
||||
await this.awardAchievement(
|
||||
userId,
|
||||
(levelUpAchievement.data as any).id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -588,9 +606,12 @@ export const aethexRoleService = {
|
|||
async setUserRoles(userId: string, roles: string[]): Promise<void> {
|
||||
try {
|
||||
const rows = roles.map((role) => ({ user_id: userId, role }));
|
||||
const { error } = await supabase.from("user_roles").upsert(rows as any, {
|
||||
onConflict: "user_id,role",
|
||||
} as any);
|
||||
const { error } = await supabase.from("user_roles").upsert(
|
||||
rows as any,
|
||||
{
|
||||
onConflict: "user_id,role",
|
||||
} as any,
|
||||
);
|
||||
if (!error) return;
|
||||
} catch {}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ export const aethexSocialService = {
|
|||
.from("user_follows")
|
||||
.select("following_id")
|
||||
.eq("follower_id", userId);
|
||||
if (!error && data) return (data as any[]).map((r: any) => r.following_id);
|
||||
if (!error && data)
|
||||
return (data as any[]).map((r: any) => r.following_id);
|
||||
} catch {}
|
||||
try {
|
||||
const raw = localStorage.getItem("mock_follows");
|
||||
|
|
@ -40,7 +41,9 @@ export const aethexSocialService = {
|
|||
} catch {}
|
||||
const raw = localStorage.getItem("mock_follows");
|
||||
const map = raw ? JSON.parse(raw) : {};
|
||||
const set: string[] = Array.from(new Set([...(map[followerId] || []), followingId]));
|
||||
const set: string[] = Array.from(
|
||||
new Set([...(map[followerId] || []), followingId]),
|
||||
);
|
||||
map[followerId] = set;
|
||||
localStorage.setItem("mock_follows", JSON.stringify(map));
|
||||
},
|
||||
|
|
@ -56,7 +59,9 @@ export const aethexSocialService = {
|
|||
} catch {}
|
||||
const raw = localStorage.getItem("mock_follows");
|
||||
const map = raw ? JSON.parse(raw) : {};
|
||||
const list: string[] = (map[followerId] || []).filter((id: string) => id !== followingId);
|
||||
const list: string[] = (map[followerId] || []).filter(
|
||||
(id: string) => id !== followingId,
|
||||
);
|
||||
map[followerId] = list;
|
||||
localStorage.setItem("mock_follows", JSON.stringify(map));
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,10 +3,23 @@ import LoadingScreen from "@/components/LoadingScreen";
|
|||
import { useAuth } from "@/contexts/AuthContext";
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
} from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Shield, UserCog, Rocket, Settings, Users, Activity } from "lucide-react";
|
||||
import {
|
||||
Shield,
|
||||
UserCog,
|
||||
Rocket,
|
||||
Settings,
|
||||
Users,
|
||||
Activity,
|
||||
} from "lucide-react";
|
||||
|
||||
export default function Admin() {
|
||||
const { user, loading, roles } = useAuth();
|
||||
|
|
@ -23,7 +36,11 @@ export default function Admin() {
|
|||
|
||||
if (loading || !user) {
|
||||
return (
|
||||
<LoadingScreen message="Verifying admin access..." showProgress duration={1000} />
|
||||
<LoadingScreen
|
||||
message="Verifying admin access..."
|
||||
showProgress
|
||||
duration={1000}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -35,10 +52,14 @@ export default function Admin() {
|
|||
<Card className="bg-red-500/10 border-red-500/30">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-red-400">Access Denied</CardTitle>
|
||||
<CardDescription>You dont have permission to access the admin panel.</CardDescription>
|
||||
<CardDescription>
|
||||
You dont have permission to access the admin panel.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button onClick={() => navigate("/dashboard")}>Go to Dashboard</Button>
|
||||
<Button onClick={() => navigate("/dashboard")}>
|
||||
Go to Dashboard
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
|
@ -54,16 +75,37 @@ export default function Admin() {
|
|||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-gradient">Admin Panel</h1>
|
||||
<p className="text-muted-foreground">Site Owner • Admin • Founder</p>
|
||||
<p className="text-muted-foreground">
|
||||
Site Owner • Admin • Founder
|
||||
</p>
|
||||
<div className="flex gap-2 mt-2">
|
||||
<Badge variant="outline" className="border-green-500/50 text-green-400">Site Owner</Badge>
|
||||
<Badge variant="outline" className="border-blue-500/50 text-blue-400">Admin</Badge>
|
||||
<Badge variant="outline" className="border-purple-500/50 text-purple-400">Founder</Badge>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="border-green-500/50 text-green-400"
|
||||
>
|
||||
Site Owner
|
||||
</Badge>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="border-blue-500/50 text-blue-400"
|
||||
>
|
||||
Admin
|
||||
</Badge>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="border-purple-500/50 text-purple-400"
|
||||
>
|
||||
Founder
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" onClick={() => navigate("/dashboard")}>Dashboard</Button>
|
||||
<Button variant="outline" onClick={() => navigate("/profile")}>Profile</Button>
|
||||
<Button variant="outline" onClick={() => navigate("/dashboard")}>
|
||||
Dashboard
|
||||
</Button>
|
||||
<Button variant="outline" onClick={() => navigate("/profile")}>
|
||||
Profile
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -74,12 +116,15 @@ export default function Admin() {
|
|||
<Shield className="h-5 w-5 text-green-400" />
|
||||
<CardTitle className="text-lg">Access Control</CardTitle>
|
||||
</div>
|
||||
<CardDescription>Owner-only access is enforced by email</CardDescription>
|
||||
<CardDescription>
|
||||
Owner-only access is enforced by email
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="text-sm space-y-1 text-muted-foreground">
|
||||
<li>
|
||||
Owner: <span className="text-foreground">mrpiglr@gmail.com</span>
|
||||
Owner:{" "}
|
||||
<span className="text-foreground">mrpiglr@gmail.com</span>
|
||||
</li>
|
||||
<li>All other users are denied access</li>
|
||||
</ul>
|
||||
|
|
@ -92,7 +137,9 @@ export default function Admin() {
|
|||
<Users className="h-5 w-5 text-blue-400" />
|
||||
<CardTitle className="text-lg">Users & Roles</CardTitle>
|
||||
</div>
|
||||
<CardDescription>Future: manage roles, invitations, and status</CardDescription>
|
||||
<CardDescription>
|
||||
Future: manage roles, invitations, and status
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-muted-foreground">Coming soon</p>
|
||||
|
|
@ -108,7 +155,12 @@ export default function Admin() {
|
|||
<CardDescription>Branding, legal, integrations</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button variant="outline" onClick={() => navigate("/get-started")}>Open Settings</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => navigate("/get-started")}
|
||||
>
|
||||
Open Settings
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
|
|
@ -138,8 +190,16 @@ export default function Admin() {
|
|||
<CardDescription>Common admin operations</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-wrap gap-2">
|
||||
<Button size="sm" onClick={() => navigate("/dashboard")}>View Dashboard</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => navigate("/onboarding")}>Run Onboarding</Button>
|
||||
<Button size="sm" onClick={() => navigate("/dashboard")}>
|
||||
View Dashboard
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => navigate("/onboarding")}
|
||||
>
|
||||
Run Onboarding
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
|
|
|
|||
|
|
@ -141,9 +141,9 @@ export default function Index() {
|
|||
Crafting Digital Realities
|
||||
</h2>
|
||||
<p className="text-lg text-muted-foreground max-w-2xl mx-auto animate-slide-up">
|
||||
Where vision meets execution. We craft experiences through
|
||||
design, development, and community.
|
||||
</p>
|
||||
Where vision meets execution. We craft experiences through
|
||||
design, development, and community.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -247,8 +247,12 @@ export default function Index() {
|
|||
<section className="py-20">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-3xl lg:text-4xl font-bold text-gradient">Everything We Offer</h2>
|
||||
<p className="text-muted-foreground mt-2">Explore services, programs, resources, and community</p>
|
||||
<h2 className="text-3xl lg:text-4xl font-bold text-gradient">
|
||||
Everything We Offer
|
||||
</h2>
|
||||
<p className="text-muted-foreground mt-2">
|
||||
Explore services, programs, resources, and community
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
|
|
@ -258,7 +262,9 @@ export default function Index() {
|
|||
<CardDescription>Studios and indie support</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button asChild className="w-full"><Link to="/game-development">Learn More</Link></Button>
|
||||
<Button asChild className="w-full">
|
||||
<Link to="/game-development">Learn More</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
|
|
@ -268,7 +274,9 @@ export default function Index() {
|
|||
<CardDescription>Architecture & delivery</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button asChild className="w-full"><Link to="/consulting">Learn More</Link></Button>
|
||||
<Button asChild className="w-full">
|
||||
<Link to="/consulting">Learn More</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
|
|
@ -278,7 +286,9 @@ export default function Index() {
|
|||
<CardDescription>Programs and guidance</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button asChild className="w-full"><Link to="/mentorship">Learn More</Link></Button>
|
||||
<Button asChild className="w-full">
|
||||
<Link to="/mentorship">Learn More</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
|
|
@ -288,7 +298,9 @@ export default function Index() {
|
|||
<CardDescription>Innovation and R&D</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button asChild className="w-full"><Link to="/research">Learn More</Link></Button>
|
||||
<Button asChild className="w-full">
|
||||
<Link to="/research">Learn More</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
|
@ -301,8 +313,12 @@ export default function Index() {
|
|||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex gap-2">
|
||||
<Button asChild variant="outline"><Link to="/docs">Docs</Link></Button>
|
||||
<Button asChild variant="outline"><Link to="/docs/tutorials">Tutorials</Link></Button>
|
||||
<Button asChild variant="outline">
|
||||
<Link to="/docs">Docs</Link>
|
||||
</Button>
|
||||
<Button asChild variant="outline">
|
||||
<Link to="/docs/tutorials">Tutorials</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -314,8 +330,12 @@ export default function Index() {
|
|||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex gap-2">
|
||||
<Button asChild variant="outline"><Link to="/community">Community</Link></Button>
|
||||
<Button asChild variant="outline"><Link to="/blog">Blog</Link></Button>
|
||||
<Button asChild variant="outline">
|
||||
<Link to="/community">Community</Link>
|
||||
</Button>
|
||||
<Button asChild variant="outline">
|
||||
<Link to="/blog">Blog</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -327,8 +347,12 @@ export default function Index() {
|
|||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex gap-2">
|
||||
<Button asChild variant="outline"><Link to="/about">About</Link></Button>
|
||||
<Button asChild variant="outline"><Link to="/contact">Contact</Link></Button>
|
||||
<Button asChild variant="outline">
|
||||
<Link to="/about">About</Link>
|
||||
</Button>
|
||||
<Button asChild variant="outline">
|
||||
<Link to="/contact">Contact</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -355,12 +379,36 @@ export default function Index() {
|
|||
{/* Interactive Technology Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 animate-fade-in">
|
||||
{[
|
||||
{ name: "Game Studios", status: "Active", color: "from-purple-500 to-blue-600" },
|
||||
{ name: "Design Systems", status: "Evolving", color: "from-blue-500 to-green-600" },
|
||||
{ name: "Creator Tools", status: "Live", color: "from-green-500 to-yellow-600" },
|
||||
{ name: "Launch Ops", status: "Scaling", color: "from-yellow-500 to-red-600" },
|
||||
{ name: "Content Pipeline", status: "In Progress", color: "from-red-500 to-purple-600" },
|
||||
{ name: "Edge Experiences", status: "Deployed", color: "from-purple-500 to-pink-600" },
|
||||
{
|
||||
name: "Game Studios",
|
||||
status: "Active",
|
||||
color: "from-purple-500 to-blue-600",
|
||||
},
|
||||
{
|
||||
name: "Design Systems",
|
||||
status: "Evolving",
|
||||
color: "from-blue-500 to-green-600",
|
||||
},
|
||||
{
|
||||
name: "Creator Tools",
|
||||
status: "Live",
|
||||
color: "from-green-500 to-yellow-600",
|
||||
},
|
||||
{
|
||||
name: "Launch Ops",
|
||||
status: "Scaling",
|
||||
color: "from-yellow-500 to-red-600",
|
||||
},
|
||||
{
|
||||
name: "Content Pipeline",
|
||||
status: "In Progress",
|
||||
color: "from-red-500 to-purple-600",
|
||||
},
|
||||
{
|
||||
name: "Edge Experiences",
|
||||
status: "Deployed",
|
||||
color: "from-purple-500 to-pink-600",
|
||||
},
|
||||
].map((tech, index) => (
|
||||
<Card
|
||||
key={index}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,13 @@ import { useAuth } from "@/contexts/AuthContext";
|
|||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import LoadingScreen from "@/components/LoadingScreen";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
|
@ -52,7 +58,13 @@ export default function Network() {
|
|||
};
|
||||
|
||||
if (loading || isLoading) {
|
||||
return <LoadingScreen message="Loading your network..." showProgress duration={1000} />;
|
||||
return (
|
||||
<LoadingScreen
|
||||
message="Loading your network..."
|
||||
showProgress
|
||||
duration={1000}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!user) return null;
|
||||
|
|
@ -68,14 +80,28 @@ export default function Network() {
|
|||
<div className="flex items-center gap-4">
|
||||
<Avatar className="h-16 w-16">
|
||||
<AvatarImage src={profile?.avatar_url} />
|
||||
<AvatarFallback>{profile?.full_name?.[0] || user.email?.[0]?.toUpperCase()}</AvatarFallback>
|
||||
<AvatarFallback>
|
||||
{profile?.full_name?.[0] ||
|
||||
user.email?.[0]?.toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold">{profile?.full_name || user.email?.split("@")[0]}</h2>
|
||||
<p className="text-sm text-muted-foreground">{profile?.role || "Member"}</p>
|
||||
<h2 className="text-xl font-semibold">
|
||||
{profile?.full_name || user.email?.split("@")[0]}
|
||||
</h2>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{profile?.role || "Member"}
|
||||
</p>
|
||||
<div className="mt-2 flex gap-2">
|
||||
<Badge variant="outline" className="border-aethex-400/50 text-aethex-400">Level {profile?.level || 1}</Badge>
|
||||
<Badge variant="outline">{(profile as any)?.experience_level || "beginner"}</Badge>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="border-aethex-400/50 text-aethex-400"
|
||||
>
|
||||
Level {profile?.level || 1}
|
||||
</Badge>
|
||||
<Badge variant="outline">
|
||||
{(profile as any)?.experience_level || "beginner"}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -83,8 +109,18 @@ export default function Network() {
|
|||
<p className="text-sm text-muted-foreground">{profile.bio}</p>
|
||||
)}
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" onClick={() => navigate("/dashboard")}>Edit Profile</Button>
|
||||
<Button variant="outline" onClick={() => navigate("/onboarding")}>Improve Profile</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => navigate("/dashboard")}
|
||||
>
|
||||
Edit Profile
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => navigate("/onboarding")}
|
||||
>
|
||||
Improve Profile
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -92,25 +128,50 @@ export default function Network() {
|
|||
<Card className="bg-card/50 border-border/50">
|
||||
<CardHeader>
|
||||
<CardTitle>Recommendations</CardTitle>
|
||||
<CardDescription>People who align with your interests</CardDescription>
|
||||
<CardDescription>
|
||||
People who align with your interests
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
{recommended.slice(0, 3).map((r) => (
|
||||
<div key={r.id} className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar className="h-10 w-10"><AvatarImage src={r.avatar_url} /><AvatarFallback>{(r.full_name || r.username || "U")[0]}</AvatarFallback></Avatar>
|
||||
<Avatar className="h-10 w-10">
|
||||
<AvatarImage src={r.avatar_url} />
|
||||
<AvatarFallback>
|
||||
{(r.full_name || r.username || "U")[0]}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div>
|
||||
<div className="font-medium">{r.full_name || r.username}</div>
|
||||
<div className="text-xs text-muted-foreground">{r.bio?.slice(0, 40) || "Member"}</div>
|
||||
<div className="font-medium">
|
||||
{r.full_name || r.username}
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{r.bio?.slice(0, 40) || "Member"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button size="sm" variant={isFollowing(r.id) ? "outline" : "default"} onClick={() => toggleFollow(r.id)}>
|
||||
{isFollowing(r.id) ? (<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>)}
|
||||
<Button
|
||||
size="sm"
|
||||
variant={isFollowing(r.id) ? "outline" : "default"}
|
||||
onClick={() => toggleFollow(r.id)}
|
||||
>
|
||||
{isFollowing(r.id) ? (
|
||||
<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>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
{recommended.length === 0 && (
|
||||
<div className="text-sm text-muted-foreground">No recommendations yet.</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
No recommendations yet.
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -121,25 +182,53 @@ export default function Network() {
|
|||
<Card className="bg-card/50 border-border/50">
|
||||
<CardHeader>
|
||||
<CardTitle>Discover People</CardTitle>
|
||||
<CardDescription>Connect with creators, clients, and members</CardDescription>
|
||||
<CardDescription>
|
||||
Connect with creators, clients, and members
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{recommended.map((r) => (
|
||||
<div key={r.id} className="flex items-center justify-between p-3 rounded-lg border border-border/50 hover:border-aethex-400/50 transition-all">
|
||||
<div
|
||||
key={r.id}
|
||||
className="flex items-center justify-between p-3 rounded-lg border border-border/50 hover:border-aethex-400/50 transition-all"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar className="h-12 w-12"><AvatarImage src={r.avatar_url} /><AvatarFallback>{(r.full_name || r.username || "U")[0]}</AvatarFallback></Avatar>
|
||||
<Avatar className="h-12 w-12">
|
||||
<AvatarImage src={r.avatar_url} />
|
||||
<AvatarFallback>
|
||||
{(r.full_name || r.username || "U")[0]}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div>
|
||||
<div className="font-semibold">{r.full_name || r.username}</div>
|
||||
<div className="text-xs text-muted-foreground">{r.bio?.slice(0, 80) || "Member"}</div>
|
||||
<div className="font-semibold">
|
||||
{r.full_name || r.username}
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{r.bio?.slice(0, 80) || "Member"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button size="sm" variant={isFollowing(r.id) ? "outline" : "default"} onClick={() => toggleFollow(r.id)}>
|
||||
{isFollowing(r.id) ? (<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>)}
|
||||
<Button
|
||||
size="sm"
|
||||
variant={isFollowing(r.id) ? "outline" : "default"}
|
||||
onClick={() => toggleFollow(r.id)}
|
||||
>
|
||||
{isFollowing(r.id) ? (
|
||||
<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>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
{recommended.length === 0 && (
|
||||
<div className="text-sm text-muted-foreground">No people found yet.</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
No people found yet.
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
|
|||
Loading…
Reference in a new issue