beeper-inbox-native
v0.4.1
Published
React Native inbox components for Beeper.
Downloads
421
Readme
beeper-inbox-native
React Native inbox components for Beeper.
The package uses the client-safe beeper-sdk/widget API and never accepts a
server API key. Your backend must mint a short-lived widget session token for
the signed-in subscriber.
<BeeperNativeInboxProvider
projectId={projectId}
publishableKey={publishableKey}
sessionToken={sessionToken}
refreshSessionToken={mintFreshSessionToken}
subscriber={{ subscriberId: user.id }}
push={{ token: fcmToken, platform: "android", autoRegister: true }}
>
<BeeperInboxPanel />
</BeeperNativeInboxProvider>Handling action presses
When a notification has an actionUrl, the built-in item shows an action button. By default,
pressing it opens the URL with Linking.openURL.
To route in-app instead (React Navigation, expo-router), pass onActionPress and return false
to skip the default:
<BeeperNativeInboxProvider
/* … */
onActionPress={({ actionUrl, item }) => {
if (actionUrl.startsWith("myapp://")) {
router.push(routeFromUrl(actionUrl));
return false; // handled: don't call Linking.openURL
}
// anything else (https links, say) falls through to Linking.openURL
}}
>- The handler can be
async; resolving tofalsealso skips the default. - The press is recorded for click analytics either way, in the background. A failed recording never blocks or cancels the action.
- If the handler throws, the URL is not opened and the error propagates, so a routing bug surfaces instead of silently falling back to the browser.
- If no app on the device can open the URL, the press does nothing rather than crashing.
Building your own UI with useBeeperInbox
useBeeperInbox() gives any component inside the provider the live inbox state and its
actions, and re-renders when the inbox changes:
import { useBeeperInbox } from "beeper-inbox-native";
function InboxTabIcon() {
const { unreadCount } = useBeeperInbox();
return <TabIcon name="bell" badge={unreadCount || undefined} />;
}
function CustomInbox() {
const { items, loading, refreshing, errorMessage, refresh, markRead, markAllRead, handleActionPress } =
useBeeperInbox();
return (
<FlatList
data={items}
keyExtractor={(item) => item._id}
refreshing={refreshing}
onRefresh={() => refresh({ silent: true })}
renderItem={({ item }) => (
<Row
item={item}
onPress={() => markRead(item._id)}
onAction={() => handleActionPress(item)}
/>
)}
/>
);
}| Field | |
| --- | --- |
| items, unreadCount | Inbox contents and unread total |
| unreadByKind | Unread per kind in the provider's unreadKinds (e.g. { order: 3 }), each capped at 100 |
| loading, refreshing | First load, and background refresh |
| connectionState, errorMessage | "idle" \| "loading" \| "live" \| "error", and the last error |
| transport | "realtime" while a live connection delivers updates, otherwise "polling" |
| subscriber | The subscriber record, once loaded |
| refresh({ silent? }) | Re-fetch now; silent skips the loading state |
| markRead(id), markAllRead() | Mark items read (optimistic) |
| hasMore, loadingMore, loadMore() | Whether older items exist, and fetch the next page of them |
| archive(id), unarchive(id) | Dismiss an item from the list (optimistic; it also counts as read), or bring it back |
| registerPushToken(token, options), unregisterPushToken(token) | Manual push device management |
| handleActionPress(item) | Run an item's action exactly as the built-in button does, including onActionPress |
Use handleActionPress in custom rows rather than calling Linking.openURL yourself, so click
analytics and your onActionPress routing stay consistent with the built-in UI.
useBeeperInbox throws if it is used outside BeeperNativeInboxProvider.
Swipe to dismiss
The package does not ship a swipe gesture, so it adds no gesture-library dependency. Wrap
your rows in the swipeable you already use and call archive:
const { archive } = useBeeperInbox();
<Swipeable onSwipeableOpen={() => archive(item._id)}>
<Row item={item} />
</Swipeable>Archived items leave the list at once. Pass archived to the provider to show them instead,
for an "Archived" screen, and call unarchive(id) there to restore one.
Tabs and paging
kind limits the provider to items whose metadata.kind matched at send time. Changing it
re-fetches, so one provider can drive tabs:
const [tab, setTab] = useState<"all" | "order" | "chat">("all");
<BeeperNativeInboxProvider {...props} kind={tab === "all" ? undefined : tab}>
<Tabs value={tab} onChange={setTab} />
<BeeperInboxList />
</BeeperNativeInboxProvider>For per-tab badges, name the kinds in unreadKinds. The counts come back with the inbox itself,
so they add no requests:
<BeeperNativeInboxProvider {...props} kind={tab === "all" ? undefined : tab} unreadKinds={["order", "chat"]}>
<Tab label="Kòmand" badge={<BeeperInboxBadge kind="order" />} />
</BeeperNativeInboxProvider>BeeperInboxList loads older pages as it scrolls. In a custom list, call loadMore() from
onEndReached and read hasMore and loadingMore. pageSize (1–100, default 20) sets
items per request. unreadCount is always the whole inbox's count.
Push tokens
Use a native FCM token for both Android and iOS with the current Beeper push sender. Expo push tokens and raw APNs tokens require an additional provider integration.
