import React, { useMemo, useState } from 'react';
import { useChannelStateContext } from 'stream-chat-react';
import './add-members-dialog.css';
type HistoryMode = 'none' | 'today' | 'all' | 'custom';
type AddMembersDialogProps = {
memberIds: string[];
};
export function AddMembersDialog({ memberIds }: AddMembersDialogProps) {
const { channel } = useChannelStateContext();
const [open, setOpen] = useState<boolean>(true);
const [mode, setMode] = useState<HistoryMode>('none');
const [customInput, setCustomInput] = useState<string>('');
const isCustomDateValid = useMemo(() => {
if (mode !== 'custom') return true;
const parsed = new Date(customInput);
return !Number.isNaN(parsed.getTime());
}, [mode, customInput]);
const handleAdd = async () => {
if (!channel) return;
const options: { hide_history_before?: string } = {};
if (mode !== 'all') {
let cutoff = new Date(); // do not show any history
if (mode === 'today') {
const startOfToday = new Date();
startOfToday.setHours(0, 0, 0, 0);
cutoff = startOfToday;
} else if (mode === 'custom') {
const parsed = new Date(customInput);
if (Number.isNaN(parsed.getTime())) return;
cutoff = parsed;
}
options.hide_history_before = cutoff.toISOString();
}
await channel.addMembers(memberIds, undefined, options);
setOpen(false);
};
if (!open) return null;
return (
<div className='sch-dialog-overlay'>
<div className='sch-dialog'>
<h3 className='sch-title'>Include conversation history?</h3>
<div className='sch-options'>
<label className='sch-option'>
<input
type='radio'
name='history'
value='none'
checked={mode === 'none'}
onChange={() => setMode('none')}
/>
<span>don't include</span>
</label>
<label className='sch-option'>
<input
type='radio'
name='history'
value='today'
checked={mode === 'today'}
onChange={() => setMode('today')}
/>
<span>from today</span>
</label>
<label className='sch-option'>
<input
type='radio'
name='history'
value='all'
checked={mode === 'all'}
onChange={() => setMode('all')}
/>
<span>from the beginning</span>
</label>
<label className='sch-option'>
<input
type='radio'
name='history'
value='custom'
checked={mode === 'custom'}
onChange={() => setMode('custom')}
/>
<span>custom</span>
</label>
</div>
{mode === 'custom' ? (
<div className='sch-custom'>
<input
className='sch-input'
type='datetime-local'
value={customInput}
onChange={(e) => setCustomInput(e.target.value)}
placeholder='YYYY-MM-DDTHH:mm'
/>
{!isCustomDateValid && (
<div className='sch-error'>Enter a valid date/time</div>
)}
</div>
) : null}
<div className='sch-actions'>
<button className='sch-btn sch-secondary' onClick={() => setOpen(false)}>
Cancel
</button>
<button
className='sch-btn sch-primary'
onClick={handleAdd}
disabled={mode === 'custom' && !isCustomDateValid}
>
Add
</button>
</div>
</div>
</div>
);
}Hide Channel History For Newly Added Members
In this tutorial we will demonstrate how to build a simple dialog that allows to specify the length of channel conversation history to be shared with a newly added member.
We will build the following simple dialog:

Minimal dialog to control history visibility when adding members
The UI below lets you choose how much of the conversation history a newly added member will see. On Add, it calls channel.addMembers() with hide_history_before mapped from the selected option:
- don’t include: hide all history before now →
hide_history_before = new Date().toISOString() - from today: show only today →
hide_history_before = startOfToday.toISOString() - from the beginning: show everything → omit
hide_history_before - custom: show from a specific date/time →
hide_history_before = new Date(input).toISOString()
Minimal CSS was added to make it pleasant and centered.
.sch-dialog-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.3);
display: grid;
place-items: center;
padding: 16px;
z-index: 1000;
}
.sch-dialog {
width: 100%;
max-width: 420px;
background: #fff;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
padding: 16px 18px;
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu,
Cantarell, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji;
}
.sch-title {
margin: 4px 0 12px;
font-size: 16px;
font-weight: 600;
}
.sch-options {
display: grid;
gap: 8px;
margin-bottom: 12px;
}
.sch-option {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
}
.sch-custom {
margin: 8px 0 12px;
}
.sch-input {
width: 100%;
box-sizing: border-box;
padding: 8px 10px;
border: 1px solid #e5e7eb;
border-radius: 8px;
font-size: 14px;
}
.sch-error {
color: #b91c1c;
font-size: 12px;
margin-top: 6px;
}
.sch-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 4px;
}
.sch-btn {
border: 0;
border-radius: 8px;
padding: 8px 12px;
font-size: 14px;
cursor: pointer;
}
.sch-primary {
background: #005fff;
color: #fff;
}
.sch-primary:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.sch-secondary {
background: #f3f4f6;
color: #111827;
}Mapping to the raw API
Here’s a standalone snippet showing the parameter shape. This mirrors the button behavior above:
// Example: include only the last 7 days of history for the new member
const cutoff = new Date();
cutoff.setDate(cutoff.getDate() - 7);
await channel.addMembers(['thierry'], undefined, {
hide_history_before: cutoff.toISOString(),
});