@nexuspay/sdk
Version:
🚀 Ultra-simple cross-chain wallet SDK - Initialize with just projectName + apiKey. Bulletproof gasless transactions across EVM/SVM chains with ANY social identifier support
346 lines (345 loc) • 19 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
* WalletConnect - Ultimate Flexible Social Wallet Creator
* Support for ANY social identifier with beautiful, customizable UI
*/
import React, { useState, useEffect } from 'react';
import { useNexus } from '../hooks/useNexus';
import { COMMON_SOCIAL_TYPES } from '../../types/index.js';
export const WalletConnect = ({ onWalletCreated, onError, chains = ['ethereum', 'arbitrum', 'solana'], allowedSocialTypes, customSocialTypes = [], className = '', theme = 'auto', }) => {
const { createWallet, isLoading, error, clearError } = useNexus();
const [socialId, setSocialId] = useState('');
const [socialType, setSocialType] = useState('');
const [selectedChains, setSelectedChains] = useState(chains);
const [walletName, setWalletName] = useState('');
const [customSocialType, setCustomSocialType] = useState('');
const [isCustomType, setIsCustomType] = useState(false);
const [showAdvanced, setShowAdvanced] = useState(false);
// Available social types (filtered if allowedSocialTypes is provided)
const availableSocialTypes = React.useMemo(() => {
const commonTypes = Object.entries(COMMON_SOCIAL_TYPES).map(([key, value]) => ({
type: value,
label: key.split('_').map(word => word.charAt(0) + word.slice(1).toLowerCase()).join(' '),
placeholder: getSocialPlaceholder(value),
}));
// Add custom types
const allTypes = [...commonTypes, ...customSocialTypes];
// Filter if allowedSocialTypes is provided
if (allowedSocialTypes) {
return allTypes.filter(type => allowedSocialTypes.includes(type.type));
}
return allTypes;
}, [allowedSocialTypes, customSocialTypes]);
// Auto-detect theme
const [currentTheme, setCurrentTheme] = useState('light');
useEffect(() => {
if (theme === 'auto') {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
setCurrentTheme(mediaQuery.matches ? 'dark' : 'light');
const handleChange = (e) => {
setCurrentTheme(e.matches ? 'dark' : 'light');
};
mediaQuery.addEventListener('change', handleChange);
return () => mediaQuery.removeEventListener('change', handleChange);
}
else {
setCurrentTheme(theme);
}
}, [theme]);
// Get placeholder text for social types
function getSocialPlaceholder(type) {
const placeholders = {
email: 'user@example.com',
twitter: '@username',
discord: 'username#1234',
telegram: '@username',
github: 'username',
instagram: '@username',
gameId: 'player123',
employeeId: 'EMP001',
customerId: 'CUST001',
ens: 'username.eth',
phone: '+1234567890',
username: 'username',
steamId: 'steam_username',
xboxGamertag: 'GamerTag',
userUuid: 'unique-user-id',
};
return placeholders[type] || `Enter your ${type}`;
}
// Handle social type change
const handleSocialTypeChange = (type) => {
setSocialType(type);
setIsCustomType(type === 'custom');
setSocialId('');
setCustomSocialType('');
};
// Handle chain selection
const handleChainToggle = (chain) => {
setSelectedChains(prev => prev.includes(chain)
? prev.filter(c => c !== chain)
: [...prev, chain]);
};
// Handle form submission
const handleSubmit = async (e) => {
e.preventDefault();
if (!socialId.trim()) {
onError?.({ code: 'INVALID_INPUT', message: 'Social ID is required' });
return;
}
if (!socialType && !isCustomType) {
onError?.({ code: 'INVALID_INPUT', message: 'Social type is required' });
return;
}
if (isCustomType && !customSocialType.trim()) {
onError?.({ code: 'INVALID_INPUT', message: 'Custom social type is required' });
return;
}
if (selectedChains.length === 0) {
onError?.({ code: 'INVALID_INPUT', message: 'At least one chain must be selected' });
return;
}
try {
clearError();
const wallet = await createWallet(socialId.trim(), isCustomType ? customSocialType.trim() : socialType, selectedChains);
onWalletCreated?.(wallet);
// Reset form
setSocialId('');
setSocialType('');
setWalletName('');
setCustomSocialType('');
setIsCustomType(false);
setShowAdvanced(false);
}
catch (err) {
onError?.(err);
}
};
// Get chain display name
const getChainDisplayName = (chain) => {
const names = {
ethereum: 'Ethereum',
arbitrum: 'Arbitrum',
solana: 'Solana',
};
return names[chain];
};
// Get chain logo emoji
const getChainLogo = (chain) => {
const logos = {
ethereum: '⟡',
arbitrum: '🔵',
solana: '🌟',
};
return logos[chain];
};
// Theme colors
const colors = {
light: {
bg: '#ffffff',
cardBg: '#f8fafc',
border: '#e2e8f0',
text: '#1e293b',
textSecondary: '#64748b',
primary: '#3b82f6',
primaryHover: '#2563eb',
success: '#10b981',
error: '#ef4444',
inputBg: '#ffffff',
inputBorder: '#d1d5db',
inputFocus: '#3b82f6',
},
dark: {
bg: '#0f172a',
cardBg: '#1e293b',
border: '#334155',
text: '#f1f5f9',
textSecondary: '#94a3b8',
primary: '#3b82f6',
primaryHover: '#2563eb',
success: '#10b981',
error: '#ef4444',
inputBg: '#334155',
inputBorder: '#475569',
inputFocus: '#3b82f6',
},
};
const c = colors[currentTheme];
return (_jsxs("div", { className: `nexus-wallet-connect ${className}`, style: {
maxWidth: '480px',
margin: '0 auto',
padding: '24px',
backgroundColor: c.bg,
borderRadius: '16px',
border: `1px solid ${c.border}`,
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
color: c.text,
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
}, children: [_jsxs("div", { style: { textAlign: 'center', marginBottom: '24px' }, children: [_jsx("h2", { style: {
margin: '0 0 8px 0',
fontSize: '24px',
fontWeight: '600',
color: c.text,
}, children: "Create Wallet" }), _jsx("p", { style: {
margin: '0',
fontSize: '14px',
color: c.textSecondary,
}, children: "Connect with any social identifier across multiple chains" })] }), error && (_jsx("div", { style: {
padding: '12px',
backgroundColor: c.error + '10',
border: `1px solid ${c.error}30`,
borderRadius: '8px',
marginBottom: '20px',
color: c.error,
fontSize: '14px',
}, children: error.message })), _jsxs("form", { onSubmit: handleSubmit, style: { display: 'flex', flexDirection: 'column', gap: '20px' }, children: [_jsxs("div", { children: [_jsx("label", { style: {
display: 'block',
fontSize: '14px',
fontWeight: '500',
marginBottom: '8px',
color: c.text,
}, children: "Social Type" }), _jsxs("select", { value: socialType, onChange: (e) => handleSocialTypeChange(e.target.value), style: {
width: '100%',
padding: '12px',
border: `1px solid ${c.inputBorder}`,
borderRadius: '8px',
fontSize: '14px',
backgroundColor: c.inputBg,
color: c.text,
outline: 'none',
transition: 'border-color 0.2s',
}, onFocus: (e) => e.target.style.borderColor = c.inputFocus, onBlur: (e) => e.target.style.borderColor = c.inputBorder, children: [_jsx("option", { value: "", children: "Select social type" }), availableSocialTypes.map((type) => (_jsx("option", { value: type.type, children: type.label }, type.type))), _jsx("option", { value: "custom", children: "Custom Type" })] })] }), isCustomType && (_jsxs("div", { children: [_jsx("label", { style: {
display: 'block',
fontSize: '14px',
fontWeight: '500',
marginBottom: '8px',
color: c.text,
}, children: "Custom Social Type" }), _jsx("input", { type: "text", value: customSocialType, onChange: (e) => setCustomSocialType(e.target.value), placeholder: "Enter custom social type (e.g., nftHolder, daoMember)", style: {
width: '100%',
padding: '12px',
border: `1px solid ${c.inputBorder}`,
borderRadius: '8px',
fontSize: '14px',
backgroundColor: c.inputBg,
color: c.text,
outline: 'none',
transition: 'border-color 0.2s',
}, onFocus: (e) => e.target.style.borderColor = c.inputFocus, onBlur: (e) => e.target.style.borderColor = c.inputBorder })] })), _jsxs("div", { children: [_jsx("label", { style: {
display: 'block',
fontSize: '14px',
fontWeight: '500',
marginBottom: '8px',
color: c.text,
}, children: "Social ID" }), _jsx("input", { type: "text", value: socialId, onChange: (e) => setSocialId(e.target.value), placeholder: isCustomType
? "Enter your custom identifier"
: socialType
? getSocialPlaceholder(socialType)
: "Enter your social identifier", style: {
width: '100%',
padding: '12px',
border: `1px solid ${c.inputBorder}`,
borderRadius: '8px',
fontSize: '14px',
backgroundColor: c.inputBg,
color: c.text,
outline: 'none',
transition: 'border-color 0.2s',
}, onFocus: (e) => e.target.style.borderColor = c.inputFocus, onBlur: (e) => e.target.style.borderColor = c.inputBorder })] }), _jsxs("div", { children: [_jsx("label", { style: {
display: 'block',
fontSize: '14px',
fontWeight: '500',
marginBottom: '8px',
color: c.text,
}, children: "Select Chains" }), _jsx("div", { style: { display: 'flex', flexWrap: 'wrap', gap: '8px' }, children: chains.map((chain) => (_jsxs("button", { type: "button", onClick: () => handleChainToggle(chain), style: {
padding: '8px 16px',
border: `1px solid ${selectedChains.includes(chain) ? c.primary : c.inputBorder}`,
borderRadius: '20px',
backgroundColor: selectedChains.includes(chain) ? c.primary : c.inputBg,
color: selectedChains.includes(chain) ? 'white' : c.text,
fontSize: '14px',
fontWeight: '500',
cursor: 'pointer',
transition: 'all 0.2s',
display: 'flex',
alignItems: 'center',
gap: '6px',
}, children: [_jsx("span", { children: getChainLogo(chain) }), getChainDisplayName(chain)] }, chain))) })] }), _jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setShowAdvanced(!showAdvanced), style: {
background: 'none',
border: 'none',
color: c.primary,
fontSize: '14px',
fontWeight: '500',
cursor: 'pointer',
padding: '0',
textDecoration: 'underline',
}, children: [showAdvanced ? 'Hide' : 'Show', " Advanced Options"] }), showAdvanced && (_jsxs("div", { style: { marginTop: '16px' }, children: [_jsx("label", { style: {
display: 'block',
fontSize: '14px',
fontWeight: '500',
marginBottom: '8px',
color: c.text,
}, children: "Wallet Name (Optional)" }), _jsx("input", { type: "text", value: walletName, onChange: (e) => setWalletName(e.target.value), placeholder: "My Wallet", style: {
width: '100%',
padding: '12px',
border: `1px solid ${c.inputBorder}`,
borderRadius: '8px',
fontSize: '14px',
backgroundColor: c.inputBg,
color: c.text,
outline: 'none',
transition: 'border-color 0.2s',
}, onFocus: (e) => e.target.style.borderColor = c.inputFocus, onBlur: (e) => e.target.style.borderColor = c.inputBorder })] }))] }), _jsx("button", { type: "submit", disabled: isLoading, style: {
width: '100%',
padding: '14px',
backgroundColor: isLoading ? c.textSecondary : c.primary,
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '16px',
fontWeight: '600',
cursor: isLoading ? 'not-allowed' : 'pointer',
transition: 'background-color 0.2s',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '8px',
}, onMouseEnter: (e) => {
if (!isLoading) {
e.currentTarget.style.backgroundColor = c.primaryHover;
}
}, onMouseLeave: (e) => {
if (!isLoading) {
e.currentTarget.style.backgroundColor = c.primary;
}
}, children: isLoading ? (_jsxs(_Fragment, { children: [_jsx("span", { style: {
width: '16px',
height: '16px',
border: '2px solid white',
borderTop: '2px solid transparent',
borderRadius: '50%',
animation: 'spin 1s linear infinite',
} }), "Creating Wallet..."] })) : ('🚀 Create Gasless Wallet') })] }), _jsxs("div", { style: {
marginTop: '24px',
padding: '16px',
backgroundColor: c.cardBg,
borderRadius: '8px',
border: `1px solid ${c.border}`,
}, children: [_jsx("h3", { style: {
margin: '0 0 12px 0',
fontSize: '16px',
fontWeight: '600',
color: c.text,
}, children: "\u2728 Features" }), _jsxs("ul", { style: {
margin: '0',
padding: '0',
listStyle: 'none',
fontSize: '14px',
color: c.textSecondary,
}, children: [_jsx("li", { style: { marginBottom: '8px' }, children: "\u26A1 Gasless transactions across all chains" }), _jsx("li", { style: { marginBottom: '8px' }, children: "\uD83D\uDD17 Cross-chain bridging & swaps" }), _jsx("li", { style: { marginBottom: '8px' }, children: "\uD83D\uDD10 Multi-chain wallet infrastructure" }), _jsx("li", { children: "\uD83C\uDFAF Any social identifier supported" })] })] }), _jsx("style", { children: `
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
` })] }));
};
export default WalletConnect;