import { useState } from "react";
import { Channel, ChannelUpdateOptions, UserResponse } from "stream-chat";
import { Modal, Pressable, StyleSheet, Text, View } from "react-native";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
import { useTheme } from "stream-chat-react-native";
import DateTimePicker, {
DateTimePickerEvent,
} from "@react-native-community/datetimepicker";
export type AddMemberWithHistoryModalProps = {
channel?: Channel;
visible: boolean;
onClose: () => void;
user: UserResponse | null;
onMemberAdded: () => void;
};
type SelectedOption = "none" | "today" | "all" | "custom";
export const AddMemberWithHistoryModal = (
props: AddMemberWithHistoryModalProps,
) => {
const [selectedOption, setSelectedOption] = useState<SelectedOption>("none");
const [customDate, setCustomDate] = useState<Date>(new Date());
const {
theme: {
colors: { accent_blue },
},
} = useTheme();
const { channel, visible, onClose, user, onMemberAdded } = props;
const options: { name: string; value: SelectedOption }[] = [
{ name: "Don't Include History", value: "none" },
{
name: "From Today",
value: "today",
},
{ name: "From the beginning", value: "all" },
{ name: "Custom", value: "custom" },
];
const handleAdd = async () => {
if (!channel || !user) {
return;
}
const updateOptions: ChannelUpdateOptions = {};
if (selectedOption !== "all") {
let cutoffDate = new Date();
if (selectedOption === "today") {
const today = new Date();
today.setHours(0, 0, 0, 0);
cutoffDate = today;
} else if (selectedOption === "custom") {
if (Number.isNaN(customDate.getTime())) {
return;
}
cutoffDate = customDate;
}
updateOptions.hide_history_before = cutoffDate.toISOString();
}
try {
await channel.addMembers([user.id], undefined, updateOptions);
} catch (error) {
console.error("Error adding member with history: ", error);
} finally {
onMemberAdded();
}
};
const setDate = (event: DateTimePickerEvent, date?: Date) => {
const { type } = event;
if (type === "set") {
if (date) {
setCustomDate(date);
}
}
};
return (
<SafeAreaProvider>
<SafeAreaView style={styles.container}>
<Modal
animationType="slide"
transparent={true}
visible={visible}
onRequestClose={onClose}
>
<View style={styles.container}>
<View style={styles.modal}>
<Text style={styles.title}>Include Conversation History?</Text>
{options.map((option) => (
<View style={[styles.option]} key={option.value}>
<Pressable
style={[styles.radioButton, { borderColor: accent_blue }]}
onPress={() => setSelectedOption(option.value)}
>
{selectedOption === option.value && (
<View
style={[
styles.radioButtonInner,
{ backgroundColor: accent_blue },
]}
/>
)}
</Pressable>
<Text style={styles.optionText}>{option.name}</Text>
</View>
))}
{selectedOption === "custom" && (
<View style={styles.datePickerContainer}>
<DateTimePicker
mode="datetime"
onChange={setDate}
value={customDate}
display="default"
/>
</View>
)}
<View style={styles.buttonContainer}>
<Pressable style={styles.button} onPress={onClose}>
<Text style={[styles.buttonText, { color: accent_blue }]}>
Cancel
</Text>
</Pressable>
<Pressable style={styles.button} onPress={handleAdd}>
<Text style={[styles.buttonText, { color: accent_blue }]}>
Add
</Text>
</Pressable>
</View>
</View>
</View>
</Modal>
</SafeAreaView>
</SafeAreaProvider>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
modal: {
backgroundColor: "white",
margin: 20,
borderRadius: 16,
padding: 20,
shadowColor: "black",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5,
},
title: {
fontSize: 18,
fontWeight: "bold",
textAlign: "center",
marginBottom: 16,
},
option: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 8,
},
optionText: {
fontSize: 16,
marginLeft: 8,
},
radioButton: {
width: 20,
height: 20,
borderRadius: 10,
borderWidth: 2,
alignItems: "center",
justifyContent: "center",
},
radioButtonInner: {
width: 12,
height: 12,
borderRadius: 6,
},
buttonContainer: {
flexDirection: "row",
justifyContent: "flex-end",
marginTop: 8,
},
button: {
padding: 8,
marginLeft: 8,
},
buttonText: {
fontSize: 16,
fontWeight: "bold",
textAlign: "center",
},
datePickerContainer: {
alignItems: "center",
justifyContent: "center",
},
});Hide Channel History For Newly Added Members
In this tutorial we will demonstrate how to build a simple Modal that allows to specify the length of channel conversation history to be shared with a newly added member.
We will build the following simple modal:

Minimal modal 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(customDate).toISOString()
Minimal styles are used for the modal.
AddMemberWithHistoryModal.tsx
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(),
});