aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jb-ui/Jenkinsfile6
-rw-r--r--jb-ui/src/JBApp.tsx18
-rw-r--r--jb-ui/src/components/EventMarquee.tsx2
-rw-r--r--jb-ui/src/pages/LinkAmtAccount.tsx84
-rw-r--r--jb-ui/src/pages/Transfer.tsx171
-rw-r--r--jb-ui/vite.config.ts102
6 files changed, 207 insertions, 176 deletions
diff --git a/jb-ui/Jenkinsfile b/jb-ui/Jenkinsfile
index 27a0ab9..faf63de 100644
--- a/jb-ui/Jenkinsfile
+++ b/jb-ui/Jenkinsfile
@@ -82,7 +82,7 @@ pipeline {
expression { env.BRANCH_NAME == 'master' }
}
steps {
- sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ thl-cdn:/root/amt-jb-cdn/"
+ sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ cdn-jb:/var/www/amt-jb-cdn/"
}
}
@@ -101,7 +101,7 @@ pipeline {
sh "cp ${env.JS_FILENAME}.js ${versioned_js}.js"
sh "cp ${env.CSS_FILENAME}.js ${versioned_css}.js"
- sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ thl-cdn:/root/amt-jb-cdn/"
+ sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ cdn-jb:/var/www/amt-jb-cdn/"
}
}
}
@@ -126,7 +126,7 @@ pipeline {
sh "cp ${env.JS_FILENAME}.js ${versioned}.js"
sh "cp ${env.CSS_FILENAME}.js ${versioned}.js"
- sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ thl-cdn:/root/amt-jb-cdn/"
+ sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ cdn-jb:/var/www/amt-jb-cdn/"
}
}
}
diff --git a/jb-ui/src/JBApp.tsx b/jb-ui/src/JBApp.tsx
index 472b976..7c99315 100644
--- a/jb-ui/src/JBApp.tsx
+++ b/jb-ui/src/JBApp.tsx
@@ -27,11 +27,15 @@ import Home from "@/pages/Home";
import MagicLink from "@/pages/MagicLink";
import Preview from "@/pages/Preview";
import Result from "@/pages/Result";
+import clsx from "clsx";
+
import Work from "@/pages/Work";
import Transfer from "@/pages/Transfer";
import {
BrowserRouter,
Outlet,
+ useLocation,
+ useMatch,
Route,
Routes,
useSearchParams,
@@ -118,6 +122,9 @@ function QueryParamProcessor() {
}
const Layout = () => {
+ const location = useLocation();
+ const isSpecialSubview = useMatch("/work/*");
+
return (
<div className="flex flex-col min-h-screen">
<header className="bg-amber-400 text-amber-950 py-2 text-center">
@@ -134,13 +141,10 @@ const Layout = () => {
<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
- "
+ 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 />
diff --git a/jb-ui/src/components/EventMarquee.tsx b/jb-ui/src/components/EventMarquee.tsx
index 6aab3f8..46508ff 100644
--- a/jb-ui/src/components/EventMarquee.tsx
+++ b/jb-ui/src/components/EventMarquee.tsx
@@ -148,7 +148,7 @@ export default function NewsTicker() {
// the browser, which is more accurate for measuring frame intervals
// than Date.now()
const loop = (timestamp: number) => {
- console.log("RAF loop, timestamp:", timestamp, lastTime.current);
+ // console.log("RAF loop, timestamp:", timestamp, lastTime.current);
if (!lastTime.current) lastTime.current = timestamp;
const delta = (timestamp - lastTime.current) / 1000;
diff --git a/jb-ui/src/pages/LinkAmtAccount.tsx b/jb-ui/src/pages/LinkAmtAccount.tsx
deleted file mode 100644
index a72626f..0000000
--- a/jb-ui/src/pages/LinkAmtAccount.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import { type FormEvent, useState } from "react";
-
-import { Button } from "@/components/ui/button";
-
-type RequestState = "idle" | "working" | "sent" | "failed" | "missing-worker";
-
-const LinkAmtAccount = function () {
- const [email, setEmail] = useState("");
- const [state, setState] = useState<RequestState>("idle");
- const [mockLink, setMockLink] = useState<string | null>(null);
- const amtWorkerId = new URLSearchParams(window.location.search).get(
- "workerId",
- );
-
- const submit = async (event: FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- if (!amtWorkerId) {
- setState("missing-worker");
- return;
- }
-
- setState("working");
- setMockLink(null);
- try {
- const response = await fetch("/auth/link-amt/request", {
- method: "POST",
- credentials: "include",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- email: email,
- amt_worker_id: amtWorkerId,
- }),
- });
- if (!response.ok) throw new Error("Account-link request failed");
- const body = (await response.json()) as { magic_link?: string };
- setMockLink(body.magic_link ?? null);
- setState("sent");
- } catch {
- setState("failed");
- }
- };
-
- return (
- <main className="flex min-h-screen items-center justify-center bg-zinc-200 p-4">
- <section className="w-full max-w-md space-y-4 rounded-lg bg-white p-6 shadow-lg">
- <h1 className="text-xl font-semibold">Link your MTurk account</h1>
- <p>Enter the email address you want to use for James Billings.</p>
- <form className="space-y-4" onSubmit={submit}>
- <input
- className="w-full rounded-md border px-3 py-2"
- type="email"
- autoComplete="email"
- required
- value={email}
- onChange={(event) => setEmail(event.target.value)}
- placeholder="you@example.com"
- />
- <Button type="submit" disabled={state === "working"}>
- {state === "working" ? "Sending…" : "Send link"}
- </Button>
- </form>
- {state === "sent" && (
- <p>Check your email to finish linking your account.</p>
- )}
- {state === "failed" && (
- <p>Unable to send the link. Please try again.</p>
- )}
- {state === "missing-worker" && (
- <p>This page is missing your MTurk worker ID.</p>
- )}
- {mockLink && (
- <p>
- Development link:{" "}
- <a className="underline" href={mockLink}>
- continue
- </a>
- </p>
- )}
- </section>
- </main>
- );
-};
-
-export default LinkAmtAccount;
diff --git a/jb-ui/src/pages/Transfer.tsx b/jb-ui/src/pages/Transfer.tsx
index 6e087d6..bef40d4 100644
--- a/jb-ui/src/pages/Transfer.tsx
+++ b/jb-ui/src/pages/Transfer.tsx
@@ -1,50 +1,167 @@
-import { clsx } from "clsx";
+import { type FormEvent, useState } from "react";
+import { useAppDispatch, useAppSelector } from "@/hooks";
+import { Button } from "@/components/ui/button";
+import max_lulu from "./max-and-lulu.jpg";
-import { useSelector } from "react-redux";
+// const handleInputChange = (
+// event: React.KeyboardEvent<HTMLInputElement>,
+// ) => {};
-const Transfer = function () {
- let error = [];
+// const handleKeyPress = (event: KeyboardEvent<HTMLInputElement>) => {};
+// const handleSubmit = (e) => {
+// e.preventDefault();
+// console.log("Form submitted successfully!");
+// };
+
+const TransferComplete = function () {
+ return (
+ <div className="px-6 my-6">
+ <h2
+ className="
+ bg-emerald-400 rounded py-2
+ text-white text-2xl font-semibold text-center"
+ >
+ Please check your email.
+ </h2>
+ <p className="text-slate-600 text-l font-semibold text-center py-5 px-6">
+ If you don't recieve anything, please check your spam folder, or try
+ again shortly.
+ </p>
+ <p className="bg-slate-200 text-xs font-semibold text-center p-3 my-3">
+ We will be assisting account transfers throughout the rest of the month.
+ If you have any further questions or concerns, please email us directly
+ with your desired account email and the AMT ID to associate with your
+ worker history.
+ </p>
+ <img src={max_lulu} alt="Max and Lulu" className="object-contain" />
+ </div>
+ );
+};
+
+type RequestState = "idle" | "working" | "sent" | "failed";
- const handleInputChange = (
- event: React.KeyboardEvent<HTMLInputElement>,
- ) => {};
+const TransferSubmit = function ({ onSubmitSuccess }) {
+ const [email, setEmail] = useState("");
+ const [state, setState] = useState<RequestState>("idle");
+ const bpuid = useAppSelector((state) => state.app.bpuid);
- const handleKeyPress = (event: KeyboardEvent<HTMLInputElement>) => {};
+ const submit = async (event: FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ setState("working");
- const handleSubmit = (e) => {
- e.preventDefault();
- console.log("Form submitted successfully!");
+ try {
+ const response = await fetch("/auth/link-amt/request", {
+ method: "POST",
+ credentials: "include",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ email: email,
+ amt_worker_id: bpuid,
+ }),
+ });
+
+ 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 (
<div className="px-6 my-6">
<h2
className="
- bg-red-500 rounded py-2
+ bg-red-700 rounded py-2
text-white text-2xl font-semibold text-center"
>
Transfer Required
</h2>
- <p
+ <h4
className="
- py-4
- text-zinc-500 text-2xl font-semibold text-center"
+ mt-2
+ bg-slate-500 rounded p-2
+ text-white text-sm font-semibold text-center"
>
- James Billings is finished 😭 Just Kidding!!!
- </p>
+ James Billings is no longer available on Amazon Mechanical Turk. Our
+ dedicated platform will enable you to do the same work as always, paid
+ directly to you.
+ <br />
+ Enter your email below to transfer your account history.
+ <br />
+ This will allow you to keep your full account history and wallet
+ balance.
+ </h4>
+
+ <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="you@example.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…" : "Send link"}
+ </Button>
+ </form>
- <input
- type="text"
- id="text-entry-input"
- aria-describedby=""
- // defaultValue={answer?.values.length ? answer?.values[0] : ""}
- // onKeyUp={handleInputChange}
- // onKeyDown={handleKeyPress} // Use onKeyDown to listen for the key press
- // title={error ? answer?.error_msg : ""}
- className={clsx("w-full border-1 rounded px-2 py-1")}
- />
+ {state === "sent" && (
+ <h4
+ className="
+ mt-2
+ bg-slate-500 rounded py-2
+ text-white text-l font-semibold text-center"
+ >
+ Check your email to finish linking your account.
+ </h4>
+ )}
+
+ {state === "failed" && <p>Unable to send the link. Please try again.</p>}
</div>
);
};
+const Transfer = function () {
+ const assignment_id = useAppSelector((state) => state.app.assignment_id);
+ const bpuid = useAppSelector((state) => state.app.bpuid);
+ const [submitted, setSubmitted] = useState(false);
+
+ 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
+ Mechanical Turk platform.
+ </p>
+ );
+ }
+
+ 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 ? (
+ <TransferComplete />
+ ) : (
+ <TransferSubmit onSubmitSuccess={() => setSubmitted(true)} />
+ )}
+ </>
+ );
+};
+
export default Transfer;
diff --git a/jb-ui/vite.config.ts b/jb-ui/vite.config.ts
index 6b0e530..2336e4a 100644
--- a/jb-ui/vite.config.ts
+++ b/jb-ui/vite.config.ts
@@ -1,62 +1,56 @@
-import react from "@vitejs/plugin-react"
-import {defineConfig} from "vite"
-import path from 'path';
-import tailwindcss from '@tailwindcss/vite'
-
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
+import path from "path";
+import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
- plugins: [
- react(),
- tailwindcss(),
-
- ],
+ plugins: [react(), tailwindcss()],
- resolve: {
- alias: {
- '@': path.resolve(__dirname, './src'),
- },
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
},
-
- server: {
- // host: "0.0.0.0",
- // port: 8001,
-
- // This forwards requests to the FastAPI development server
- // that must also be running
- proxy: {
- '^/(status|statuses|report|survey)(/|$)': {
- target: 'http://localhost:8000',
- changeOrigin: true,
- }
- }
+ },
+
+ server: {
+ // host: "0.0.0.0",
+ // port: 8001,
+
+ // This forwards requests to the FastAPI development server
+ // that must also be running
+ proxy: {
+ "^/(auth|status|statuses|report|survey)(/|$)": {
+ target: "http://localhost:8000",
+ changeOrigin: true,
+ },
},
+ },
- define: {
- 'process.env.NODE_ENV': JSON.stringify('production')
- },
+ define: {
+ "process.env.NODE_ENV": JSON.stringify("production"),
+ },
- build: {
- cssCodeSplit: false,
- lib: {
- name: "jb-ui",
- entry: 'src/main.tsx',
+ build: {
+ cssCodeSplit: false,
+ lib: {
+ name: "jb-ui",
+ entry: "src/main.tsx",
+ },
+ rollupOptions: {
+ output: {
+ entryFileNames: "james-billings.js",
+ assetFileNames: (assetInfo) => {
+ if (assetInfo.names[0].endsWith(".css")) {
+ return "james-has-style.css";
+ }
+
+ return "assets/[name].[hash][extname]";
},
- rollupOptions: {
- output: {
- entryFileNames: 'james-billings.js',
- assetFileNames: (assetInfo) => {
-
- if (assetInfo.names[0].endsWith('.css')) {
- return 'james-has-style.css';
- }
-
- return 'assets/[name].[hash][extname]';
- },
- globals: {
- react: 'React',
- 'react-dom': 'ReactDOM'
- }
- }
- }
- }
-}) \ No newline at end of file
+ globals: {
+ react: "React",
+ "react-dom": "ReactDOM",
+ },
+ },
+ },
+ },
+});