diff --git a/client/components/admin/AdminChangelogDigest.tsx b/client/components/admin/AdminChangelogDigest.tsx index 1315ba1d..315aab9d 100644 --- a/client/components/admin/AdminChangelogDigest.tsx +++ b/client/components/admin/AdminChangelogDigest.tsx @@ -1,4 +1,10 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { formatDistanceToNow } from "date-fns"; @@ -84,8 +90,13 @@ export default function AdminChangelogDigest({ Version {entry.version} • {entry.author}

- - {formatDistanceToNow(new Date(entry.date), { addSuffix: true })} + + {formatDistanceToNow(new Date(entry.date), { + addSuffix: true, + })}

@@ -100,10 +111,14 @@ export default function AdminChangelogDigest({ key={`${entry.id}-change-${idx}`} className="flex items-start gap-2" > - + - {change.type.charAt(0).toUpperCase() + change.type.slice(1)}: + {change.type.charAt(0).toUpperCase() + + change.type.slice(1)} + : {" "} {change.description} diff --git a/client/components/admin/AdminStatusOverview.tsx b/client/components/admin/AdminStatusOverview.tsx index a846fbc4..7ed8f604 100644 --- a/client/components/admin/AdminStatusOverview.tsx +++ b/client/components/admin/AdminStatusOverview.tsx @@ -1,4 +1,10 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import type { LucideIcon } from "lucide-react"; @@ -25,8 +31,7 @@ interface AdminStatusOverviewProps { } const statusBadgeClass: Record = { - operational: - "border-emerald-500/30 bg-emerald-500/10 text-emerald-200", + operational: "border-emerald-500/30 bg-emerald-500/10 text-emerald-200", degraded: "border-yellow-500/30 bg-yellow-500/10 text-yellow-200", outage: "border-red-500/40 bg-red-500/10 text-red-200", }; @@ -71,7 +76,9 @@ export default function AdminStatusOverview({

-
+
@@ -113,9 +120,7 @@ export default function AdminStatusOverview({ Healthy services

- {services.length - ? `${healthyServices}/${services.length}` - : "—"} + {services.length ? `${healthyServices}/${services.length}` : "—"}

@@ -132,13 +137,18 @@ export default function AdminStatusOverview({
-

{service.name}

+

+ {service.name} +

{service.responseTime} ms • {service.uptime} uptime

- + {service.status} diff --git a/client/components/blog/BlogCategoryChips.tsx b/client/components/blog/BlogCategoryChips.tsx index c92d1b4b..7bd259e1 100644 --- a/client/components/blog/BlogCategoryChips.tsx +++ b/client/components/blog/BlogCategoryChips.tsx @@ -7,7 +7,11 @@ interface BlogCategoryChipsProps { onSelect: (id: string) => void; } -const BlogCategoryChips = ({ categories, selected, onSelect }: BlogCategoryChipsProps) => { +const BlogCategoryChips = ({ + categories, + selected, + onSelect, +}: BlogCategoryChipsProps) => { if (!categories.length) return null; return ( diff --git a/client/components/blog/BlogHero.tsx b/client/components/blog/BlogHero.tsx index 4292d1f7..437ccd7d 100644 --- a/client/components/blog/BlogHero.tsx +++ b/client/components/blog/BlogHero.tsx @@ -14,7 +14,13 @@ interface BlogHeroProps { onViewAll?: () => void; } -const BlogHero = ({ featured, totalCount, search, onSearchChange, onViewAll }: BlogHeroProps) => { +const BlogHero = ({ + featured, + totalCount, + search, + onSearchChange, + onViewAll, +}: BlogHeroProps) => { return (
@@ -32,7 +38,9 @@ const BlogHero = ({ featured, totalCount, search, onSearchChange, onViewAll }: B Ideas, updates, and behind-the-scenes craft from the AeThex team

- Explore engineering deep dives, platform updates, community spotlights, and changelog summaries. We publish what we learn building AeThex across games, cloud, and creator ecosystems. + Explore engineering deep dives, platform updates, community + spotlights, and changelog summaries. We publish what we learn + building AeThex across games, cloud, and creator ecosystems.

@@ -75,7 +83,9 @@ const BlogHero = ({ featured, totalCount, search, onSearchChange, onViewAll }: B > {featured.title} -

{featured.excerpt}

+

+ {featured.excerpt} +

{featured.author || "AeThex Team"} @@ -93,13 +103,16 @@ const BlogHero = ({ featured, totalCount, search, onSearchChange, onViewAll }: B
) : (

- We are preparing our latest feature article. Check back soon for fresh insights straight from the AeThex ship room. + We are preparing our latest feature article. Check back soon + for fresh insights straight from the AeThex ship room.

diff --git a/client/components/blog/BlogNewsletterSection.tsx b/client/components/blog/BlogNewsletterSection.tsx index 4e9ac515..38b81bd4 100644 --- a/client/components/blog/BlogNewsletterSection.tsx +++ b/client/components/blog/BlogNewsletterSection.tsx @@ -15,9 +15,13 @@ const BlogNewsletterSection = () => {
-

Stay in the AeThex signal

+

+ Stay in the AeThex signal +

- Subscribe for release notes, engineering write-ups, and community highlights. Expect one curated update every week—only the essentials. + Subscribe for release notes, engineering write-ups, and + community highlights. Expect one curated update every + week—only the essentials.

@@ -27,13 +31,17 @@ const BlogNewsletterSection = () => { placeholder="your@email.com" className="h-12 flex-1 rounded-full border-border/50 bg-background/70 px-6 text-sm" /> -

- By subscribing you agree to receive emails from AeThex. Unsubscribe anytime in a single click. + By subscribing you agree to receive emails from AeThex. + Unsubscribe anytime in a single click.

diff --git a/client/components/blog/BlogPostGrid.tsx b/client/components/blog/BlogPostGrid.tsx index 186319f5..17cbb0dc 100644 --- a/client/components/blog/BlogPostGrid.tsx +++ b/client/components/blog/BlogPostGrid.tsx @@ -11,7 +11,11 @@ interface BlogPostGridProps { emptyState?: React.ReactNode; } -const BlogPostGrid = ({ posts, placeholderImage = "/placeholder.svg", emptyState }: BlogPostGridProps) => { +const BlogPostGrid = ({ + posts, + placeholderImage = "/placeholder.svg", + emptyState, +}: BlogPostGridProps) => { if (!posts.length) { return (
@@ -38,25 +42,39 @@ const BlogPostGrid = ({ posts, placeholderImage = "/placeholder.svg", emptyState
) : (
- Placeholder + Placeholder
)}
- + {post.category || "General"} {post.readTime ? ( - {post.readTime} + + {post.readTime} + ) : null}
- + {post.title} -

{post.excerpt}

+

+ {post.excerpt} +

@@ -81,7 +99,10 @@ const BlogPostGrid = ({ posts, placeholderImage = "/placeholder.svg", emptyState {post.comments?.toLocaleString() ?? 0}
@@ -235,9 +260,15 @@ const Blog = () => { {insight.icon}
-

{insight.label}

-

{insight.value}

-

{insight.helper}

+

+ {insight.label} +

+

+ {insight.value} +

+

+ {insight.helper} +

@@ -249,10 +280,18 @@ const Blog = () => {
-

Latest updates

-

Fresh from the AeThex ship room

+

+ Latest updates +

+

+ Fresh from the AeThex ship room +

-
diff --git a/client/pages/Changelog.tsx b/client/pages/Changelog.tsx index 9c65f205..d6c1d66e 100644 --- a/client/pages/Changelog.tsx +++ b/client/pages/Changelog.tsx @@ -1,6 +1,12 @@ import { useState } from "react"; import Layout from "@/components/Layout"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -34,7 +40,7 @@ interface ChangelogEntry { id: string; version: string; date: string; - type: 'major' | 'minor' | 'patch'; + type: "major" | "minor" | "patch"; category: string; title: string; description: string; @@ -44,9 +50,9 @@ interface ChangelogEntry { } interface ChangelogItem { - type: 'added' | 'improved' | 'fixed' | 'removed' | 'security'; + type: "added" | "improved" | "fixed" | "removed" | "security"; description: string; - impact: 'high' | 'medium' | 'low'; + impact: "high" | "medium" | "low"; } export const changelogEntries: ChangelogEntry[] = [ @@ -57,126 +63,162 @@ export const changelogEntries: ChangelogEntry[] = [ type: "major", category: "Platform Enhancement", title: "Major Platform Improvements & New Features", - description: "Comprehensive platform upgrade with new dashboard features, improved user experience, and enhanced system monitoring capabilities.", + description: + "Comprehensive platform upgrade with new dashboard features, improved user experience, and enhanced system monitoring capabilities.", author: "AeThex Development Team", pullRequest: "#121e8c26", changes: [ { type: "added", - description: "New comprehensive Profile system with overseer dashboard and cross-site communication monitoring", - impact: "high" - }, - { - type: "added", - description: "System Status page with real-time monitoring of all AeThex services and infrastructure", - impact: "high" + description: + "New comprehensive Profile system with overseer dashboard and cross-site communication monitoring", + impact: "high", }, { type: "added", - description: "Comprehensive Tutorials library with categorized learning content and filtering capabilities", - impact: "medium" + description: + "System Status page with real-time monitoring of all AeThex services and infrastructure", + impact: "high", }, { type: "added", - description: "Nested Documentation routing system with improved navigation and breadcrumbs", - impact: "medium" + description: + "Comprehensive Tutorials library with categorized learning content and filtering capabilities", + impact: "medium", }, { type: "added", - description: "Documentation-specific tutorials section with interactive content types", - impact: "medium" + description: + "Nested Documentation routing system with improved navigation and breadcrumbs", + impact: "medium", }, { type: "added", - description: "Login access options on onboarding page to prevent duplicate account creation", - impact: "medium" + description: + "Documentation-specific tutorials section with interactive content types", + impact: "medium", + }, + { + type: "added", + description: + "Login access options on onboarding page to prevent duplicate account creation", + impact: "medium", }, { type: "improved", - description: "Enhanced navigation system with user-specific menu items when authenticated", - impact: "medium" + description: + "Enhanced navigation system with user-specific menu items when authenticated", + impact: "medium", }, { type: "improved", - description: "Dashboard user interface with proper profile data integration and XP progression", - impact: "medium" + description: + "Dashboard user interface with proper profile data integration and XP progression", + impact: "medium", }, { type: "improved", - description: "Authentication flow with better error handling and redirect logic", - impact: "high" + description: + "Authentication flow with better error handling and redirect logic", + impact: "high", }, { type: "fixed", - description: "Resolved Dashboard infinite loading screen issue when accessing without authentication", - impact: "high" + description: + "Resolved Dashboard infinite loading screen issue when accessing without authentication", + impact: "high", }, { type: "fixed", - description: "Fixed toast notification bouncing animations that were causing UI disruption", - impact: "medium" + description: + "Fixed toast notification bouncing animations that were causing UI disruption", + impact: "medium", }, { type: "fixed", - description: "Corrected database adapter table name mismatches and TypeScript compilation errors", - impact: "high" + description: + "Corrected database adapter table name mismatches and TypeScript compilation errors", + impact: "high", }, { type: "fixed", - description: "Resolved DNS configuration issues for custom domain deployment", - impact: "medium" + description: + "Resolved DNS configuration issues for custom domain deployment", + impact: "medium", }, { type: "fixed", - description: "Fixed user profile property access issues throughout the application", - impact: "medium" + description: + "Fixed user profile property access issues throughout the application", + impact: "medium", }, { type: "security", - description: "Enhanced authentication redirect security with proper session handling", - impact: "high" - } - ] - } + description: + "Enhanced authentication redirect security with proper session handling", + impact: "high", + }, + ], + }, ]; const getTypeIcon = (type: string) => { switch (type) { - case 'added': return ; - case 'improved': return ; - case 'fixed': return ; - case 'removed': return ; - case 'security': return ; - default: return ; + case "added": + return ; + case "improved": + return ; + case "fixed": + return ; + case "removed": + return ; + case "security": + return ; + default: + return ; } }; const getTypeColor = (type: string) => { switch (type) { - case 'added': return 'bg-green-500'; - case 'improved': return 'bg-blue-500'; - case 'fixed': return 'bg-orange-500'; - case 'removed': return 'bg-red-500'; - case 'security': return 'bg-purple-500'; - default: return 'bg-gray-500'; + case "added": + return "bg-green-500"; + case "improved": + return "bg-blue-500"; + case "fixed": + return "bg-orange-500"; + case "removed": + return "bg-red-500"; + case "security": + return "bg-purple-500"; + default: + return "bg-gray-500"; } }; const getVersionBadgeColor = (type: string) => { switch (type) { - case 'major': return 'bg-purple-600'; - case 'minor': return 'bg-blue-600'; - case 'patch': return 'bg-green-600'; - default: return 'bg-gray-600'; + case "major": + return "bg-purple-600"; + case "minor": + return "bg-blue-600"; + case "patch": + return "bg-green-600"; + default: + return "bg-gray-600"; } }; const getImpactColor = (impact: string) => { switch (impact) { - case 'high': return 'text-red-400'; - case 'medium': return 'text-yellow-400'; - case 'low': return 'text-green-400'; - default: return 'text-gray-400'; + case "high": + return "text-red-400"; + case "medium": + return "text-yellow-400"; + case "low": + return "text-green-400"; + default: + return "text-gray-400"; } }; @@ -185,20 +227,28 @@ export default function Changelog() { const [selectedType, setSelectedType] = useState("all"); const [selectedCategory, setSelectedCategory] = useState("all"); - const filteredEntries = changelogEntries.filter(entry => { - const matchesSearch = entry.title.toLowerCase().includes(searchTerm.toLowerCase()) || - entry.description.toLowerCase().includes(searchTerm.toLowerCase()) || - entry.changes.some(change => - change.description.toLowerCase().includes(searchTerm.toLowerCase()) - ); + const filteredEntries = changelogEntries.filter((entry) => { + const matchesSearch = + entry.title.toLowerCase().includes(searchTerm.toLowerCase()) || + entry.description.toLowerCase().includes(searchTerm.toLowerCase()) || + entry.changes.some((change) => + change.description.toLowerCase().includes(searchTerm.toLowerCase()), + ); const matchesType = selectedType === "all" || entry.type === selectedType; - const matchesCategory = selectedCategory === "all" || - entry.category.toLowerCase().replace(/\s+/g, '-') === selectedCategory; - + const matchesCategory = + selectedCategory === "all" || + entry.category.toLowerCase().replace(/\s+/g, "-") === selectedCategory; + return matchesSearch && matchesType && matchesCategory; }); - const categories = ["all", "platform-enhancement", "security", "performance", "ui-ux"]; + const categories = [ + "all", + "platform-enhancement", + "security", + "performance", + "ui-ux", + ]; const types = ["all", "major", "minor", "patch"]; return ( @@ -213,11 +263,15 @@ export default function Changelog() { AeThex Changelog

- Track the latest updates, improvements, and fixes to the AeThex platform + Track the latest updates, improvements, and fixes to the + AeThex platform

- @@ -227,7 +281,7 @@ export default function Changelog() {
- + {/* Stats */}
@@ -235,21 +289,27 @@ export default function Changelog() {

Total Releases

-

{changelogEntries.length}

+

+ {changelogEntries.length} +

- +

New Features

- {changelogEntries.reduce((acc, entry) => - acc + entry.changes.filter(c => c.type === 'added').length, 0 + {changelogEntries.reduce( + (acc, entry) => + acc + + entry.changes.filter((c) => c.type === "added") + .length, + 0, )}

@@ -257,15 +317,19 @@ export default function Changelog() {
- +

Bug Fixes

- {changelogEntries.reduce((acc, entry) => - acc + entry.changes.filter(c => c.type === 'fixed').length, 0 + {changelogEntries.reduce( + (acc, entry) => + acc + + entry.changes.filter((c) => c.type === "fixed") + .length, + 0, )}

@@ -273,15 +337,19 @@ export default function Changelog() {
- +

Improvements

- {changelogEntries.reduce((acc, entry) => - acc + entry.changes.filter(c => c.type === 'improved').length, 0 + {changelogEntries.reduce( + (acc, entry) => + acc + + entry.changes.filter((c) => c.type === "improved") + .length, + 0, )}

@@ -310,9 +378,11 @@ export default function Changelog() { onChange={(e) => setSelectedType(e.target.value)} className="bg-slate-800/50 border-slate-600 text-white rounded-md px-3 py-2" > - {types.map(type => ( + {types.map((type) => ( ))} @@ -321,13 +391,17 @@ export default function Changelog() { onChange={(e) => setSelectedCategory(e.target.value)} className="bg-slate-800/50 border-slate-600 text-white rounded-md px-3 py-2" > - {categories.map(category => ( + {categories.map((category) => ( ))} @@ -338,11 +412,16 @@ export default function Changelog() { {/* Changelog Entries */}
{filteredEntries.map((entry, index) => ( - +
- + v{entry.version} @@ -350,68 +429,83 @@ export default function Changelog() {
- {new Date(entry.date).toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric' + {new Date(entry.date).toLocaleDateString("en-US", { + year: "numeric", + month: "long", + day: "numeric", })}
{entry.pullRequest && ( - )}
- + {entry.title} {entry.description} - +
By {entry.author}
- +
{/* Group changes by type */} - {['added', 'improved', 'fixed', 'security', 'removed'].map(changeType => { - const changesOfType = entry.changes.filter(change => change.type === changeType); - if (changesOfType.length === 0) return null; - - return ( -
-
- {getTypeIcon(changeType)} -

- {changeType} ({changesOfType.length}) -

+ {["added", "improved", "fixed", "security", "removed"].map( + (changeType) => { + const changesOfType = entry.changes.filter( + (change) => change.type === changeType, + ); + if (changesOfType.length === 0) return null; + + return ( +
+
+ {getTypeIcon(changeType)} +

+ {changeType} ({changesOfType.length}) +

+
+
    + {changesOfType.map((change, changeIndex) => ( +
  • +
    +
    +

    + {change.description} +

    + + {change.impact} impact + +
    +
  • + ))} +
-
    - {changesOfType.map((change, changeIndex) => ( -
  • -
    -
    -

    {change.description}

    - - {change.impact} impact - -
    -
  • - ))} -
-
- ); - })} + ); + }, + )}
@@ -426,7 +520,8 @@ export default function Changelog() { No changelog entries found

- Try adjusting your search terms or filters to find what you're looking for. + Try adjusting your search terms or filters to find what you're + looking for.

@@ -440,10 +535,14 @@ export default function Changelog() { Stay Updated

- Follow our development progress and get notified about new releases + Follow our development progress and get notified about new + releases

- diff --git a/client/pages/Login.tsx b/client/pages/Login.tsx index 8f982c31..d19e63cc 100644 --- a/client/pages/Login.tsx +++ b/client/pages/Login.tsx @@ -35,7 +35,9 @@ export default function Login() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [fullName, setFullName] = useState(""); - const [manualVerificationLink, setManualVerificationLink] = useState(null); + const [manualVerificationLink, setManualVerificationLink] = useState< + string | null + >(null); const navigate = useNavigate(); const { signIn, signUp, signInWithOAuth, user, loading, profileComplete } = useAuth(); @@ -99,7 +101,8 @@ export default function Login() { console.error("Authentication error:", error); toastError({ title: "Authentication failed", - description: error?.message || "Something went wrong. Please try again.", + description: + error?.message || "Something went wrong. Please try again.", }); } finally { setIsLoading(false); @@ -203,7 +206,13 @@ export default function Login() { size="sm" variant="outline" className="mt-3 border-aethex-400/40" - onClick={() => window.open(manualVerificationLink, "_blank", "noopener")} + onClick={() => + window.open( + manualVerificationLink, + "_blank", + "noopener", + ) + } > Open verification link diff --git a/server/email.ts b/server/email.ts index c802a802..ceb8d0d7 100644 --- a/server/email.ts +++ b/server/email.ts @@ -1,8 +1,10 @@ import { Resend } from "resend"; const resendApiKey = process.env.RESEND_API_KEY; -const defaultFromAddress = process.env.RESEND_FROM_EMAIL ?? "AeThex OS "; -const verifySupportEmail = process.env.VERIFY_SUPPORT_EMAIL ?? "support@aethex.biz"; +const defaultFromAddress = + process.env.RESEND_FROM_EMAIL ?? "AeThex OS "; +const verifySupportEmail = + process.env.VERIFY_SUPPORT_EMAIL ?? "support@aethex.biz"; const resendClient = resendApiKey ? new Resend(resendApiKey) : null; @@ -42,7 +44,9 @@ export const emailService = {
`; - const text = [`Welcome to AeThex, ${safeName}!`, "", + const text = [ + `Welcome to AeThex, ${safeName}!`, + "", "Use the link below to verify your account:", verificationUrl, "",