feat(chat): migrate to lucide icons and add contact block/delete actions - #3
Merged
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@expo/vector-icons(Ionicons) tolucide-react-native, matching the web app's icon set 1:1 by name for easier cross-platform greppability.FEATURES.blockContact/FEATURES.deleteContactsince the session-auth backend routes don't exist yet, shown with a "Coming soon" badge instead of hidden.MessageEventpolyfill (install-message-event-polyfill.ts) sopartysocket's WebSocket message cloning doesn't throw under Hermes, which has no globalMessageEvent.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 anIcon.src/features/chat/components/conversation-actions-sheet.tsx— bot toggle, unassign, block/unblock, delete contact, send flow / saved replies entries; switched fromSheettoSheetModal/BottomSheetModal.src/features/contacts/— newuse-contact-block.ts,use-delete-contact.tshooks;contact-row.tsxgains swipeable block/delete actions; newcomponents/contact-actions-sheet.tsx,components/contact-status-icons.tsx.src/features/conversations/—use-conversation-actions.tsupdates, newstatus-icons.tsx(replaces deletedtag-chips.tsx),conversation-row.tsxandchannel-badge.tsxupdates.src/config/features.ts— newblockContact/deleteContactflags (bothfalse).src/lib/install-message-event-polyfill.ts(new) — wired intosrc/app/_layout.tsx.jest.config.js— mapslucide-react-nativeto its CJS build so Jest can transform it.package.json/pnpm-lock.yaml— addlucide-react-native,react-native-svg.babel.config.js(new).src/i18n/locales/*.json— new strings for the above (all 19 locales).Test plan
pnpm lintpnpm 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-polyfillReview cleanup pass
Follow-up commits addressing
/review-prfindings (0 CRITICAL, 1 HIGH bug, 2 MEDIUM, plus dead code/perf):chore(cleanup): removed unusedSaveOff/Trash2icons, the direct@expo/vector-iconsdep, dead eslint-disables, and the unreachableinSequencebranch.refactor(contacts): extracted shared cache-patching (patch-conversation-list-cache.ts) and fetch-with-timeout (contact-fetch.ts) helpers; fixed a cache-invalidation race inuse-contact-block.tsand replaced an over-broad invalidation inuse-delete-contact.tswith a targeted filter.refactor(chat): extracted sharedconfirmDestructiveandFeatureGatedListItemused 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).ContactRowand stabilized its callback/array props somemoactually short-circuits re-renders.Verification:
pnpm lint,pnpm typecheck, and the fullpnpm testsuite (476 tests) are green.