From fe2cd390f62f61737eadf9548ba4e1c6f1696163 Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Fri, 12 Dec 2025 03:48:57 +0300 Subject: [PATCH] feat(p2p): add Kurdish diaspora payment methods (130+ total) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 61 new payment methods for diaspora countries: - Germany (EUR): Sparkasse, Commerzbank, DKB, etc. - Sweden (SEK): Swish, Nordea, SEB, Swedbank - UK (GBP): Faster Payments, Barclays, HSBC, Monzo - France (EUR): Crédit Agricole, Lydia, BNP Paribas - Netherlands (EUR): iDEAL, ABN AMRO, Bunq, Tikkie - Belgium (EUR): Bancontact, KBC - Austria (EUR): Erste Bank, Raiffeisen - Switzerland (CHF): TWINT, UBS, PostFinance - Norway (NOK): Vipps, DNB, SpareBank 1 - Denmark (DKK): MobilePay, Danske Bank - Australia (AUD): PayID, Commonwealth Bank - Canada (CAD): Interac e-Transfer, TD Bank - Expand FiatCurrency type: SEK, GBP, CHF, NOK, DKK, AUD, CAD - Update CreateAd, BlockTrade, ExpressMode components - Add regional labels (Bakur, Başûr, Rojhilat, EU diaspora) --- shared/lib/p2p-fiat.ts | 15 +- web/src/components/p2p/BlockTrade.tsx | 385 ++++++++++ web/src/components/p2p/CreateAd.tsx | 18 +- web/src/components/p2p/ExpressMode.tsx | 369 +++++++++ .../015_expanded_payment_methods.sql | 714 ++++++++++++++++++ 5 files changed, 1496 insertions(+), 5 deletions(-) create mode 100644 web/src/components/p2p/BlockTrade.tsx create mode 100644 web/src/components/p2p/ExpressMode.tsx create mode 100644 web/supabase/migrations/015_expanded_payment_methods.sql diff --git a/shared/lib/p2p-fiat.ts b/shared/lib/p2p-fiat.ts index 02a1de6d..bff84741 100644 --- a/shared/lib/p2p-fiat.ts +++ b/shared/lib/p2p-fiat.ts @@ -41,7 +41,20 @@ export interface ValidationRule { required?: boolean; } -export type FiatCurrency = 'TRY' | 'IQD' | 'IRR' | 'EUR' | 'USD'; +// Fiat currencies including Kurdish Diaspora countries +export type FiatCurrency = + | 'TRY' // Turkish Lira (Turkey - 15M+ Kurds) + | 'IQD' // Iraqi Dinar (Kurdistan Region - 6M+ Kurds) + | 'IRR' // Iranian Rial (Rojhilat - 8M+ Kurds) + | 'EUR' // Euro (Germany, France, Netherlands, Belgium, Austria) + | 'USD' // US Dollar + | 'GBP' // British Pound (UK - 50K+ Kurds) + | 'SEK' // Swedish Krona (Sweden - 100K+ Kurds) + | 'CHF' // Swiss Franc (Switzerland - 30K+ Kurds) + | 'NOK' // Norwegian Krone (Norway - 30K+ Kurds) + | 'DKK' // Danish Krone (Denmark - 25K+ Kurds) + | 'AUD' // Australian Dollar (Australia - 20K+ Kurds) + | 'CAD'; // Canadian Dollar (Canada - 30K+ Kurds) export type CryptoToken = 'HEZ' | 'PEZ'; export type OfferStatus = 'open' | 'paused' | 'locked' | 'completed' | 'cancelled'; diff --git a/web/src/components/p2p/BlockTrade.tsx b/web/src/components/p2p/BlockTrade.tsx new file mode 100644 index 00000000..d2399ca2 --- /dev/null +++ b/web/src/components/p2p/BlockTrade.tsx @@ -0,0 +1,385 @@ +/** + * Block Trade Component - OKX-Style OTC Trading + * + * Block trades are for large volume trades that are handled differently + * from regular P2P trades. They offer: + * - Custom pricing negotiation + * - Dedicated support + * - Multi-tranche settlements + * - Enhanced privacy + */ + +import React, { useState } from 'react'; +import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Badge } from '@/components/ui/badge'; +import { Textarea } from '@/components/ui/textarea'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'; +import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import { + Blocks, Shield, Clock, Lock, MessageSquare, ChevronRight, + Building2, AlertTriangle +} from 'lucide-react'; +import { supabase } from '@/lib/supabase'; +import { useAuth } from '@/contexts/AuthContext'; +import { toast } from 'sonner'; +import type { CryptoToken, FiatCurrency } from '@pezkuwi/lib/p2p-fiat'; + +interface BlockTradeRequest { + id: string; + type: 'buy' | 'sell'; + token: CryptoToken; + fiat_currency: FiatCurrency; + amount: number; + target_price?: number; + message?: string; + status: 'pending' | 'negotiating' | 'approved' | 'in_progress' | 'completed' | 'cancelled'; + created_at: string; +} + +const SUPPORTED_TOKENS: CryptoToken[] = ['HEZ', 'PEZ']; + +// All supported fiat currencies including Kurdish Diaspora countries +const SUPPORTED_FIATS: { code: FiatCurrency; name: string; symbol: string; region: string }[] = [ + // Primary regions (Kurdistan & neighboring) + { code: 'TRY', name: 'Turkish Lira', symbol: '₺', region: 'Bakur' }, + { code: 'IQD', name: 'Iraqi Dinar', symbol: 'د.ع', region: 'Başûr' }, + { code: 'IRR', name: 'Iranian Rial', symbol: '﷼', region: 'Rojhilat' }, + // Eurozone diaspora + { code: 'EUR', name: 'Euro', symbol: '€', region: 'EU' }, + // Other diaspora regions + { code: 'USD', name: 'US Dollar', symbol: '$', region: 'USA' }, + { code: 'GBP', name: 'British Pound', symbol: '£', region: 'UK' }, + { code: 'SEK', name: 'Swedish Krona', symbol: 'kr', region: 'Sweden' }, + { code: 'CHF', name: 'Swiss Franc', symbol: 'Fr.', region: 'Switzerland' }, + { code: 'NOK', name: 'Norwegian Krone', symbol: 'kr', region: 'Norway' }, + { code: 'DKK', name: 'Danish Krone', symbol: 'kr', region: 'Denmark' }, + { code: 'AUD', name: 'Australian Dollar', symbol: 'A$', region: 'Australia' }, + { code: 'CAD', name: 'Canadian Dollar', symbol: 'C$', region: 'Canada' }, +]; + +// Minimum amounts for block trade (in USD equivalent) +const MINIMUM_BLOCK_AMOUNTS: Record = { + HEZ: 10000, // 10,000 HEZ minimum + PEZ: 50000, // 50,000 PEZ minimum +}; + +export function BlockTrade() { + const [showRequestModal, setShowRequestModal] = useState(false); + const [type, setType] = useState<'buy' | 'sell'>('buy'); + const [token, setToken] = useState('HEZ'); + const [fiat, setFiat] = useState('USD'); + const [amount, setAmount] = useState(''); + const [targetPrice, setTargetPrice] = useState(''); + const [message, setMessage] = useState(''); + const [isSubmitting, setIsSubmitting] = useState(false); + const [requests, setRequests] = useState([]); + + const { user } = useAuth(); + const fiatSymbol = SUPPORTED_FIATS.find(f => f.code === fiat)?.symbol || ''; + const minAmount = MINIMUM_BLOCK_AMOUNTS[token]; + + // Fetch user's block trade requests + React.useEffect(() => { + if (!user) return; + + const fetchRequests = async () => { + const { data, error } = await supabase + .from('p2p_block_trade_requests') + .select('*') + .eq('user_id', user.id) + .order('created_at', { ascending: false }); + + if (!error && data) { + setRequests(data); + } + }; + + fetchRequests(); + }, [user]); + + const handleSubmitRequest = async () => { + if (!user) { + toast.error('Please login to submit a block trade request'); + return; + } + + const amountNum = parseFloat(amount); + if (isNaN(amountNum) || amountNum < minAmount) { + toast.error(`Minimum amount for ${token} block trade is ${minAmount.toLocaleString()} ${token}`); + return; + } + + setIsSubmitting(true); + try { + const { data, error } = await supabase + .from('p2p_block_trade_requests') + .insert({ + user_id: user.id, + type, + token, + fiat_currency: fiat, + amount: amountNum, + target_price: targetPrice ? parseFloat(targetPrice) : null, + message: message || null, + status: 'pending' + }) + .select() + .single(); + + if (error) throw error; + + toast.success('Block trade request submitted! Our OTC desk will contact you within 24 hours.'); + setShowRequestModal(false); + setAmount(''); + setTargetPrice(''); + setMessage(''); + + // Add to local state + setRequests(prev => [data, ...prev]); + } catch (err) { + console.error('Block trade request error:', err); + toast.error('Failed to submit request'); + } finally { + setIsSubmitting(false); + } + }; + + const getStatusBadge = (status: BlockTradeRequest['status']) => { + const styles: Record = { + pending: 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30', + negotiating: 'bg-blue-500/20 text-blue-400 border-blue-500/30', + approved: 'bg-green-500/20 text-green-400 border-green-500/30', + in_progress: 'bg-purple-500/20 text-purple-400 border-purple-500/30', + completed: 'bg-gray-500/20 text-gray-400 border-gray-500/30', + cancelled: 'bg-red-500/20 text-red-400 border-red-500/30', + }; + return styles[status] || styles.pending; + }; + + return ( + <> + + +
+
+
+ +
+
+ Block Trade (OTC) + + Large volume trades with custom pricing + +
+
+ + VIP + +
+
+ + {/* Features */} +
+
+ + Private Negotiation +
+
+ + Escrow Protected +
+
+ + Dedicated Support +
+
+ + Flexible Settlement +
+
+ + {/* Minimum Amounts Info */} +
+

