aboutsummaryrefslogtreecommitdiff
path: root/jb-ui/src/JBApp.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'jb-ui/src/JBApp.tsx')
-rw-r--r--jb-ui/src/JBApp.tsx405
1 files changed, 242 insertions, 163 deletions
diff --git a/jb-ui/src/JBApp.tsx b/jb-ui/src/JBApp.tsx
index 76e3f29..c55cd73 100644
--- a/jb-ui/src/JBApp.tsx
+++ b/jb-ui/src/JBApp.tsx
@@ -1,29 +1,52 @@
import {
- EventMessage,
- EventType,
- PingMessage,
- PongMessage,
- PongMessageKindEnum,
- StatsMessage,
- StatusApi,
- SubscribeMessage, SubscribeMessageKindEnum,
- TaskStatusResponse,
- UserWalletBalance,
- UserWalletBalanceResponse,
- WalletApi
+ EventMessage,
+ EventType,
+ PingMessage,
+ PongMessage,
+ PongMessageKindEnum,
+ StatsMessage,
+ StatusApi,
+ SubscribeMessage,
+ SubscribeMessageKindEnum,
+ TaskStatusResponse,
+ UserWalletBalance,
+ UserWalletBalanceResponse,
+ UserLedgerWallets,
+ UserLedgerWalletAccountTypeEnum,
+ WalletApi,
+ CashoutMethodsResponse,
} 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 { useGetMeQuery } from "@/models/authAPI";
+import {
+ setAssignmentID,
+ setProductUserID,
+ setUserDisplayedWalletBalance,
+ setUserWallet,
+ setUserAttemptCreditWallet,
+} from "@/models/appSlice";
+
+import { addCashoutMethods } from "@/models/cashoutMethodsSlice";
+
import { addEvent } from "@/models/grlEventsSlice";
import { addStatsData } from "@/models/grlStatsSlice";
-import Home from "@/pages/Home";
-import Preview from "@/pages/Preview";
+import MagicLink from "@/pages/MagicLink";
import Result from "@/pages/Result";
+import clsx from "clsx";
+
import Work from "@/pages/Work";
-import { BrowserRouter, Outlet, Route, Routes, useSearchParams } from "react-router-dom";
-import useWebSocket from 'react-use-websocket';
+import Transfer from "@/pages/Transfer";
+import {
+ BrowserRouter,
+ Outlet,
+ useMatch,
+ Route,
+ Routes,
+ useSearchParams,
+} from "react-router-dom";
+import useWebSocket from "react-use-websocket";
import NewsTicker from "./components/EventMarquee";
import { useEffect } from "react";
@@ -32,178 +55,234 @@ import Wallet from "@/components/Wallet";
import "@/index.css";
import { setTaskStatus, setUserWalletBalance } from "@/models/appSlice";
import { Profiling } from "./components/Profiling";
+import Redemption from "./components/Redemption";
-type Message = PingMessage | PongMessage | SubscribeMessage | EventMessage | StatsMessage;
+type Message =
+ | PingMessage
+ | PongMessage
+ | SubscribeMessage
+ | EventMessage
+ | StatsMessage;
function isStatsMessage(msg: Message): msg is StatsMessage {
- return msg.kind === 'stats';
+ return msg.kind === "stats";
}
function isEventMessage(msg: Message): msg is EventMessage {
- return msg.kind === 'event';
+ return msg.kind === "event";
}
function isPingMessage(msg: Message): msg is PingMessage {
- return msg.kind === 'ping';
+ return msg.kind === "ping";
}
function QueryParamProcessor() {
- const dispatch = useAppDispatch()
- const [searchParams] = useSearchParams();
+ const dispatch = useAppDispatch();
+ const [searchParams] = useSearchParams();
+ const { data: user } = useGetMeQuery();
- useEffect(() => {
- const worker_id = searchParams.get('workerId');
- const assignment_id = searchParams.get('assignmentId');
- const tsid = searchParams.get('tsid');
- const turkSubmitTo = searchParams.get('turkSubmitTo');
+ useEffect(() => {
+ if (user?.product_user_id) {
+ dispatch(setProductUserID(user.product_user_id));
- if (turkSubmitTo) {
- dispatch(setTurkSubmitTo(turkSubmitTo))
- }
+ new WalletApi()
+ .getCashoutMethodsProductIdCashoutMethodsGet(bpid, user.product_user_id)
+ .then((res) => {
+ const response = res.data as CashoutMethodsResponse;
+ dispatch(addCashoutMethods(response.cashout_methods));
+ });
- 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));
- });
- }
+ new WalletApi()
+ .getUserWalletBalanceProductIdWalletGet(
+ bpid, // productId
+ user.product_user_id,
+ )
+ .then((res) => {
+ const response = res.data as UserWalletBalanceResponse;
+ const balance = response.wallet as UserWalletBalance;
+ dispatch(setUserWalletBalance(balance));
+ });
- if (assignment_id) {
- dispatch(setAssignmentID(assignment_id))
- }
+ new WalletApi()
+ .getUserWalletsProductIdWalletsGet(bpid, user.product_user_id)
+ .then((res) => {
+ const response = res.data as UserLedgerWallets;
- 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);
- });
- }
+ if (response.displayed_balances) {
+ setUserDisplayedWalletBalance(response.displayed_balances[0]);
+ }
- }, [searchParams]);
+ const userWallet = response.wallets?.find(
+ (w) =>
+ w.account_type === UserLedgerWalletAccountTypeEnum.UserWallet,
+ );
+ if (userWallet) {
+ setUserWallet(userWallet);
+ }
- return <Outlet />;
+ const userAttemptCreditWallet = response.wallets?.find(
+ (w) =>
+ w.account_type ===
+ UserLedgerWalletAccountTypeEnum.UserAttemptCredit,
+ );
+ if (userAttemptCreditWallet) {
+ setUserAttemptCreditWallet(userAttemptCreditWallet);
+ }
+ });
+ }
+ }, [user]);
+
+ useEffect(() => {
+ const assignment_id = searchParams.get("assignmentId");
+ const tsid = searchParams.get("tsid");
+ const worker_id = searchParams.get("workerId");
+
+ if (worker_id) {
+ dispatch(setProductUserID(worker_id));
+ }
+
+ 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">
- <header className="bg-amber-400 text-amber-950 py-2 text-center">
- <a href="https://www.reddit.com/r/Marketresearch/comments/1s2tl0o/open_letter_to_cint_supplier_quality_issues/" target="_blank">
- <h4 className="text-[12px]">
- Letter to Cint: supplier quality issues, and malware-linked panels.
- </h4>
- </a>
- </header>
-
- <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">
- <NewsTicker />
- <Footer />
- </footer>
-
- </div >
- );
+ const isWork = useMatch("/work/*");
+ const isPreview = useMatch("/preview/*");
+ const isSpecialSubview = Boolean(isWork || isPreview);
+
+ return (
+ <div className="flex flex-col min-h-screen">
+ <header className="bg-amber-400 text-amber-950 py-2 text-center">
+ <a
+ href="https://www.reddit.com/r/Marketresearch/comments/1s2tl0o/open_letter_to_cint_supplier_quality_issues/"
+ target="_blank"
+ >
+ <h4 className="text-[12px]">
+ Letter to Cint: supplier quality issues, and malware-linked panels.
+ </h4>
+ </a>
+ </header>
+
+ <main className="flex flex-1 bg-zinc-200">
+ <div className="flex flex-col items-center justify-center flex-1">
+ <div
+ className={clsx(
+ "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",
+ isSpecialSubview && "border-6 border-amber-400",
+ )}
+ >
+ <Wallet />
+ <Profiling />
+ <Redemption />
+ <Outlet />
+ </div>
+ </div>
+ </main>
+
+ <footer className="bg-slate-700 text-zinc-200 p-2 text-center font-mono">
+ <NewsTicker />
+ <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)
+ 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 (isEventMessage(msg)) {
+ // For simplicity, we just log the event messages here.
+ // You can extend this to update the UI or trigger notifications as needed.
+
+ switch (msg.data.event_type) {
+ case EventType.TaskEnter:
+ case EventType.TaskFinish:
+ case EventType.UserCreated:
+ dispatch(addEvent(msg.data));
+ break;
+
+ default:
+ // do nothing for now
+ break;
}
+ } else if (isPingMessage(msg)) {
+ const pong: PongMessage = {
+ kind: PongMessageKindEnum.Pong,
+ };
+ sendJsonMessage(pong);
+ }
}
- );
-
- useEffect(() => {
- if (lastMessage !== null) {
- let msg: Message = JSON.parse(lastMessage.data);
-
- if (isStatsMessage(msg)) {
- dispatch(addStatsData(msg.data))
-
- } else if (isEventMessage(msg)) {
- // For simplicity, we just log the event messages here.
- // You can extend this to update the UI or trigger notifications as needed.
-
- switch (msg.data.event_type) {
- case EventType.TaskEnter:
- case EventType.TaskFinish:
- case EventType.UserCreated:
- dispatch(addEvent(msg.data));
- break
-
- default:
- // do nothing for now
- break;
- }
-
- } 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>
- )
+ }, [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={<Work />} />
+ <Route path="/auth/magic-link/" element={<MagicLink />} />
+
+ <Route path="/preview/" element={<Transfer />} />
+ <Route path="/work/" element={<Transfer />} />
+ <Route path="/result/" element={<Result />} />
+ </Route>
+ </Route>
+ </Routes>
+ </BrowserRouter>
+ );
}
-export default JBApp; \ No newline at end of file
+export default JBApp;