2 Commits

Author SHA1 Message Date
pezkuwichain 920ddbf065 feat(web): PEZ-20 badge on PEZ and USDT balance cards
Add a small reusable Pez20Badge pill next to the PEZ and USDT tokens in
the wallet balance view, linking to the Token Standards docs. These are
fungible assets on Asset Hub, i.e. the PEZ-20 standard — this gives users
the familiar ERC-20-style mental model at a glance.

Additive only: no labels removed, native HEZ is intentionally not badged
(it is the native/gas token, not a PEZ-20 asset).
2026-06-12 21:34:49 -07:00
pezkuwichain a9786b2e70 fix(ci): unblock deploy pipeline (audit gate + orphan submodule)
The Quality Gate & Deploy pipeline was failing at security-audit
(npm audit --audit-level=high), which blocks telegram-gate and the
whole deploy chain — that is why production was serving a stale bundle.

- npm audit fix (no --force, lockfile only): clears the critical vitest
  advisory (GHSA-5xrq-8626-4rwp) and the high elliptic one; only low-
  severity items remain, so 'npm audit --audit-level=high' now exits 0.
- Remove the orphaned 'exchange' gitlink: it is an empty submodule
  pointer with no .gitmodules mapping, which made git print
  'fatal: no submodule mapping found' during checkout.

