86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
'use client';
|
|
|
|
import React, {
|
|
useCallback,
|
|
useEffect,
|
|
useState,
|
|
useRef,
|
|
FC,
|
|
ReactNode,
|
|
} from 'react';
|
|
import { useNeynarContext } from '@neynar/react';
|
|
export const NeynarAuthButton: FC<{
|
|
children: ReactNode;
|
|
onLogin: (code: string) => void;
|
|
}> = (props) => {
|
|
const { children, onLogin } = props;
|
|
const { client_id } = useNeynarContext();
|
|
const [showModal, setShowModal] = useState(false);
|
|
const authWindowRef = useRef<Window | null>(null);
|
|
const neynarLoginUrl = `${
|
|
process.env.NEYNAR_LOGIN_URL ?? 'https://app.neynar.com/login'
|
|
}?client_id=${client_id}`;
|
|
const authOrigin = new URL(neynarLoginUrl).origin;
|
|
const modalRef = useRef<HTMLDivElement>(null);
|
|
const handleMessage = useCallback(
|
|
async (event: MessageEvent) => {
|
|
if (
|
|
event.origin === authOrigin &&
|
|
event.data &&
|
|
event.data.is_authenticated
|
|
) {
|
|
authWindowRef.current?.close();
|
|
window.removeEventListener('message', handleMessage); // Remove listener here
|
|
delete event.data.user.profile;
|
|
const _user = {
|
|
signer_uuid: event.data.signer_uuid,
|
|
...event.data.user,
|
|
};
|
|
onLogin(Buffer.from(JSON.stringify(_user)).toString('base64'));
|
|
}
|
|
},
|
|
[client_id, onLogin]
|
|
);
|
|
const handleSignIn = useCallback(() => {
|
|
const width = 600,
|
|
height = 700;
|
|
const left = window.screen.width / 2 - width / 2;
|
|
const top = window.screen.height / 2 - height / 2;
|
|
const windowFeatures = `width=${width},height=${height},top=${top},left=${left}`;
|
|
authWindowRef.current = window.open(
|
|
neynarLoginUrl,
|
|
'_blank',
|
|
windowFeatures
|
|
);
|
|
if (!authWindowRef.current) {
|
|
console.error(
|
|
'Failed to open the authentication window. Please check your pop-up blocker settings.'
|
|
);
|
|
return;
|
|
}
|
|
window.addEventListener('message', handleMessage, false);
|
|
}, [client_id, handleMessage]);
|
|
const closeModal = () => setShowModal(false);
|
|
useEffect(() => {
|
|
return () => {
|
|
window.removeEventListener('message', handleMessage); // Cleanup function to remove listener
|
|
};
|
|
}, [handleMessage]);
|
|
const handleOutsideClick = useCallback((event: any) => {
|
|
if (modalRef.current && !modalRef.current.contains(event.target)) {
|
|
closeModal();
|
|
}
|
|
}, []);
|
|
useEffect(() => {
|
|
if (showModal) {
|
|
document.addEventListener('mousedown', handleOutsideClick);
|
|
} else {
|
|
document.removeEventListener('mousedown', handleOutsideClick);
|
|
}
|
|
return () => {
|
|
document.removeEventListener('mousedown', handleOutsideClick);
|
|
};
|
|
}, [showModal, handleOutsideClick]);
|
|
return <div onClick={handleSignIn} className="flex-1">{children}</div>;
|
|
};
|