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

add discourse #75

Merged
merged 12 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
102 changes: 102 additions & 0 deletions src/components/pages/attestations/Discourse/StepFour.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { useState } from 'react';
import {
Box,
Button,
CircularProgress,
Stack,
Typography,
} from '@mui/material';
import { FaLink } from 'react-icons/fa';
import { useNavigate } from 'react-router-dom';
import { Address } from 'viem';
import { useAccount } from 'wagmi';

import { AttestPayload } from '../../../../interfaces';
import EASService from '../../../../services/eas.service';
import useSnackbarStore from '../../../../store/useSnackbarStore';
import { contracts } from '../../../../utils/contracts/eas/contracts';
import { useSigner } from '../../../../utils/eas-wagmi-utils';

interface StepFourProps {
attestedSignutare: AttestPayload | null;
}

const StepFour: React.FC<StepFourProps> = ({ attestedSignutare }) => {
const { showSnackbar } = useSnackbarStore();
const navigate = useNavigate();
const signer = useSigner();
const { chainId } = useAccount();
const [isLoading, setIsLoading] = useState<boolean>(false);

const easContractAddress = contracts.find(
(contract) => contract.chainId === chainId
)?.easContractAddress;

const easService = signer
? new EASService(easContractAddress as Address, signer)
: null;

const handleAttestByDelegation = async () => {
if (!easService) {
throw new Error('EAS service not initialized');
}
if (!attestedSignutare) throw new Error('No attested signature provided');

setIsLoading(true);
try {
await easService.attestByDelegation(attestedSignutare);
showSnackbar('Attestation successfully completed.', {
severity: 'success',
});
navigate('/identifiers');
} catch (error) {
console.error('Error attesting identifier:', error);
showSnackbar('Failed to complete the attestation. Please try again.', {
severity: 'error',
});
} finally {
setIsLoading(false);
}
};

return (
<Stack
spacing={3}
sx={{
textAlign: 'center',
py: 12,
px: 2,
}}
>
<Typography variant="h5" fontWeight="bold">
Finalize Delegated Attestation
</Typography>
<Typography>
To complete the process, you will be asked to sign a message with your
wallet, confirming ownership of the provided address.
</Typography>
<Box>
<Button
variant="contained"
startIcon={
isLoading ? (
<CircularProgress color="inherit" size={20} />
) : (
<FaLink />
)
}
sx={{ mt: 2, px: 4 }}
onClick={handleAttestByDelegation}
disabled={isLoading}
>
{isLoading ? 'Processing...' : 'Sign Delegated Attestation'}
</Button>
</Box>
<Typography variant="caption">
You need to pay some <b>gas</b> to complete the process.
</Typography>
</Stack>
);
};

export default StepFour;
73 changes: 73 additions & 0 deletions src/components/pages/attestations/Discourse/StepOne.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Box, Button, Stack, Typography } from '@mui/material';
import { jwtDecode } from 'jwt-decode';
import { FaDiscourse } from 'react-icons/fa';

import { useGenerateDiscourseVerificationTokenMutation } from '../../../../services/api/eas/query';

interface StepOneProps {
handleNextStep: () => void;
}

const StepOne: React.FC<StepOneProps> = ({ handleNextStep }) => {
const { mutate: mutateGenerateDiscourseVerificationToken, isPending } =
useGenerateDiscourseVerificationTokenMutation();

const handleGenerateDiscourseVerificationToken = async () => {
const siweJwt = localStorage.getItem('OCI_TOKEN') as string;

mutateGenerateDiscourseVerificationToken(
{
siweJwt,
},
{
onSuccess: (response) => {
const { data } = response;

localStorage.setItem(
'DISCOURSE_VERIFICATION_TOKEN',
data.verificationJwt
);

const { code } = jwtDecode(data.verificationJwt) as { code: string };
localStorage.setItem('DISCOURSE_VERIFICATION_CODE', code);

handleNextStep();
},
onError: (error) => {
console.error('Failed to generate token:', error);
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance error handling with user feedback.

Currently, errors are only logged to the console. Consider showing a snackbar or error message to inform users when token generation fails.

 onError: (error) => {
   console.error('Failed to generate token:', error);
+  // Use the same snackbar pattern as in StepFour
+  showSnackbar('Failed to generate verification token. Please try again.', {
+    severity: 'error',
+  });
 },

Committable suggestion skipped: line range outside the PR's diff.

}
);
};

return (
<Stack
spacing={2}
sx={{
textAlign: 'center',
py: 12,
}}
>
<Typography variant="h5" fontWeight="bold">
Let&rsquo;s get started!
</Typography>
<Typography variant="body2">
To attest your Discourse account, you need to generate a token.
</Typography>
<Box sx={{ display: 'block' }}>
<Button
variant="contained"
startIcon={<FaDiscourse />}
disabled={isPending}
onClick={handleGenerateDiscourseVerificationToken}
aria-busy={isPending}
aria-live="polite"
>
{isPending ? 'Generating token...' : 'Generate token'}
</Button>
</Box>
</Stack>
);
};

export default StepOne;
96 changes: 96 additions & 0 deletions src/components/pages/attestations/Discourse/StepThree.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React from 'react';
import {
Box,
Button,
CircularProgress,
Stack,
Typography,
} from '@mui/material';
import { FaLink } from 'react-icons/fa6';
import { useAccount } from 'wagmi';

import { Provider } from '../../../../enums';
import { AttestPayload } from '../../../../interfaces';
import { useLinkIdentifierMutation } from '../../../../services/api/eas/query';
import { capitalize } from '../../../../utils/helper';

interface StepThreeProps {
provider: Provider | undefined;
handlePrepareAttestation: (payload: AttestPayload) => void;
}

const StepThree: React.FC<StepThreeProps> = ({
provider,
handlePrepareAttestation,
}) => {
const { chainId } = useAccount();
const { mutate: mutateIdentifier, isPending } = useLinkIdentifierMutation(
chainId as number
);

const handleGenerateSignedDelegation = async () => {
const siweJwt = localStorage.getItem('OCI_TOKEN');
if (!siweJwt || !provider) return;

const anyJwt = localStorage.getItem('DISCOURSE_JWT') as string;

mutateIdentifier(
{
siweJwt,
anyJwt,
},
{
onSuccess: (response) => {
const { data } = response;
handlePrepareAttestation(data);
},
onError: (error) => {
console.error(error);
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance error handling with user feedback.

Similar to StepOne, errors are only logged to console without user feedback.

 onError: (error) => {
   console.error(error);
+  showSnackbar('Failed to link identifier. Please try again.', {
+    severity: 'error',
+  });
 },

Committable suggestion skipped: line range outside the PR's diff.

}
);
};

if (!provider) {
return null;
}

return (
<Stack
spacing={3}
sx={{
textAlign: 'center',
py: 12,
px: 2,
}}
>
<Typography variant="h5" fontWeight="bold">
Connect Your {capitalize(provider)} Account to Your Wallet
</Typography>
<Typography>
To proceed, please verify your account by linking it to your wallet
address. This step ensures your {capitalize(provider)} account is
securely associated with your wallet.
</Typography>
<Box>
<Button
variant="contained"
startIcon={
isPending ? (
<CircularProgress color="inherit" size={20} />
) : (
<FaLink />
)
}
sx={{ mt: 2, px: 4 }}
onClick={handleGenerateSignedDelegation}
disabled={isPending}
>
{isPending ? 'Processing...' : 'Get Signed Delegated Attestation'}
</Button>
</Box>
</Stack>
);
};

export default StepThree;
Loading
Loading