Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(app/worker/profile/hcaptcha-labeling): add labeling page #119

Merged
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
8b031e2
feat(app/worker/profile/hcaptcha-labeling): add labeling page
KacperKoza343 Jun 6, 2024
8645227
fix(app/layout): fix layout
KacperKoza343 Jun 7, 2024
aa07544
feat(app/worker/hcaptcha-labeling): update hcaptcha labeling
KacperKoza343 Jun 17, 2024
7465531
Merge branch 'feature/human-app-frontend' into HAF-37-wfc-page-h-capt…
KacperKoza343 Jun 17, 2024
b53c822
feat(app/worker/hcaptcha): add servces
KacperKoza343 Jun 17, 2024
e8d77d0
feat(app/worker/hcaptcha): add props
KacperKoza343 Jun 17, 2024
3c2d664
feat(app/worker): update services
KacperKoza343 Jun 17, 2024
7b80491
fix(app): layout
KacperKoza343 Jun 17, 2024
1a859a6
feat(app/worker/auth): add updating JWT payload
KacperKoza343 Jun 17, 2024
6e0f4ac
feat(app/worker/auth): update signout
KacperKoza343 Jun 18, 2024
e7fdf86
fix(app/worker/stats): fix user stats details
KacperKoza343 Jun 18, 2024
5739b71
feat(app/worker/labeling): fix stats, labaling page reload and hard r…
KacperKoza343 Jun 19, 2024
a0c2ab8
fix(app/worker/labeling): fix copy
KacperKoza343 Jun 19, 2024
f30c99c
Merge pull request #130 from blockydevs/feat/add-extending-user-data
MicDebBlocky Jun 19, 2024
6374ecd
Merge pull request #133 from blockydevs/feat/update-labeling
MicDebBlocky Jun 19, 2024
90ba3a8
refactor(app/worker/labeling): fix axxroding to review
KacperKoza343 Jun 19, 2024
715bedc
Merge branch 'HAF-37-wfc-page-h-captcha-labeling' of https://github.c…
KacperKoza343 Jun 19, 2024
3253125
refactor(app/woreker/profile/labling): refactor according to review
KacperKoza343 Jun 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/apps/human-app/frontend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ VITE_TERMS_OF_SERVICE_URL=https://humanprotocol.org/app/terms-and-conditions/
VITE_HUMAN_PROTOCOL_HELP_URL=https://humanprotocol.org/
VITE_HUMAN_PROTOCOL_URL=https://app.humanprotocol.org/
VITE_H_CAPTCHA_SITE_KEY=key
VITE_HMT_DAILY_SPENT_LIMIT=22
VITE_DAILY_SOLVED_CAPTCHA_LIMIT=22
VITE_H_CAPTCHA_EXCHANGE_URL=https://foundation-exchange.hmt.ai
VITE_H_CAPTCHA_LABELING_BASE_URL=https://foundation-accounts.hmt.ai
VITE_SYNAPS_KEY=key
VITE_WALLET_CONNECT_PROJECT_ID=key
VITE_DAPP_META_NAME=Human App
Expand Down
2 changes: 1 addition & 1 deletion packages/apps/human-app/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@fontsource/inter": "^5.0.17",
"@hcaptcha/react-hcaptcha": "^1.10.1",
"@hcaptcha/react-hcaptcha": "^0.3.6",
"@hookform/resolvers": "^3.3.4",
"@mui/icons-material": "^5.15.7",
"@mui/material": "^5.15.7",
Expand Down
4 changes: 4 additions & 0 deletions packages/apps/human-app/frontend/src/api/api-paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export const apiPaths = {
registerAddress: {
path: '/user/register-address',
},
enableHCaptchaLabeling: '/labeling/h-captcha/enable',
verifyHCaptchaLabeling: '/labeling/h-captcha/verify',
hCaptchaUserStats: '/labeling/h-captcha/user-stats',
dailyHmtSpend: '/labeling/h-captcha/daily-hmt-spent',
},
operator: {
web3Auth: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { z } from 'zod';
import { useQuery } from '@tanstack/react-query';
import { apiPaths } from '@/api/api-paths';
import { apiClient } from '@/api/api-client';

const dailyHmtSpentSchema = z.object({
spend: z.number(),
});

export type DailyHmtSpentSchemaSuccess = z.infer<typeof dailyHmtSpentSchema>;

export async function getDailyHmtSpent() {
return apiClient(apiPaths.worker.dailyHmtSpend, {
successSchema: dailyHmtSpentSchema,
authenticated: true,
options: { method: 'GET' },
});
}

export function useDailyHmtSpent() {
return useQuery({
queryFn: getDailyHmtSpent,
queryKey: ['getDailyHmtSpent'],
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* eslint-disable camelcase -- ...*/
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom';
import { z } from 'zod';
import { routerPaths } from '@/router/router-paths';
import { apiClient } from '@/api/api-client';
import { apiPaths } from '@/api/api-paths';

const enableHCaptchaLabelingSuccessSchema = z.object({
site_key: z.string(),
});

export type EnableHCaptchaLabelingSuccessResponse = z.infer<
typeof enableHCaptchaLabelingSuccessSchema
>;

async function enableHCaptchaLabeling() {
return apiClient(apiPaths.worker.enableHCaptchaLabeling, {
successSchema: enableHCaptchaLabelingSuccessSchema,
authenticated: true,
options: { method: 'POST' },
});
}

export function useEnableHCaptchaLabelingMutation() {
const queryClient = useQueryClient();
const navigate = useNavigate();

return useMutation({
mutationFn: enableHCaptchaLabeling,
onSuccess: async () => {
navigate(routerPaths.worker.HcaptchaLabeling);
await queryClient.invalidateQueries();
},
onError: async () => {
await queryClient.invalidateQueries();
},
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { z } from 'zod';
import { useQuery } from '@tanstack/react-query';
import { apiPaths } from '@/api/api-paths';
import { apiClient } from '@/api/api-client';

const hcaptchaUserStatsSchema = z.object({
balance: z.object({
available: z.number(),
estimated: z.number(),
recent: z.number(),
total: z.number(),
}),
served: z.number(),
solved: z.number(),
verified: z.number(),
// TODO verify response
currentDateStats: z.object({
served: z.number().optional(),
solved: z.number().optional(),
verified: z.number().optional(),
}),
// TODO verify response
currentEarningsStats: z.object({
hmtEarned: z.number().optional(),
}),
});

export type HCaptchaUserStatsSuccess = z.infer<typeof hcaptchaUserStatsSchema>;

export async function getHCaptchaUsersStats() {
return apiClient(apiPaths.worker.hCaptchaUserStats, {
authenticated: true,
successSchema: hcaptchaUserStatsSchema,
options: { method: 'GET' },
});
}

export function useHCaptchaUserStats() {
return useQuery({
queryFn: getHCaptchaUsersStats,
queryKey: ['getHCaptchaUsersStats'],
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { z } from 'zod';
import { apiClient } from '@/api/api-client';
import { apiPaths } from '@/api/api-paths';
import type { ResponseError } from '@/shared/types/global.type';

function solveHCaptcha({ token }: { token: string }) {
return apiClient(apiPaths.worker.verifyHCaptchaLabeling, {
successSchema: z.unknown(),
authenticated: true,
options: { method: 'POST', body: JSON.stringify({ token }) },
});
}

export function useSolveHCaptchaMutation(callbacks?: {
onSuccess?: (() => void) | (() => Promise<void>);
onError?:
| ((error: ResponseError) => void)
| ((error: ResponseError) => Promise<void>);
}) {
const queryClient = useQueryClient();

return useMutation({
mutationFn: solveHCaptcha,
onSuccess: async () => {
if (callbacks?.onSuccess) {
await callbacks.onSuccess();
}
await queryClient.invalidateQueries();
},
onError: async (error) => {
if (callbacks?.onError) {
await callbacks.onError(error);
}
await queryClient.invalidateQueries();
},
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function RequireWalletConnect({ children }: { children: JSX.Element }) {
const location = useLocation();

if (walletConnect.initializing) {
return <PageCardLoader />;
return <PageCardLoader cardMaxWidth="100%" />;
}

if (!walletConnect.isConnected) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function RequireWeb3Auth({ children }: { children: JSX.Element }) {
const location = useLocation();

if (web3Auth.status === 'loading') {
return <PageCardLoader />;
return <PageCardLoader cardMaxWidth="100%" />;
}

if (!web3Auth.user) {
Expand Down
7 changes: 2 additions & 5 deletions packages/apps/human-app/frontend/src/auth/auth-context.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable camelcase -- ... */
import { useState, createContext, useEffect } from 'react';
import { jwtDecode } from 'jwt-decode';
import { z } from 'zod';
Expand All @@ -7,14 +8,10 @@ import { browserAuthProvider } from '@/shared/helpers/browser-auth-provider';
const userDataSchema = z.object({
email: z.string(),
userId: z.number(),
site_key: z.string().optional().nullable(),
address: z.string().nullable(),
// eslint-disable-next-line camelcase -- camel case defined by api
reputation_network: z.string(),
// eslint-disable-next-line camelcase -- camel case defined by api
kyc_status: z.string().optional().nullable(),
// eslint-disable-next-line camelcase -- camel case defined by api
kyc_added_on_chain: z.boolean().optional(), // TODO that should be verified when adding KYC info on chain feature is done
// eslint-disable-next-line camelcase -- camel case defined by api
email_notifications: z.boolean().optional(), // TODO that should be verified when email notifications feature is done
});

Expand Down
2 changes: 1 addition & 1 deletion packages/apps/human-app/frontend/src/auth/require-auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function RequireAuth({ children }: { children: JSX.Element }) {
const location = useLocation();

if (auth.status === 'loading') {
return <PageCardLoader />;
return <PageCardLoader cardMaxWidth="100%" />;
}

if (!auth.user) {
Expand Down
11 changes: 0 additions & 11 deletions packages/apps/human-app/frontend/src/components/h-captcha.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,8 @@ interface CaptchaProps {
export function Captcha({ setCaptchaToken }: CaptchaProps) {
const captchaRef = useRef<HCaptcha>(null);

const onLoad = () => {
// this reaches out to the hCaptcha JS API and runs the
// execute function on it. you can use other functions as
// documented here:
// https://docs.hcaptcha.com/configuration#jsapi
if (captchaRef.current) {
captchaRef.current.execute();
}
};

return (
<HCaptcha
onLoad={onLoad}
onVerify={setCaptchaToken}
ref={captchaRef}
sitekey={env.VITE_H_CAPTCHA_SITE_KEY}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ export const workerDrawerTopMenuItems: TopMenuItem[] = [
{t('components.DrawerNavigation.jobs')}
</Typography>
</Grid>,
{ label: t('components.DrawerNavigation.captchaLabelling') },
{
label: t('components.DrawerNavigation.captchaLabelling'),
link: routerPaths.worker.enableLabeler,
},
{
label: t('components.DrawerNavigation.jobsDiscovery'),
link: routerPaths.worker.jobsDiscovery,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { breakpoints } from '@/styles/theme';
import { TopNotification } from '@/components/ui/top-notification';
import type { TopNotificationPayload } from '@/components/layout/protected/layout-notification-context';
import { ProtectedLayoutContext } from '@/components/layout/protected/layout-notification-context';
import { useIsHCaptchaLabelingPage } from '@/hooks/use-is-hcaptcha-labeling-page';
import { Footer } from '../footer';
import { Navbar } from './navbar';

Expand All @@ -20,6 +21,7 @@ const Main = styled('main', {
isMobile?: boolean;
}>(({ theme, open, isMobile }) => ({
width: '100%',
display: 'flex',
flex: '1',
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
Expand All @@ -37,20 +39,31 @@ const Main = styled('main', {
export function Layout({
pageHeaderProps,
renderDrawer,
renderHCaptchaStatisticsDrawer,
}: {
pageHeaderProps: PageHeaderProps;
renderDrawer: (open: boolean) => JSX.Element;
renderHCaptchaStatisticsDrawer?: (isOpen: boolean) => JSX.Element;
}) {
const isHCaptchaLabelingPage = useIsHCaptchaLabelingPage();
const [notification, setNotification] =
useState<TopNotificationPayload | null>(null);
const isMobile = useIsMobile();
const [drawerOpen, setDrawerOpen] = useState(!isMobile);
const [hcaptchaDrawerOpen, setHcaptchaDrawerOpen] = useState(false);
const { backgroundColor } = useBackgroundColorStore();
const toggleUserStatsDrawer = isHCaptchaLabelingPage
? () => {
setHcaptchaDrawerOpen((state) => !state);
}
: undefined;

useEffect(() => {
if (isMobile) {
setHcaptchaDrawerOpen(false);
setDrawerOpen(false);
} else {
setHcaptchaDrawerOpen(false);
setDrawerOpen(true);
}
}, [isMobile]);
Expand Down Expand Up @@ -84,8 +97,16 @@ export function Layout({
backgroundColor,
}}
>
<Navbar open={drawerOpen} setOpen={setDrawerOpen} />
<Navbar
open={drawerOpen}
setOpen={setDrawerOpen}
toggleUserStatsDrawer={toggleUserStatsDrawer}
userStatsDrawerOpen={hcaptchaDrawerOpen}
/>
{renderDrawer(drawerOpen)}
{isHCaptchaLabelingPage && renderHCaptchaStatisticsDrawer
? renderHCaptchaStatisticsDrawer(hcaptchaDrawerOpen)
: null}
<Main isMobile={isMobile} open={drawerOpen}>
<Grid
container
Expand All @@ -95,6 +116,7 @@ export function Layout({
gap: '2rem',
flexDirection: 'column',
padding: '0 2rem',
flexWrap: 'nowrap',
[breakpoints.mobile]: {
gap: '1rem',
padding: '0 1rem',
Expand Down Expand Up @@ -125,7 +147,9 @@ export function Layout({
<Grid item>
<PageHeader {...pageHeaderProps} />
</Grid>
<Outlet />
<Grid sx={{ height: '100%' }}>
<Outlet />
</Grid>
</Grid>
</Main>
<Footer isProtected />
Expand Down
Loading
Loading