Skip to content

Commit 63fd4dd

Browse files
[HUMAN App] refactor: oracle registration page (#3014)
1 parent 1b7d81f commit 63fd4dd

File tree

12 files changed

+223
-147
lines changed

12 files changed

+223
-147
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './use-oracle-registration-flow';
2+
export * from './use-is-already-registered';
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { useRegisteredOracles } from '@/shared/contexts/registered-oracles';
2+
3+
export const useIsAlreadyRegistered = (address: string | undefined) => {
4+
const { registeredOracles } = useRegisteredOracles();
5+
6+
return Boolean(address && registeredOracles?.includes(address));
7+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { useState, useCallback } from 'react';
2+
3+
export function useOracleInstructions(
4+
instructions?: string | URL | null | undefined
5+
) {
6+
const [hasViewedInstructions, setHasViewedInstructions] = useState(false);
7+
8+
const handleInstructionsView = useCallback(() => {
9+
window.open(instructions ?? '', '_blank');
10+
setHasViewedInstructions(true);
11+
}, [instructions]);
12+
13+
return { hasViewedInstructions, handleInstructionsView };
14+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { useOracleInstructions } from './use-oracle-instructions';
2+
import { useOracleRegistration } from './use-oracle-registration';
3+
4+
export function useOracleRegistrationFlow(
5+
address: string,
6+
oracleInstructions?: string | URL | null | undefined
7+
) {
8+
const { handleRegistration, isRegistrationPending, registrationError } =
9+
useOracleRegistration(address);
10+
11+
const { hasViewedInstructions, handleInstructionsView } =
12+
useOracleInstructions(oracleInstructions);
13+
14+
return {
15+
hasViewedInstructions,
16+
handleInstructionsView,
17+
handleRegistration,
18+
isRegistrationPending,
19+
registrationError,
20+
};
21+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useCallback } from 'react';
2+
import {
3+
type RegistrationInExchangeOracleDto,
4+
useExchangeOracleRegistrationMutation,
5+
} from '@/modules/worker/oracle-registration/sevices';
6+
import { useRegisteredOracles } from '@/shared/contexts/registered-oracles';
7+
8+
export function useOracleRegistration(oracleAddress: string | undefined) {
9+
const { setRegisteredOracles } = useRegisteredOracles();
10+
const {
11+
mutate: registerInOracle,
12+
isPending: isRegistrationPending,
13+
error: registrationError,
14+
} = useExchangeOracleRegistrationMutation();
15+
16+
const handleRegistration = useCallback(
17+
(data: RegistrationInExchangeOracleDto) => {
18+
registerInOracle(data, {
19+
onSuccess() {
20+
if (oracleAddress) {
21+
setRegisteredOracles((prev) =>
22+
prev ? [...prev, oracleAddress] : [oracleAddress]
23+
);
24+
}
25+
},
26+
});
27+
},
28+
[oracleAddress, registerInOracle, setRegisteredOracles]
29+
);
30+
31+
return {
32+
handleRegistration,
33+
isRegistrationPending,
34+
registrationError,
35+
};
36+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './registration.page';
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { Box, Stack } from '@mui/material';
2+
import { FormProvider, useForm } from 'react-hook-form';
3+
import { useTranslation } from 'react-i18next';
4+
import { zodResolver } from '@hookform/resolvers/zod';
5+
import { Button } from '@/shared/components/ui/button';
6+
import { HCaptchaForm } from '@/shared/components/hcaptcha/h-captcha-form';
7+
import {
8+
registrationInExchangeOracleDtoSchema,
9+
type RegistrationInExchangeOracleDto,
10+
} from './sevices';
11+
import { useOracleRegistrationFlow } from './hooks';
12+
13+
function useRegistrationForm(address: string) {
14+
return useForm<RegistrationInExchangeOracleDto>({
15+
defaultValues: {
16+
// eslint-disable-next-line camelcase
17+
oracle_address: address,
18+
// eslint-disable-next-line camelcase
19+
h_captcha_token: '',
20+
},
21+
resolver: zodResolver(registrationInExchangeOracleDtoSchema),
22+
});
23+
}
24+
25+
export function RegistrationForm({
26+
address,
27+
oracleInstructions,
28+
}: Readonly<{
29+
address: string;
30+
oracleInstructions: string | URL | null | undefined;
31+
}>) {
32+
const { t } = useTranslation();
33+
const methods = useRegistrationForm(address);
34+
const {
35+
hasViewedInstructions,
36+
handleInstructionsView,
37+
handleRegistration,
38+
isRegistrationPending: isLoading,
39+
registrationError: error,
40+
} = useOracleRegistrationFlow(address, oracleInstructions);
41+
42+
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
43+
void methods.handleSubmit(handleRegistration)(event);
44+
};
45+
46+
return (
47+
<>
48+
<Button onClick={handleInstructionsView} fullWidth variant="contained">
49+
{t('worker.registrationInExchangeOracle.instructionsButton')}
50+
</Button>
51+
<Box>{t('worker.registrationInExchangeOracle.completeMessage')}</Box>
52+
<FormProvider {...methods}>
53+
<form onSubmit={handleSubmit}>
54+
<Stack alignItems="center" spacing={2}>
55+
<HCaptchaForm error={error} name="h_captcha_token" />
56+
<Button
57+
disabled={!hasViewedInstructions}
58+
fullWidth
59+
loading={isLoading}
60+
type="submit"
61+
variant="contained"
62+
>
63+
{t('worker.registrationInExchangeOracle.completeButton')}
64+
</Button>
65+
</Stack>
66+
</form>
67+
</FormProvider>
68+
</>
69+
);
70+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { Box, Grid, Paper, Stack } from '@mui/material';
2+
import { useTranslation } from 'react-i18next';
3+
import { Navigate, useParams } from 'react-router-dom';
4+
import { RegistrationForm } from '@/modules/worker/oracle-registration/registration-form';
5+
import { Loader } from '@/shared/components/ui/loader';
6+
import { routerPaths } from '@/router/router-paths';
7+
import { useGetOracles } from '../services/oracles';
8+
import { useIsAlreadyRegistered } from './hooks';
9+
10+
function isAddress(address: string | undefined): address is string {
11+
return address !== undefined && address.length > 0;
12+
}
13+
14+
export function RegistrationPage() {
15+
const { t } = useTranslation();
16+
const { address: oracleAddress } = useParams<{ address: string }>();
17+
const { data, isLoading } = useGetOracles();
18+
const isAlreadyRegistered = useIsAlreadyRegistered(oracleAddress);
19+
20+
const oracleData = data?.find((o) => o.address === oracleAddress);
21+
22+
if (oracleData === undefined || !isAddress(oracleAddress)) {
23+
return <Navigate to={routerPaths.worker.jobsDiscovery} />;
24+
}
25+
26+
if (isAlreadyRegistered) {
27+
return (
28+
<Navigate
29+
to={`${routerPaths.worker.jobs}/${oracleAddress}`}
30+
state={oracleAddress}
31+
/>
32+
);
33+
}
34+
35+
return (
36+
<Grid alignItems="center" container justifyContent="center">
37+
<Grid item xs={12}>
38+
<Paper
39+
sx={{
40+
height: '100%',
41+
minHeight: '70vh',
42+
width: '100%',
43+
boxShadow: 'none',
44+
padding: '40px',
45+
borderRadius: '20px',
46+
display: 'flex',
47+
justifyContent: 'center',
48+
alignItems: 'center',
49+
}}
50+
>
51+
<Stack maxWidth="350px" spacing={2}>
52+
{isLoading ? (
53+
<Loader />
54+
) : (
55+
<>
56+
<Box>
57+
{t('worker.registrationInExchangeOracle.requiredMessage')}
58+
</Box>
59+
<RegistrationForm
60+
address={oracleAddress}
61+
oracleInstructions={oracleData.registrationInstructions}
62+
/>
63+
</>
64+
)}
65+
</Stack>
66+
</Paper>
67+
</Grid>
68+
</Grid>
69+
);
70+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './registration-in-exchange-oracles';

0 commit comments

Comments
 (0)