Quick Sign In
diff --git a/client/pages/ProfilePassport.tsx b/client/pages/ProfilePassport.tsx
index a9584acd..ddbcb47d 100644
--- a/client/pages/ProfilePassport.tsx
+++ b/client/pages/ProfilePassport.tsx
@@ -590,7 +590,7 @@ const ProfilePassport = () => {
variant="ghost"
className="h-8 px-2 text-xs text-aethex-200"
>
-
+
View mission
diff --git a/client/pages/ProjectDetail.tsx b/client/pages/ProjectDetail.tsx
new file mode 100644
index 00000000..bbc5e6bc
--- /dev/null
+++ b/client/pages/ProjectDetail.tsx
@@ -0,0 +1,280 @@
+import { useEffect, useState } from "react";
+import { useParams, Link } from "react-router-dom";
+import Layout from "@/components/Layout";
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Separator } from "@/components/ui/separator";
+import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
+import {
+ Github,
+ ExternalLink,
+ LayoutDashboard,
+ Calendar,
+ Cpu,
+ Activity,
+} from "lucide-react";
+
+const API_BASE = import.meta.env.VITE_API_BASE || "";
+
+interface Project {
+ id: string;
+ title: string;
+ description?: string | null;
+ status?: string | null;
+ technologies?: string[] | null;
+ github_url?: string | null;
+ live_url?: string | null;
+ image_url?: string | null;
+ engine?: string | null;
+ priority?: string | null;
+ progress?: number | null;
+ created_at?: string | null;
+ updated_at?: string | null;
+}
+
+interface Owner {
+ id: string;
+ username?: string | null;
+ full_name?: string | null;
+ avatar_url?: string | null;
+}
+
+const STATUS_COLORS: Record = {
+ planning: "bg-slate-500/20 text-slate-300 border-slate-600",
+ in_progress: "bg-blue-500/20 text-blue-300 border-blue-600",
+ completed: "bg-green-500/20 text-green-300 border-green-600",
+ on_hold: "bg-yellow-500/20 text-yellow-300 border-yellow-600",
+};
+
+const STATUS_LABELS: Record = {
+ planning: "Planning",
+ in_progress: "In Progress",
+ completed: "Completed",
+ on_hold: "On Hold",
+};
+
+const formatDate = (v?: string | null) => {
+ if (!v) return null;
+ const d = new Date(v);
+ if (isNaN(d.getTime())) return null;
+ return d.toLocaleDateString(undefined, { dateStyle: "medium" });
+};
+
+export default function ProjectDetail() {
+ const { projectId } = useParams<{ projectId: string }>();
+ const [project, setProject] = useState(null);
+ const [owner, setOwner] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [notFound, setNotFound] = useState(false);
+
+ useEffect(() => {
+ if (!projectId) return;
+ setLoading(true);
+ fetch(`${API_BASE}/api/projects/${projectId}`)
+ .then((r) => {
+ if (r.status === 404) { setNotFound(true); return null; }
+ return r.json();
+ })
+ .then((body) => {
+ if (!body) return;
+ setProject(body.project);
+ setOwner(body.owner);
+ })
+ .catch(() => setNotFound(true))
+ .finally(() => setLoading(false));
+ }, [projectId]);
+
+ if (loading) {
+ return (
+
+
+
+ );
+ }
+
+ if (notFound || !project) {
+ return (
+
+
+
Project not found.
+
+
+
+ );
+ }
+
+ const statusKey = project.status ?? "planning";
+ const statusClass = STATUS_COLORS[statusKey] ?? STATUS_COLORS.planning;
+ const statusLabel = STATUS_LABELS[statusKey] ?? statusKey;
+
+ const ownerSlug = owner?.username ?? owner?.id;
+ const ownerName = owner?.full_name || owner?.username || "Unknown";
+ const ownerInitials = ownerName
+ .split(" ")
+ .map((w) => w[0])
+ .join("")
+ .slice(0, 2)
+ .toUpperCase();
+
+ return (
+
+
+ {/* Header */}
+
+
+
+ {statusLabel}
+
+ {project.priority && (
+
+ {project.priority} priority
+
+ )}
+
+
{project.title}
+ {project.description && (
+
+ {project.description}
+
+ )}
+
+
+ {/* Action buttons */}
+
+
+
+
+
+ {/* Meta card */}
+
+
+
+ Details
+
+
+
+ {owner && (
+
+
+
+
+ {ownerInitials}
+
+
+
+
Owner
+ {ownerSlug ? (
+
+ {ownerName}
+
+ ) : (
+
{ownerName}
+ )}
+
+
+ )}
+
+ {project.engine && (
+
+
+
+
Engine
+
{project.engine}
+
+
+ )}
+
+ {typeof project.progress === "number" && (
+
+
+
+
Progress — {project.progress}%
+
+
+
+ )}
+
+ {(project.created_at || project.updated_at) && (
+
+
+
+ {project.created_at && (
+
+ Created {formatDate(project.created_at)}
+
+ )}
+ {project.updated_at && (
+
+ Updated {formatDate(project.updated_at)}
+
+ )}
+
+
+ )}
+
+
+
+ {/* Technologies */}
+ {project.technologies && project.technologies.length > 0 && (
+
+
+
+ Technologies
+
+
+
+
+ {project.technologies.map((tech) => (
+
+ {tech}
+
+ ))}
+
+
+
+ )}
+
+
+
+ );
+}
diff --git a/client/pages/admin/AdminAnalytics.tsx b/client/pages/admin/AdminAnalytics.tsx
index b65cf0db..cc8344bf 100644
--- a/client/pages/admin/AdminAnalytics.tsx
+++ b/client/pages/admin/AdminAnalytics.tsx
@@ -30,7 +30,7 @@ import {
ArrowDownRight,
} from "lucide-react";
import { useAuth } from "@/contexts/AuthContext";
-import { aethexToast } from "@/components/ui/aethex-toast";
+import { aethexToast } from "@/lib/aethex-toast";
interface Analytics {
users: {
diff --git a/client/pages/admin/AdminModeration.tsx b/client/pages/admin/AdminModeration.tsx
index 8f92054f..10d72785 100644
--- a/client/pages/admin/AdminModeration.tsx
+++ b/client/pages/admin/AdminModeration.tsx
@@ -43,7 +43,7 @@ import {
AlertCircle,
} from "lucide-react";
import { useAuth } from "@/contexts/AuthContext";
-import { aethexToast } from "@/components/ui/aethex-toast";
+import { aethexToast } from "@/lib/aethex-toast";
interface Report {
id: string;
diff --git a/client/pages/candidate/CandidateInterviews.tsx b/client/pages/candidate/CandidateInterviews.tsx
index d5365cc6..933337c4 100644
--- a/client/pages/candidate/CandidateInterviews.tsx
+++ b/client/pages/candidate/CandidateInterviews.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
-import { Link } from "wouter";
+import { Link } from "react-router-dom";
import Layout from "@/components/Layout";
import SEO from "@/components/SEO";
import { Button } from "@/components/ui/button";
@@ -33,7 +33,7 @@ import {
AlertCircle,
} from "lucide-react";
import { useAuth } from "@/contexts/AuthContext";
-import { aethexToast } from "@/components/ui/aethex-toast";
+import { aethexToast } from "@/lib/aethex-toast";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
interface Interview {
diff --git a/client/pages/candidate/CandidateOffers.tsx b/client/pages/candidate/CandidateOffers.tsx
index 9f41fbc3..1613df78 100644
--- a/client/pages/candidate/CandidateOffers.tsx
+++ b/client/pages/candidate/CandidateOffers.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
-import { Link } from "wouter";
+import { Link } from "react-router-dom";
import Layout from "@/components/Layout";
import SEO from "@/components/SEO";
import { Button } from "@/components/ui/button";
@@ -41,7 +41,7 @@ import {
ExternalLink,
} from "lucide-react";
import { useAuth } from "@/contexts/AuthContext";
-import { aethexToast } from "@/components/ui/aethex-toast";
+import { aethexToast } from "@/lib/aethex-toast";
interface Offer {
id: string;
diff --git a/client/pages/candidate/CandidatePortal.tsx b/client/pages/candidate/CandidatePortal.tsx
index 4814da58..6017005c 100644
--- a/client/pages/candidate/CandidatePortal.tsx
+++ b/client/pages/candidate/CandidatePortal.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
-import { Link } from "wouter";
+import { Link } from "react-router-dom";
import Layout from "@/components/Layout";
import SEO from "@/components/SEO";
import { Button } from "@/components/ui/button";
@@ -30,7 +30,7 @@ import {
TrendingUp,
} from "lucide-react";
import { useAuth } from "@/contexts/AuthContext";
-import { aethexToast } from "@/components/ui/aethex-toast";
+import { aethexToast } from "@/lib/aethex-toast";
interface ProfileData {
profile: {
diff --git a/client/pages/candidate/CandidateProfile.tsx b/client/pages/candidate/CandidateProfile.tsx
index 18872031..625d7628 100644
--- a/client/pages/candidate/CandidateProfile.tsx
+++ b/client/pages/candidate/CandidateProfile.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
-import { Link } from "wouter";
+import { Link } from "react-router-dom";
import Layout from "@/components/Layout";
import SEO from "@/components/SEO";
import { Button } from "@/components/ui/button";
@@ -38,7 +38,7 @@ import {
CheckCircle2,
} from "lucide-react";
import { useAuth } from "@/contexts/AuthContext";
-import { aethexToast } from "@/components/ui/aethex-toast";
+import { aethexToast } from "@/lib/aethex-toast";
interface WorkHistory {
company: string;
diff --git a/client/pages/dashboards/GameForgeDashboard.tsx b/client/pages/dashboards/GameForgeDashboard.tsx
index 30c81d2d..657ba3c5 100644
--- a/client/pages/dashboards/GameForgeDashboard.tsx
+++ b/client/pages/dashboards/GameForgeDashboard.tsx
@@ -1,6 +1,6 @@
import { useState, useEffect, useMemo } from "react";
import { useNavigate } from "react-router-dom";
-import Layout from "@/components/Layout";
+import GameForgeLayout from "@/components/gameforge/GameForgeLayout";
import { Button } from "@/components/ui/button";
import { useAuth } from "@/contexts/AuthContext";
import { useArmTheme } from "@/contexts/ArmThemeContext";
@@ -154,7 +154,7 @@ export default function GameForgeDashboard() {
if (!user) {
return (
-
+
@@ -169,12 +169,12 @@ export default function GameForgeDashboard() {
-
+
);
}
return (
-
+
-
+
);
}
diff --git a/client/pages/dev-platform/ApiReference.tsx b/client/pages/dev-platform/ApiReference.tsx
index 13f7e64e..52aaee73 100644
--- a/client/pages/dev-platform/ApiReference.tsx
+++ b/client/pages/dev-platform/ApiReference.tsx
@@ -1,4 +1,4 @@
-import Layout from "@/components/Layout";
+import { DevPlatformLayout } from "@/components/dev-platform/layouts/DevPlatformLayout";
import SEO from "@/components/SEO";
import { Breadcrumbs } from "@/components/dev-platform/Breadcrumbs";
import { ThreeColumnLayout } from "@/components/dev-platform/layouts/ThreeColumnLayout";
@@ -67,7 +67,7 @@ export default function ApiReference() {
);
return (
-
+
-
+
);
}
diff --git a/client/pages/dev-platform/CodeExamples.tsx b/client/pages/dev-platform/CodeExamples.tsx
index 516f3a3c..0e3ae090 100644
--- a/client/pages/dev-platform/CodeExamples.tsx
+++ b/client/pages/dev-platform/CodeExamples.tsx
@@ -1,5 +1,5 @@
import { useState } from "react";
-import Layout from "@/components/Layout";
+import { DevPlatformLayout } from "@/components/dev-platform/layouts/DevPlatformLayout";
import SEO from "@/components/SEO";
import { Breadcrumbs } from "@/components/dev-platform/Breadcrumbs";
import { ExampleCard } from "@/components/dev-platform/ExampleCard";
@@ -165,7 +165,7 @@ export default function CodeExamples() {
});
return (
-