From 8751ba26ebf7b7761b9e237f2bf3453623dd1018 Mon Sep 17 00:00:00 2001
From: polwex <polwex@sortug.com>
Date: Mon, 6 Oct 2025 10:13:39 +0700
Subject: added frontend WS connection for demonstration purposes

---
 gui/src/components/post/Loader.tsx | 148 +++++++++++++++++++++++++++++++++++++
 1 file changed, 148 insertions(+)
 create mode 100644 gui/src/components/post/Loader.tsx

(limited to 'gui/src/components/post/Loader.tsx')

diff --git a/gui/src/components/post/Loader.tsx b/gui/src/components/post/Loader.tsx
new file mode 100644
index 0000000..e45e01a
--- /dev/null
+++ b/gui/src/components/post/Loader.tsx
@@ -0,0 +1,148 @@
+import { useQuery, useQueryClient } from "@tanstack/react-query";
+import spinner from "@/assets/triangles.svg";
+import { useEffect, useRef, useState } from "react";
+import useLocalState from "@/state/state";
+import type { FullNode, PostID } from "@/types/trill";
+import type { Ship } from "@/types/urbit";
+import type { AsyncRes } from "@/types/ui";
+import { toFlat } from "@/logic/trill/helpers";
+
+type Props = {
+  host: Ship;
+  id: PostID;
+  nest?: number; // nested quotes
+  rter?: Ship;
+  rtat?: number;
+  rtid?: PostID;
+  className?: string;
+};
+function PostData(props: Props) {
+  const { api } = useLocalState((s) => ({
+    api: s.api,
+  }));
+
+  const { host, id, nest } = props;
+
+  const [enest, setEnest] = useState(nest || 0);
+  useEffect(() => {
+    if (nest) setEnest(nest);
+  }, [nest]);
+
+  return function (Component: React.ElementType) {
+    // const [showNested, setShowNested] = useState(nest <= 3);
+    const handleShowNested = (e: React.MouseEvent) => {
+      e.stopPropagation();
+      setEnest(enest! - 3);
+    };
+    const [dead, setDead] = useState(false);
+    const [denied, setDenied] = useState(false);
+    const { isLoading, isError, data, refetch } = useQuery({
+      queryKey: ["trill-thread", host, id],
+      queryFn: fetchNode,
+    });
+    const queryClient = useQueryClient();
+    const dataRef = useRef(data);
+    useEffect(() => {
+      dataRef.current = data;
+    }, [data]);
+
+    async function fetchNode(): AsyncRes<FullNode> {
+      let error = "";
+      const res = await api!.scryThread(host, id);
+      console.log("scry res", res);
+      if ("error" in res) error = res.error;
+      if ("ok" in res) return res;
+      else {
+        const res2 = await api!.peekThread(host, id);
+        return res2;
+      }
+    }
+    async function peekTheNode() {
+      // let timer;
+      // peekNode({ ship: host, id });
+      // timer = setTimeout(() => {
+      //   const gotPost = dataRef.current && "fpost" in dataRef.current;
+      //   setDead(!gotPost);
+      //   // clearTimeout(timer);
+      // }, 10_000);
+    }
+
+    // useEffect(() => {
+    //   const path = `${host}/${id}`;
+    //   if (path in peekedPosts) {
+    //     queryClient.setQueryData(["trill-thread", host, id], {
+    //       fpost: peekedPosts[path],
+    //     });
+    //   } else if (path in deniedPosts) {
+    //     setDenied(true);
+    //   }
+    // }, [peekedPosts]);
+    // useEffect(() => {
+    //   const path = `${host}/${id}`;
+    //   if (path in deniedPosts) setDenied(true);
+    // }, [deniedPosts]);
+
+    // useEffect(() => {
+    //   const l = lastThread;
+    //   if (l && l.thread == id) {
+    //     queryClient.setQueryData(["trill-thread", host, id], { fpost: l });
+    //   }
+    // }, [lastThread]);
+    function retryPeek(e: React.MouseEvent) {
+      // e.stopPropagation();
+      // setDead(false);
+      // peekTheNode();
+    }
+    if (enest > 3)
+      return (
+        <div className={props.className}>
+          <div className="lazy x-center not-found">
+            <button className="x-center" onMouseUp={handleShowNested}>
+              Load more
+            </button>
+          </div>
+        </div>
+      );
+    else
+      return data ? (
+        dead ? (
+          <div className={props.className}>
+            <div className="no-response x-center not-found">
+              <p>{host} did not respond</p>
+              <button className="x-center" onMouseUp={retryPeek}>
+                Try again
+              </button>
+            </div>
+          </div>
+        ) : denied ? (
+          <div className={props.className}>
+            <p className="x-center not-found">
+              {host} denied you access to this post
+            </p>
+          </div>
+        ) : "error" in data ? (
+          <div className={props.className}>
+            <p className="x-center not-found">Post not found</p>
+            <p className="x-center not-found">{data.error}</p>
+          </div>
+        ) : (
+          <Component
+            data={toFlat(data.ok)}
+            refetch={refetch}
+            {...props}
+            nest={enest}
+          />
+        )
+      ) : // no data
+      isLoading || isError ? (
+        <div className={props.className}>
+          <img className="x-center post-spinner" src={spinner} alt="" />
+        </div>
+      ) : (
+        <div className={props.className}>
+          <p>...</p>
+        </div>
+      );
+  };
+}
+export default PostData;
-- 
cgit v1.2.3

