fix: use People Chain API for tiki and identityKyc pallets

- DashboardContext: query tiki/kyc from peopleApi instead of relay api
- KycApprovalTab: use peopleApi for identityKyc.pendingKycApplications
- NewCitizenApplication: all KYC operations now use People Chain

These pallets are on People Chain, not Relay Chain. This fixes the
"mafe te tuneye" error when accessing Citizens portal.
This commit is contained in:
2026-02-10 18:09:26 +03:00
parent 76e024276c
commit e53be65975
3 changed files with 50 additions and 44 deletions
+11 -9
View File
@@ -37,7 +37,8 @@ interface IdentityInfo {
} }
export function KycApprovalTab() { export function KycApprovalTab() {
const { api, isApiReady, selectedAccount, connectWallet } = usePezkuwi(); // identityKyc pallet is on People Chain, dynamicCommissionCollective is on Relay Chain
const { api, isApiReady, peopleApi, isPeopleReady, selectedAccount, connectWallet } = usePezkuwi();
const { toast } = useToast(); const { toast } = useToast();
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@@ -47,27 +48,28 @@ export function KycApprovalTab() {
const [processing, setProcessing] = useState(false); const [processing, setProcessing] = useState(false);
const [showDetailsModal, setShowDetailsModal] = useState(false); const [showDetailsModal, setShowDetailsModal] = useState(false);
// Load pending KYC applications // Load pending KYC applications from People Chain
useEffect(() => { useEffect(() => {
if (!api || !isApiReady) { if (!peopleApi || !isPeopleReady) {
return; return;
} }
loadPendingApplications(); loadPendingApplications();
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [api, isApiReady]); }, [peopleApi, isPeopleReady]);
const loadPendingApplications = async () => { const loadPendingApplications = async () => {
if (!api || !isApiReady) { // identityKyc pallet is on People Chain
if (!peopleApi || !isPeopleReady) {
setLoading(false); setLoading(false);
return; return;
} }
setLoading(true); setLoading(true);
try { try {
// Get all pending applications // Get all pending applications from People Chain
const entries = await api.query.identityKyc.pendingKycApplications.entries(); const entries = await peopleApi.query.identityKyc.pendingKycApplications.entries();
const apps: PendingApplication[] = []; const apps: PendingApplication[] = [];
const identityMap = new Map<string, IdentityInfo>(); const identityMap = new Map<string, IdentityInfo>();
@@ -76,9 +78,9 @@ export function KycApprovalTab() {
const address = key.args[0].toString(); const address = key.args[0].toString();
const application = value.toJSON() as Record<string, unknown>; const application = value.toJSON() as Record<string, unknown>;
// Get identity info for this address // Get identity info for this address from People Chain
try { try {
const identity = await api.query.identityKyc.identities(address); const identity = await peopleApi.query.identityKyc.identities(address);
if (!identity.isEmpty) { if (!identity.isEmpty) {
const identityData = identity.toJSON() as Record<string, unknown>; const identityData = identity.toJSON() as Record<string, unknown>;
identityMap.set(address, { identityMap.set(address, {
@@ -22,7 +22,8 @@ interface NewCitizenApplicationProps {
type FormData = Omit<CitizenshipData, 'walletAddress' | 'timestamp'>; type FormData = Omit<CitizenshipData, 'walletAddress' | 'timestamp'>;
export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ onClose, referrerAddress }) => { export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ onClose, referrerAddress }) => {
const { api, isApiReady, selectedAccount, connectWallet } = usePezkuwi(); // identityKyc pallet is on People Chain
const { api, isApiReady, peopleApi, isPeopleReady, selectedAccount, connectWallet } = usePezkuwi();
const { register, handleSubmit, watch, setValue, formState: { errors } } = useForm<FormData>(); const { register, handleSubmit, watch, setValue, formState: { errors } } = useForm<FormData>();
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
@@ -33,13 +34,15 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
const [agreed, setAgreed] = useState(false); const [agreed, setAgreed] = useState(false);
const [confirming, setConfirming] = useState(false); const [confirming, setConfirming] = useState(false);
const [applicationHash, setApplicationHash] = useState<string>(''); const [applicationHash, setApplicationHash] = useState<string>('');
const [checkingStatus, setCheckingStatus] = useState(false);
const maritalStatus = watch('maritalStatus'); const maritalStatus = watch('maritalStatus');
const childrenCount = watch('childrenCount'); const childrenCount = watch('childrenCount');
const handleApprove = async () => { const handleApprove = async () => {
if (!api || !selectedAccount) { // identityKyc pallet is on People Chain
setError('Please connect your wallet first'); if (!peopleApi || !isPeopleReady || !selectedAccount) {
setError('Please connect your wallet and wait for People Chain connection');
return; return;
} }
@@ -48,15 +51,15 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
const { web3FromAddress } = await import('@pezkuwi/extension-dapp'); const { web3FromAddress } = await import('@pezkuwi/extension-dapp');
const injector = await web3FromAddress(selectedAccount.address); const injector = await web3FromAddress(selectedAccount.address);
if (import.meta.env.DEV) console.log('Confirming citizenship application (self-confirmation)...'); if (import.meta.env.DEV) console.log('Confirming citizenship application on People Chain (self-confirmation)...');
// Call confirm_citizenship() extrinsic - self-confirmation for Welati Tiki // Call confirm_citizenship() extrinsic on People Chain - self-confirmation for Welati Tiki
const tx = api.tx.identityKyc.confirmCitizenship(); const tx = peopleApi.tx.identityKyc.confirmCitizenship();
await tx.signAndSend(selectedAccount.address, { signer: injector.signer }, ({ status, events, dispatchError }) => { await tx.signAndSend(selectedAccount.address, { signer: injector.signer }, ({ status, events, dispatchError }) => {
if (dispatchError) { if (dispatchError) {
if (dispatchError.isModule) { if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule); const decoded = peopleApi.registry.findMetaError(dispatchError.asModule);
if (import.meta.env.DEV) console.error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`); if (import.meta.env.DEV) console.error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`);
setError(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`); setError(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`);
} else { } else {
@@ -68,7 +71,7 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
} }
if (status.isInBlock || status.isFinalized) { if (status.isInBlock || status.isFinalized) {
if (import.meta.env.DEV) console.log('✅ Citizenship confirmed successfully!'); if (import.meta.env.DEV) console.log('✅ Citizenship confirmed successfully on People Chain!');
if (import.meta.env.DEV) console.log('Block hash:', status.asInBlock || status.asFinalized); if (import.meta.env.DEV) console.log('Block hash:', status.asInBlock || status.asFinalized);
// Check for CitizenshipConfirmed event // Check for CitizenshipConfirmed event
@@ -105,17 +108,17 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
window.location.href = '/'; window.location.href = '/';
}; };
// Check KYC status on mount // Check KYC status on mount (identityKyc pallet is on People Chain)
useEffect(() => { useEffect(() => {
const checkKycStatus = async () => { const checkKycStatus = async () => {
if (!api || !isApiReady || !selectedAccount) { if (!peopleApi || !isPeopleReady || !selectedAccount) {
return; return;
} }
setCheckingStatus(true); setCheckingStatus(true);
try { try {
const status = await getKycStatus(api, selectedAccount.address); const status = await getKycStatus(peopleApi, selectedAccount.address);
if (import.meta.env.DEV) console.log('Current KYC Status:', status); if (import.meta.env.DEV) console.log('Current KYC Status from People Chain:', status);
if (status === 'Approved') { if (status === 'Approved') {
if (import.meta.env.DEV) console.log('KYC already approved! Redirecting to dashboard...'); if (import.meta.env.DEV) console.log('KYC already approved! Redirecting to dashboard...');
@@ -138,21 +141,21 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
}; };
checkKycStatus(); checkKycStatus();
}, [api, isApiReady, selectedAccount, onClose]); }, [peopleApi, isPeopleReady, selectedAccount, onClose]);
// Subscribe to KYC approval events // Subscribe to KYC approval events on People Chain
useEffect(() => { useEffect(() => {
if (!api || !isApiReady || !selectedAccount || !waitingForApproval) { if (!peopleApi || !isPeopleReady || !selectedAccount || !waitingForApproval) {
return; return;
} }
if (import.meta.env.DEV) console.log('Setting up KYC approval listener for:', selectedAccount.address); if (import.meta.env.DEV) console.log('Setting up KYC approval listener on People Chain for:', selectedAccount.address);
const unsubscribe = subscribeToKycApproval( const unsubscribe = subscribeToKycApproval(
api, peopleApi,
selectedAccount.address, selectedAccount.address,
() => { () => {
if (import.meta.env.DEV) console.log('KYC Approved! Redirecting to dashboard...'); if (import.meta.env.DEV) console.log('KYC Approved on People Chain! Redirecting to dashboard...');
setKycApproved(true); setKycApproved(true);
setWaitingForApproval(false); setWaitingForApproval(false);
@@ -173,11 +176,12 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
unsubscribe(); unsubscribe();
} }
}; };
}, [api, isApiReady, selectedAccount, waitingForApproval, onClose]); }, [peopleApi, isPeopleReady, selectedAccount, waitingForApproval, onClose]);
const onSubmit = async (data: FormData) => { const onSubmit = async (data: FormData) => {
if (!api || !isApiReady || !selectedAccount) { // identityKyc pallet is on People Chain
setError('Please connect your wallet first'); if (!peopleApi || !isPeopleReady || !selectedAccount) {
setError('Please connect your wallet and wait for People Chain connection');
return; return;
} }
@@ -190,8 +194,8 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
setSubmitting(true); setSubmitting(true);
try { try {
// Check KYC status before submitting // Check KYC status before submitting (from People Chain)
const currentStatus = await getKycStatus(api, selectedAccount.address); const currentStatus = await getKycStatus(peopleApi, selectedAccount.address);
if (currentStatus === 'Approved') { if (currentStatus === 'Approved') {
setError('Your KYC has already been approved! Redirecting to dashboard...'); setError('Your KYC has already been approved! Redirecting to dashboard...');
@@ -250,10 +254,10 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
throw new Error(`Invalid IPFS CID: ${cidString}`); throw new Error(`Invalid IPFS CID: ${cidString}`);
} }
// Submit to blockchain // Submit to blockchain (identityKyc pallet is on People Chain)
if (import.meta.env.DEV) console.log('Submitting KYC application to blockchain...'); if (import.meta.env.DEV) console.log('Submitting KYC application to People Chain...');
const result = await submitKycApplication( const result = await submitKycApplication(
api, peopleApi,
selectedAccount, selectedAccount,
citizenshipData.fullName, citizenshipData.fullName,
citizenshipData.email, citizenshipData.email,
+9 -9
View File
@@ -17,7 +17,7 @@ const DashboardContext = createContext<DashboardData | undefined>(undefined);
export function DashboardProvider({ children }: { children: ReactNode }) { export function DashboardProvider({ children }: { children: ReactNode }) {
const { user } = useAuth(); const { user } = useAuth();
const { api, isApiReady, selectedAccount } = usePezkuwi(); const { peopleApi, isPeopleReady, selectedAccount } = usePezkuwi();
const [profile, setProfile] = useState<Record<string, unknown> | null>(null); const [profile, setProfile] = useState<Record<string, unknown> | null>(null);
const [nftDetails, setNftDetails] = useState<{ citizenNFT: TikiNFTDetails | null; roleNFTs: TikiNFTDetails[]; totalNFTs: number }>({ const [nftDetails, setNftDetails] = useState<{ citizenNFT: TikiNFTDetails | null; roleNFTs: TikiNFTDetails[]; totalNFTs: number }>({
citizenNFT: null, citizenNFT: null,
@@ -54,29 +54,29 @@ export function DashboardProvider({ children }: { children: ReactNode }) {
}, [user]); }, [user]);
const fetchScoresAndTikis = useCallback(async () => { const fetchScoresAndTikis = useCallback(async () => {
if (!selectedAccount || !api) return; // tiki and identityKyc pallets are on People Chain, not Relay Chain
if (!selectedAccount || !peopleApi || !isPeopleReady) return;
setLoading(true); setLoading(true);
try { try {
const status = await getKycStatus(api, selectedAccount.address); const status = await getKycStatus(peopleApi, selectedAccount.address);
setKycStatus(status); setKycStatus(status);
const details = await getAllTikiNFTDetails(api, selectedAccount.address); const details = await getAllTikiNFTDetails(peopleApi, selectedAccount.address);
setNftDetails(details); setNftDetails(details);
} catch (error) { } catch (error) {
if (import.meta.env.DEV) console.error('Error fetching data:', error); if (import.meta.env.DEV) console.error('Error fetching tiki/kyc data from People Chain:', error);
} finally { } finally {
setLoading(false); setLoading(false);
} }
}, [selectedAccount, api]); }, [selectedAccount, peopleApi, isPeopleReady]);
useEffect(() => { useEffect(() => {
fetchProfile(); fetchProfile();
if (selectedAccount && api && isApiReady) { if (selectedAccount && peopleApi && isPeopleReady) {
fetchScoresAndTikis(); fetchScoresAndTikis();
} }
}, [user, selectedAccount, api, isApiReady, fetchProfile, fetchScoresAndTikis]); }, [user, selectedAccount, peopleApi, isPeopleReady, fetchProfile, fetchScoresAndTikis]);
const citizenNumber = nftDetails.citizenNFT const citizenNumber = nftDetails.citizenNFT
? generateCitizenNumber(nftDetails.citizenNFT.owner, nftDetails.citizenNFT.collectionId, nftDetails.citizenNFT.itemId) ? generateCitizenNumber(nftDetails.citizenNFT.owner, nftDetails.citizenNFT.collectionId, nftDetails.citizenNFT.itemId)