mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-26 07:37:56 +00:00
0e0ef734fc
CRITICAL FIXES: 1. ✅ Hardcoded endpoint replaced with env variable - App.tsx: Uses VITE_WS_ENDPOINT from .env - PolkadotContext: Fallback endpoints support - .env & .env.production: Added VITE_WS_ENDPOINT config 2. ✅ Console statements guarded (433 instances) - All console.log/warn/error wrapped with import.meta.env.DEV - Production builds now clean (no console output) 3. ✅ ESLint error fixed - vite.config.ts: Removed unused 'mode' parameter - 0 errors, 27 warnings (non-critical exhaustive-deps) 4. ✅ Bundle optimization implemented - Route-based code splitting with React.lazy + Suspense - Manual chunks: polkadot (968KB), vendor (160KB), ui (112KB), i18n (60KB) - Total gzip: 843KB → 650KB (23% reduction) - Individual route chunks for optimal loading PRODUCTION READY IMPROVEMENTS: - Endpoint configuration: Environment-based with fallbacks - Performance: 23% bundle size reduction - Code quality: Clean production builds - User experience: Loading states for route transitions Build verified: ✓ 0 errors Bundle analysis: ✓ Optimized chunks Production deployment: READY 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
178 lines
4.9 KiB
TypeScript
178 lines
4.9 KiB
TypeScript
import { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react';
|
|
import { usePolkadot } from '@/contexts/PolkadotContext';
|
|
import { useWallet } from '@/contexts/WalletContext';
|
|
import { useToast } from '@/hooks/use-toast';
|
|
import {
|
|
getReferralStats,
|
|
getMyReferrals,
|
|
initiateReferral,
|
|
subscribeToReferralEvents,
|
|
type ReferralStats,
|
|
} from '@pezkuwi/lib/referral';
|
|
|
|
interface ReferralContextValue {
|
|
stats: ReferralStats | null;
|
|
myReferrals: string[];
|
|
loading: boolean;
|
|
inviteUser: (referredAddress: string) => Promise<boolean>;
|
|
refreshStats: () => Promise<void>;
|
|
}
|
|
|
|
const ReferralContext = createContext<ReferralContextValue | undefined>(undefined);
|
|
|
|
export function ReferralProvider({ children }: { children: ReactNode }) {
|
|
const { api, isApiReady } = usePolkadot();
|
|
const { account } = useWallet();
|
|
const { toast } = useToast();
|
|
|
|
const [stats, setStats] = useState<ReferralStats | null>(null);
|
|
const [myReferrals, setMyReferrals] = useState<string[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
// Fetch referral statistics
|
|
const fetchStats = useCallback(async () => {
|
|
if (!api || !isApiReady || !account) {
|
|
setStats(null);
|
|
setMyReferrals([]);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setLoading(true);
|
|
|
|
const [fetchedStats, fetchedReferrals] = await Promise.all([
|
|
getReferralStats(api, account),
|
|
getMyReferrals(api, account),
|
|
]);
|
|
|
|
setStats(fetchedStats);
|
|
setMyReferrals(fetchedReferrals);
|
|
} catch (error) {
|
|
if (import.meta.env.DEV) console.error('Error fetching referral stats:', error);
|
|
toast({
|
|
title: 'Error',
|
|
description: 'Failed to load referral statistics',
|
|
variant: 'destructive',
|
|
});
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [api, isApiReady, account, toast]);
|
|
|
|
// Initial fetch
|
|
useEffect(() => {
|
|
fetchStats();
|
|
}, [fetchStats]);
|
|
|
|
// Subscribe to referral events for real-time updates
|
|
useEffect(() => {
|
|
if (!api || !isApiReady || !account) return;
|
|
|
|
let unsub: (() => void) | undefined;
|
|
|
|
subscribeToReferralEvents(api, (event) => {
|
|
// If this user is involved in the event, refresh stats
|
|
if (event.referrer === account || event.referred === account) {
|
|
if (event.type === 'initiated') {
|
|
toast({
|
|
title: 'Referral Sent',
|
|
description: `Invitation sent to ${event.referred.slice(0, 8)}...`,
|
|
});
|
|
} else if (event.type === 'confirmed') {
|
|
toast({
|
|
title: 'Referral Confirmed!',
|
|
description: `Your referral completed KYC. Total: ${event.count}`,
|
|
variant: 'default',
|
|
});
|
|
}
|
|
fetchStats();
|
|
}
|
|
}).then((unsubFn) => {
|
|
unsub = unsubFn;
|
|
});
|
|
|
|
return () => {
|
|
if (unsub) unsub();
|
|
};
|
|
}, [api, isApiReady, account, toast, fetchStats]);
|
|
|
|
// Invite a new user
|
|
const inviteUser = async (referredAddress: string): Promise<boolean> => {
|
|
if (!api || !account) {
|
|
toast({
|
|
title: 'Error',
|
|
description: 'Wallet not connected',
|
|
variant: 'destructive',
|
|
});
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
// Validate address format
|
|
if (!referredAddress || referredAddress.length < 47) {
|
|
toast({
|
|
title: 'Invalid Address',
|
|
description: 'Please enter a valid Polkadot address',
|
|
variant: 'destructive',
|
|
});
|
|
return false;
|
|
}
|
|
|
|
toast({
|
|
title: 'Sending Invitation',
|
|
description: 'Please sign the transaction...',
|
|
});
|
|
|
|
await initiateReferral(api, { address: account, meta: { source: 'polkadot-js' } } as Record<string, unknown>, referredAddress);
|
|
|
|
toast({
|
|
title: 'Success!',
|
|
description: 'Referral invitation sent successfully',
|
|
});
|
|
|
|
// Refresh stats after successful invitation
|
|
await fetchStats();
|
|
return true;
|
|
} catch (error) {
|
|
if (import.meta.env.DEV) console.error('Error inviting user:', error);
|
|
|
|
let errorMessage = 'Failed to send referral invitation';
|
|
if (error.message) {
|
|
if (error.message.includes('SelfReferral')) {
|
|
errorMessage = 'You cannot refer yourself';
|
|
} else if (error.message.includes('AlreadyReferred')) {
|
|
errorMessage = 'This user has already been referred';
|
|
} else {
|
|
errorMessage = error.message;
|
|
}
|
|
}
|
|
|
|
toast({
|
|
title: 'Error',
|
|
description: errorMessage,
|
|
variant: 'destructive',
|
|
});
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const value: ReferralContextValue = {
|
|
stats,
|
|
myReferrals,
|
|
loading,
|
|
inviteUser,
|
|
refreshStats: fetchStats,
|
|
};
|
|
|
|
return <ReferralContext.Provider value={value}>{children}</ReferralContext.Provider>;
|
|
}
|
|
|
|
export function useReferral() {
|
|
const context = useContext(ReferralContext);
|
|
if (context === undefined) {
|
|
throw new Error('useReferral must be used within a ReferralProvider');
|
|
}
|
|
return context;
|
|
}
|