summaryrefslogtreecommitdiff
path: root/jb-ui/src/JBApp.tsx
diff options
context:
space:
mode:
authorMax Nanis2026-02-18 20:42:03 -0500
committerMax Nanis2026-02-18 20:42:03 -0500
commit3eaa56f0306ead818f64c3d99fc6d230d9b970a4 (patch)
tree9fecc2f1456e6321572e0e65f57106916df173e2 /jb-ui/src/JBApp.tsx
downloadamt-jb-3eaa56f0306ead818f64c3d99fc6d230d9b970a4.tar.gz
amt-jb-3eaa56f0306ead818f64c3d99fc6d230d9b970a4.zip
HERE WE GO, HERE WE GO, HERE WE GO
Diffstat (limited to 'jb-ui/src/JBApp.tsx')
-rw-r--r--jb-ui/src/JBApp.tsx178
1 files changed, 178 insertions, 0 deletions
diff --git a/jb-ui/src/JBApp.tsx b/jb-ui/src/JBApp.tsx
new file mode 100644
index 0000000..5c99e61
--- /dev/null
+++ b/jb-ui/src/JBApp.tsx
@@ -0,0 +1,178 @@
+import {
+ EventMessage,
+ PingMessage,
+ PongMessage,
+ PongMessageKindEnum,
+ StatsMessage,
+ StatusApi,
+ SubscribeMessage, SubscribeMessageKindEnum,
+ TaskStatusResponse,
+ UserWalletBalance,
+ UserWalletBalanceResponse,
+ WalletApi
+} from "@/api_fsb";
+import Footer from "@/components/Footer";
+import { useAppDispatch } from "@/hooks";
+import { bpid, routeBasename, tagManager } from "@/lib/utils";
+import { setAssignmentID, setProductUserID, setTurkSubmitTo } from "@/models/appSlice";
+import { addStatsData } from "@/models/grlStatsSlice";
+import Home from "@/pages/Home";
+import Preview from "@/pages/Preview";
+import Result from "@/pages/Result";
+import Work from "@/pages/Work";
+import { BrowserRouter, Outlet, Route, Routes, useSearchParams } from "react-router-dom";
+import useWebSocket from 'react-use-websocket';
+
+import { useEffect } from "react";
+
+import Wallet from "@/components/Wallet";
+import "@/index.css";
+import { setTaskStatus, setUserWalletBalance } from "@/models/appSlice";
+import { Profiling } from "./components/Profiling";
+
+type Message = PingMessage | PongMessage | SubscribeMessage | EventMessage | StatsMessage;
+
+function isStatsMessage(msg: Message): msg is StatsMessage {
+ return msg.kind === 'stats';
+}
+
+function isPingMessage(msg: Message): msg is PingMessage {
+ return msg.kind === 'ping';
+}
+
+function QueryParamProcessor() {
+ const dispatch = useAppDispatch()
+ const [searchParams] = useSearchParams();
+
+ useEffect(() => {
+ const worker_id = searchParams.get('workerId');
+ const assignment_id = searchParams.get('assignmentId');
+ const tsid = searchParams.get('tsid');
+ const turkSubmitTo = searchParams.get('turkSubmitTo');
+
+ if (turkSubmitTo) {
+ dispatch(setTurkSubmitTo(turkSubmitTo))
+ }
+
+ if (worker_id) {
+ dispatch(setProductUserID(worker_id))
+
+ new WalletApi().getUserWalletBalanceProductIdWalletGet(
+ bpid, // productId
+ worker_id, // bpuid
+ ).then(res => {
+ const response = res.data as UserWalletBalanceResponse;
+ const balance = response.wallet as UserWalletBalance;
+ dispatch(setUserWalletBalance(balance));
+ });
+ }
+
+ if (assignment_id) {
+ dispatch(setAssignmentID(assignment_id))
+ }
+
+ if (tsid) {
+ new StatusApi().getTaskStatusProductIdStatusTsidGet(
+ bpid, // productId
+ tsid).then(res => {
+ const response: TaskStatusResponse = res.data;
+ dispatch(setTaskStatus(response))
+ }).catch((error) => {
+ console.error("Error fetching task status:", error);
+ });
+ }
+
+ }, [searchParams]);
+
+ return <Outlet />;
+}
+
+const Layout = () => {
+ return (
+ <div className="flex flex-col min-h-screen">
+
+ <main className="flex flex-1 bg-zinc-200">
+ <div className="flex flex-col items-center justify-center flex-1">
+ <div className="
+ w-full max-w-full
+ p-2 bg-white shadow-lg
+ text-center space-y-4
+ md:max-w-5/8 md:rounded-lg
+ rounded-none
+ ">
+ <Wallet />
+ <Profiling />
+ <Outlet />
+ </div>
+ </div>
+ </main >
+
+ <footer className="bg-slate-700 text-zinc-200 p-2 text-center font-mono">
+ <Footer />
+ </footer>
+
+ </div >
+ );
+};
+
+function JBApp() {
+ const dispatch = useAppDispatch()
+
+ const { sendJsonMessage, lastMessage } = useWebSocket(
+ "wss://fsb.generalresearch.com/ws/events/", {
+ onOpen: () => {
+ const subscribe: SubscribeMessage = {
+ "kind": SubscribeMessageKindEnum.Subscribe,
+ "product_id": bpid
+ }
+ sendJsonMessage(subscribe)
+ }
+ }
+ );
+
+ useEffect(() => {
+ if (lastMessage !== null) {
+ let msg: Message = JSON.parse(lastMessage.data);
+
+ if (isStatsMessage(msg)) {
+ dispatch(addStatsData(msg.data))
+
+ } else if (isPingMessage(msg)) {
+ const pong: PongMessage = {
+ "kind": PongMessageKindEnum.Pong,
+ }
+ sendJsonMessage(pong)
+ }
+ }
+ }, [lastMessage]);
+
+ useEffect(() => {
+ if (!tagManager) return;
+
+ var _mtm = window._mtm = window._mtm || [];
+ _mtm.push({ 'mtm.startTime': (new Date().getTime()), 'event': 'mtm.Start' });
+ var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
+ g.async = true;
+ g.src = tagManager;
+ if (s.parentNode) {
+ s.parentNode.insertBefore(g, s);
+ }
+ }, [tagManager])
+
+ return (
+ <BrowserRouter basename={routeBasename}>
+ <Routes>
+ <Route element={<QueryParamProcessor />}>
+ <Route element={<Layout />}>
+ <Route path="/" element={<Home />} />
+ <Route path="/preview/" element={<Preview />} />
+ <Route path="/work/" element={<Work />} />
+ <Route path="/result/" element={<Result />} />
+ </Route>
+ </Route>
+ </Routes>
+ </BrowserRouter>
+ )
+}
+
+export default JBApp; \ No newline at end of file