Skip to content

refactor(app): migrate to shared/features structure and harden popup flows#178

Merged
Kelbie merged 26 commits intomainfrom
refactor/modal-config-features-folder-structure
Mar 6, 2026
Merged

refactor(app): migrate to shared/features structure and harden popup flows#178
Kelbie merged 26 commits intomainfrom
refactor/modal-config-features-folder-structure

Conversation

@Kelbie
Copy link
Contributor

@Kelbie Kelbie commented Mar 6, 2026

What / Why

  • Reorganize the app around features/ and shared/ boundaries so screens, hooks, providers, stores, and UI primitives live in clearer ownership layers.
  • Stabilize popup, profile, and restart behavior after the HeroUI bottom-sheet migration exposed teardown, overlay, and profile-scoping edge cases.
  • Fold in related settings, transaction, and theme cleanup that was needed to complete the migration without leaving broken flows behind.

What changed

  • Migrated a large set of app modules from legacy components/, hooks/, helper/, and stores/ locations into features/, shared/, and updated route/config wiring to match.
  • Reworked the popup system around HeroUI BottomSheet, split popup APIs by domain, unified actionable sheets under button-handler flows, added payment-status toasts, and fixed sheet layering above native modals.
  • Hardened profile lifecycle handling by fixing first-session key derivation, moving profile-scoped storage to pubkey-based keys with migration, improving session orchestration/restart behavior, and tightening provider/store cleanup during switches and deletes.
  • Updated settings and supporting UX by adding/removing debug storage flows as the branch evolved, refreshing theme token usage across major screens, and adding the iOS widget target.
  • Synced rule docs and repo guidance with the new structure and popup/profile safety constraints.

Test plan

  1. Verify popup sheets, button-handler flows, and payment-status toasts render and dismiss correctly from send, receive, wallet, and message surfaces.
  2. Verify profile create, switch, import, restart, and delete flows preserve the root mnemonic, isolate profile data, and do not leave blocked-touch overlays behind.
  3. Verify settings, transaction detail, receive/send, and wallet screens still navigate and render correctly after the features/ and shared/ migration.
  4. Run project validation for linting, type-checking, formatting, dead-code checks, and relevant tests before merge.

Notes / Risks

  • This is a large structural branch touching routing, popup infrastructure, profile/session handling, and docs, so the main review risk is behavioral regressions hidden inside file moves.
  • The branch includes both architectural moves and user-facing fixes because several popup/profile issues only surfaced during the migration and were fixed in place.

Made with Cursor

Kelbie added 26 commits March 3, 2026 19:34
…der rules

- Modal screens: helpers (modalFlow, slideFromRight, modalWithBlur, cardFade,
  fullScreenModal, modalTransparent), remove redundant defaults, fix transaction
  detail header (headerShown: true)
- Settings flow: add _layout as group flow, slideFromRight animation, fix drawer
  nav path (no leading slash)
- Camera: fix scan overlay corners (inline styles for consistency)
- Folder structure: add .cursor/rules/folder-structure.mdc, update AGENTS.md and
  code-quality architecture boundaries
- Features/shared migration: components, hooks, helper, stores, providers moved
  to features/ and shared/

Made-with: Cursor
- Migrate utils/nip17 → shared/lib/nostr/nip17, remove duplicate
- Consolidate map utils (utils/ + features/map/utils/) → shared/lib/map/
- Move hero-transition → shared/providers/hero-transition/
- Move transfer → shared/blocks/transfer/
- Remove utils/ and features/map/utils/ directories
- docs: update folder-structure (utils deprecated, providers/blocks rules)
- docs: fix theme-system-architecture (helper/themeEngine → shared/lib/themeEngine)

Made-with: Cursor
- Replace react-native-actions-sheet with HeroUI BottomSheet for profile
  switcher, emoji picker, and button handler
- Redesign profile switcher to scrollable-with-snap-points layout:
  Select profile header, scrollable list, fixed footer with Generate new
  account and Import nsec
- Add named popup functions (profileSwitcherPopup, emojiPickerPopup,
  buttonHandlerPopup) aligned with popups.ts API
- Add actionSheetTypes and bridge for custom sheet payloads
- Metro resolver for heroui-native; PopupHost handles custom sheets

Made-with: Cursor
- Group popup imports in SendTokenScreen and UserMessagesScreen
- Simplify ImportNsec return in profileSwitcher

Made-with: Cursor
Migrate remaining actionable popup button sheets to buttonHandlerPopup, add nested pushSheet support for SendToken emoji flow, and fix bottom-sheet reopen behavior by syncing close events reliably in PopupHost.

Made-with: Cursor
- Add SheetHeader and SheetContent for consistent action sheet layout
- Remove horizontal padding from profile-style sheets (px-0)
- Fix import nsec form field padding (move Description outside TextField)
- Use AmountFormatter for profile selector balances to match wallet header
- Add IMPORT_NSEC_LABEL constant to avoid duplication

