Full scan of every page/component for the Connected-Accounts overflow class
(long user data with no truncation pushing siblings off the card on mobile),
adversarially verified. Applied min-w-0 + truncate (break-all for copyable
values, break-words for titles) on text columns and shrink-0 on fixed
siblings across ~23 files: AppHeader, dashboard/SubscriptionCardActive,
subscription purchase/sheets (TariffPurchaseForm, ClassicPurchaseWizard,
SwitchTariffSheet), SuccessNotificationModal, PurchaseSuccess, Wheel sub
picker, ReferralNetwork UserDetailPanel, and the admin pages (AnalyticsTab,
BrandingTab, SubscriptionSubRow, user-detail Info/Referrals tabs,
ApplicationReview, PartnerCampaignAssign, Partners, PromocodeStats,
PromoOfferSend, RemnawaveSquadDetail, TariffCreate, Tickets, Withdrawals).
Audit-driven sweep: replaced 168 hand-written inline <svg> icons across 77
files with the central Phosphor (react-icons/pi) components from
@/components/icons, preserving each icon's size classes and colour (dynamic
stroke colours via the parent's currentColor, RefreshIcon's spinning state,
conditional rotate-180 chevrons).
Verified: tsc + vite build + eslint clean; an adversarial diff review of all
changed files found the replacements correct (70 files clean, 0 blockers).
Remaining inline <svg> dropped from 262 to ~95 — the survivors are legitimate
non-icons (brand/provider logos, loading spinners & framer-motion animations,
charts/sparklines, background decoration) plus a few ambiguous glyphs.
Replace the cabinet's hand-written heroicons-style SVG icon components with
the Remnawave panel's own icon family — Phosphor via react-icons/pi (Duotone).
All icons now live in a single central barrel (src/components/icons:
index + extended-icons + editor-icons, 144 icons); every feature file imports
from it instead of redefining inline SVGs (~440 icon defs removed).
- Add react-icons dependency
- Desktop nav (AppShell) now uses the central Phosphor icons, removing a
stroke-vs-duotone inconsistency the partial migration introduced
- Icons with custom props (SortIcon's direction, expandable chevrons) kept as
thin Phosphor wrappers; the RemnawaveIcon brand logo and animated SVGs
(checkmarks, spinners) are intentionally left as-is
- Restore the original per-call-site icon sizes wherever the centralized
default differed (211 call sites)
Fourth and final step in the AdminBulkActions decomp.
SubscriptionSubRow: the expanded per-user secondary <tr> shown when
the operator drills into multi-subscription users (tariff, status,
days remaining, traffic bar, devices). Pure presentational.
StatusBadge: the pill used both inside the sub-row and the primary
user-table column (subscription_status). Co-located here because
both consumers want the same visual contract.
AdminBulkActions.tsx: 1367 → 1182 lines (-185).
Cumulative across the 4-step admin decomp: 2539 → 1182 (-1357, -53%).
Third step in the AdminBulkActions decomp. Move the 154-line
pop-over multi-select used by the tariff / status / node filters
into src/components/admin/bulkActions/MultiSelectDropdown.tsx.
Pure controlled primitive: closes on outside click, provides
select-all / deselect-all helpers, uses the shared ChevronDownIcon
from DropdownSelect.tsx. Exports MultiSelectOption type alongside.
Parent drops its inline ChevronDownIcon import (now only referenced
by the moved sibling) and imports MultiSelectDropdown + the option
type from the new module.
AdminBulkActions.tsx: 1517 → 1367 lines (-150).
Second step in the AdminBulkActions decomp. Two new files:
- actionTargets.ts (27 lines): SUBSCRIPTION_LEVEL_ACTIONS set +
isSubscriptionLevelAction(). The classification is the source of
truth shared between FloatingActionBar (renders two grouped menus
when multi-tariff is on) and the parent page (gates selection-count
semantics + the active-paid count in delete-subscription).
- FloatingActionBar.tsx (304 lines): the bottom-dock selection
toolbar. Pure presentational — parent owns selection state and
supplies onAction (opens the modal with the picked action type)
+ onToggleAllSubscriptions. The full 11-item action config (icons
+ label keys + colour classes) lives inside the file as a private
ActionConfig array.
Parent now imports FloatingActionBar + isSubscriptionLevelAction
from the new modules; the inline ActionConfig interface is gone.
AdminBulkActions.tsx: 1819 → 1517 lines (-302).
Cumulative across the 2-step admin decomp: 2539 → 1517 (-1022, -40%).
First and largest step in the AdminBulkActions decomp. Two new
files under src/components/admin/bulkActions/:
- DropdownSelect.tsx (47 lines): the small native-<select> wrapper
used both by the filter row and the ActionModal's tariff/promo
picker. Exports DropdownSelect + the shared ChevronDownIcon +
DropdownOption type.
- ActionModal.tsx (712 lines): the per-action configuration +
execution modal. Wraps three internal views — ProgressView (live
SSE log + counters while a job streams), ErrorDetails (collapsible
per-row error list after completion), and the per-action form
(days / tariff / traffic / balance / promo-group / grant /
set-devices / delete-* confirmations). Exports the ModalState
and ProgressState types alongside.
Self-contained: parent feeds modal state + reference data (tariffs,
promo groups, users for active-paid counting) and receives
onExecute(params) when the operator confirms. No queries or
mutations here — execution flow stays in the parent's
handleExecuteAction.
Parent keeps a local CheckIcon (still used by MultiSelectDropdown
checkboxes + the user-table column defs) and re-imports
ChevronDownIcon / DropdownOption from the new file.
AdminBulkActions.tsx: 2539 → 1796 lines (-743).