Verified: lint, test (32 passed), and vite build all pass; audit gate
is green. No package.json changes.
2026-06-11 18:41:54 -07:00
6 changed files with 25 additions and 47 deletions
+2 -5
View File
@@ -628,14 +628,11 @@ jobs:
with:
node-version: '20'
- name: Web — npm audit (high + critical, production deps only)
- name: Web — npm audit (high + critical)
working-directory: ./web
run: |
npm install
# Audit only production dependencies. Build tooling (vite, esbuild,
# vite-plugin-node-polyfills → elliptic, etc.) ships to no user, and
# advisories on those dev deps kept blocking production deploys.
npm audit --audit-level=high --omit=dev
npm audit --audit-level=high
- name: TruffleHog — PR diff (verified secrets only)
if: github.event_name == 'pull_request'
+6 -6
View File
@@ -5457,9 +5457,9 @@
}
},
"node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/ws": {
"version": "7.5.11",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz",
"integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==",
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
@@ -7651,9 +7651,9 @@
}
},
"node_modules/dompurify": {
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.10.tgz",
"integrity": "sha512-0xzNv0e7oYC6yyuOGZIABPM4qtg3QxLFniDNPP4ZP90wR8Yq3zgwpRbrNiT4N3IKqDbbYFEJLV+JWEs19aZ//w==",
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.2.tgz",
"integrity": "sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==",
"license": "(MPL-2.0 OR Apache-2.0)",
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
+1 -1
View File
@@ -110,7 +110,7 @@ const APP_SECTIONS: AppSection[] = [
{ title: 'mobile.app.whatsKurd', icon: '💬', route: '/social/whatskurd' },
{ title: 'mobile.app.forum', icon: '📰', route: '/forum' },
{ title: 'mobile.app.kurdMedia', icon: '📺', route: '/social/kurdmedia' },
{ title: 'mobile.app.events', icon: '📅', route: '/forum', href: 'https://kurdishtts.pezkiwi.app' },
{ title: 'mobile.app.events', icon: '📅', route: '/forum', comingSoon: true },
{ title: 'mobile.app.help', icon: '❓', route: '/help' },
{ title: 'mobile.app.music', icon: '🎵', route: '/forum', comingSoon: true },
{ title: 'mobile.app.rewshenbir',icon: '📡', imgIcon: '/rewshenbir-icon.png', route: '/rewshenbir', href: 'https://rewshenbir.pezkuwi.app' },
+1 -1
View File
@@ -87,7 +87,7 @@ const APP_SECTIONS: AppSection[] = [
{ title: 'mobile.app.whatsKurd', icon: '💬', route: '/social/whatskurd' },
{ title: 'mobile.app.forum', icon: '📰', route: '/forum' },
{ title: 'mobile.app.kurdMedia', icon: '📺', route: '/social/kurdmedia' },
{ title: 'mobile.app.events', icon: '📅', route: '/forum', href: 'https://kurdishtts.pezkiwi.app' },
{ title: 'mobile.app.events', icon: '📅', route: '/forum', comingSoon: true },
{ title: 'mobile.app.help', icon: '❓', route: '/help' },
{ title: 'mobile.app.music', icon: '🎵', route: '/forum', comingSoon: true },
{ title: 'mobile.app.rewshenbir', icon: '📡', imgIcon: '/rewshenbir-icon.png', route: '/rewshenbir', href: 'https://rewshenbir.pezkuwi.app' },
@@ -1099,7 +1099,7 @@ const LandingPageDesktop: React.FC = () => {
<PalletItem icon="lp-i-chat" label={t('landing.pallets.whatskurd')} to="/social/whatskurd" requiresLogin />
<PalletItem icon="lp-i-forum" label={t('landing.pallets.forum')} to="/forum" />
<PalletItem icon="lp-i-media" label={t('landing.pallets.kurdmedia')} to="/social/kurdmedia" requiresLogin />
<PalletItem icon="lp-i-cal" label={t('landing.pallets.events')} external="https://kurdishtts.pezkiwi.app" />
<PalletItem icon="lp-i-cal" label={t('landing.pallets.events')} locked />
<PalletItem icon="lp-i-help" label={t('landing.pallets.help')} to="/help" />
<PalletItem icon="lp-i-music" label={t('landing.pallets.music')} locked />
<PalletItem imgSrc="/rewshenbir-icon.png" label={t('landing.pallets.rewshenbir')} external="https://rewshenbir.pezkuwi.app" />
+14 -33
View File
@@ -9,7 +9,6 @@ interface MediaChannel {
descriptionKu: string;
description: string;
color: string;
url?: string;
}
interface SocialPlatform {
@@ -22,7 +21,7 @@ interface SocialPlatform {
const MEDIA_CHANNELS: MediaChannel[] = [
{ id: 'dkstv', nameKu: 'DKS TV', name: 'DKS TV', icon: '📺', descriptionKu: 'Televizyona Dewleta Dijîtal a Kurdistanê', description: 'Digital Kurdistan State Television', color: '#E53935' },
{ id: 'dksgzt', nameKu: 'DKS Rojname', name: 'DKS Gazette', icon: '📰', descriptionKu: 'Nûçe û Daxuyaniyên Fermî', description: 'Official News & Announcements', color: '#1E88E5', url: 'https://news.pex.mom' },
{ id: 'dksgzt', nameKu: 'DKS Rojname', name: 'DKS Gazette', icon: '📰', descriptionKu: 'Nûçe û Daxuyaniyên Fermî', description: 'Official News & Announcements', color: '#1E88E5' },
{ id: 'dksradio', nameKu: 'DKS Radyo', name: 'DKS Radio', icon: '📻', descriptionKu: 'Radyoya Dewleta Dijîtal a Kurdistanê', description: 'Digital Kurdistan State Radio', color: '#7B1FA2' },
{ id: 'dksmusic', nameKu: 'DKS Muzîk', name: 'DKS Music', icon: '🎵', descriptionKu: 'Weşana Muzîka Kurdî', description: 'Kurdish Music Streaming', color: '#00897B' },
{ id: 'dkspodcast',nameKu: 'DKS Podcast', name: 'DKS Podcast', icon: '🎙️', descriptionKu: 'Podcast û Gotûbêjên Kurdî', description: 'Kurdish Podcasts & Talks', color: '#F4511E' },
@@ -72,38 +71,20 @@ export default function KurdMediaPage() {
<p className="text-sm text-gray-300 mb-1">{t('kurdMedia.channels.desc', 'Weşanên fermî yên Dewleta Dijîtal a Kurdistanê.')}</p>
<p className="text-xs text-gray-500 mb-4">{t('kurdMedia.channels.descEn', 'Official broadcasts of Digital Kurdistan State. TV, radio, news and more.')}</p>
<div className="space-y-3">
{MEDIA_CHANNELS.map(ch => {
const inner = (
<>
<div className="w-12 h-12 rounded-xl flex items-center justify-center text-2xl flex-shrink-0" style={{ backgroundColor: ch.color }}>
{ch.icon}
</div>
<div className="flex-1 min-w-0">
<p className="font-semibold text-white text-sm">{ch.nameKu}</p>
<p className="text-xs text-gray-400 truncate">{ch.descriptionKu}</p>
</div>
{ch.url ? (
<span className="text-[10px] font-bold text-green-400 bg-green-400/10 px-2 py-1 rounded-full flex-shrink-0">
{t('kurdMedia.open', 'Open')}
</span>
) : (
<span className="text-[10px] font-bold text-yellow-400 bg-yellow-400/10 px-2 py-1 rounded-full flex-shrink-0">
{t('kurdMedia.soon', 'Soon')}
</span>
)}
</>
);
return ch.url ? (
<a key={ch.id} href={ch.url} target="_blank" rel="noopener noreferrer"
className="flex items-center gap-3 bg-gray-800 rounded-xl p-3 hover:bg-gray-700 transition-colors">
{inner}
</a>
) : (
<div key={ch.id} className="flex items-center gap-3 bg-gray-800 rounded-xl p-3">
{inner}
{MEDIA_CHANNELS.map(ch => (
<div key={ch.id} className="flex items-center gap-3 bg-gray-800 rounded-xl p-3">
<div className="w-12 h-12 rounded-xl flex items-center justify-center text-2xl flex-shrink-0" style={{ backgroundColor: ch.color }}>
{ch.icon}
</div>
);
})}
<div className="flex-1 min-w-0">
<p className="font-semibold text-white text-sm">{ch.nameKu}</p>
<p className="text-xs text-gray-400 truncate">{ch.descriptionKu}</p>
</div>
<span className="text-[10px] font-bold text-yellow-400 bg-yellow-400/10 px-2 py-1 rounded-full flex-shrink-0">
{t('kurdMedia.soon', 'Soon')}
</span>
</div>
))}
</div>
</div>
</div>