Canned Responses
Canned Responses
Section titled “Canned Responses”Summary
Section titled “Summary”Canned Responses enable agents to use pre-defined message templates for common queries, improving response time and consistency.
User Story: As a support agent, I want to use pre-defined response templates so that I can respond quickly to common customer questions.
Acceptance Criteria:
- ✅ Browse available canned responses
- ✅ Search canned responses by keyword
- ✅ Insert canned response into message input
- ✅ Preview response before sending
- ✅ Filter by category/tags
- ✅ Support variable interpolation
Inputs:
- Search query
- Selected canned response
Outputs:
- Filtered list of canned responses
- Formatted response text with variables replaced
Load Canned Responses Flow
Section titled “Load Canned Responses Flow”User Opens Chat Screen ↓Dispatch: fetchCannedResponses() ↓API Request: GET /canned_responses ↓Transform Response Data ↓Store in Redux (cannedResponses.byId, allIds) ↓Ready for Use in Message InputInsert Canned Response Flow
Section titled “Insert Canned Response Flow”User Types '/' in Message Input ↓Show Canned Response Picker ↓User Types Search Query ↓Filter Canned Responses by Short Code or Content ↓Display Matching Responses ↓User Selects Response ↓Replace Variables ({{contact.name}}, {{agent.name}}) ↓Insert into Message Input ↓User Reviews and SendsAPI/Contracts
Section titled “API/Contracts”Fetch Canned Responses
Section titled “Fetch Canned Responses”Request:
GET /api/v1/accounts/{accountId}/canned_responsesResponse:
{ data: CannedResponse[]}
interface CannedResponse { id: number; short_code: string; content: string; account_id: number;}Variable Substitution
Section titled “Variable Substitution”Supported Variables:
const VARIABLES = { 'contact.name': () => contact.name, 'contact.email': () => contact.email, 'agent.name': () => currentUser.name, 'agent.email': () => currentUser.email,};Example
Section titled “Example”Canned Response Picker
Section titled “Canned Response Picker”export const CannedResponsePicker = ({ onSelect,}: { onSelect: (response: CannedResponse) => void;}) => { const [search, setSearch] = useState(''); const cannedResponses = useAppSelector(selectAllCannedResponses);
const filteredResponses = useMemo(() => { return cannedResponses.filter( response => response.shortCode.includes(search) || response.content.toLowerCase().includes(search.toLowerCase()) ); }, [cannedResponses, search]);
return ( <View> <TextInput value={search} onChangeText={setSearch} placeholder="Search canned responses..." /> <FlatList data={filteredResponses} renderItem={({ item }) => ( <TouchableOpacity onPress={() => onSelect(item)}> <View style={tailwind('p-3 border-b border-gray-3')}> <Text style={tailwind('text-blue-9 font-inter-semibold-20')}> /{item.shortCode} </Text> <Text style={tailwind('text-gray-11 text-xs mt-1')} numberOfLines={2}> {item.content} </Text> </View> </TouchableOpacity> )} /> </View> );};Further Reading
Section titled “Further Reading”- Messaging - Message composition