eny.space Landingpage
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(dashboard): reduce placeholder and mock data

+79 -34
+1 -1
app/api/pds/atproto/helpers.ts
··· 99 99 } 100 100 101 101 export function getPdsBaseUrlFromService(service: any): string { 102 - const raw = service?.encrypted_config?.hostname as string | undefined; 102 + const raw = (service?.hostname || service?.encrypted_config?.hostname) as string | undefined; 103 103 if (!raw) { 104 104 throw new Error("Missing PDS host"); 105 105 }
+18 -13
app/dashboard/atproto-test-client.tsx
··· 4 4 import { Heading } from "@/components/heading"; 5 5 import { Paragraph } from "@/components/paragraph"; 6 6 import { Button } from "@/actions/components/ui/button"; 7 + import { isPdsReady as checkPdsReady, pdsStateLabel } from "@/lib/pds-state"; 7 8 8 9 type ServiceResponse = { 10 + hostname?: string; 9 11 encrypted_config?: { 10 12 hostname?: string; 11 13 }; ··· 44 46 () => (handlePrefix && pdsBareHost ? `${handlePrefix}.${pdsBareHost}` : ""), 45 47 [handlePrefix, pdsBareHost], 46 48 ); 47 - const pdsStateNum = useMemo(() => { 48 - if (pdsState === null) return null; 49 - const n = typeof pdsState === "number" ? pdsState : Number(pdsState); 50 - return Number.isFinite(n) ? n : null; 51 - }, [pdsState]); 52 - const isPdsReady = pdsStateNum !== null && pdsStateNum >= 3; 49 + const pdsReady = checkPdsReady(pdsState); 53 50 const createAccountDisabled = 54 - loading || !inviteCode || !handlePrefix || !newPassword || !isPdsReady; 51 + loading || !inviteCode || !handlePrefix || !newPassword || !pdsReady; 55 52 const createSessionDisabled = 56 - loading || !handlePrefix || !newPassword || !isPdsReady; 53 + loading || !handlePrefix || !newPassword || !pdsReady; 57 54 58 55 useEffect(() => { 59 56 const load = async () => { ··· 61 58 const res = await fetch("/api/pds/service", { method: "GET" }); 62 59 if (!res.ok) throw new Error(`Failed to load service (${res.status})`); 63 60 const data = (await res.json()) as ServiceResponse; 64 - const host = data?.encrypted_config?.hostname || ""; 61 + console.log("[AtprotoTestClient] service response:", data); 62 + const host = data?.hostname || data?.encrypted_config?.hostname || ""; 63 + if (!host) console.warn("[AtprotoTestClient] hostname is empty — buttons will be disabled"); 65 64 setPdsHost(host); 66 65 setPdsState(data?.state ?? null); 67 66 ··· 71 70 setSessionIdentifier(`user1.${bare}`); 72 71 } 73 72 } catch (e) { 73 + console.error("[AtprotoTestClient] fetch failed:", e); 74 74 setError(e instanceof Error ? e.message : "Unknown error"); 75 75 } 76 76 }; ··· 171 171 <Paragraph className="text-sm text-white/70"> 172 172 PDS endpoint:{" "} 173 173 <a 174 - href={pdsHost} 174 + href={`https://pdsls.dev/${pdsBareHost}`} 175 175 target="_blank" 176 176 rel="noreferrer" 177 177 className="font-mono text-white underline underline-offset-2 hover:text-white/80" ··· 183 183 <Paragraph className="text-sm text-white/70">Loading PDS endpoint…</Paragraph> 184 184 )} 185 185 186 - {pdsStateNum !== null && !isPdsReady && ( 186 + {pdsState !== null && !pdsReady && ( 187 187 <Paragraph className="text-sm text-amber-100/90"> 188 - PDS not ready yet (state={pdsStateNum}). Waiting for provisioning to finish. 188 + PDS not ready yet ({pdsStateLabel(pdsState)}). Waiting for provisioning to finish. 189 + </Paragraph> 190 + )} 191 + {pdsReady && pdsState !== null && Number(pdsState) === 2 && ( 192 + <Paragraph className="text-sm text-sky-200/90"> 193 + PDS is awaiting its first user — create an invite code and account below to complete setup. 189 194 </Paragraph> 190 195 )} 191 196 ··· 193 198 <div className="flex flex-wrap gap-2"> 194 199 <Button 195 200 onClick={createInvite} 196 - disabled={loading || !pdsBareHost || !isPdsReady} 201 + disabled={loading || !pdsBareHost || !pdsReady} 197 202 className="rounded-full" 198 203 > 199 204 {loading ? "Working..." : "Create invite"}
+36 -19
app/dashboard/page.tsx
··· 15 15 import { CollapsibleSection } from "./collapsible-section"; 16 16 import { prelaunch } from "@/lib/prelaunch"; 17 17 import { getPriceIdForPlan } from "@/lib/stripe-plans"; 18 + import { getPdsServiceForCurrentUser } from "../api/pds/atproto/helpers"; 19 + import { pdsStateLabel } from "@/lib/pds-state"; 18 20 19 21 type DashboardPageProps = { 20 22 searchParams?: Promise<{ ··· 43 45 redirect("/welcome"); 44 46 } 45 47 46 - const pdsStatus = subscribed ? "active" : "provisioning"; 47 - const pdsHostname = 48 - user.email?.split("@")[0]?.toLowerCase().replace(/[^a-z0-9-]/g, "-") + 49 - ".eny.space" || "pending.eny.space"; 50 - const pdsDashboardUrl = `https://${pdsHostname}`; 48 + let pdsHostname: string | null = null; 49 + let pdsStatus = subscribed ? "active" : "provisioning"; 50 + 51 + try { 52 + const { service } = await getPdsServiceForCurrentUser(); 53 + pdsHostname = service?.hostname || service?.encrypted_config?.hostname || null; 54 + if (service?.state !== undefined && service.state !== null) { 55 + pdsStatus = pdsStateLabel(service.state); 56 + } 57 + } catch { 58 + // Service not provisioned yet or API unavailable — fall back to subscription-derived status 59 + } 60 + 61 + const pdsDashboardUrl = pdsHostname ? `https://pdsls.dev/${pdsHostname}` : null; 51 62 52 63 return ( 53 64 <main className="mx-auto flex w-full max-w-7xl flex-col gap-4 px-4 py-6 sm:px-6"> ··· 69 80 </div> 70 81 <div className="space-y-1"> 71 82 <Paragraph className="text-sm font-medium text-white/60">Hostname</Paragraph> 72 - <a 73 - href={pdsDashboardUrl} 74 - target="_blank" 75 - rel="noreferrer" 76 - className="text-base font-semibold text-primary underline underline-offset-2" 77 - > 78 - {pdsHostname} 79 - </a> 83 + {pdsDashboardUrl ? ( 84 + <a 85 + href={pdsDashboardUrl} 86 + target="_blank" 87 + rel="noreferrer" 88 + className="text-base font-semibold text-primary underline underline-offset-2" 89 + > 90 + {pdsHostname} 91 + </a> 92 + ) : ( 93 + <Paragraph className="text-base font-semibold text-white/50">Pending</Paragraph> 94 + )} 80 95 </div> 81 96 </div> 82 97 <div className="flex flex-wrap gap-3 pt-1"> 83 - <ButtonLink 84 - href={pdsDashboardUrl} 85 - className="border border-white/80 bg-transparent uppercase tracking-wide text-white hover:bg-white/10 hover:border-white focus-visible:ring-white/50" 86 - > 87 - Open dashboard 88 - </ButtonLink> 98 + {pdsDashboardUrl && ( 99 + <ButtonLink 100 + href={pdsDashboardUrl} 101 + className="border border-white/80 bg-transparent uppercase tracking-wide text-white hover:bg-white/10 hover:border-white focus-visible:ring-white/50" 102 + > 103 + Open dashboard 104 + </ButtonLink> 105 + )} 89 106 </div> 90 107 </CardContent> 91 108 </Card>
+4 -1
app/dashboard/service-details-client.tsx
··· 3 3 import { useEffect, useState } from "react"; 4 4 import { Heading } from "@/components/heading"; 5 5 import { Paragraph } from "@/components/paragraph"; 6 + import { pdsStateLabel } from "@/lib/pds-state"; 6 7 7 8 type ServiceStats = { 8 9 cpuUsagePercent?: number; ··· 86 87 } 87 88 88 89 const data = (await res.json()) as ServiceResponse; 90 + console.log("[ServiceDetailsClient] response:", data); 91 + console.log("[ServiceDetailsClient] stats:", data.stats ?? "MISSING — stats section will not render"); 89 92 setService(data); 90 93 } catch (err) { 91 94 console.error("Failed to load service details", err); ··· 216 219 State 217 220 </Paragraph> 218 221 <Paragraph className="text-sm font-mono text-white"> 219 - {String(service.state)} 222 + {pdsStateLabel(service.state)} 220 223 </Paragraph> 221 224 </div> 222 225 )}
+20
lib/pds-state.ts
··· 1 + const PDS_STATE_LABELS: Record<number, string> = { 2 + 0: "Pending", 3 + 1: "Deploying", 4 + 2: "Awaiting first user", 5 + 3: "Running", 6 + 4: "Error", 7 + }; 8 + 9 + export function pdsStateLabel(state: number | string | null | undefined): string { 10 + if (state === null || state === undefined) return "Unknown"; 11 + const n = typeof state === "number" ? state : Number(state); 12 + if (!Number.isFinite(n)) return String(state); 13 + return PDS_STATE_LABELS[n] ?? `Unknown (state ${n})`; 14 + } 15 + 16 + export function isPdsReady(state: number | string | null | undefined): boolean { 17 + if (state === null || state === undefined) return false; 18 + const n = typeof state === "number" ? state : Number(state); 19 + return Number.isFinite(n) && n >= 2; 20 + }