Made-with: Cursor
- Update popup, code-quality, zustand, secure-storage, text, theme, git rules
- Fix globs and path refs: helper/* → shared/lib/*, components/* → shared/*
- Replace DevPopupPanel refs with Wallet __DEV__ test buttons
- Update knip.json ignoreIssues paths
- Fix @module JSDoc in shared/ui, engine, utils, colorUtils
- Add @fileoverview to profileSessionOrchestrator

Made-with: Cursor
- Remove SettingsStorageScreen and storage route from settings flow
- Add iOS widget target (Info.plist, Swift entry, expo-target.config)
- Update settings layout, keyring screen, and explore screen
- Update importNsec sheet and .gitignore

Made-with: Cursor
- createProfileScopedStorage() now uses active profile pubkey for keys
- Key format: {name}:profile:{pubkey} for all profiles (no index collision)
- Add migrateProfileScopedKeys() one-time migration from index-based keys
- clearAllProfileScopedData() now accepts pubkeys instead of indexes
- Wire migration in MigrationGate (runs on every launch, idempotent)
- Fixes imported profiles seeing swap/other data from wrong accounts

Made-with: Cursor
… CocoManager cleanup race

Move PopupHost outside AccountScopedProviders so it is never unmounted
during profile switches, preventing the BottomSheet from being torn down
mid-animation which would leave a native overlay blocking touches.

Add pendingCleanup tracking to CocoManager so initialize() awaits any
in-flight cleanup() before proceeding, avoiding race conditions during
hot reload or rapid profile switches.

Made-with: Cursor
- Add storage route and SettingsStorageScreen for debug inspection
- Add shared/lib/debug/storageInventory for AsyncStorage, SecureStore, coco DB
- Refactor payments: skeleton loading, display contacts before decryption
- Update assets: optimize images, remove unused blue.jpg and initializing.png

Made-with: Cursor
- Update theme system architecture docs
- Apply semantic tokens to feed, mint, payments, settings, transactions, user, wallet
- Avatar gradient and profile switcher updates
- Wallet header and mint balance display refinements

Made-with: Cursor
- Add PaymentStatusToast, CompactToast, usePaymentStatusListener
- Add paymentStatusStore and parsePaymentError
- Refactor popup engine, bridge, PopupHost
- Update receive/send/wallet screens
- Add .easignore

Made-with: Cursor
…ate docs

- Split popups.ts into popups/ domain modules (copy, payment, token, etc.)
- Rename profileSwitcher/ to profile-switcher/ for kebab-case consistency
- Extract liveSheetTypes.ts for circular import fix
- Update popup-toast-sheet-guidelines.mdc with current structure
- Remove withSheetProvider HOC and app/message dead code

Made-with: Cursor
- Extract AnimatedCheckpointDot, simplify TransferStepChain
- Add useReceiveHistoryEntry hook for receive flow
- Refactor HistoryEntryTimeline, ReceiveTokenScreen, MeltQuoteScreen
- Add send popup exports to popups barrel

Made-with: Cursor
…ents

Close SQLite connections on CocoManager cleanup, capture accountIndex at
render time in SendTokenScreen, add cancellation guard to payment status
listener, clear payment status store before profile reload, gate
profile-scoped store hydration on profileStore readiness, guard
CocoManager access from popup host, pass accountIndex as prop to
NostrNDKProvider, document rehydrateProfileStores as reserved, and add
periodic safety/security audit rule for profile-scoped code.

Made-with: Cursor
…lear delete

Profile switching, creation, import, and deletion were unreliable because
Updates.reloadAsync() silently fails in production (no expo-updates config),
the WalletScreen action queue lost actions when navigation/focus failed,
FullWindowOverlay ghost windows captured touches after JS reload, and
deleteAccount called clearAllSecureData which nuked the root mnemonic
causing new identities to appear instead of deleting.

- Add react-native-restart for reliable native app restarts
- Create appRestart.ts with priority chain (DevSettings → RNRestart → Updates)
- Rewrite profileSessionOrchestrator with AsyncStorage-based transition guard,
  registered controls pattern, and direct orchestrator calls from drawer
- Delete profileActionStore and remove WalletScreen action queue
- Disable FullWindowOverlay on PopupHost to prevent ghost windows
- Add clearPerProfileSecureData() that preserves root mnemonic
- Nuclear deleteAllProfiles: CocoManager.completeReset + clearAllSecureData +
  AsyncStorage.clear + Redux purge — nothing survives
- DeleteScreen always calls deleteAllProfiles for full wipe
- Register transition controls and key derivation in app/_layout.tsx

Made-with: Cursor
Profile creation could fail on the first session after a fresh wipe because
NostrKeysProvider generated and stored the root mnemonic during initialization,
but getKeysForAccount still depended on stale hook state and returned null until
a later refresh or relaunch. This makes account derivation fall back to reading
SecureStore directly and refreshes the mnemonic after generation so create flows
work immediately.

It also adds a dev-only deterministic mnemonic override for fresh wallets via
Expo config and simplifies the key derivation test suite around the one root
mnemonic and imported nsec path the app actually relies on, including pinned
Cashu values for imported profiles.

Made-with: Cursor
The dev mnemonic override did not need the extra Expo config plumbing.
Use EXPO_PUBLIC_DEBUG_MNEMONIC directly in secureStorage and keep the
package script focused on restarting Expo with a clean cache.

Made-with: Cursor
Re-enable HeroUI's full-window overlay for PopupHost so button-handler sheets stack above modal and form-sheet presentations. Update the popup and profile-safety docs to preserve that layering behavior while still tearing sheets down before restart.

Made-with: Cursor
Rename the remaining Redux migration files to explicit deprecated paths so their migration-only role is obvious. Trim dead legacy exports at the same time so knip stays clean without hiding real issues.

Made-with: Cursor
Remove unused feed image-overlay, stories, and note components while moving shared container and scroll offset helpers to clearer homes. This keeps exports aligned with the current feature structure and trims dead code surfaced by the cleanup tooling.

Made-with: Cursor
Apply formatting cleanup to wrapped imports, exports, and type declarations so generated and hand-edited files stay consistent with the current code style.

Made-with: Cursor
@Kelbie Kelbie merged commit 7d53b31 into main Mar 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant