Files
self/sdk/qrcode/OpenPassportQRcode.tsx

129 lines
4.0 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { OpenPassportAttestation } from '../../common/src/utils/openPassportAttestation';
import { OpenPassportVerifier } from '@openpassport/core';
import { BounceLoader } from 'react-spinners';
import Lottie from 'lottie-react';
import CHECK_ANIMATION from './animations/check_animation.json';
import X_ANIMATION from './animations/x_animation.json';
import LED from './components/LED';
import { WEBSOCKET_URL } from '../../common/src/constants/constants';
import { UserIdType } from '../../common/src/utils/utils';
import { v4 as uuidv4 } from 'uuid';
import { QRcodeSteps } from './utils/utils';
import { containerStyle, ledContainerStyle, qrContainerStyle } from './utils/styles';
import dynamic from 'next/dynamic';
import { initWebSocket } from './utils/websocket';
const QRCodeSVG = dynamic(() => import('qrcode.react').then((mod) => mod.QRCodeSVG), {
ssr: false,
});
interface OpenPassportQRcodeProps {
appName: string;
userId: string;
userIdType: UserIdType;
openPassportVerifier: OpenPassportVerifier;
onSuccess: (attestation: OpenPassportAttestation) => void;
websocketUrl?: string;
size?: number;
}
// Create a wrapper component that handles client-side rendering
const OpenPassportQRcodeWrapper: React.FC<OpenPassportQRcodeProps> = (props) => {
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
if (!isClient) {
return null;
}
return <OpenPassportQRcode {...props} />;
};
// Your existing OpenPassportQRcode component
const OpenPassportQRcode: React.FC<OpenPassportQRcodeProps> = ({
appName,
userId,
userIdType,
openPassportVerifier,
onSuccess,
websocketUrl = WEBSOCKET_URL,
size = 300,
}) => {
const [proofStep, setProofStep] = useState(QRcodeSteps.WAITING_FOR_MOBILE);
const [proofVerified, setProofVerified] = useState(false);
const [sessionId, setSessionId] = useState(uuidv4());
useEffect(() => {
initWebSocket(
websocketUrl,
sessionId,
setProofStep,
setProofVerified,
openPassportVerifier,
onSuccess
);
}, [sessionId, websocketUrl, openPassportVerifier]);
const generateUniversalLink = () => {
const baseUrl = 'https://proofofpassport-merkle-tree.xyz';
const path = '/open-passport';
const data = openPassportVerifier.getIntent(appName, userId, userIdType, sessionId);
return `${baseUrl}${path}?data=${data}`;
};
const renderProofStatus = () => (
<div style={containerStyle}>
<div style={ledContainerStyle}>
<LED connectionStatus={proofStep} />
</div>
<div style={qrContainerStyle(size)}>
{(() => {
switch (proofStep) {
case QRcodeSteps.PROOF_GENERATION_STARTED:
case QRcodeSteps.PROOF_GENERATED:
return <BounceLoader loading={true} size={200} color="#94FBAB" />;
case QRcodeSteps.PROOF_VERIFIED:
if (proofVerified) {
return (
<Lottie
animationData={CHECK_ANIMATION}
style={{ width: 200, height: 200 }}
onComplete={() => {
setProofStep(QRcodeSteps.WAITING_FOR_MOBILE);
}}
loop={false}
/>
);
} else {
return (
<Lottie
animationData={X_ANIMATION}
style={{ width: 200, height: 200 }}
onComplete={() => {
setProofStep(QRcodeSteps.WAITING_FOR_MOBILE);
}}
loop={false}
/>
);
}
default:
return (
<QRCodeSVG
value={generateUniversalLink()}
size={size}
/>
);
}
})()}
</div>
</div>
);
return <div style={containerStyle}>{renderProofStatus()}</div>;
};
export default OpenPassportQRcodeWrapper;