Minimum Block Trade Amounts:

+
+ {Object.entries(MINIMUM_BLOCK_AMOUNTS).map(([t, min]) => ( + + {min.toLocaleString()} {t} + + ))} +
+
+ + {/* Request Button */} + + + {/* Active Requests */} + {requests.length > 0 && ( +
+

Your Requests:

+ {requests.slice(0, 3).map(req => ( +
+
+ + {req.type.toUpperCase()} + + + {req.amount.toLocaleString()} {req.token} + +
+ + {req.status.replace('_', ' ')} + +
+ ))} +
+ )} +
+
+ + {/* Request Modal */} + + + + + + Block Trade Request + + + Submit a request for our OTC desk to handle your large volume trade. + + + +
+ {/* Buy/Sell Toggle */} + setType(v as 'buy' | 'sell')}> + + + Buy + + + Sell + + + + + {/* Token & Fiat */} +
+
+ + +
+
+ + +
+
+ + {/* Amount */} +
+ + setAmount(e.target.value)} + className="bg-gray-800 border-gray-700" + /> +

+ Minimum: {minAmount.toLocaleString()} {token} +

+
+ + {/* Target Price (Optional) */} +
+ +
+ setTargetPrice(e.target.value)} + className="bg-gray-800 border-gray-700 pr-16" + /> + + {fiatSymbol}/{token} + +
+
+ + {/* Message */} +
+ +