# Hide history for new members

> **Info:** This is release candidate documentation for **Stream Chat React SDK v15**. For the latest stable version, see the [latest version (v14)](https://getstream.io/chat/docs/sdk/react/).

This recipe builds a dialog that asks how much of the conversation history a new member sees when they're added to a channel. The options behind it, and what the new member sees, are explained in [History visibility for new members](https://getstream.io/chat/docs/sdk/react/v15/features/channels/history-visibility-for-new-members/).

The dialog offers four choices:

![Dialog for the past conversation history access restriction](https://getstream.io/docs-assets/images/77341c318aad.png)

## Minimal dialog to control history visibility when adding members

On Add, the dialog calls `Channel.addMembers()` with the option that matches the choice:

- **don't include**: no history → `hide_history: true`
- **from today**: only today → `hide_history_before` set to the start of today
- **from the beginning**: everything → no option
- **custom**: from a date and time the user picks → `hide_history_before` set to that `Date`

`hide_history_before` is a `Date`, and it must be in the past.

The dialog is a `GlobalModal` from the SDK with `Prompt` inside it. The modal handles the overlay, the focus and closing on Escape, and `Prompt` lays out the title, the body and the buttons. [Dialogs](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/dialogs/#modals) explains both.

```tsx title="src/AddMembersButton.tsx"
import type { ChannelUpdateOptions } from "stream-chat";
import { useState } from "react";
import { GlobalModal, Prompt, useChannel } from "stream-chat-react";
import "./AddMembersButton.css";

type HistoryMode = "none" | "today" | "all" | "custom";

const historyOptions: { label: string; mode: HistoryMode }[] = [
  { label: "don't include", mode: "none" },
  { label: "from today", mode: "today" },
  { label: "from the beginning", mode: "all" },
  { label: "custom", mode: "custom" },
];

// The addMembers options for a choice, or undefined when the custom date isn't valid.
const getHistoryOptions = (
  mode: HistoryMode,
  customInput: string,
): ChannelUpdateOptions | undefined => {
  if (mode === "all") return {};
  if (mode === "none") return { hide_history: true };

  if (mode === "today") {
    const startOfToday = new Date();
    startOfToday.setHours(0, 0, 0, 0);
    return { hide_history_before: startOfToday };
  }

  const cutoff = new Date(customInput);
  if (Number.isNaN(cutoff.getTime()) || cutoff > new Date()) return undefined;
  return { hide_history_before: cutoff };
};

export const AddMembersButton = ({ memberIds }: { memberIds: string[] }) => {
  const channel = useChannel();
  const [open, setOpen] = useState(false);
  const [mode, setMode] = useState<HistoryMode>("none");
  const [customInput, setCustomInput] = useState("");

  const options = getHistoryOptions(mode, customInput);
  const close = () => setOpen(false);

  const handleAdd = async () => {
    if (!options) return;
    try {
      await channel.addMembers({ members: memberIds, ...options });
      close();
    } catch (error) {
      console.error("Could not add the members", error);
    }
  };

  return (
    <>
      <button onClick={() => setOpen(true)} type="button">
        Add members
      </button>
      <GlobalModal onClose={close} open={open}>
        <Prompt.Root>
          <Prompt.Header close={close} title="Include conversation history?" />
          <Prompt.Body>
            <div className="history-options">
              {historyOptions.map((option) => (
                <label className="history-option" key={option.mode}>
                  <input
                    checked={mode === option.mode}
                    name="history"
                    onChange={() => setMode(option.mode)}
                    type="radio"
                    value={option.mode}
                  />
                  <span>{option.label}</span>
                </label>
              ))}
            </div>
            {mode === "custom" && (
              <div className="history-custom">
                <input
                  aria-label="Show history from"
                  className="history-custom__input"
                  onChange={(event) => setCustomInput(event.target.value)}
                  type="datetime-local"
                  value={customInput}
                />
                {!options && (
                  <div className="history-custom__error">
                    Enter a valid date and time in the past
                  </div>
                )}
              </div>
            )}
          </Prompt.Body>
          <Prompt.Footer>
            <Prompt.FooterControls>
              <Prompt.FooterControlsButtonSecondary onClick={close}>
                Cancel
              </Prompt.FooterControlsButtonSecondary>
              <Prompt.FooterControlsButtonPrimary
                disabled={!options}
                onClick={handleAdd}
              >
                Add
              </Prompt.FooterControlsButtonPrimary>
            </Prompt.FooterControls>
          </Prompt.Footer>
        </Prompt.Root>
      </GlobalModal>
    </>
  );
};
```

```css title="src/AddMembersButton.css"
.history-options {
  display: grid;
  gap: 8px;
}

.history-option {
  align-items: center;
  display: flex;
  gap: 8px;
}

.history-custom {
  margin-top: 12px;
}

.history-custom__input {
  box-sizing: border-box;
  padding: 8px 10px;
  width: 100%;
}

.history-custom__error {
  color: #b91c1c;
  font-size: 12px;
  margin-top: 6px;
}
```

Render `AddMembersButton` inside a channel, for example in a header of your own, with the ids of the users to add. `useChannel()` gives it the channel. Adding members needs the `update-channel-members` capability.

## Best practices

- Default to the most private choice, "don't include", unless your app has a reason to share history.
- Pass a `Date`, not a string, and check that it's in the past before calling `addMembers`.
- Say in the dialog what the new member will see.
- Handle a failed request. `addMembers` rejects when the user may not add members or the date isn't valid. The dialog above logs the error and stays open; show the user a message in your app.
- Leave the rule to the server when the user shouldn't choose: one function that always passes the same options, as on [History visibility for new members](https://getstream.io/chat/docs/sdk/react/v15/features/channels/history-visibility-for-new-members/#hiding-history-for-every-member-your-app-adds).

### Mapping to the raw API

The dialog's choices are the options of a single call. For example, this adds Thierry with the last seven days of history:

```ts
const cutoff = new Date();
cutoff.setDate(cutoff.getDate() - 7);

await channel.addMembers({
  members: ["thierry"],
  hide_history_before: cutoff,
});
```

The second argument is an optional message that announces the change in the channel. `undefined` adds the member without one.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v15/recipes/app/hide-history-for-new-members/](https://getstream.io/chat/docs/sdk/react/v15/recipes/app/hide-history-for-new-members/).