From a49c5d8bccfef11975005012493bc578db531ce6 Mon Sep 17 00:00:00 2001 From: Xory Date: Sat, 7 Feb 2026 16:12:58 +0200 Subject: [PATCH] change: everything --- app/components/post.tsx | 38 +- app/root.tsx | 7 +- app/routes.ts | 3 +- app/routes/api.posts.$postId.ts | 16 + app/routes/create.tsx | 108 ++--- app/routes/home.tsx | 72 +-- app/routes/login.tsx | 210 +++++--- app/routes/view.tsx | 2 +- app/util/mobile-opt.tsx | 26 + package.json | 1 + pnpm-lock.yaml | 837 +++++++++++++++++++++++++++++++- public/favicon.ico | Bin 15086 -> 0 bytes tsconfig.cloudflare.json | 1 - vite.config.ts | 2 + wrangler.jsonc | 13 +- 15 files changed, 1107 insertions(+), 229 deletions(-) create mode 100644 app/routes/api.posts.$postId.ts create mode 100644 app/util/mobile-opt.tsx delete mode 100644 public/favicon.ico diff --git a/app/components/post.tsx b/app/components/post.tsx index f9f8d6b..c0d7295 100644 --- a/app/components/post.tsx +++ b/app/components/post.tsx @@ -23,36 +23,36 @@ export interface PostProps { postId: number; } - export default function Post({ postId }: PostProps) { const [postContent, setPostContent] = useState(); const [isLoading, setIsLoading] = useState(true); useEffect(() => { const fetchPost = async () => { - const response = await fetch(`http://localhost:8787/posts/${postId}/view`); - const jsonContent: Array = await response.json(); + try { + // CHANGED: Fetch from your internal resource route + // This triggers the 'loader' we created in step 2 + const response = await fetch(`/api/posts/${postId}`); + + if (!response.ok) throw new Error("Failed to fetch"); - let newPostContent: PostContent = jsonContent[0] as PostContent; + const jsonContent: Array = await response.json(); + let newPostContent: PostContent = jsonContent[0] as PostContent; - if (newPostContent) { - setPostContent(newPostContent); + if (newPostContent) { + setPostContent(newPostContent); + } + } catch (error) { + console.error("Error fetching post:", error); + } finally { setIsLoading(false); } }; fetchPost(); - }, []); + }, [postId]); // Added postId to dependency array - if (isLoading) { - return
Loading...
; - } + if (isLoading) return
Loading...
; + if (!postContent) return

Failed to load!

; - if (!postContent) { - return

Failed to load!

; - } - - - return ( - - ) -} + return ; +} \ No newline at end of file diff --git a/app/root.tsx b/app/root.tsx index 5fb4ad4..5109c51 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -30,7 +30,12 @@ export function Layout({ children }: { children: React.ReactNode }) { - + anum + + + + + diff --git a/app/routes.ts b/app/routes.ts index d33cfab..fb08231 100644 --- a/app/routes.ts +++ b/app/routes.ts @@ -4,5 +4,6 @@ export default [ index("routes/home.tsx"), route("login", "routes/login.tsx"), route("create", "routes/create.tsx"), - route("view", "routes/view.tsx") + route("view", "routes/view.tsx"), + route("api/posts/:postId", "routes/api.posts.$postId.ts") ] satisfies RouteConfig; diff --git a/app/routes/api.posts.$postId.ts b/app/routes/api.posts.$postId.ts new file mode 100644 index 0000000..0604a62 --- /dev/null +++ b/app/routes/api.posts.$postId.ts @@ -0,0 +1,16 @@ +import { type LoaderFunctionArgs } from "react-router"; + +export async function loader({ params, context }: LoaderFunctionArgs) { + const { postId } = params; + + // 'context.cloudflare.env' contains your bindings + const { API } = context.cloudflare.env; + + // Use the Service Binding to talk to the backend + // This is much faster than a standard fetch over the internet + const response = await API.fetch( + `http://internal/posts/${postId}/view` + ); + + return response; +} \ No newline at end of file diff --git a/app/routes/create.tsx b/app/routes/create.tsx index eb11e4d..9eff2f1 100644 --- a/app/routes/create.tsx +++ b/app/routes/create.tsx @@ -1,92 +1,90 @@ import { useState } from "react"; -import { useNavigate } from "react-router"; +import { Form, useActionData, useNavigate } from "react-router"; import { useLocation } from "react-router"; +import { redirect, type ActionFunctionArgs } from "react-router"; + + +// server-side action so we don't have to use clearnet for front-backend comms +// praise cloudflare +export async function action({ request, context }: ActionFunctionArgs) { + const formData = await request.formData(); + const env = context.cloudflare.env as { API: Fetcher }; + + const postTitle = formData.get("title") as string; + const postContent = formData.get("content") as string; + const parentId = formData.get("parentId") as string; + + // internal url uses ternary operator + const path = parentId + ? `/posts/${parentId}/reply` + : "/posts/add"; + + const response = await env.API.fetch(new Request(`http://internal${path}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + // forward cookies or auth won't work + "Cookie": request.headers.get("Cookie") || "", + }, + body: JSON.stringify({ + title: postTitle, + content: postContent, + }), + })); + + if (!response.ok) { + const error = await response.text(); + return { error: `Failed to create post: ${response.status} - ${error}` }; + } + + return redirect("/"); +} export default function CreatePostPage() { const location = useLocation(); const stateParentId = location.state?.parentId; - const [postTitle, setPostTitle] = useState(""); - const [postContent, setPostContent] = useState(""); const [parentId, setParentId] = useState(stateParentId || ""); - const navigate = useNavigate(); console.log(stateParentId); console.log(parentId); - async function createPost() { - if (parentId) { - const response = await fetch(`http://localhost:8787/posts/${parentId}/reply`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - title: postTitle, - content: postContent // god bless HTTPS - }), - credentials: 'include' - }); - if (!response.ok) { - throw new Error(`Got ${response.status} when trying to log in.`) - } - navigate("/"); - } else { - const response = await fetch("http://localhost:8787/posts/add", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - title: postTitle, - content: postContent // god bless HTTPS - }), - credentials: 'include' - }); - if (!response.ok) { - throw new Error(`Got ${response.status} when trying to log in.`) - } - navigate("/"); - } - } - - return ( -
-

Create Post

+
+

Create Post

-
-
+ +
setPostTitle(e.target.value)} + required />