From db46670a997867b6c2bff04596a1eabd49f28bd0 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Sun, 30 Aug 2026 11:41:02 +0200 Subject: [PATCH] smaller fixes --- src/components/DeveloperOnboardingModal.css | 45 +- src/components/DeveloperOnboardingModal.tsx | 206 +++++---- src/components/SecuritySetupCards.tsx | 444 ++++++++++++-------- src/pages/dashboard/DashboardPlugins.tsx | 38 +- 4 files changed, 399 insertions(+), 334 deletions(-) diff --git a/src/components/DeveloperOnboardingModal.css b/src/components/DeveloperOnboardingModal.css index 52879ba..dac7a20 100644 --- a/src/components/DeveloperOnboardingModal.css +++ b/src/components/DeveloperOnboardingModal.css @@ -7,7 +7,8 @@ display: flex; align-items: center; justify-content: center; - padding: 1.5rem; + padding: 1.25rem; + overflow-y: auto; } .dev-onboarding-embedded { @@ -22,10 +23,27 @@ border-radius: 16px; width: 100%; max-width: 580px; - padding: 2.25rem; + max-height: calc(100vh - 2.5rem); + overflow-y: auto; + padding: 1.75rem; position: relative; box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5); color: var(--text-color, #e2e8f0); + scrollbar-width: thin; + scrollbar-color: rgba(255, 255, 255, 0.15) transparent; +} + +.dev-modal-container::-webkit-scrollbar { + width: 6px; +} + +.dev-modal-container::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.15); + border-radius: 4px; +} + +.dev-modal-container::-webkit-scrollbar-track { + background: transparent; } .dev-modal-close { @@ -372,46 +390,47 @@ .dev-monetization-box { background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 12px; - padding: 1.25rem; + border-radius: 10px; + padding: 0.85rem 1rem; } .dev-monetization-header { display: flex; - gap: 0.75rem; - align-items: flex-start; + gap: 0.65rem; + align-items: center; color: #f97316; } .dev-monetization-header h4 { - margin: 0 0 0.2rem 0; + margin: 0 0 0.15rem 0; color: #fff; - font-size: 1rem; + font-size: 0.95rem; } .dev-monetization-header p { margin: 0; - font-size: 0.85rem; + font-size: 0.8rem; color: var(--text-muted, #94a3b8); } .dev-check-list { list-style: none; padding: 0; - margin: 1rem 0 0 0; + margin: 0.5rem 0 0 0; display: flex; flex-direction: column; - gap: 0.5rem; + gap: 0.35rem; } .dev-check-list li { display: flex; align-items: center; - gap: 0.5rem; - font-size: 0.85rem; + gap: 0.45rem; + font-size: 0.8rem; color: #e2e8f0; } .dev-check-list svg { color: #22c55e; + flex-shrink: 0; } diff --git a/src/components/DeveloperOnboardingModal.tsx b/src/components/DeveloperOnboardingModal.tsx index 39466d6..f29d46c 100644 --- a/src/components/DeveloperOnboardingModal.tsx +++ b/src/components/DeveloperOnboardingModal.tsx @@ -25,7 +25,7 @@ export const DeveloperOnboardingModal: React.FC = embedded = false, }) => { const { t } = useTranslation(); - const { user, login } = useAuth(); + const { user, login, refreshUser } = useAuth(); const [step, setStep] = useState(1); const [entityType, setEntityType] = useState<'individual' | 'organization'>('individual'); const [orgType, setOrgType] = useState(''); @@ -582,117 +582,93 @@ export const DeveloperOnboardingModal: React.FC = {/* ── STEP 5: Finish & Confirmation ── */} {step === 5 && (
- {!isSellingPaid ? ( - <> -
-
- -
-

Ready to Publish Free Plugins!

-

Your developer profile is configured for free & open-source uploads.

-
-
-
    -
  • Publish unlimited free plugins ($0 fee)
  • -
  • Full analytics and review dashboard
  • -
  • Option to add address & sell paid plugins anytime later
  • -
-
- - {/* ── Security Requirement for Developers ── */} - {!hasSecureAuth && ( -
- {}} - /> -
+
+
+ {!isSellingPaid ? ( + + ) : ( + )} - - {/* ── Mandatory Legal Consent ── */} -
-
+
-
- -
- + {/* ── Security Requirement for Developers ── */} + {hasSecureAuth ? ( +
+ + Security Verified: 2FA / Passkey protection is active on your account. +
) : ( - <> -
-
- -
-

{t('developer.onboarding.intent_paid')}

-

{t('developer.onboarding.intent_paid_desc')}

-
-
-
    -
  • Automated payouts directly to your bank account
  • -
  • Set custom pricing, discounts, and coupons
  • -
  • Automated license key generation for buyers
  • -
-
+
+ { + if (refreshUser) await refreshUser(); + }} + /> +
+ )} - {/* ── Security Requirement for Developers ── */} - {!hasSecureAuth && ( -
- {}} - /> -
- )} + {/* ── Mandatory Legal Consent ── */} +
+ +
- {/* ── Mandatory Legal Consent ── */} -
- -
- -
+ {/* Actions */} +
+ {isSellingPaid ? ( + <> -
- - )} + + ) : ( + + )} +
-
- +
+
)} diff --git a/src/components/SecuritySetupCards.tsx b/src/components/SecuritySetupCards.tsx index 8695ff9..69d13c4 100644 --- a/src/components/SecuritySetupCards.tsx +++ b/src/components/SecuritySetupCards.tsx @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import { useAuth } from '../App'; import api from '../api'; import { startRegistration } from '@simplewebauthn/browser'; +import { QRCodeSVG } from 'qrcode.react'; import { RecoveryCodesModal } from './RecoveryCodesModal'; import { Fingerprint, @@ -24,6 +25,7 @@ interface SecuritySetupCardsProps { onSkip?: () => void; canSkip?: boolean; isRequired?: boolean; + compact?: boolean; } export const SecuritySetupCards: React.FC = ({ @@ -33,6 +35,7 @@ export const SecuritySetupCards: React.FC = ({ onSkip, canSkip = false, isRequired = false, + compact = false, }) => { const { login, user, refreshUser } = useAuth(); @@ -50,7 +53,7 @@ export const SecuritySetupCards: React.FC = ({ // TOTP State const [totpLoading, setTotpLoading] = useState(false); - const [totpQr, setTotpQr] = useState(null); + const [totpUri, setTotpUri] = useState(null); const [totpSecret, setTotpSecret] = useState(null); const [totpCode, setTotpCode] = useState(''); const [totpVerifying, setTotpVerifying] = useState(false); @@ -63,7 +66,7 @@ export const SecuritySetupCards: React.FC = ({ setExpandedBox(null); } else { setExpandedBox(box); - if (box === 'totp' && !totpQr && !totpSuccess) { + if (box === 'totp' && !totpUri && !totpSuccess) { loadTotpSetup(); } } @@ -74,7 +77,7 @@ export const SecuritySetupCards: React.FC = ({ setTotpLoading(true); setTotpError(null); const res = await api.post('/user/2fa/setup'); - setTotpQr(res.data.qrCode); + setTotpUri(res.data.uri); setTotpSecret(res.data.secret); } catch (err: any) { setTotpError(err.response?.data?.error || 'Failed to initialize 2FA setup.'); @@ -172,7 +175,14 @@ export const SecuritySetupCards: React.FC = ({ const hasSecureAuth = Boolean(user?.totp_enabled || (user?.passkey_count && user.passkey_count > 0) || user?.has_passkey); return ( -
= ({ borderRadius: 20, border: '1px solid var(--mp-border, rgba(255,255,255,0.08))', boxShadow: '0 20px 40px -15px rgba(0,0,0,0.5)', + boxSizing: 'border-box', }}> {/* Header */} -
-
- + {compact ? ( +
+
+
+ +
+
+

+ {title} +

+

+ {description} +

+
+
+ {isRequired && ( + + Required + + )}
-

- {title} -

-

- {description} -

- - {isRequired && ( + ) : ( +
- Required for Plugin Publishing & Developer Verification +
- )} -
+

+ {title} +

+

+ {description} +

+ + {isRequired && ( +
+ Required for Plugin Publishing & Developer Verification +
+ )} +
+ )} {/* Boxes Grid */} -
+
{/* ── Box 1: Passkey / Biometrics (Recommended) ── */}
= ({ onClick={() => toggleBox('passkey')} style={{ width: '100%', - padding: '1.25rem 1.5rem', + padding: compact ? '0.75rem 0.9rem' : '1.25rem 1.5rem', display: 'flex', alignItems: 'center', justifyContent: 'space-between', @@ -261,11 +316,11 @@ export const SecuritySetupCards: React.FC = ({ textAlign: 'left', }} > -
+
= ({ justifyContent: 'center', flexShrink: 0, }}> - +
-
- +
+ Passkey & Biometrics - Recommended + Recommended
-

+

Fastest & most secure. Touch ID, Face ID, Windows Hello, or Security Key.

-
- {expandedBox === 'passkey' ? : } +
+ {expandedBox === 'passkey' ? : }
{/* Passkey Expanded Content */} {expandedBox === 'passkey' && (
- How it works: Passkeys replace passwords and SMS codes with cryptographic keys stored securely in your device’s keychain (Apple Keychain, Google Password Manager, Windows Hello, 1Password, or YubiKey). They are 100% phishing-proof. + How it works: Passkeys replace passwords and SMS codes with cryptographic keys stored securely in your device's keychain. They are 100% phishing-proof.
{passkeyError && ( @@ -330,15 +385,15 @@ export const SecuritySetupCards: React.FC = ({ display: 'flex', alignItems: 'center', gap: '0.5rem', - padding: '0.75rem 1rem', + padding: '0.65rem 0.85rem', background: 'rgba(239, 68, 68, 0.1)', border: '1px solid rgba(239, 68, 68, 0.25)', borderRadius: 8, color: '#f87171', - fontSize: '0.85rem', - marginBottom: '1rem', + fontSize: '0.82rem', + marginBottom: '0.85rem', }}> - + {passkeyError}
)} @@ -348,21 +403,21 @@ export const SecuritySetupCards: React.FC = ({ display: 'flex', alignItems: 'center', gap: '0.5rem', - padding: '0.85rem 1rem', + padding: '0.75rem 1rem', background: 'rgba(34, 197, 94, 0.12)', border: '1px solid rgba(34, 197, 94, 0.3)', borderRadius: 8, color: '#4ade80', - fontSize: '0.9rem', + fontSize: '0.85rem', fontWeight: 600, }}> - - Passkey created successfully! Redirecting... + + Passkey created successfully!
) : ( -
+
-