From ed201936813d9a720b51e6cb40a05267b94e7314 Mon Sep 17 00:00:00 2001
From: Max Nanis
Date: Thu, 10 Sep 2026 17:46:41 -0700
Subject: Typescript prettier
Committing seperate so it's easier to see actual changes.
---
jb-ui/src/components/Wallet.tsx | 859 +++++++++++++++++++++-------------------
1 file changed, 443 insertions(+), 416 deletions(-)
(limited to 'jb-ui/src/components/Wallet.tsx')
diff --git a/jb-ui/src/components/Wallet.tsx b/jb-ui/src/components/Wallet.tsx
index e4fc694..933dc9a 100644
--- a/jb-ui/src/components/Wallet.tsx
+++ b/jb-ui/src/components/Wallet.tsx
@@ -1,464 +1,491 @@
import {
- UserLedgerTransactionsResponse,
- UserLedgerTransactionsResponseTransactionsInner,
- WalletApi
+ UserLedgerTransactionsResponse,
+ UserLedgerTransactionsResponseTransactionsInner,
+ WalletApi,
} from "@/api_fsb";
import { useAppDispatch, useAppSelector } from "@/hooks";
-import { bpid, formatCentsToUSD, } from "@/lib/utils";
+import { bpid, formatCentsToUSD } from "@/lib/utils";
import {
- setTxPagination, setTxTotalItems, setTxTotalPages,
- setUserLedgerSummary,
- setUserLedgerTxs
+ setTxPagination,
+ setTxTotalItems,
+ setTxTotalPages,
+ setUserLedgerSummary,
+ setUserLedgerTxs,
} from "@/models/appSlice";
import {
- RowData, createColumnHelper, flexRender, getCoreRowModel,
- useReactTable
+ RowData,
+ createColumnHelper,
+ flexRender,
+ getCoreRowModel,
+ useReactTable,
} from "@tanstack/react-table";
import moment from "moment";
import { useEffect, useState } from "react";
-declare module '@tanstack/react-table' {
- interface ColumnMeta {
- align?: 'left' | 'center' | 'right';
- }
+declare module "@tanstack/react-table" {
+ interface ColumnMeta {
+ align?: "left" | "center" | "right";
+ }
}
// Function to calculate background color based on balance
const getBackgroundColor = (balance: number | undefined): string => {
- if (balance === undefined || balance === null) return 'bg-blue-600';
-
- if (balance > 0) {
- return 'bg-blue-600';
- } else if (balance <= -100) {
- return 'bg-red-600';
- } else {
- // Interpolate between blue and red for values between 0 and -100
- // progress goes from 0 (at balance = 0) to 1 (at balance = -100)
- const progress = Math.abs(balance) / 100;
-
- // Blue RGB: (37, 99, 235) - Tailwind blue-600
- // Red RGB: (220, 38, 38) - Tailwind red-600
- const r = Math.round(37 + (220 - 37) * progress);
- const g = Math.round(99 + (38 - 99) * progress);
- const b = Math.round(235 + (38 - 235) * progress);
-
- return `rgb(${r}, ${g}, ${b})`;
- }
+ if (balance === undefined || balance === null) return "bg-blue-600";
+
+ if (balance > 0) {
+ return "bg-blue-600";
+ } else if (balance <= -100) {
+ return "bg-red-600";
+ } else {
+ // Interpolate between blue and red for values between 0 and -100
+ // progress goes from 0 (at balance = 0) to 1 (at balance = -100)
+ const progress = Math.abs(balance) / 100;
+
+ // Blue RGB: (37, 99, 235) - Tailwind blue-600
+ // Red RGB: (220, 38, 38) - Tailwind red-600
+ const r = Math.round(37 + (220 - 37) * progress);
+ const g = Math.round(99 + (38 - 99) * progress);
+ const b = Math.round(235 + (38 - 235) * progress);
+
+ return `rgb(${r}, ${g}, ${b})`;
+ }
};
-
const WalletHeader = () => {
- const amount = useAppSelector(state => state.app.userWalletBalance)?.amount ?? 0
-
- const bgStyle = typeof getBackgroundColor(amount) === 'string' &&
- getBackgroundColor(amount).startsWith('bg-')
- ? {}
- : { backgroundColor: getBackgroundColor(amount) };
-
- const bgClass = typeof getBackgroundColor(amount) === 'string' &&
- getBackgroundColor(amount).startsWith('bg-')
- ? getBackgroundColor(amount)
- : '';
-
- return (
-
-
- User Wallet:
-
- {amount >= 0 ? (
-
- {`${formatCentsToUSD(Math.abs(amount))}`}
-
- ) : (
-
- {`(${formatCentsToUSD(Math.abs(amount))})`}
-
- )}
-
-
-
- )
+ const amount =
+ useAppSelector((state) => state.app.userWalletBalance)?.amount ?? 0;
+
+ const bgStyle =
+ typeof getBackgroundColor(amount) === "string" &&
+ getBackgroundColor(amount).startsWith("bg-")
+ ? {}
+ : { backgroundColor: getBackgroundColor(amount) };
+
+ const bgClass =
+ typeof getBackgroundColor(amount) === "string" &&
+ getBackgroundColor(amount).startsWith("bg-")
+ ? getBackgroundColor(amount)
+ : "";
+
+ return (
+
+
+ User Wallet:
+
+ {amount >= 0 ? (
+
+ {`${formatCentsToUSD(Math.abs(amount))}`}
+
+ ) : (
+
+ {`(${formatCentsToUSD(Math.abs(amount))})`}
+
+ )}
+
+
+ );
};
const WalletSummary = () => {
- const summary = useAppSelector(state => state.app.userLedgerSummary)
-
- const survey_completes = summary?.bp_payment?.entry_count ?? 0
- const survey_completes_f = (survey_completes ?? 0).toLocaleString('en-US')
-
- const survey_adjustments = summary?.bp_adjustment?.entry_count ?? 0
- const survey_adjustments_f = (survey_adjustments ?? 0).toLocaleString('en-US')
-
- const min_payout: number = summary?.bp_payment?.min_amount ?? 0
- const max_payout: number = summary?.bp_payment?.max_amount ?? 0
- const adj_total: number = summary?.bp_adjustment?.total_amount ?? 0
- const user_payments_total: number = (summary?.user_payout_request?.total_amount ?? 0) * -1
-
- return (
-
-
Completes:
-
{survey_completes_f} surveys
-
-
Avg Payouts:
-
{formatCentsToUSD(min_payout)} – {formatCentsToUSD(max_payout)}
-
-
Survey Adjustments:
-
{survey_adjustments_f}
-
-
Adjustment Amount:
-
- {adj_total >= 0 ? (
-
- {`${formatCentsToUSD(adj_total)}`}
-
- ) : (
-
- {`(${formatCentsToUSD(Math.abs(adj_total))})`}
-
- )}
-
-
-
User Payments:
-
- {user_payments_total >= 0 ? (
-
- {`${formatCentsToUSD(user_payments_total)}`}
-
- ) : (
-
- {`(${formatCentsToUSD(Math.abs(user_payments_total))})`}
-
- )}
-
-
-
- )
+ const summary = useAppSelector((state) => state.app.userLedgerSummary);
+
+ const survey_completes = summary?.bp_payment?.entry_count ?? 0;
+ const survey_completes_f = (survey_completes ?? 0).toLocaleString("en-US");
+
+ const survey_adjustments = summary?.bp_adjustment?.entry_count ?? 0;
+ const survey_adjustments_f = (survey_adjustments ?? 0).toLocaleString(
+ "en-US",
+ );
+
+ const min_payout: number = summary?.bp_payment?.min_amount ?? 0;
+ const max_payout: number = summary?.bp_payment?.max_amount ?? 0;
+ const adj_total: number = summary?.bp_adjustment?.total_amount ?? 0;
+ const user_payments_total: number =
+ (summary?.user_payout_request?.total_amount ?? 0) * -1;
+
+ return (
+
+
Completes:
+
{survey_completes_f} surveys
+
+
Avg Payouts:
+
+ {formatCentsToUSD(min_payout)} – {formatCentsToUSD(max_payout)}
+
+
+
Survey Adjustments:
+
{survey_adjustments_f}
+
+
Adjustment Amount:
+
+ {adj_total >= 0 ? (
+
+ {`${formatCentsToUSD(adj_total)}`}
+
+ ) : (
+
+ {`(${formatCentsToUSD(Math.abs(adj_total))})`}
+
+ )}
+
+
+
User Payments:
+
+ {user_payments_total >= 0 ? (
+
+ {`${formatCentsToUSD(user_payments_total)}`}
+
+ ) : (
+
+ {`(${formatCentsToUSD(Math.abs(user_payments_total))})`}
+
+ )}
+
+
+ );
};
const WalletTransactionsHeader = () => {
- const tx_cnt = useAppSelector(state => state.app.txTotalItems)
- const txt_cnt_f = (tx_cnt ?? 0).toLocaleString('en-US')
-
- const [showTx, setShowTx] = useState(false);
-
- return (
-
-
setShowTx(!showTx)}>
-
-
+ setShowTx(!showTx)}
+ >
+
setShowTx(!showTx)}
- >
- Total Transactions: {txt_cnt_f}
-
-
- setShowTx(!showTx)}
- >
- (Click to {showTx ? 'hide' : 'show'})
-
-
-
-
- {showTx && (
- <>
-
- >
- )}
+ onClick={() => setShowTx(!showTx)}
+ >
+ Total Transactions: {txt_cnt_f}
+
-
- )
+
setShowTx(!showTx)}
+ >
+ (Click to {showTx ? "hide" : "show"})
+
+
+
+ {showTx && (
+ <>
+
+ >
+ )}
+
+ );
};
-
const WalletTransactions = () => {
- const dispatch = useAppDispatch()
- const bpuid = useAppSelector(state => state.app.bpuid)
- const userLedgerTxs = useAppSelector(state => state.app.userLedgerTxs);
-
- const txPagination = useAppSelector(state => state.app.txPagination);
- const txTotalPages = useAppSelector(state => state.app.txTotalPages);
-
- useEffect(() => {
- if (!bpuid) return;
-
- new WalletApi().getUserTransactionHistoryProductIdTransactionHistoryGet(
- bpid, // productId
- bpuid, // bpuid
- undefined, // createdAfter
- undefined, // createdBefore
- "-created", // orderBy
- txPagination.pageIndex + 1, // page
- txPagination.pageSize // pageSize
- ).then(res => {
- const response = res.data as UserLedgerTransactionsResponse;
- console.log("Wallet: fetched user ledger", response);
- dispatch(setUserLedgerSummary(response.summary));
-
- dispatch(setUserLedgerTxs(response.transactions ?? []))
- dispatch(setTxTotalItems(response.total!))
- dispatch(setTxTotalPages(response.pages!))
- });
-
- }, [bpuid, txPagination.pageIndex, txPagination.pageSize]);
-
- const columnHelper = createColumnHelper()
- const columns = [
- columnHelper.accessor('created', {
- header: () => 'Date',
- cell: (info) => moment(info.getValue()).format('M/D/YY H:mm'),
- size: 110,
- meta: {
- align: 'left'
- }
- }),
- columnHelper.accessor('description', {
- header: () => 'Type',
- cell: props => {
- const desc = props.getValue();
- switch (desc) {
- case 'Task Complete':
- return 'Survey 🎉';
- case 'Task Adjustment':
- return 'Reject ⚠️';
- case 'Compensation Bonus':
- return 'Bonus 🎁';
- case 'HIT Bonus':
- return 'Bonus';
- case 'HIT Reward':
- return 'Assignment';
- default:
- return desc;
- }
- },
- size: 80,
- meta: {
- align: 'left'
- }
- }),
- columnHelper.accessor('amount', {
- header: () => 'Amount',
- cell: (props) => {
- const val = props.renderValue() as number;
- const isPositive = val >= 0;
- const emoji = isPositive ? "⬆\uFE0E" : "⬇\uFE0E";
- const colorClass = isPositive ? 'font-variant-emoji-text text-emerald-300' : 'font-variant-emoji-text text-rose-300';
+ const dispatch = useAppDispatch();
+ const bpuid = useAppSelector((state) => state.app.bpuid);
+ const userLedgerTxs = useAppSelector((state) => state.app.userLedgerTxs);
+
+ const txPagination = useAppSelector((state) => state.app.txPagination);
+ const txTotalPages = useAppSelector((state) => state.app.txTotalPages);
+
+ useEffect(() => {
+ if (!bpuid) return;
+
+ new WalletApi()
+ .getUserTransactionHistoryProductIdTransactionHistoryGet(
+ bpid, // productId
+ bpuid, // bpuid
+ undefined, // createdAfter
+ undefined, // createdBefore
+ "-created", // orderBy
+ txPagination.pageIndex + 1, // page
+ txPagination.pageSize, // pageSize
+ )
+ .then((res) => {
+ const response = res.data as UserLedgerTransactionsResponse;
+ console.log("Wallet: fetched user ledger", response);
+ dispatch(setUserLedgerSummary(response.summary));
+
+ dispatch(setUserLedgerTxs(response.transactions ?? []));
+ dispatch(setTxTotalItems(response.total!));
+ dispatch(setTxTotalPages(response.pages!));
+ });
+ }, [bpuid, txPagination.pageIndex, txPagination.pageSize]);
+
+ const columnHelper =
+ createColumnHelper();
+ const columns = [
+ columnHelper.accessor("created", {
+ header: () => "Date",
+ cell: (info) => moment(info.getValue()).format("M/D/YY H:mm"),
+ size: 110,
+ meta: {
+ align: "left",
+ },
+ }),
+ columnHelper.accessor("description", {
+ header: () => "Type",
+ cell: (props) => {
+ const desc = props.getValue();
+ switch (desc) {
+ case "Task Complete":
+ return "Survey 🎉";
+ case "Task Adjustment":
+ return "Reject ⚠️";
+ case "Compensation Bonus":
+ return "Bonus 🎁";
+ case "HIT Bonus":
+ return "Bonus";
+ case "HIT Reward":
+ return "Assignment";
+ default:
+ return desc;
+ }
+ },
+ size: 80,
+ meta: {
+ align: "left",
+ },
+ }),
+ columnHelper.accessor("amount", {
+ header: () => "Amount",
+ cell: (props) => {
+ const val = props.renderValue() as number;
+ const isPositive = val >= 0;
+ const emoji = isPositive ? "⬆\uFE0E" : "⬇\uFE0E";
+ const colorClass = isPositive
+ ? "font-variant-emoji-text text-emerald-300"
+ : "font-variant-emoji-text text-rose-300";
+
+ return (
+
+ {`${emoji} ${formatCentsToUSD(Math.abs(val))}`}
+
+ );
+ },
+ size: 70,
+ meta: {
+ align: "center",
+ },
+ }),
+ columnHelper.accessor("balance_after", {
+ header: () => "Balance",
+ cell: (props) => {
+ const val = props.renderValue() as number;
+ const isPositive = val >= 0;
+ const colorClass = isPositive ? "text-emerald-300" : "text-rose-300";
+
+ return (
+ <>
+ {isPositive ? (
+
+ {`${formatCentsToUSD(Math.abs(val))}`}
+
+ ) : (
+
+ {`(${formatCentsToUSD(Math.abs(val))})`}
+
+ )}
+ >
+ );
+ },
+ size: 70,
+ meta: {
+ align: "center",
+ },
+ }),
+ ];
+
+ const table = useReactTable({
+ data: userLedgerTxs,
+ columns: columns,
+ getCoreRowModel: getCoreRowModel(),
+ manualPagination: true,
+ pageCount: txTotalPages,
+ onPaginationChange: (updater) => {
+ dispatch(
+ setTxPagination(
+ typeof updater === "function" ? updater(txPagination) : updater,
+ ),
+ );
+ },
+ state: {
+ pagination: txPagination,
+ },
+ });
+
+ return (
+
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => {
+ const align = header.column.columnDef.meta?.align || "left";
+ const alignClass =
+ align === "center"
+ ? "text-center"
+ : align === "right"
+ ? "text-right"
+ : "text-left";
return (
-
- {`${emoji} ${formatCentsToUSD(Math.abs(val))}`}
-
- )
- },
- size: 70,
- meta: {
- align: 'center'
- }
- }),
- columnHelper.accessor('balance_after', {
- header: () => 'Balance',
- cell: (props) => {
- const val = props.renderValue() as number;
- const isPositive = val >= 0;
- const colorClass = isPositive ? 'text-emerald-300' : 'text-rose-300';
+
+ {flexRender(
+ header.column.columnDef.header,
+ header.getContext(),
+ )}
+
+ );
+ })}
+
+ ))}
+
+
+ {table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => {
+ const align = cell.column.columnDef.meta?.align || "left";
+ const alignClass =
+ align === "center"
+ ? "text-center"
+ : align === "right"
+ ? "text-right"
+ : "text-left";
return (
- <>
- {isPositive ? (
-
- {`${formatCentsToUSD(Math.abs(val))}`}
-
- ) : (
-
- {`(${formatCentsToUSD(Math.abs(val))})`}
-
- )}
- >
- )
- },
- size: 70,
- meta: {
- align: 'center'
- }
- }),
- ]
-
- const table = useReactTable({
- 'data': userLedgerTxs,
- 'columns': columns,
- getCoreRowModel: getCoreRowModel(),
- manualPagination: true,
- pageCount: txTotalPages,
- onPaginationChange: (updater) => {
- dispatch(setTxPagination(
- typeof updater === 'function' ? updater(txPagination) : updater
- ));
- },
- state: {
- pagination: txPagination,
- },
- });
-
- return (
-
-
-
- {table.getHeaderGroups().map((headerGroup) => (
-
-
- {headerGroup.headers.map((header) => {
- const align = header.column.columnDef.meta?.align || 'left';
- const alignClass = align === 'center' ? 'text-center' : align === 'right' ? 'text-right' : 'text-left';
-
- return (
-
- {flexRender(
- header.column.columnDef.header,
- header.getContext(),
- )}
-
- )
- })}
-
- ))}
-
-
- {table.getRowModel().rows.map((row) => (
-
- {row.getVisibleCells().map((cell) => {
- const align = cell.column.columnDef.meta?.align || 'left';
- const alignClass = align === 'center' ? 'text-center' :
- align === 'right' ? 'text-right' : 'text-left';
-
- return (
-
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
-
- )
- })}
-
- ))}
-
-
-
-
-
-
-
- {/* Page info */}
-
- Page {table.getState().pagination.pageIndex + 1} of{' '}
- {table.getPageCount()}
-
-
- {/* Navigation buttons */}
-
- table.previousPage()}
- disabled={!table.getCanPreviousPage()}
- className="px-3 py-1 border border-blue-200 rounded
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ );
+ })}
+
+ ))}
+
+
+
+
+
+
+ {/* Page info */}
+
+ Page {table.getState().pagination.pageIndex + 1} of{" "}
+ {table.getPageCount()}
+
+
+ {/* Navigation buttons */}
+
+ table.previousPage()}
+ disabled={!table.getCanPreviousPage()}
+ className="px-3 py-1 border border-blue-200 rounded
font-variant-emoji-text
hover:cursor-pointer hover:bg-blue-700
disabled:opacity-50 disabled:cursor-not-allowed"
- >
- {'⬅\uFE0E'}
-
- table.nextPage()}
- disabled={!table.getCanNextPage()}
- className="px-3 py-1 border border-blue-200 rounded
+ >
+ {"⬅\uFE0E"}
+
+ table.nextPage()}
+ disabled={!table.getCanNextPage()}
+ className="px-3 py-1 border border-blue-200 rounded
font-variant-emoji-text
hover:cursor-pointer hover:bg-blue-700
disabled:opacity-50 disabled:cursor-not-allowed"
- >
- {'⮕\uFE0E'}
-
-
-
- {/* Page size selector */}
-
table.setPageSize(Number(e.target.value))}
- className="px-2 py-1 border border-blue-200 rounded
+ >
+ {"⮕\uFE0E"}
+
+
+
+ {/* Page size selector */}
+ table.setPageSize(Number(e.target.value))}
+ className="px-2 py-1 border border-blue-200 rounded
hover:cursor-pointer hover:bg-blue-700"
- >
- {[10, 20, 30, 40].map(pageSize => (
-
- Show {pageSize}
-
- ))}
-
-
-
-
-
-
-
-
- )
+ >
+ {[10, 20, 30, 40].map((pageSize) => (
+
+ Show {pageSize}
+
+ ))}
+
+
+
+
+
+
+
+ );
};
-
const Wallet = () => {
- const dispatch = useAppDispatch()
- const bpuid = useAppSelector(state => state.app.bpuid)
- const pagination = useAppSelector(state => state.app.txPagination);
-
- useEffect(() => {
- if (!bpuid) return;
-
- new WalletApi().getUserTransactionHistoryProductIdTransactionHistoryGet(
- bpid, // productId
- bpuid, // bpuid
- undefined, // createdAfter
- undefined, // createdBefore
- "-created", // orderBy
- pagination.pageIndex + 1, // page
- pagination.pageSize // pageSize
- ).then(res => {
- const response = res.data as UserLedgerTransactionsResponse;
- dispatch(setUserLedgerSummary(response.summary));
- dispatch(setUserLedgerTxs(response.transactions ?? []))
-
- dispatch(setTxPagination({
- pageIndex: (response.page ?? 1) - 1,
- pageSize: response.size ?? 10,
- }))
- dispatch(setTxTotalItems(response.total ?? 0))
- dispatch(setTxTotalPages(response.pages ?? 9))
- });
-
- }, [bpuid])
-
- if (!bpuid) return null;
-
- return (
- {
+ const response = res.data as UserLedgerTransactionsResponse;
+ dispatch(setUserLedgerSummary(response.summary));
+ dispatch(setUserLedgerTxs(response.transactions ?? []));
+
+ dispatch(
+ setTxPagination({
+ pageIndex: (response.page ?? 1) - 1,
+ pageSize: response.size ?? 10,
+ }),
+ );
+ dispatch(setTxTotalItems(response.total ?? 0));
+ dispatch(setTxTotalPages(response.pages ?? 9));
+ });
+ }, [bpuid]);
+
+ if (!bpuid) return null;
+
+ return (
+
-
-
-
-
- )
+ "
+ >
+
+
+
+
+ );
};
-
-export default Wallet;
\ No newline at end of file
+export default Wallet;
--
cgit v1.2.3
From f82ac61b6a044467ab37c0645c3fe99b40bedfc5 Mon Sep 17 00:00:00 2001
From: Max Nanis
Date: Fri, 11 Sep 2026 23:06:59 -0700
Subject: replace references to bpuid with logged in user
---
jb-ui/src/JBApp.tsx | 14 +++-----
jb-ui/src/components/Footer.tsx | 7 ++--
jb-ui/src/components/Profiling.tsx | 38 ++++++++++++--------
jb-ui/src/components/Wallet.tsx | 19 +++++-----
jb-ui/src/models/authAPI.ts | 3 +-
jb-ui/src/pages/Preview.tsx | 3 +-
jb-ui/src/pages/Transfer.tsx | 9 ++---
jb-ui/src/pages/Work.tsx | 71 +++++++++-----------------------------
jb-ui/src/types/authApi.ts | 6 ++++
9 files changed, 73 insertions(+), 97 deletions(-)
create mode 100644 jb-ui/src/types/authApi.ts
(limited to 'jb-ui/src/components/Wallet.tsx')
diff --git a/jb-ui/src/JBApp.tsx b/jb-ui/src/JBApp.tsx
index fd0eeba..a69cc85 100644
--- a/jb-ui/src/JBApp.tsx
+++ b/jb-ui/src/JBApp.tsx
@@ -16,6 +16,7 @@ import {
import Footer from "@/components/Footer";
import { useAppDispatch } from "@/hooks";
import { bpid, routeBasename, tagManager } from "@/lib/utils";
+import { useGetMeQuery } from "@/models/authAPI";
import {
setAssignmentID,
setProductUserID,
@@ -72,24 +73,19 @@ function isPingMessage(msg: Message): msg is PingMessage {
function QueryParamProcessor() {
const dispatch = useAppDispatch();
const [searchParams] = useSearchParams();
+ const { data: user, isLoading, isError } = useGetMeQuery();
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));
+ if (user?.product_user_id) {
+ dispatch(setProductUserID(user.product_user_id));
new WalletApi()
.getUserWalletBalanceProductIdWalletGet(
bpid, // productId
- worker_id, // bpuid
+ user.product_user_id,
)
.then((res) => {
const response = res.data as UserWalletBalanceResponse;
diff --git a/jb-ui/src/components/Footer.tsx b/jb-ui/src/components/Footer.tsx
index eede06c..ec458f2 100644
--- a/jb-ui/src/components/Footer.tsx
+++ b/jb-ui/src/components/Footer.tsx
@@ -1,8 +1,7 @@
-import { useAppSelector } from "@/hooks";
+import { useGetMeQuery } from "@/models/authAPI";
const Footer = () => {
- const bpuid = useAppSelector((state) => state.app.bpuid);
- const assignment_id = useAppSelector((state) => state.app.assignment_id);
+ const { data: user, isLoading, isError } = useGetMeQuery();
return (
{
help:{" "}
support@jamesbillings67.com
diff --git a/jb-ui/src/components/Profiling.tsx b/jb-ui/src/components/Profiling.tsx
index 96b06b2..23b8457 100644
--- a/jb-ui/src/components/Profiling.tsx
+++ b/jb-ui/src/components/Profiling.tsx
@@ -1,4 +1,5 @@
import { UpkQuestionChoice } from "@/api_fsb";
+import { useGetMeQuery } from "@/models/authAPI";
import { ChevronRightIcon } from "lucide-react";
import { KeyboardEvent, MouseEvent, useEffect, useRef, useState } from "react";
@@ -46,7 +47,7 @@ const TextEntry = () => {
// const selectAnswer = useSelector(selectAnswerForQuestion(question));
const metadata = activeQuestion?._metadata;
const validation = activeQuestion?._validation;
- const bpuid = useAppSelector((state) => state.app.bpuid);
+ const { data: user, isLoading, isError } = useGetMeQuery();
if (!metadata) return null;
if (!validation) return null;
@@ -67,11 +68,14 @@ const TextEntry = () => {
const handleKeyPress = (event: KeyboardEvent) => {
if (!activeQuestion.question_id) return;
- if (!bpuid) return;
+ if (!user?.product_user_id) return;
if (event.key === "Enter") {
dispatch(
- saveAnswer({ questionId: activeQuestion.question_id!, bpuid: bpuid }),
+ saveAnswer({
+ questionId: activeQuestion.question_id!,
+ bpuid: user.product_user_id,
+ }),
);
}
};
@@ -109,14 +113,14 @@ export default function useKeyboardMode(rowModel: RowModel) {
const dispatch = useAppDispatch();
const activeQuestion = useSelector(selectActiveQuestion);
- const bpuid = useAppSelector((state) => state.app.bpuid);
+ const { data: user, isLoading, isError } = useGetMeQuery();
const keyboardSelectionIdxRef = useRef(0);
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (!activeQuestion) return;
- if (!bpuid) return;
+ if (!user?.product_user_id) return;
// if (!keyboardEnabled) {
// return;
@@ -141,7 +145,10 @@ export default function useKeyboardMode(rowModel: RowModel) {
if (event.key === "Enter") {
dispatch(
- saveAnswer({ questionId: activeQuestion.question_id!, bpuid: bpuid }),
+ saveAnswer({
+ questionId: activeQuestion.question_id!,
+ bpuid: user.product_user_id,
+ }),
);
}
@@ -507,15 +514,18 @@ const ProfilingQuestionSubmitButton = () => {
const activeQuestion = useSelector(selectActiveQuestion);
const activeQuestionValidation = useSelector(selectActiveQuestionValidation);
- const bpuid = useAppSelector((state) => state.app.bpuid);
+ const { data: user, isLoading, isError } = useGetMeQuery();
const handleOnClick = () => {
if (!activeQuestion) return;
if (!activeQuestionValidation?.isComplete) return;
- if (!bpuid) return;
+ if (!user?.product_user_id) return;
dispatch(
- saveAnswer({ questionId: activeQuestion.question_id!, bpuid: bpuid }),
+ saveAnswer({
+ questionId: activeQuestion.question_id!,
+ bpuid: user.product_user_id,
+ }),
);
};
@@ -749,14 +759,14 @@ const Profiling = () => {
const [showProfiling, setShowProfiling] = useState(false);
const dispatch = useAppDispatch();
- const bpuid = useAppSelector((state) => state.app.bpuid);
+ const { data: user, isLoading, isError } = useGetMeQuery();
useEffect(() => {
- if (!bpuid) return;
- dispatch(fetchNewQuestions(bpuid));
- }, [bpid, bpuid]);
+ if (!user?.product_user_id) return;
+ dispatch(fetchNewQuestions(user.product_user_id));
+ }, [bpid, user?.product_user_id]);
- if (!bpuid) return null;
+ if (!user?.product_user_id) return null;
return (
{
const WalletTransactions = () => {
const dispatch = useAppDispatch();
- const bpuid = useAppSelector((state) => state.app.bpuid);
+ const { data: user, isLoading, isError } = useGetMeQuery();
const userLedgerTxs = useAppSelector((state) => state.app.userLedgerTxs);
const txPagination = useAppSelector((state) => state.app.txPagination);
const txTotalPages = useAppSelector((state) => state.app.txTotalPages);
useEffect(() => {
- if (!bpuid) return;
+ if (!user?.product_user_id) return;
new WalletApi()
.getUserTransactionHistoryProductIdTransactionHistoryGet(
bpid, // productId
- bpuid, // bpuid
+ user.product_user_id,
undefined, // createdAfter
undefined, // createdBefore
"-created", // orderBy
@@ -215,7 +216,7 @@ const WalletTransactions = () => {
dispatch(setTxTotalItems(response.total!));
dispatch(setTxTotalPages(response.pages!));
});
- }, [bpuid, txPagination.pageIndex, txPagination.pageSize]);
+ }, [user?.product_user_id, txPagination.pageIndex, txPagination.pageSize]);
const columnHelper =
createColumnHelper
();
@@ -438,16 +439,16 @@ const WalletTransactions = () => {
const Wallet = () => {
const dispatch = useAppDispatch();
- const bpuid = useAppSelector((state) => state.app.bpuid);
const pagination = useAppSelector((state) => state.app.txPagination);
+ const { data: user, isLoading, isError } = useGetMeQuery();
useEffect(() => {
- if (!bpuid) return;
+ if (!user?.product_user_id) return;
new WalletApi()
.getUserTransactionHistoryProductIdTransactionHistoryGet(
bpid, // productId
- bpuid, // bpuid
+ user.product_user_id,
undefined, // createdAfter
undefined, // createdBefore
"-created", // orderBy
@@ -468,9 +469,9 @@ const Wallet = () => {
dispatch(setTxTotalItems(response.total ?? 0));
dispatch(setTxTotalPages(response.pages ?? 9));
});
- }, [bpuid]);
+ }, [user?.product_user_id]);
- if (!bpuid) return null;
+ if (!user?.product_user_id) return null;
return (
({
- getMe: builder.query({
+ getMe: builder.query
({
query: () => "/session",
providesTags: ["User"],
}),
diff --git a/jb-ui/src/pages/Preview.tsx b/jb-ui/src/pages/Preview.tsx
index 6e50b0d..1926975 100644
--- a/jb-ui/src/pages/Preview.tsx
+++ b/jb-ui/src/pages/Preview.tsx
@@ -95,7 +95,6 @@ export const Leaderboards = () => {
const [payouts, setPayouts] = useState(null);
const [completes, setCompletes] = useState(null);
- // const bpuid = useAppSelector(state => state.app.bpuid)
const bpuid = undefined;
useEffect(() => {
@@ -105,7 +104,7 @@ export const Leaderboards = () => {
LeaderboardCode.CompleteCount,
frequency,
"us",
- bpuid, // bpuid
+ bpuid,
undefined, // within_time
10,
)
diff --git a/jb-ui/src/pages/Transfer.tsx b/jb-ui/src/pages/Transfer.tsx
index bef40d4..4192eee 100644
--- a/jb-ui/src/pages/Transfer.tsx
+++ b/jb-ui/src/pages/Transfer.tsx
@@ -1,5 +1,6 @@
import { type FormEvent, useState } from "react";
import { useAppDispatch, useAppSelector } from "@/hooks";
+import { useGetMeQuery } from "@/models/authAPI";
import { Button } from "@/components/ui/button";
import max_lulu from "./max-and-lulu.jpg";
@@ -43,7 +44,7 @@ type RequestState = "idle" | "working" | "sent" | "failed";
const TransferSubmit = function ({ onSubmitSuccess }) {
const [email, setEmail] = useState("");
const [state, setState] = useState("idle");
- const bpuid = useAppSelector((state) => state.app.bpuid);
+ const { data: user, isLoading, isError } = useGetMeQuery();
const submit = async (event: FormEvent) => {
event.preventDefault();
@@ -56,7 +57,7 @@ const TransferSubmit = function ({ onSubmitSuccess }) {
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: email,
- amt_worker_id: bpuid,
+ amt_worker_id: user?.product_user_id,
}),
});
@@ -132,10 +133,10 @@ 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 (!bpuid) {
+ if (!user?.product_user_id) {
return (
No Worker ID found. Please access this page through the Amazon
diff --git a/jb-ui/src/pages/Work.tsx b/jb-ui/src/pages/Work.tsx
index e33328e..84cb946 100644
--- a/jb-ui/src/pages/Work.tsx
+++ b/jb-ui/src/pages/Work.tsx
@@ -51,8 +51,7 @@ import Markdown from "react-markdown";
const Report = ({ onClose }: { onClose: () => void }) => {
const [showComplete, setShowComplete] = useState(false);
const [selectedValues, setSelectedValues] = useState([]);
-
- const bpuid = useAppSelector((state) => state.app.bpuid);
+ const { data: user, isLoading, isError } = useGetMeQuery();
const ts = useAppSelector((state) => state.app.taskStatus);
const handleCheckboxChange = (value: ReportValue, checked: boolean) => {
@@ -62,12 +61,12 @@ const Report = ({ onClose }: { onClose: () => void }) => {
};
const clicked_submit = () => {
- if (!bpuid) return;
+ if (!user?.product_user_id) return;
// ReportValue.NUMBER_0
console.log("selectedValues:", selectedValues);
const rt: ReportTask = {
- bpuid: bpuid,
+ bpuid: user.product_user_id,
reasons: selectedValues,
notes: "",
};
@@ -122,9 +121,10 @@ const Report = ({ onClose }: { onClose: () => void }) => {
return Please finish a Task to report its status.
;
}
- if (showComplete) {
- return ;
- }
+ // TODO! What do we do here, redirect back to / with a thank you + wallet refresh?
+ // if (showComplete) {
+ // return ;
+ // }
return (
@@ -189,43 +189,6 @@ const Report = ({ onClose }: { onClose: () => void }) => {
);
};
-const SubimtAMT = () => {
- const bpuid = useAppSelector((state) => state.app.bpuid);
- const assignment_id = useAppSelector((state) => state.app.assignment_id);
- const ts = useAppSelector((state) => state.app.taskStatus);
- const turkSubmitTo = useAppSelector((state) => state.app.turkSubmitTo);
-
- const formRef = useRef(null);
-
- useEffect(() => {
- if (!ts) return;
- if (!bpuid) return;
- if (!assignment_id) return;
- if (!turkSubmitTo) return;
-
- if (formRef.current) {
- formRef.current.submit();
- }
- }, [ts?.tsid, bpuid, assignment_id, turkSubmitTo]);
-
- return (
- <>
-
- >
- );
-};
-
const SurveyMonitor = () => {
const dispatch = useAppDispatch();
@@ -235,7 +198,7 @@ const SurveyMonitor = () => {
const [showComplete, setShowComplete] = useState(false);
const [showReport, setShowReport] = useState(false);
- const bpuid = useAppSelector((state) => state.app.bpuid);
+ const { data: user, isLoading, isError } = useGetMeQuery();
const entered = useAppSelector((state) => state.app.currentBucketEntered);
const isLow = useAppSelector((state) => isLowBalance(state));
@@ -263,7 +226,7 @@ const SurveyMonitor = () => {
// }, [ts]);
useEffect(() => {
- if (!bpuid) return;
+ if (!user?.product_user_id) return;
if (!entered) return;
if (!isPolling) return;
@@ -271,7 +234,7 @@ const SurveyMonitor = () => {
new StatusApi()
.listTaskStatusesProductIdStatusGet(
bpid, // productId
- bpuid, // Worker ID
+ user.product_user_id, // Worker ID
entered, // startedAfter
moment.utc().unix(), // startedBefore
)
@@ -418,8 +381,9 @@ const SurveyMonitor = () => {
Report Survey
-
- {showComplete && }
+ {/* TODO! What do we do here, redirect back to / with wallet */}
+ {/* TODO! refresh? The confetti is on a different page. */}
+ {/* {showComplete && } */}
{showReport && setShowReport(false)} />}
>
) : (
@@ -731,7 +695,7 @@ const BucketDetails = () => {
const SurveyEnter = () => {
const dispatch = useAppDispatch();
const loi = useAppSelector((state) => state.app.loi);
- const bpuid = useAppSelector((state) => state.app.bpuid);
+ const { data: user, isLoading, isError } = useGetMeQuery();
const available_cnt = useAppSelector((state) => getAvailabilityCount(state));
const buckets = useAppSelector((state) => state.app.currentBuckets);
@@ -739,12 +703,12 @@ const SurveyEnter = () => {
const isLow = useAppSelector((state) => isLowBalance(state));
useEffect(() => {
- if (!bpuid) return;
+ if (!user?.product_user_id) return;
new OfferwallApi()
.topNPlusBlockOfferwallProductIdOfferwallD48cce47Get(
bpid, // productId
- bpuid, // bpuid
+ user.product_user_id,
undefined, // ip
undefined, // countryIso
undefined, // languages
@@ -766,7 +730,7 @@ const SurveyEnter = () => {
dispatch(setCurrentBuckets(top_n_res.buckets));
dispatch(setOfferwallReasons(top_n_res.offerwall_reasons ?? []));
});
- }, [loi, bpuid]);
+ }, [loi, user?.product_user_id]);
const start_survey = () => {
if (!bucket?.uri) return;
@@ -834,7 +798,6 @@ type RequestState = "idle" | "working" | "sent" | "failed";
const Login = () => {
const [email, setEmail] = useState("");
const [state, setState] = useState("idle");
- const bpuid = useAppSelector((state) => state.app.bpuid);
// const dispatch = useAppDispatch();
const submit = async (event: FormEvent) => {
diff --git a/jb-ui/src/types/authApi.ts b/jb-ui/src/types/authApi.ts
new file mode 100644
index 0000000..19aeee0
--- /dev/null
+++ b/jb-ui/src/types/authApi.ts
@@ -0,0 +1,6 @@
+export interface User {
+ email: string;
+ display_name: string | null;
+ blocked: boolean;
+ product_user_id: string;
+}
--
cgit v1.2.3
From 83821dff9984fb950e53f23baf99d7a74fb88abd Mon Sep 17 00:00:00 2001
From: Max Nanis
Date: Sun, 13 Sep 2026 10:41:49 -0700
Subject: refrences to HIT removed. Still can't test. Basic CashoutMethod
retrival until backup updated. use of the new Wallets endpoint.
---
jb-ui/src/JBApp.tsx | 69 +++++++++++++++++++++++++++------
jb-ui/src/components/Redemption.tsx | 67 ++++++++++++++++++++++++++++++++
jb-ui/src/components/Wallet.tsx | 20 ++++++----
jb-ui/src/models/app.ts | 8 ++++
jb-ui/src/models/appSlice.ts | 30 ++++++++++++++
jb-ui/src/models/cashoutMethodsSlice.ts | 37 ++++++++++++++++++
jb-ui/src/pages/Preview.tsx | 8 ++--
jb-ui/src/pages/Result.tsx | 18 +++------
jb-ui/src/pages/Work.tsx | 33 +++++++---------
jb-ui/src/store.ts | 2 +
10 files changed, 239 insertions(+), 53 deletions(-)
create mode 100644 jb-ui/src/components/Redemption.tsx
create mode 100644 jb-ui/src/models/cashoutMethodsSlice.ts
(limited to 'jb-ui/src/components/Wallet.tsx')
diff --git a/jb-ui/src/JBApp.tsx b/jb-ui/src/JBApp.tsx
index 6c31164..4870e9b 100644
--- a/jb-ui/src/JBApp.tsx
+++ b/jb-ui/src/JBApp.tsx
@@ -11,7 +11,11 @@ import {
TaskStatusResponse,
UserWalletBalance,
UserWalletBalanceResponse,
+ UserLedgerWallets,
+ UserLedgerWalletAccountTypeEnum,
+ UserDisplayedWalletBalance,
WalletApi,
+ CashoutMethodsResponse,
} from "@/api_fsb";
import Footer from "@/components/Footer";
import { useAppDispatch } from "@/hooks";
@@ -20,8 +24,13 @@ import { useGetMeQuery } from "@/models/authAPI";
import {
setAssignmentID,
setProductUserID,
- setTurkSubmitTo,
+ 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";
@@ -50,6 +59,7 @@ 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
@@ -76,17 +86,16 @@ function QueryParamProcessor() {
const { data: user, isLoading, isError } = useGetMeQuery();
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));
+ new WalletApi()
+ .getCashoutMethodsProductIdCashoutMethodsGet(bpid, user.product_user_id)
+ .then((res) => {
+ const response = res.data as CashoutMethodsResponse;
+ dispatch(addCashoutMethods(response.cashout_methods));
+ });
+
new WalletApi()
.getUserWalletBalanceProductIdWalletGet(
bpid, // productId
@@ -97,6 +106,43 @@ function QueryParamProcessor() {
const balance = response.wallet as UserWalletBalance;
dispatch(setUserWalletBalance(balance));
});
+
+ new WalletApi()
+ .getUserWalletsProductIdWalletsGet(bpid, user.product_user_id)
+ .then((res) => {
+ const response = res.data as UserLedgerWallets;
+
+ if (response.displayed_balances) {
+ setUserDisplayedWalletBalance(response.displayed_balances[0]);
+ }
+
+ const userWallet = response.wallets?.find(
+ (w) =>
+ w.account_type === UserLedgerWalletAccountTypeEnum.UserWallet,
+ );
+ if (userWallet) {
+ setUserWallet(userWallet);
+ }
+
+ 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) {
@@ -125,8 +171,8 @@ function QueryParamProcessor() {
const Layout = () => {
const location = useLocation();
- const isWork = useMatch("/work*");
- const isPreview = useMatch("/preview*");
+ const isWork = useMatch("/work/*");
+ const isPreview = useMatch("/preview/*");
const isSpecialSubview = Boolean(isWork || isPreview);
return (
@@ -152,6 +198,7 @@ const Layout = () => {
>
+
diff --git a/jb-ui/src/components/Redemption.tsx b/jb-ui/src/components/Redemption.tsx
new file mode 100644
index 0000000..0a91ab3
--- /dev/null
+++ b/jb-ui/src/components/Redemption.tsx
@@ -0,0 +1,67 @@
+import { clsx } from "clsx";
+import { useAppDispatch, useAppSelector } from "@/hooks";
+import { UpkQuestionChoice } from "@/api_fsb";
+import { useGetMeQuery } from "@/models/authAPI";
+import { ChevronRightIcon } from "lucide-react";
+import { KeyboardEvent, MouseEvent, useEffect, useRef, useState } from "react";
+import { useSelector } from "react-redux";
+import { cashoutMethodsSelectors } from "@/models/cashoutMethodsSlice";
+
+const RedemptionHeader = () => {
+ const cashout_methods = useSelector(cashoutMethodsSelectors.selectAll);
+
+ return (
+ <>
+
+ {/* {cashout_methods.length} Redemption Methods */}
+ 30+ Redemption Methods
+
+ >
+ );
+};
+
+const RedemptionModalBody = () => {
+ return (
+
+
+ Paypal, Visa, Giftcards will be available. Finishing processing the
+ transfer from Amazon.
+
+
+ );
+};
+
+const Redemption = () => {
+ const dispatch = useAppDispatch();
+ const { data: user, isLoading, isError } = useGetMeQuery();
+ const [showRedemption, setShowRedemption] = useState(false);
+
+ return (
+
+
setShowRedemption(!showRedemption)}
+ >
+
+
+
+ {/* (Click to {showRedemption ? "hide" : "show"}) */}
+ Details within 24hr.
+
+
+
+ {showRedemption &&
}
+
+ );
+};
+
+export default Redemption;
diff --git a/jb-ui/src/components/Wallet.tsx b/jb-ui/src/components/Wallet.tsx
index 3f5c6a4..3bb23a9 100644
--- a/jb-ui/src/components/Wallet.tsx
+++ b/jb-ui/src/components/Wallet.tsx
@@ -54,7 +54,13 @@ const getBackgroundColor = (balance: number | undefined): string => {
const WalletHeader = () => {
const amount =
- useAppSelector((state) => state.app.userWalletBalance)?.amount ?? 0;
+ useAppSelector((state) => state.app.userDisplayedWalletBalance?.amount) ??
+ 0;
+
+ const amount_string =
+ useAppSelector(
+ (state) => state.app.userDisplayedWalletBalance?.amount_string,
+ ) ?? "$0.00";
const bgStyle =
typeof getBackgroundColor(amount) === "string" &&
@@ -77,13 +83,9 @@ const WalletHeader = () => {
User Wallet:
{amount >= 0 ? (
-
- {`${formatCentsToUSD(Math.abs(amount))}`}
-
+ {`${amount_string}`}
) : (
-
- {`(${formatCentsToUSD(Math.abs(amount))})`}
-
+ {`(${amount_string})`}
)}
@@ -93,6 +95,10 @@ const WalletHeader = () => {
const WalletSummary = () => {
const summary = useAppSelector((state) => state.app.userLedgerSummary);
+ const userWallet = useAppSelector((state) => state.app.userWallet);
+
+ userWallet;
+
const survey_completes = summary?.bp_payment?.entry_count ?? 0;
const survey_completes_f = (survey_completes ?? 0).toLocaleString("en-US");
diff --git a/jb-ui/src/models/app.ts b/jb-ui/src/models/app.ts
index 4c3e69e..db54e0d 100644
--- a/jb-ui/src/models/app.ts
+++ b/jb-ui/src/models/app.ts
@@ -5,6 +5,8 @@ import {
UserLedgerTransactionTypesSummary,
UserLedgerTransactionsResponseTransactionsInner,
OfferwallReason,
+ UserLedgerWallet,
+ UserDisplayedWalletBalance,
} from "@/api_fsb";
import { PaginationState } from "@tanstack/react-table";
@@ -33,6 +35,12 @@ export interface App {
userLedgerTxCount?: number;
userLedgerTxs: UserLedgerTransactionsResponseTransactionsInner[];
+ // --- new approach
+ userDisplayedWalletBalance?: UserDisplayedWalletBalance;
+ userWallet?: UserLedgerWallet;
+ userAttemptCreditWallet?: UserLedgerWallet;
+ // ---
+
txPagination: PaginationState;
txTotalItems?: number;
txTotalPages?: number;
diff --git a/jb-ui/src/models/appSlice.ts b/jb-ui/src/models/appSlice.ts
index 46c6a2f..42a776e 100644
--- a/jb-ui/src/models/appSlice.ts
+++ b/jb-ui/src/models/appSlice.ts
@@ -4,6 +4,8 @@ import {
UserLedgerTransactionsResponseTransactionsInner,
UserLedgerTransactionTypesSummary,
UserWalletBalance,
+ UserDisplayedWalletBalance,
+ UserLedgerWallet,
OfferwallReason,
} from "@/api_fsb";
import { App } from "@/models/app";
@@ -26,6 +28,12 @@ const initialState: App = {
userLedgerTxCount: undefined,
userLedgerTxs: [],
+ // --- new approach
+ userDisplayedWalletBalance: undefined,
+ userWallet: undefined,
+ userAttemptCreditWallet: undefined,
+ // ---
+
txPagination: { pageIndex: 0, pageSize: 10 },
txTotalItems: undefined,
txTotalPages: undefined,
@@ -91,6 +99,24 @@ const appSlice = createSlice({
state.userWalletBalance = action.payload;
},
+ // --- New approach ---
+ setUserDisplayedWalletBalance(
+ state,
+ action: PayloadAction,
+ ) {
+ state.userDisplayedWalletBalance = action.payload;
+ },
+
+ setUserWallet(state, action: PayloadAction) {
+ state.userWallet = action.payload;
+ },
+
+ setUserAttemptCreditWallet(state, action: PayloadAction) {
+ state.userAttemptCreditWallet = action.payload;
+ },
+
+ // --- ---
+
setUserLedgerSummary(
state,
action: PayloadAction,
@@ -138,6 +164,10 @@ export const {
setUserLedgerSummary,
setUserLedgerTxs,
+ setUserDisplayedWalletBalance,
+ setUserWallet,
+ setUserAttemptCreditWallet,
+
setTxPagination,
setTxTotalItems,
setTxTotalPages,
diff --git a/jb-ui/src/models/cashoutMethodsSlice.ts b/jb-ui/src/models/cashoutMethodsSlice.ts
new file mode 100644
index 0000000..92c03da
--- /dev/null
+++ b/jb-ui/src/models/cashoutMethodsSlice.ts
@@ -0,0 +1,37 @@
+import { CashoutMethodOut } from "@/api_fsb";
+import type { RootState } from "@/store";
+import { createSlice, createEntityAdapter } from "@reduxjs/toolkit";
+
+// Entity adapter for normalized storage
+const cashoutMethodsAdapter = createEntityAdapter({
+ selectId: (model: CashoutMethodOut) => model.id!,
+ sortComparer: (a, b) => {
+ return (b.min_value ?? 0) - (a.min_value ?? 0);
+ },
+});
+
+const cashoutMethodsSlice = createSlice({
+ name: "cashoutMethods",
+ initialState: cashoutMethodsAdapter.getInitialState(),
+
+ reducers: {
+ addCashoutMethod: cashoutMethodsAdapter.addOne,
+ addCashoutMethods: cashoutMethodsAdapter.addMany,
+ upsertCashoutMethod: cashoutMethodsAdapter.upsertOne, // Add or Update
+ },
+});
+
+export const { addCashoutMethod, addCashoutMethods, upsertCashoutMethod } =
+ cashoutMethodsSlice.actions;
+
+export const cashoutMethodsSelectors = cashoutMethodsAdapter.getSelectors(
+ (state: RootState) => state.cashoutMethods,
+);
+
+export const selectAllCashoutMethods = (
+ state: RootState,
+): CashoutMethodOut[] => {
+ return cashoutMethodsSelectors.selectAll(state) ?? [];
+};
+
+export default cashoutMethodsSlice.reducer;
diff --git a/jb-ui/src/pages/Preview.tsx b/jb-ui/src/pages/Preview.tsx
index 85e49f2..900621e 100644
--- a/jb-ui/src/pages/Preview.tsx
+++ b/jb-ui/src/pages/Preview.tsx
@@ -378,10 +378,10 @@ const Preview = () => {
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.
+ for. 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.
diff --git a/jb-ui/src/pages/Result.tsx b/jb-ui/src/pages/Result.tsx
index 477f77e..6385bc7 100644
--- a/jb-ui/src/pages/Result.tsx
+++ b/jb-ui/src/pages/Result.tsx
@@ -21,9 +21,7 @@ export const Complete = () => {
{ts?.user_payout_string}
-
- You may close this tab and return to submit the HIT
-
+ You may close this tab
>
);
};
@@ -35,9 +33,7 @@ export const Enter = () => {
You're currently in the Survey
-
- You may close this tab and return to submit the HIT
-
+ You may close this tab
>
);
};
@@ -50,13 +46,11 @@ export const InComplete = () => {
return (
<>
- HIT Complete
+ Attempt Complete
Survey terminated the attempt.
-
- You may close this tab and return to submit the HIT
-
+ You may close this tab
>
);
};
@@ -68,9 +62,7 @@ export const Unknown = () => {
You're not currently eligible for any Surveys
-
- You may close this tab and return to submit the HIT
-
+ You may close this tab
>
);
};
diff --git a/jb-ui/src/pages/Work.tsx b/jb-ui/src/pages/Work.tsx
index dbe3601..50ed930 100644
--- a/jb-ui/src/pages/Work.tsx
+++ b/jb-ui/src/pages/Work.tsx
@@ -1,4 +1,5 @@
import { useGetMeQuery } from "@/models/authAPI";
+import { Link } from "react-router-dom";
import {
BucketTask,
OfferwallApi,
@@ -183,7 +184,7 @@ const Report = ({ onClose }: { onClose: () => void }) => {
hover:cursor-pointer hover:bg-rose-400 hover:text-rose-50"
onClick={clicked_submit}
>
- Submit and Complete HIT
+ Submit and Complete Attempt
@@ -306,7 +307,7 @@ const SurveyMonitor = () => {
}
// This is if they have finished a survey complete and it resulted in a
- // COMPLETE or a INCOMPLETE (doesn't matter). They can now submit the HIT.
+ // COMPLETE or a INCOMPLETE (doesn't matter). They can now submit the Attempt.
//
// 2 - INCOMPLETE, 3 - COMPLETE
return (
@@ -326,7 +327,7 @@ const SurveyMonitor = () => {
py-2
text-zinc-500 text-md font-medium text-center"
>
- You may now submit the HIT.
+ You may now submit the attempt.
)}
@@ -351,7 +352,9 @@ const SurveyMonitor = () => {
pt-0 pb-4
text-red-950 text-sm font-semibold text-center"
>
- Please return the HIT to avoid having your assignment rejected.
+
+ Click to Refresh and Try Again
+
>
@@ -368,7 +371,7 @@ const SurveyMonitor = () => {
hover:cursor-pointer hover:bg-emerald-400 hover:text-emerald-50"
onClick={() => setShowComplete(true)}
>
- Submit HIT
+ Finish Attempt
{
className="
text-red-600 text-lg font-semibold text-center"
>
- Your balance is low. You cannot submit the HIT at this time.
-
-
-
- Please return the HIT to avoid having your assignment rejected.
+ Your balance is low.
)}
@@ -709,6 +704,8 @@ const SurveyEnter = () => {
new OfferwallApi()
.topNPlusBlockOfferwallProductIdOfferwallD48cce47Get(
bpid, // productId
+ // "7d9240132c695c05cd0ba47e2580158719f8215b",
+ // "71.225.51.26",
user.product_user_id,
undefined, // ip
undefined, // countryIso
@@ -760,12 +757,12 @@ const SurveyEnter = () => {
Your balance is low.
- You may continue to attempt surveys, but you will be advised to
- return the HIT if your survey attempt does not result in a complete.
+ You may continue to attempt surveys, but you will not earn an
+ attempt credit if your survey attempt does not result in a complete.
- HIT submissions with a balance exceeding -$1.00 will return in
- rejected assignments.
+ Attempts with a balance exceeding -$1.00 will not be issued an
+ attempt credit.
)}
diff --git a/jb-ui/src/store.ts b/jb-ui/src/store.ts
index baf13b7..081de9f 100644
--- a/jb-ui/src/store.ts
+++ b/jb-ui/src/store.ts
@@ -4,6 +4,7 @@ import grlEventsReducers from "@/models/grlEventsSlice";
import { authApi } from "@/models/authAPI";
import profilingQuestionsReducers from "@/models/profilingQuestionsSlice";
+import cashoutMethodReducers from "@/models/cashoutMethodsSlice";
import type { Action, ThunkAction } from "@reduxjs/toolkit";
import { configureStore } from "@reduxjs/toolkit";
@@ -15,6 +16,7 @@ export const store = configureStore({
stats: grlStatsReducers,
events: grlEventsReducers,
profilingQuestions: profilingQuestionsReducers,
+ cashoutMethods: cashoutMethodReducers,
},
middleware: (getDefault) => getDefault().concat(authApi.middleware),
});
--
cgit v1.2.3
From b464e311b44a5f3baeb1568ba55b6322a1a11638 Mon Sep 17 00:00:00 2001
From: Max Nanis
Date: Sun, 13 Sep 2026 11:43:52 -0700
Subject: Fix pnpm build error requirements
---
jb-ui/src/AuthContext.tsx | 28 ----------------------------
jb-ui/src/JBApp.tsx | 8 +-------
jb-ui/src/components/Footer.tsx | 2 +-
jb-ui/src/components/Profiling.tsx | 10 +++++-----
jb-ui/src/components/Redemption.tsx | 14 ++++----------
jb-ui/src/components/Wallet.tsx | 4 ++--
jb-ui/src/pages/Preview.tsx | 9 ++++++---
jb-ui/src/pages/Transfer.tsx | 11 +++++++----
jb-ui/src/pages/Work.tsx | 12 ++++++------
9 files changed, 32 insertions(+), 66 deletions(-)
delete mode 100644 jb-ui/src/AuthContext.tsx
(limited to 'jb-ui/src/components/Wallet.tsx')
diff --git a/jb-ui/src/AuthContext.tsx b/jb-ui/src/AuthContext.tsx
deleted file mode 100644
index 85bcdb0..0000000
--- a/jb-ui/src/AuthContext.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-// AuthContext.jsx
-import { createContext, useContext, useEffect, useState } from "react";
-
-const AuthContext = createContext(null);
-
-export function AuthProvider({ children }) {
- const [user, setUser] = useState(null);
- const [loading, setLoading] = useState(true);
-
- useEffect(() => {
- fetch("/api/me", { credentials: "include" })
- .then((res) => (res.ok ? res.json() : null))
- .then(setUser)
- .finally(() => setLoading(false));
- }, []);
-
- return (
-
- {children}
-
- );
-}
-
-export function useAuth() {
- return useContext(AuthContext);
-}
diff --git a/jb-ui/src/JBApp.tsx b/jb-ui/src/JBApp.tsx
index 4870e9b..c55cd73 100644
--- a/jb-ui/src/JBApp.tsx
+++ b/jb-ui/src/JBApp.tsx
@@ -13,7 +13,6 @@ import {
UserWalletBalanceResponse,
UserLedgerWallets,
UserLedgerWalletAccountTypeEnum,
- UserDisplayedWalletBalance,
WalletApi,
CashoutMethodsResponse,
} from "@/api_fsb";
@@ -33,9 +32,7 @@ import { addCashoutMethods } from "@/models/cashoutMethodsSlice";
import { addEvent } from "@/models/grlEventsSlice";
import { addStatsData } from "@/models/grlStatsSlice";
-import Home from "@/pages/Home";
import MagicLink from "@/pages/MagicLink";
-import Preview from "@/pages/Preview";
import Result from "@/pages/Result";
import clsx from "clsx";
@@ -44,7 +41,6 @@ import Transfer from "@/pages/Transfer";
import {
BrowserRouter,
Outlet,
- useLocation,
useMatch,
Route,
Routes,
@@ -83,7 +79,7 @@ function isPingMessage(msg: Message): msg is PingMessage {
function QueryParamProcessor() {
const dispatch = useAppDispatch();
const [searchParams] = useSearchParams();
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
useEffect(() => {
if (user?.product_user_id) {
@@ -169,8 +165,6 @@ function QueryParamProcessor() {
}
const Layout = () => {
- const location = useLocation();
-
const isWork = useMatch("/work/*");
const isPreview = useMatch("/preview/*");
const isSpecialSubview = Boolean(isWork || isPreview);
diff --git a/jb-ui/src/components/Footer.tsx b/jb-ui/src/components/Footer.tsx
index ec458f2..e65255f 100644
--- a/jb-ui/src/components/Footer.tsx
+++ b/jb-ui/src/components/Footer.tsx
@@ -1,7 +1,7 @@
import { useGetMeQuery } from "@/models/authAPI";
const Footer = () => {
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
return (
{
// const selectAnswer = useSelector(selectAnswerForQuestion(question));
const metadata = activeQuestion?._metadata;
const validation = activeQuestion?._validation;
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
if (!metadata) return null;
if (!validation) return null;
@@ -113,7 +113,7 @@ export default function useKeyboardMode(rowModel: RowModel) {
const dispatch = useAppDispatch();
const activeQuestion = useSelector(selectActiveQuestion);
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
const keyboardSelectionIdxRef = useRef(0);
@@ -514,7 +514,7 @@ const ProfilingQuestionSubmitButton = () => {
const activeQuestion = useSelector(selectActiveQuestion);
const activeQuestionValidation = useSelector(selectActiveQuestionValidation);
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
const handleOnClick = () => {
if (!activeQuestion) return;
@@ -759,7 +759,7 @@ const Profiling = () => {
const [showProfiling, setShowProfiling] = useState(false);
const dispatch = useAppDispatch();
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
useEffect(() => {
if (!user?.product_user_id) return;
diff --git a/jb-ui/src/components/Redemption.tsx b/jb-ui/src/components/Redemption.tsx
index 0a91ab3..1d76f17 100644
--- a/jb-ui/src/components/Redemption.tsx
+++ b/jb-ui/src/components/Redemption.tsx
@@ -1,14 +1,10 @@
import { clsx } from "clsx";
-import { useAppDispatch, useAppSelector } from "@/hooks";
-import { UpkQuestionChoice } from "@/api_fsb";
-import { useGetMeQuery } from "@/models/authAPI";
-import { ChevronRightIcon } from "lucide-react";
-import { KeyboardEvent, MouseEvent, useEffect, useRef, useState } from "react";
-import { useSelector } from "react-redux";
-import { cashoutMethodsSelectors } from "@/models/cashoutMethodsSlice";
+import { useState } from "react";
+// import { useSelector } from "react-redux";
+// import { cashoutMethodsSelectors } from "@/models/cashoutMethodsSlice";
const RedemptionHeader = () => {
- const cashout_methods = useSelector(cashoutMethodsSelectors.selectAll);
+ // const cashout_methods = useSelector(cashoutMethodsSelectors.selectAll);
return (
<>
@@ -32,8 +28,6 @@ const RedemptionModalBody = () => {
};
const Redemption = () => {
- const dispatch = useAppDispatch();
- const { data: user, isLoading, isError } = useGetMeQuery();
const [showRedemption, setShowRedemption] = useState(false);
return (
diff --git a/jb-ui/src/components/Wallet.tsx b/jb-ui/src/components/Wallet.tsx
index 3bb23a9..819eff7 100644
--- a/jb-ui/src/components/Wallet.tsx
+++ b/jb-ui/src/components/Wallet.tsx
@@ -194,7 +194,7 @@ const WalletTransactionsHeader = () => {
const WalletTransactions = () => {
const dispatch = useAppDispatch();
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
const userLedgerTxs = useAppSelector((state) => state.app.userLedgerTxs);
const txPagination = useAppSelector((state) => state.app.txPagination);
@@ -446,7 +446,7 @@ const WalletTransactions = () => {
const Wallet = () => {
const dispatch = useAppDispatch();
const pagination = useAppSelector((state) => state.app.txPagination);
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
useEffect(() => {
if (!user?.product_user_id) return;
diff --git a/jb-ui/src/pages/Preview.tsx b/jb-ui/src/pages/Preview.tsx
index 900621e..c58a85e 100644
--- a/jb-ui/src/pages/Preview.tsx
+++ b/jb-ui/src/pages/Preview.tsx
@@ -5,13 +5,12 @@ 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";
import { clsx } from "clsx";
import moment from "moment";
-import { useEffect, useState } from "react";
+import { FormEvent, useEffect, useState } from "react";
const showSmartRank = (
item: LeaderboardRow,
@@ -247,7 +246,11 @@ export const Leaderboards = () => {
type RequestState = "idle" | "working" | "failed";
-const LoginForm = function ({ onSubmitSuccess }) {
+interface LoginFormProps {
+ onSubmitSuccess: () => void;
+}
+
+const LoginForm = function ({ onSubmitSuccess }: LoginFormProps) {
const [email, setEmail] = useState("");
const [state, setState] = useState("idle");
diff --git a/jb-ui/src/pages/Transfer.tsx b/jb-ui/src/pages/Transfer.tsx
index 0d174c1..8079da2 100644
--- a/jb-ui/src/pages/Transfer.tsx
+++ b/jb-ui/src/pages/Transfer.tsx
@@ -1,5 +1,5 @@
import { type FormEvent, useState } from "react";
-import { useAppDispatch, useAppSelector } from "@/hooks";
+import { useAppSelector } from "@/hooks";
import { useGetMeQuery } from "@/models/authAPI";
import { Button } from "@/components/ui/button";
import max_lulu from "./max-and-lulu.jpg";
@@ -41,10 +41,14 @@ const TransferComplete = function () {
type RequestState = "idle" | "working" | "sent" | "failed";
-const TransferSubmit = function ({ onSubmitSuccess }) {
+interface TransferSubmitProps {
+ onSubmitSuccess: () => void;
+}
+
+const TransferSubmit = function ({ onSubmitSuccess }: TransferSubmitProps) {
const [email, setEmail] = useState("");
const [state, setState] = useState("idle");
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
const submit = async (event: FormEvent) => {
event.preventDefault();
@@ -133,7 +137,6 @@ const TransferSubmit = function ({ onSubmitSuccess }) {
const Transfer = function () {
const bpuid = useAppSelector((state) => state.app.bpuid);
- const { data: user, isLoading, isError } = useGetMeQuery();
const [submitted, setSubmitted] = useState(false);
if (!bpuid) {
diff --git a/jb-ui/src/pages/Work.tsx b/jb-ui/src/pages/Work.tsx
index 50ed930..6d0b1c1 100644
--- a/jb-ui/src/pages/Work.tsx
+++ b/jb-ui/src/pages/Work.tsx
@@ -47,13 +47,13 @@ import {
} from "@tanstack/react-table";
import { XIcon } from "lucide-react";
import moment from "moment/moment";
-import { useEffect, useRef, useState } from "react";
+import { useEffect, useState } from "react";
import Markdown from "react-markdown";
const Report = ({ onClose }: { onClose: () => void }) => {
- const [showComplete, setShowComplete] = useState(false);
+ const [, setShowComplete] = useState(false);
const [selectedValues, setSelectedValues] = useState([]);
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
const ts = useAppSelector((state) => state.app.taskStatus);
const handleCheckboxChange = (value: ReportValue, checked: boolean) => {
@@ -197,10 +197,10 @@ const SurveyMonitor = () => {
const [isPolling, setIsPolling] = useState(true);
// const [timeAgo, setTimeAgo] = useState("");
- const [showComplete, setShowComplete] = useState(false);
+ const [, setShowComplete] = useState(false);
const [showReport, setShowReport] = useState(false);
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
const entered = useAppSelector((state) => state.app.currentBucketEntered);
const isLow = useAppSelector((state) => isLowBalance(state));
@@ -691,7 +691,7 @@ const BucketDetails = () => {
const SurveyEnter = () => {
const dispatch = useAppDispatch();
const loi = useAppSelector((state) => state.app.loi);
- const { data: user, isLoading, isError } = useGetMeQuery();
+ const { data: user } = useGetMeQuery();
const available_cnt = useAppSelector((state) => getAvailabilityCount(state));
const buckets = useAppSelector((state) => state.app.currentBuckets);
--
cgit v1.2.3