Insights Custom Instructions
This package contains React hooks and utilities for managing Sales Strategist custom instructions through the Analytics API.
Overview
Custom instructions allow administrators to configure guidance at three hierarchical levels:
- Team: Instructions that apply to all team members
- Group: Instructions specific to user groups
- Individual: Instructions for specific users
The resolution follows a priority hierarchy: Individual > Group > Team
Installation
pnpm add @shared/custom-instructions
Quick Start
import {
useCustomInstructions,
useCreateCustomInstruction,
} from '@shared/custom-instructions'
function MyComponent() {
// List instructions
const { data, isLoading } = useCustomInstructions()
// Create instruction
const { mutate: createInstruction } = useCreateCustomInstruction()
// Use them in your component
// ...
}
Available Hooks
Query Hooks (Data Fetching)
| Hook | Purpose | Parameters |
|---|---|---|
useCustomInstructions | Fetch paginated list of instructions | params?: ListCustomInstructionsParams |
useAllCustomInstructions | Fetch ALL instructions across all pages | params?: Omit<ListCustomInstructionsParams, 'page' \| 'per_page'> |
useCustomInstruction | Fetch single instruction by ID | id: number |
useResolvedInstructions | Fetch resolved instructions for current user | params: ResolvedInstructionsParams |
Mutation Hooks (Data Modification)
| Hook | Purpose | Parameters |
|---|---|---|
useCreateCustomInstruction | Create new instruction | CreateCustomInstructionParams |
useUpdateCustomInstruction | Update existing instruction | { id: number, params: UpdateCustomInstructionParams } |
useDeleteCustomInstruction | Delete single instruction | id: number |
useBulkDeleteCustomInstructions | Delete multiple instructions | { custom_instruction_ids: number[] } |
Architecture
File Structure
All implementation files are organized in a flat structure at src/ root, following a consistent naming pattern:
src/
├── customInstructions.hooks.ts # React Query hooks
├── customInstructions.api.ts # API request functions
├── customInstructions.constants.ts # Constants and configurations
├── customInstructions.types.ts # TypeScript types and interfaces
├── customInstructions.spec.ts # Unit tests
└── index.ts # Public exports
API Endpoints
All hooks interact with the following endpoints:
GET /v2/sales_strategist/custom_instructions- List instructionsPOST /v2/sales_strategist/custom_instructions- Create instructionGET /v2/sales_strategist/custom_instructions/:id- Get single instructionPUT /v2/sales_strategist/custom_instructions/:id- Update instructionDELETE /v2/sales_strategist/custom_instructions/:id- Delete instructionPOST /v2/sales_strategist/custom_instructions/bulk_delete_instructions- Bulk deleteGET /v2/sales_strategist/custom_instructions/resolved- Get resolved instructions
Usage Examples
List Custom Instructions
import { useCustomInstructions } from '@shared/custom-instructions'
function CustomInstructionsList() {
const { data, isLoading, error } = useCustomInstructions({
per_page: 25,
page: 1,
sort_by: 'created_at',
sort_direction: 'desc'
})
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error loading instructions</div>
return (
<div>
{data?.data.map(instruction => (
<div key={instruction.id}>{instruction.instructions}</div>
))}
</div>
)
}
Get All Custom Instructions (All Pages)
Automatically fetches all pages when you need all instructions (e.g., for validation):
import { useAllCustomInstructions } from '@shared/custom-instructions'
function InstructionsValidation() {
const { data, isLoading, totalCount } = useAllCustomInstructions({
sort_by: 'created_at',
sort_direction: 'desc'
})
if (isLoading) return <div>Loading all instructions...</div>
// data is an array with ALL instructions across all pages
const teamInstructionExists = data?.some(
instruction => instruction.instruction_type === 'team'
) ?? false
return (
<div>
<p>Total instructions: {totalCount}</p>
<p>Team instruction exists: {teamInstructionExists ? 'Yes' : 'No'}</p>
</div>
)
}
Get Single Custom Instruction
import { useCustomInstruction } from '@shared/custom-instructions'
function CustomInstructionDetail({ id }: { id: number }) {
const { data, isLoading } = useCustomInstruction(id)
if (isLoading) return <div>Loading...</div>
return <div>{data?.instructions}</div>
}
Get Resolved Instructions
Fetch the resolved instructions for the current user based on the hierarchy (Individual > Group > Team):
import { useResolvedInstructions } from '@shared/custom-instructions'
function ResolvedInstructions() {
const { data } = useResolvedInstructions()
const instructions = JSON.parse(data?.resolved_instructions || '{}')
return (
<div>
{instructions.custom_instructions?.individual_preferences && (
<p>{instructions.custom_instructions.individual_preferences.content}</p>
)}
</div>
)
}
Create Custom Instruction
import { useCreateCustomInstruction } from '@shared/custom-instructions'
import { successToast, errorToast } from '@rhapsody/toasts'
function CreateInstructionForm() {
const { mutate, isLoading } = useCreateCustomInstruction()
const handleCreateTeamInstruction = () => {
mutate(
{
agent_name: 'sales_strategist',
instructions: 'Team-wide guidance text',
instruction_type: 'team'
},
{
onSuccess: () => successToast({ title: 'Instruction created!' }),
onError: () => errorToast({ title: 'Failed to create instruction' })
}
)
}
const handleCreateGroupInstruction = () => {
mutate({
agent_name: 'sales_strategist',
instructions: 'Group-specific guidance',
instruction_type: 'group',
group_ids: [3312, 430]
})
}
const handleCreateIndividualInstruction = () => {
mutate({
agent_name: 'sales_strategist',
instructions: 'Individual user guidance',
instruction_type: 'individual',
target_user_id: 9421
})
}
return (
<div>
<button onClick={handleCreateTeamInstruction}>Create Team</button>
<button onClick={handleCreateGroupInstruction}>Create Group</button>
<button onClick={handleCreateIndividualInstruction}>Create Individual</button>
</div>
)
}
Update Custom Instruction
import { useUpdateCustomInstruction } from '@shared/custom-instructions'
function UpdateInstructionForm({ id }: { id: number }) {
const { mutate } = useUpdateCustomInstruction()
const handleUpdate = () => {
mutate({
id,
params: {
instructions: 'Updated instruction text',
agent_name: 'sales_strategist_manager'
}
})
}
// Transform instruction type
const handleTransformToGroup = () => {
mutate({
id,
params: {
instruction_type: 'group',
group_ids: [3312, 430, 3319]
}
})
}
return (
<div>
<button onClick={handleUpdate}>Update Text</button>
<button onClick={handleTransformToGroup}>Transform to Group</button>
</div>
)
}
Delete Custom Instruction
import { useDeleteCustomInstruction } from '@shared/custom-instructions'
function DeleteInstructionButton({ id }: { id: number }) {
const { mutate, isLoading } = useDeleteCustomInstruction()
const handleDelete = () => {
if (confirm('Are you sure?')) {
mutate(id)
}
}
return (
<button onClick={handleDelete} disabled={isLoading}>
Delete
</button>
)
}
Bulk Delete Custom Instructions
import { useBulkDeleteCustomInstructions } from '@shared/custom-instructions'
function BulkDeleteInstructions({ ids }: { ids: number[] }) {
const { mutate, isLoading } = useBulkDeleteCustomInstructions()
const handleBulkDelete = () => {
if (confirm(`Delete ${ids.length} instructions?`)) {
mutate({ custom_instruction_ids: ids })
}
}
return (
<button onClick={handleBulkDelete} disabled={isLoading}>
Delete Selected ({ids.length})
</button>
)
}
Features
- ✅ Automatic Cache Invalidation: All mutation hooks automatically invalidate relevant queries after successful operations
- ✅ TypeScript Support: Fully typed with TypeScript for enhanced developer experience
- ✅ Error Handling: Built-in error handling with
throwIfNotOkHookfor consistent error responses - ✅ Pagination & Sorting: Support for pagination and sorting in list queries
- ✅ Type Transformations: Update instructions can transform between types (team ↔ group ↔ individual)
API Reference
Query Hooks
useCustomInstructions(params?, options?)- Fetch paginated list of custom instructionsuseAllCustomInstructions(params?, options?)- Fetch ALL custom instructions across all pages automaticallyuseCustomInstruction(id, options?)- Fetch a single custom instructionuseResolvedInstructions(params, options?)- Fetch resolved instructions for current user
Mutation Hooks
useCreateCustomInstruction()- Create a new custom instructionuseUpdateCustomInstruction()- Update an existing custom instructionuseDeleteCustomInstruction()- Delete a custom instructionuseBulkDeleteCustomInstructions()- Delete multiple custom instructions
API Functions
getCustomInstructions(params?)- Fetch list of instructions (non-hook)getCustomInstruction(id)- Fetch single instruction (non-hook)getResolvedInstructions(params)- Fetch resolved instructions (non-hook)createCustomInstruction(params)- Create instruction (non-hook)updateCustomInstruction(id, params)- Update instruction (non-hook)deleteCustomInstruction(id)- Delete instruction (non-hook)bulkDeleteCustomInstructions(params)- Bulk delete instructions (non-hook)
Utility Functions
invalidateCustomInstructionsQueries()- Invalidate all custom instructions queriesinvalidateCustomInstructionQuery(id)- Invalidate a specific instruction queryinvalidateResolvedInstructionsQueries()- Invalidate resolved instructions queries
Types
type InstructionType = 'team' | 'group' | 'individual'
type AgentName = 'sales_strategist' | 'sales_strategist_manager'
interface CustomInstruction {
id: number
agent_name: AgentName
instructions: string | null
instruction_type: InstructionType
user_id: number | null
group_id: number | null
group_ids: number[] | null
collection_id: string | null
created_by_user_id: number
team_id: number
created_at: string
updated_at: string
}
interface CreateCustomInstructionParams {
agent_name: AgentName
instructions: string
instruction_type: InstructionType
target_user_id?: number // Required for 'individual' type
group_ids?: number[] // Required for 'group' type
}
interface UpdateCustomInstructionParams {
agent_name?: AgentName
instructions?: string
instruction_type?: InstructionType
target_user_id?: number
group_ids?: number[]
}
interface ListCustomInstructionsParams {
per_page?: number
page?: number
sort_by?: 'created_at' | 'instructions'
sort_direction?: 'asc' | 'desc'
}
Authorization & Feature Flags
Important: All endpoints require:
- Team Admin privileges
- The
:coaching_agent_insightsfeature flag must be enabled
Non-admin users or teams without the feature flag will receive a 403 Forbidden error.
Validation Rules
Character Limits
- Instructions text: Maximum 2000 characters
Type-Specific Requirements
- Individual: Must provide
target_user_id - Group: Must provide
group_ids(non-empty array) - Team: No additional parameters required
Allowed Values2000 characters
Type-Specific Requirements
| Type | Required Fields |
|---|---|
team | None |
group | group_ids (non-empty array) |
individual | target_user_id |
Allowed Values
- agent_name:
sales_strategist|sales_strategist_manager - instruction_type:
team|group|individual
Support
For issues or questions, contact:
- Team: @SalesLoft/analytics-aces
- Additional Approvers: @SalesLoft/metric-mavericks