fix(client): DM-only info, seed on API error, proper cross-group back stack

Three related UX fixes on the client.

1. Participants count on profile

   DMs always have exactly two participants (you and the contact) so a
   "Участников: 1" row was confusing — either it's obviously the other
   person or it's wrong depending on how you count. Removed for direct
   conversations; the row still appears for group chats (and shows an
   em-dash until v2.1.0 gives groups a real member list).

2. Dev feed seed now activates on network / 404 errors

   The seed was only surfaced when the real API returned an EMPTY
   array. If the node was down (Network request failed) or the endpoint
   replied 404, the catch block quietly set posts to [] and the list
   stayed blank — defeating the point of the seed. Now both the empty-
   response path AND the network-error path fall back to getDevSeedFeed(),
   so scrolling / like-toggling works even without a running node.

   Also made the __DEV__ lookup more defensive: use `globalThis.__DEV__`
   at runtime instead of the typed global. Some bundler configurations
   have the TS type but not the runtime binding, or vice-versa — the
   runtime lookup always agrees with Metro.

3. Back from profile → previous screen instead of tab root

   Root cause: AnimatedSlot rendered <Slot>, which is stack-less. When
   /chats/xyz pushed /profile/abc (cross-group), the chats group
   unmounted. Hitting Back then re-entered chats at its root (/chats
   list) rather than /chats/xyz.

   Replaced <Slot> with <Stack> in AnimatedSlot. Tab switching still
   stays flat because NavBar uses router.replace (which maps to
   navigation.replace on the Stack — no history accumulation).
   Cross-group pushes (post author tap from feed, avatar tap from chat
   header, compose modal) now live in the outer Stack's history, so
   Back pops correctly to the caller.

   The nested Stacks (chats/_layout.tsx, feed/_layout.tsx,
   profile/_layout.tsx) still handle intra-group navigation as before.
   The PanResponder-based swipe-right-to-back was removed since the
   native Stack now provides iOS edge-swipe natively; Android uses the
   system back button.

   animation: 'none' keeps the visual swap instant — matches the prior
   Slot look so nothing flashes slide-animations that weren't there
   before. Sub-group layouts can opt into slide_from_right themselves
   (profile/_layout.tsx and feed/_layout.tsx already do).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
vsecoder
2026-04-18 20:16:38 +03:00
parent 98a0a4b8ba
commit 93040a0684
4 changed files with 53 additions and 79 deletions

View File

@@ -164,18 +164,17 @@ const SEED_POSTS: FeedPostItem[] = [
},
];
/** True when the current build is a Metro dev bundle. __DEV__ is a
* global injected by Metro at bundle time and typed via react-native's
* ambient declarations, so no ts-ignore is needed. */
function isDev(): boolean {
return typeof __DEV__ !== 'undefined' && __DEV__ === true;
}
/**
* Returns the dev-seed post list (only in __DEV__). Called by the Feed
* screen as a fallback when the real API returned an empty list.
* Returns the dev-seed post list. Only returns actual items in dev
* builds; release bundles return an empty array so fake posts never
* appear in production.
*
* We use the runtime `globalThis.__DEV__` lookup rather than the typed
* `__DEV__` global because some builds can have the TS typing
* out-of-sync with the actual injected value.
*/
export function getDevSeedFeed(): FeedPostItem[] {
if (!isDev()) return [];
const g = globalThis as unknown as { __DEV__?: boolean };
if (g.__DEV__ !== true) return [];
return SEED_POSTS;
}