mirror of
https://github.com/pezkuwichain/pezkuwi-telegram-miniapp.git
synced 2026-06-17 10:11:11 +00:00
feat: update Be Citizen to new applyForCitizenship API
- Single tx (applyForCitizenship) instead of 2-step setIdentity+applyForKyc - Keccak-256 identity hash via js-sha3 - Referral code replaced with referrer SS58 address - Success screen shows pending referral status instead of citizen ID - Updated all 6 translation files with new keys
This commit is contained in:
@@ -38,7 +38,7 @@ export function CitizenForm({ walletAddress, onSubmit }: Props) {
|
||||
const [region, setRegion] = useState<Region | ''>('');
|
||||
const [email, setEmail] = useState('');
|
||||
const [profession, setProfession] = useState('');
|
||||
const [referralCode, setReferralCode] = useState('');
|
||||
const [referrerAddress, setReferrerAddress] = useState('');
|
||||
const [consent, setConsent] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
@@ -120,7 +120,7 @@ export function CitizenForm({ walletAddress, onSubmit }: Props) {
|
||||
region: region as Region,
|
||||
email,
|
||||
profession,
|
||||
referralCode: referralCode || undefined,
|
||||
referrerAddress: referrerAddress || undefined,
|
||||
walletAddress,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
@@ -319,15 +319,15 @@ export function CitizenForm({ walletAddress, onSubmit }: Props) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Referral Code */}
|
||||
{/* Referrer Address */}
|
||||
<div>
|
||||
<label className={labelClass}>{t('citizen.referralCode')}</label>
|
||||
<label className={labelClass}>{t('citizen.referrerAddress')}</label>
|
||||
<input
|
||||
type="text"
|
||||
value={referralCode}
|
||||
onChange={(e) => setReferralCode(e.target.value)}
|
||||
value={referrerAddress}
|
||||
onChange={(e) => setReferrerAddress(e.target.value)}
|
||||
className={inputClass}
|
||||
placeholder={t('citizen.referralCodePlaceholder')}
|
||||
placeholder={t('citizen.referrerPlaceholder')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -11,16 +11,15 @@ import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import type { CitizenshipData } from '@/lib/citizenship';
|
||||
import {
|
||||
generateCommitmentHash,
|
||||
generateNullifierHash,
|
||||
calculateIdentityHash,
|
||||
saveCitizenshipLocally,
|
||||
uploadToIPFS,
|
||||
submitCitizenshipApplication,
|
||||
applyCitizenship,
|
||||
} from '@/lib/citizenship';
|
||||
|
||||
interface Props {
|
||||
citizenshipData: CitizenshipData;
|
||||
onSuccess: (blockHash?: string) => void;
|
||||
onSuccess: (identityHash: string, blockHash?: string) => void;
|
||||
onError: (error: string) => void;
|
||||
}
|
||||
|
||||
@@ -32,23 +31,24 @@ export function CitizenProcessing({ citizenshipData, onSuccess, onError }: Props
|
||||
const { peopleApi, keypair } = useWallet();
|
||||
|
||||
const [state, setState] = useState<ProcessingState>('preparing');
|
||||
const [ipfsCid, setIpfsCid] = useState<string>('');
|
||||
const [identityHash, setIdentityHash] = useState<string>('');
|
||||
|
||||
// Prepare data on mount
|
||||
useEffect(() => {
|
||||
const prepare = async () => {
|
||||
try {
|
||||
// Generate commitment hash
|
||||
generateCommitmentHash(citizenshipData);
|
||||
generateNullifierHash(citizenshipData.walletAddress, citizenshipData.timestamp);
|
||||
// Mock IPFS upload
|
||||
const ipfsCid = await uploadToIPFS(citizenshipData);
|
||||
|
||||
// Calculate identity hash (keccak256)
|
||||
const hash = calculateIdentityHash(citizenshipData.fullName, citizenshipData.email, [
|
||||
ipfsCid,
|
||||
]);
|
||||
setIdentityHash(hash);
|
||||
|
||||
// Save encrypted data locally
|
||||
saveCitizenshipLocally(citizenshipData);
|
||||
|
||||
// Mock IPFS upload
|
||||
const cid = await uploadToIPFS(citizenshipData);
|
||||
setIpfsCid(cid);
|
||||
|
||||
// Small delay to show animation
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||
|
||||
@@ -72,18 +72,16 @@ export function CitizenProcessing({ citizenshipData, onSuccess, onError }: Props
|
||||
hapticImpact('medium');
|
||||
|
||||
try {
|
||||
const result = await submitCitizenshipApplication(
|
||||
const result = await applyCitizenship(
|
||||
peopleApi,
|
||||
keypair,
|
||||
citizenshipData.fullName,
|
||||
citizenshipData.email,
|
||||
ipfsCid,
|
||||
`Citizenship application - ${citizenshipData.region}`
|
||||
identityHash,
|
||||
citizenshipData.referrerAddress || null
|
||||
);
|
||||
|
||||
if (result.success) {
|
||||
hapticNotification('success');
|
||||
onSuccess(result.blockHash);
|
||||
onSuccess(identityHash, result.blockHash);
|
||||
} else {
|
||||
hapticNotification('error');
|
||||
onError(result.error || t('citizen.submissionFailed'));
|
||||
@@ -96,7 +94,7 @@ export function CitizenProcessing({ citizenshipData, onSuccess, onError }: Props
|
||||
peopleApi,
|
||||
keypair,
|
||||
citizenshipData,
|
||||
ipfsCid,
|
||||
identityHash,
|
||||
hapticImpact,
|
||||
hapticNotification,
|
||||
onSuccess,
|
||||
@@ -124,6 +122,9 @@ export function CitizenProcessing({ citizenshipData, onSuccess, onError }: Props
|
||||
{state === 'preparing' && (
|
||||
<p className="text-sm text-muted-foreground">{citizenshipData.fullName}</p>
|
||||
)}
|
||||
{state === 'ready' && (
|
||||
<p className="text-xs text-muted-foreground">{t('citizen.depositRequired')}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Sign Button */}
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
/**
|
||||
* Citizen Success Screen
|
||||
* Shows after successful citizenship application submission
|
||||
* Displays pending referral status instead of final approval
|
||||
*/
|
||||
|
||||
import { CheckCircle } from 'lucide-react';
|
||||
import { CheckCircle, Clock } from 'lucide-react';
|
||||
import { useTranslation } from '@/i18n';
|
||||
import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { formatAddress } from '@/lib/wallet-service';
|
||||
import { generateCitizenNumber } from '@/lib/citizenship';
|
||||
|
||||
interface Props {
|
||||
address: string;
|
||||
identityHash: string;
|
||||
onOpenApp: () => void;
|
||||
}
|
||||
|
||||
export function CitizenSuccess({ address, onOpenApp }: Props) {
|
||||
export function CitizenSuccess({ address, identityHash, onOpenApp }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const { hapticImpact } = useTelegram();
|
||||
|
||||
// Generate a citizen number based on address
|
||||
const citizenNumber = generateCitizenNumber(address, 42, 0);
|
||||
const citizenId = `#42-0-${citizenNumber}`;
|
||||
|
||||
const handleOpenApp = () => {
|
||||
hapticImpact('medium');
|
||||
onOpenApp();
|
||||
@@ -36,15 +33,18 @@ export function CitizenSuccess({ address, onOpenApp }: Props) {
|
||||
|
||||
{/* Title */}
|
||||
<div className="text-center space-y-2">
|
||||
<h1 className="text-2xl font-bold">{t('citizen.successTitle')}</h1>
|
||||
<p className="text-muted-foreground">{t('citizen.successSubtitle')}</p>
|
||||
<h1 className="text-2xl font-bold">{t('citizen.applicationSubmitted')}</h1>
|
||||
<div className="flex items-center justify-center gap-2 text-yellow-500">
|
||||
<Clock className="w-4 h-4" />
|
||||
<p className="text-sm">{t('citizen.pendingReferral')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Citizen ID Card */}
|
||||
{/* Application Info Card */}
|
||||
<div className="w-full max-w-sm bg-muted/50 rounded-2xl p-5 space-y-4 border border-border">
|
||||
<div>
|
||||
<p className="text-xs text-muted-foreground">{t('citizen.citizenId')}</p>
|
||||
<p className="text-xl font-mono font-bold text-primary">{citizenId}</p>
|
||||
<p className="text-xs text-muted-foreground">{t('citizen.identityHash')}</p>
|
||||
<p className="text-sm font-mono break-all">{formatAddress(identityHash)}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-muted-foreground">{t('citizen.walletAddress')}</p>
|
||||
@@ -52,6 +52,11 @@ export function CitizenSuccess({ address, onOpenApp }: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Info Note */}
|
||||
<p className="text-xs text-muted-foreground text-center max-w-sm">
|
||||
{t('citizen.applicationInfo')}
|
||||
</p>
|
||||
|
||||
{/* Open App Button */}
|
||||
<button
|
||||
onClick={handleOpenApp}
|
||||
|
||||
Reference in New Issue
Block a user