aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Nanis2026-09-12 14:30:31 -0700
committerMax Nanis2026-09-12 14:30:31 -0700
commitb2261f9101480afb31322cf620f028cdade0671c (patch)
tree0bcba3696b0566138145d80a8fcb9230b172f2c5
parentf82ac61b6a044467ab37c0645c3fe99b40bedfc5 (diff)
downloadamt-jb-b2261f9101480afb31322cf620f028cdade0671c.tar.gz
amt-jb-b2261f9101480afb31322cf620f028cdade0671c.zip
new landing page that combines leaderboard + login. fixing worker_id assignment, it'll still be needed until transfer is finished
-rw-r--r--jb-ui/src/JBApp.tsx13
-rw-r--r--jb-ui/src/pages/Preview.tsx142
-rw-r--r--jb-ui/src/pages/Transfer.tsx13
-rw-r--r--jb-ui/src/pages/Work.tsx78
4 files changed, 131 insertions, 115 deletions
diff --git a/jb-ui/src/JBApp.tsx b/jb-ui/src/JBApp.tsx
index a69cc85..6c31164 100644
--- a/jb-ui/src/JBApp.tsx
+++ b/jb-ui/src/JBApp.tsx
@@ -78,6 +78,11 @@ function QueryParamProcessor() {
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 (user?.product_user_id) {
dispatch(setProductUserID(user.product_user_id));
@@ -119,7 +124,10 @@ function QueryParamProcessor() {
const Layout = () => {
const location = useLocation();
- const isSpecialSubview = useMatch("/work/*");
+
+ const isWork = useMatch("/work*");
+ const isPreview = useMatch("/preview*");
+ const isSpecialSubview = Boolean(isWork || isPreview);
return (
<div className="flex flex-col min-h-screen">
@@ -225,9 +233,8 @@ function JBApp() {
<Route element={<Layout />}>
<Route path="/" element={<Work />} />
<Route path="/auth/magic-link/" element={<MagicLink />} />
- {/* <Route path="/work/" element={<Work />} /> */}
- <Route path="/preview/" element={<Preview />} />
+ <Route path="/preview/" element={<Transfer />} />
<Route path="/work/" element={<Transfer />} />
<Route path="/result/" element={<Result />} />
</Route>
diff --git a/jb-ui/src/pages/Preview.tsx b/jb-ui/src/pages/Preview.tsx
index 1926975..85e49f2 100644
--- a/jb-ui/src/pages/Preview.tsx
+++ b/jb-ui/src/pages/Preview.tsx
@@ -5,6 +5,7 @@ import {
LeaderboardFrequency,
LeaderboardRow,
} from "@/api_fsb";
+import { Button } from "@/components/ui/button";
import { useAppSelector } from "@/hooks";
import { bpid, formatCentsToUSD, truncate } from "@/lib/utils";
import { activeSurveys, activeUsers, maxPayout } from "@/models/grlStatsSlice";
@@ -244,6 +245,98 @@ export const Leaderboards = () => {
);
};
+type RequestState = "idle" | "working" | "failed";
+
+const LoginForm = function ({ onSubmitSuccess }) {
+ const [email, setEmail] = useState("");
+ const [state, setState] = useState<RequestState>("idle");
+
+ // const dispatch = useAppDispatch();
+ const submit = async (event: FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ setState("working");
+
+ try {
+ const response = await fetch("/auth/magic-link/request", {
+ method: "POST",
+ credentials: "include",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ email: email,
+ }),
+ });
+
+ if (!response.ok) throw new Error("Account-link request failed");
+ const body = (await response.json()) as { magic_link?: string };
+ console.log(body.magic_link ?? null);
+ onSubmitSuccess();
+ } catch {
+ setState("failed");
+ }
+ };
+
+ return (
+ <>
+ <form className="w-full" onSubmit={submit}>
+ <div className="flex items-center border-b-4 border-blue-700 py-2">
+ <input
+ className="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none font-semibold"
+ type="email"
+ autoComplete="email"
+ required
+ value={email}
+ onChange={(event) => setEmail(event.target.value)}
+ placeholder="hello@jamesbillings67.com"
+ aria-label="Email address"
+ />
+
+ <button
+ className="flex-shrink-0 bg-blue-700 hover:bg-blue-800 text-white py-1 px-2 rounded cursor-pointer font-semibold"
+ type="submit"
+ disabled={state === "working"}
+ >
+ {state === "working" ? "Sending…" : "Login / Signup"}
+ </button>
+ </div>
+ </form>
+
+ {state === "failed" && <p>Unable to send the link. Please try again.</p>}
+ </>
+ );
+};
+
+const LoginSent = function () {
+ return (
+ <div className="my-1">
+ <h2
+ className="
+ bg-emerald-400 rounded py-2
+ text-white text-l font-semibold text-center"
+ >
+ Please check your email.
+ </h2>
+ <p className="text-slate-800 text-xs font-semibold text-center my-1 py-2">
+ If you don't recieve anything, please check your spam folder, or try
+ again shortly.
+ </p>
+ </div>
+ );
+};
+
+const Login = () => {
+ const [submitted, setSubmitted] = useState(false);
+
+ return (
+ <>
+ {submitted ? (
+ <LoginSent />
+ ) : (
+ <LoginForm onSubmitSuccess={() => setSubmitted(true)} />
+ )}
+ </>
+ );
+};
+
// Preview Component
const Preview = () => {
/**
@@ -267,33 +360,32 @@ const Preview = () => {
);
return (
- <div className="max-h-[calc(100vh-10rem)] overflow-y-auto">
- <div className="bg-zinc-100 rounded py-2 m-0">
- <p className="text-center text-sm italic text-zinc-600">
- {users_f} people are actively attempting {surveys_f} available surveys
- right now.
- </p>
- </div>
+ <>
+ <Login />
+
+ <div className="max-h-[calc(100vh-10rem)] overflow-y-auto">
+ <div className="bg-zinc-100 rounded py-2 m-0">
+ <p className="text-center text-sm italic text-zinc-600">
+ {users_f} people are actively attempting {surveys_f} available
+ surveys right now.
+ </p>
+ </div>
- <Leaderboards />
-
- <div className="bg-zinc-100 rounded py-2 px-6 m-0 text-xs text-center">
- <p className="py-1">
- Get paid to take surveys. Our algorithm attempts to pair you with the
- highest paying survey available at the moment (right now, the highest
- paying survey is {survey_max_cpi_f}) that you are eligible for, each
- attempt is a valid HIT. Try as many as you can, our system will self
- regulate you: we want to ensure you have a high chance of being paired
- with a survey based on what surveys are available, as their
- availability constantly changes.
- </p>
- <p className="py-1">
- Each HIT is paid when you attempt to take a survey and if you complete
- the survey, you will be awarded a bonus equal to that in which the
- survey pays out.
- </p>
+ <Leaderboards />
+
+ <div className="bg-zinc-100 rounded py-2 px-6 m-0 text-xs text-center">
+ <p className="py-1">
+ Get paid to take surveys. Our algorithm attempts to pair you with
+ the highest paying survey available at the moment (right now, the
+ highest paying survey is {survey_max_cpi_f}) that you are eligible
+ for, each attempt is a valid HIT. Try as many as you can, our system
+ will self regulate you: we want to ensure you have a high chance of
+ being paired with a survey based on what surveys are available, as
+ their availability constantly changes.
+ </p>
+ </div>
</div>
- </div>
+ </>
);
};
export default Preview;
diff --git a/jb-ui/src/pages/Transfer.tsx b/jb-ui/src/pages/Transfer.tsx
index 4192eee..0d174c1 100644
--- a/jb-ui/src/pages/Transfer.tsx
+++ b/jb-ui/src/pages/Transfer.tsx
@@ -132,11 +132,11 @@ const TransferSubmit = function ({ onSubmitSuccess }) {
};
const Transfer = function () {
- const assignment_id = useAppSelector((state) => state.app.assignment_id);
+ const bpuid = useAppSelector((state) => state.app.bpuid);
const { data: user, isLoading, isError } = useGetMeQuery();
const [submitted, setSubmitted] = useState(false);
- if (!user?.product_user_id) {
+ if (!bpuid) {
return (
<p className="text-center text-2xl py-3 text-red-800 font-semibold">
No Worker ID found. Please access this page through the Amazon
@@ -145,15 +145,6 @@ const Transfer = function () {
);
}
- if (!assignment_id) {
- return (
- <p className="text-center text-2xl py-3 text-red-800 font-semibold">
- No Assignment ID found. Please access this page through the Amazon
- Mechanical Turk platform.
- </p>
- );
- }
-
return (
<>
{submitted ? (
diff --git a/jb-ui/src/pages/Work.tsx b/jb-ui/src/pages/Work.tsx
index 84cb946..dbe3601 100644
--- a/jb-ui/src/pages/Work.tsx
+++ b/jb-ui/src/pages/Work.tsx
@@ -11,6 +11,7 @@ import {
TaskStatusResponse,
TopNPlusBlockOfferWall,
} from "@/api_fsb";
+import Preview from "@/pages/Preview";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
@@ -793,81 +794,6 @@ const SurveyEnter = () => {
);
};
-type RequestState = "idle" | "working" | "sent" | "failed";
-
-const Login = () => {
- const [email, setEmail] = useState("");
- const [state, setState] = useState<RequestState>("idle");
-
- // const dispatch = useAppDispatch();
- const submit = async (event: FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- setState("working");
-
- try {
- const response = await fetch("/auth/magic-link/request", {
- method: "POST",
- credentials: "include",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- email: email,
- }),
- });
-
- if (!response.ok) throw new Error("Account-link request failed");
-
- const body = (await response.json()) as { magic_link?: string };
- console.log(body.magic_link ?? null);
- } catch {
- setState("failed");
- }
- };
-
- return (
- <div className="px-6 my-6">
- <h2
- className="
- bg-blue-700 rounded py-2
- text-white text-2xl font-semibold text-center"
- >
- Please Login
- </h2>
-
- <form onSubmit={submit}>
- <input
- className="w-full rounded-md border-3 border-slate-700 px-3 py-2 font-semibold my-5"
- type="email"
- autoComplete="email"
- required
- value={email}
- onChange={(event) => setEmail(event.target.value)}
- placeholder="hello@jamesbillings67.com"
- />
- <Button
- className="w-1/2 font-semibold bg-slate-600 cursor-pointer hover:bg-blue-950"
- type="submit"
- disabled={state === "working"}
- >
- {state === "working" ? "Sending…" : "Login"}
- </Button>
- </form>
-
- {state === "sent" && (
- <h4
- className="
- mt-2
- bg-slate-500 rounded py-2
- text-white text-l font-semibold text-center"
- >
- Check your email to login.
- </h4>
- )}
-
- {state === "failed" && <p>Unable to send the link. Please try again.</p>}
- </div>
- );
-};
-
const Work = () => {
const entered = useAppSelector((state) => state.app.currentBucketEntered);
// const assignment_id = useAppSelector((state) => state.app.assignment_id);
@@ -886,7 +812,7 @@ const Work = () => {
if (isLoading) return <div>Loading...</div>;
if (isError || !user) {
- return <Login />;
+ return <Preview />;
}
return <>{entered ? <SurveyMonitor /> : <SurveyEnter />}</>;