Skip to content

feat(chat): migrate to lucide icons and add contact block/delete actions - #3

Merged
realcodesiman merged 6 commits into
mainfrom
feat/chat-ui-refinements
Sep 1, 2026
Merged

realcodesiman merged 6 commits into
mainfrom
feat/chat-ui-refinements

Conversation

@realcodesiman

@realcodesiman realcodesiman commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Migrate the icon system from @expo/vector-icons (Ionicons) to lucide-react-native, matching the web app's icon set 1:1 by name for easier cross-platform greppability.
  • Expand the conversation actions sheet (chat header + contact row) with bot enable/disable, unassign, contact block/unblock, and delete contact — block/delete are gated behind FEATURES.blockContact/FEATURES.deleteContact since the session-auth backend routes don't exist yet, shown with a "Coming soon" badge instead of hidden.
  • Add a MessageEvent polyfill (install-message-event-polyfill.ts) so partysocket's WebSocket message cloning doesn't throw under Hermes, which has no global MessageEvent.

Changes

  • src/components/ui/icon.tsx — full Ionicons → lucide-react-native rewrite with a semantic icon registry; touches nearly every UI/feature component that renders an Icon.
  • src/features/chat/components/conversation-actions-sheet.tsx — bot toggle, unassign, block/unblock, delete contact, send flow / saved replies entries; switched from Sheet to SheetModal/BottomSheetModal.
  • src/features/contacts/ — new use-contact-block.ts, use-delete-contact.ts hooks; contact-row.tsx gains swipeable block/delete actions; new components/contact-actions-sheet.tsx, components/contact-status-icons.tsx.
  • src/features/conversations/use-conversation-actions.ts updates, new status-icons.tsx (replaces deleted tag-chips.tsx), conversation-row.tsx and channel-badge.tsx updates.
  • src/config/features.ts — new blockContact/deleteContact flags (both false).
  • src/lib/install-message-event-polyfill.ts (new) — wired into src/app/_layout.tsx.
  • jest.config.js — maps lucide-react-native to its CJS build so Jest can transform it.
  • package.json / pnpm-lock.yaml — add lucide-react-native, react-native-svg.
  • babel.config.js (new).
  • src/i18n/locales/*.json — new strings for the above (all 19 locales).

Test plan

  • pnpm lint
  • pnpm tsc --noEmit (or project's check-types script)
  • pnpm test — new/updated tests: use-contact-block, use-delete-contact, use-conversations-infinite, use-conversation-actions, conversation-row, conversation-status, status-icons, contact-row, avatar, icon, conversation-actions-sheet, use-saved-replies, send-message-multipart, install-message-event-polyfill
  • Manual verification: icons render correctly across chat, contacts, conversations, settings; conversation actions sheet (bot toggle, assign/unassign, archive, block/delete showing "Coming soon"); contact row swipe actions hidden while flags are off

Review cleanup pass

Follow-up commits addressing /review-pr findings (0 CRITICAL, 1 HIGH bug, 2 MEDIUM, plus dead code/perf):

  • chore(cleanup): removed unused SaveOff/Trash2 icons, the direct @expo/vector-icons dep, dead eslint-disables, and the unreachable inSequence branch.
  • refactor(contacts): extracted shared cache-patching (patch-conversation-list-cache.ts) and fetch-with-timeout (contact-fetch.ts) helpers; fixed a cache-invalidation race in use-contact-block.ts and replaced an over-broad invalidation in use-delete-contact.ts with a targeted filter.
  • refactor(chat): extracted shared confirmDestructive and FeatureGatedListItem used by both action sheets; added success/error toast feedback on block/unblock/delete (previously failed silently); lazy-mounted each action sheet's child sheets so they only fetch once actually opened.
  • fix(contacts): fixed the contacts "..." actions sheet not opening on the first tap (sheet mounted after the ref was already expanded).
  • Perf: memoized ContactRow and stabilized its callback/array props so memo actually short-circuits re-renders.

Verification: pnpm lint, pnpm typecheck, and the full pnpm test suite (476 tests) are green.

Replace Ionicons with lucide-react-native across the app for a shared icon
set with the web app, and expand the conversation actions sheet with bot
toggle, unassign, contact block/unblock, and delete (the latter two
feature-flagged off pending session-auth backend routes).
Drops SaveOff/Trash2 icon registry entries (zero production consumers),
the direct @expo/vector-icons dependency (unused, still present
transitively via expo), unused eslint-disable directives for a rule
that isn't enabled, and the unreachable inSequence branch in
ContactStatusStrip.
Extracts patchConversationListCache/rollbackConversationListCache as a
shared skeleton for the conversation-list cache patchers in
use-conversation-actions.ts and use-contact-block.ts, and a shared
authorizedFetch (with a 15s timeout) deduping postBlockContact and
deleteContactRequest.

Also fixes two bugs surfaced during dedup:
- use-contact-block.ts now cancels conversations-list queries before
  patching and invalidates them on settle (previously only contact
  detail was invalidated, leaving a race window).
- use-delete-contact.ts now does a targeted list filter instead of
  invalidating the entire conversations query space.
Adds shared confirmDestructive (wraps the repeated Alert.alert
cancel/destructive-confirm shape) and FeatureGatedListItem (the
ListItem + Icon + "Coming soon" Badge pattern), applied to both
conversation-actions-sheet.tsx and contact-actions-sheet.tsx.

Block/unblock/delete now show success and error toasts instead of
failing silently while the sheet closes as if it succeeded, using the
previously-unwired contacts.deleted i18n key plus new
blockedSuccess/unblockedSuccess keys across all locales.

Also lazy-mounts the four child sheets in contact-actions-sheet.tsx
(assignment, tag picker, custom field, sequence picker) and the
assignment sheet in conversation-actions-sheet.tsx, so each only
fires its query once actually opened instead of on every "..." press.
openActions expanded the sheet ref synchronously but
ContactActionsSheet only mounts after useContactDetail resolves, so
the first "..." tap did nothing. Uses a pending-open ref plus an
effect that expands once the selected contact's detail is loaded,
matching the working pattern in contact-panel.tsx.

Also wraps ContactRow in memo (matching ConversationRow), replaces
the four per-item inline arrow props on ContactsScreen with stable
useCallback handlers, and memoizes ContactRow's per-render
SwipeAction arrays so memo actually short-circuits re-renders.
Unrelated single-line reflows left uncommitted in the tree; no
behavior change.
@realcodesiman
realcodesiman merged commit c991761 into main Sep 1, 2026
1 check passed
@realcodesiman
realcodesiman deleted the feat/chat-ui-refinements branch September 1, 2026 08:26
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