Message Reminders

Message reminders allow users to set reminders for messages. This feature is useful when users want to be notified about messages that they need to follow up on. The article explains how message reminders are managed by the React SDK.

Message reminders rely on state management performed by the low-level JS client. The low-level client guide explains how to perform CRUD operations.

Message Reminder UI Interaction

Users can create, update or delete message reminders by accessing the relevant message action from the message actions menu:

Then the message reminder notification is displayed as a part of the message UI (or removed from the UI if the reminder has been deleted):

Get Message Reminder Data

The React SDK components use the client.reminders controller to perform the CRUD operations. The controller keeps reactive state - a mapping of message id to Reminder instances. Reminder instances have in turn their own reactive state that extends the ReminderResponse from the server with timeLeftMs.

export type ReminderState = {
  channel_cid: string;
  created_at: Date;
  message: MessageResponse | null;
  message_id: string;
  remind_at: Date | null;
  timeLeftMs: number | null;
  updated_at: Date;
  user: UserResponse | null;
  user_id: string;
};

We can subscribe to the reminder state changes on two levels:

  1. Subscribe to a specific reminder state changes
import { useMessageReminder, useStateStore } from "stream-chat-react";
import type { LocalMessage, ReminderState } from "stream-chat";

const reminderStateSelector = (state: ReminderState) => ({
  timeLeftMs: state.timeLeftMs,
});

const Component = ({ message }: { message: LocalMessage }) => {
  // access the message reminder instance
  const reminder = useMessageReminder(message.id);
  const { timeLeftMs } =
    useStateStore(reminder?.state, reminderStateSelector) ?? {};
};

The timeLeftMs value is periodically updated. The update frequency increases as the deadline is approached and decreases as it is left behind (once per day, then last day every hour, last hour every minute and vice verse when increasing the distance from the deadline).

  1. Subscribe to reminders pagination

The pagination is handler by the RemindersPaginator. The items paginated are not Reminder instances but ReminderResponse objects retrieved from the server.

import {
  InfiniteScrollPaginator,
  useChatContext,
  useStateStore,
} from 'stream-chat-react';
import type { PaginatorState, ReminderResponse} from 'stream-chat';
const { CustomLoadingIndicator } from '../LoadingIndicator'
const { CustomReminderListingItem } from './CustomReminderListingItem'

const reminderPaginatorStateSelector = (state: PaginatorState<ReminderResponse>) => ({
  isLoading: state.isLoading,
  items: state.items,
});

const Component = () => {
  const { client } = useChatContext();
  const { items, isLoading } = useStateStore(
    client.reminders.paginator.state,
    reminderPaginatorStateSelector,
  );

  return (
    <InfiniteScrollPaginator
      loadNextOnScrollToBottom={client.reminders.queryNextReminders}
      threshold={40}
    >
      {items && (
        <div>
          {items.map((item) => (
            <CustomReminderListingItem reminder={item} key={item.message_id} />
          ))}
        </div>
      )}
      {isLoading && <CustomLoadingIndicator />}
    </InfiniteScrollPaginator>
  );
};

Message Reminder Configuration

It is possible to configure the reminder time offsets from which a user can select:

const minute = 60 * 1000;
client.reminders.updateConfig({
  scheduledOffsetsMs: [30 * minute, 60 * minute],
});

Also, it is possible to configure the time boundary, when the reminder notification will stop refreshing the information about the time elapsed since the deadline:

const day = 24 * 60 * 60 * 1000;
client.reminders.updateConfig({
  stopTimerRefreshBoundaryMs: day,
});

Overriding Default Message Reminder Components

It is possible to override the default components related to message reminders in the React SDK:

import { Channel, ReminderNotificationProps, useMessageReminder, useStateStore } from 'stream-chat-react';
import type { LocalMessage, ReminderState } from 'stream-chat';

const reminderStateSelector = (state: ReminderState) => ({
  timeLeftMs: state.timeLeftMs,
});

const CustomReminderNotification = ({ reminder }: ReminderNotificationProps) => {
  const { timeLeftMs } = useStateStore(reminder?.state, reminderStateSelector) ?? {};

  return (
    // ... the reminder notification UI
  )
};

const Component = () => {

  return (
    <Channel ReminderNotification={CustomReminderNotification}>
      {/* ... */}
    </Channel>
  );
}
© Getstream.io, Inc. All Rights Reserved.