Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: segments API v2 #1205

Merged
merged 11 commits into from
Jan 30, 2024
113 changes: 70 additions & 43 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,10 @@ import {
PushProviderListResponse,
PushProviderUpsertResponse,
QueryChannelsAPIResponse,
QuerySegmentsOptions,
ReactionResponse,
ReactivateUserOptions,
ReactivateUsersOptions,
Recipient,
RecipientFilters,
RecipientQueryOptions,
ReservedMessageFields,
ReviewFlagReportOptions,
ReviewFlagReportResponse,
Expand All @@ -138,8 +136,7 @@ import {
SearchPayload,
Segment,
SegmentData,
SegmentFilters,
SegmentQueryOptions,
SegmentType,
SendFileAPIResponse,
StreamChatOptions,
SyncOptions,
Expand All @@ -159,6 +156,7 @@ import {
UpdatedMessage,
UpdateMessageAPIResponse,
UpdateMessageOptions,
UpdateSegmentData,
UserCustomEvent,
UserFilters,
UserOptions,
Expand Down Expand Up @@ -2824,56 +2822,106 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
}

/**
* createSegment - Creates a Campaign Segment
* createSegment - Creates a segment
*
* @private
* @param {SegmentType} type Segment type
* @param {string} id Segment ID (valid UUID)
* @param {string} name Segment name (valid UUID)
* @param {SegmentData} params Segment data
*
* @return {Segment} The Created Segment
* @return {Segment} The created Segment
*/
async createSegment(params: SegmentData) {
const { segment } = await this.post<{ segment: Segment }>(this.baseURL + `/segments`, { segment: params });
private async createSegment(type: SegmentType, id: string, name: string, data?: SegmentData): Promise<Segment> {
const body = {
id,
type,
name,
data,
};
const { segment } = await this.post<{ segment: Segment }>(this.baseURL + `/segments`, body);
return segment;
}

/**
* querySegments - Query Campaign Segments
* createUserSegment - Creates a user segment
*
* @param {string} id Segment ID (valid UUID)
* @param {string} name Segment name
* @param {SegmentData} data Segment data
*
* @return {Segment} The created Segment
*/
async createUserSegment(id: string, name: string, data?: SegmentData): Promise<Segment> {
return await this.createSegment('user', id, name, data);
}

/**
* createChannelSegment - Creates a channel segment
*
* @param {string} id Segment ID (valid UUID)
* @param {string} name Segment name
* @param {SegmentData} data Segment data
*
* @return {Segment} The created Segment
*/
async createChannelSegment(id: string, name: string, data?: SegmentData): Promise<Segment> {
return await this.createSegment('channel', id, name, data);
}

/**
* updateSegment - Update a segment
*
* @param {string} id Segment ID
* @param {Partial<UpdateSegmentData>} data Data to update
*
* @return {Segment} Updated Segment
*/
async updateSegment(id: string, data: Partial<UpdateSegmentData>) {
const { segment } = await this.put<{ segment: Segment }>(this.baseURL + `/segments/${id}`, data);
return segment;
}

/**
* querySegments - Query Segments
*
* @param {filter} filter MongoDB style filter conditions
* @param {QuerySegmentsOptions} options Options for sorting/paginating the results
*
* @return {Segment[]} Segments
*/
async querySegments(filters: SegmentFilters, options: SegmentQueryOptions = {}) {
async querySegments(filter: {}, options: QuerySegmentsOptions = {}) {
return await this.get<{
segments: Segment[];
}>(this.baseURL + `/segments`, {
payload: {
filter_conditions: filters,
filter,
...options,
},
});
}

/**
* updateSegment - Update a Campaign Segment
* deleteSegment - Delete a Campaign Segment
*
* @param {string} id Segment ID
* @param {Partial<SegmentData>} params Segment data
*
* @return {Segment} Updated Segment
* @return {Promise<APIResponse>} The Server Response
*/
async updateSegment(id: string, params: Partial<SegmentData>) {
const { segment } = await this.put<{ segment: Segment }>(this.baseURL + `/segments/${id}`, { segment: params });
return segment;
async deleteSegment(id: string) {
return this.delete<APIResponse>(this.baseURL + `/segments/${id}`);
}

/**
* deleteSegment - Delete a Campaign Segment
* segmentTargetExists - Check if a target exists in a segment
*
* @param {string} id Segment ID
* @param {string} segmentId Segment ID
* @param {string} targetId Target ID
*
* @return {Promise<APIResponse>} The Server Response
*/
async deleteSegment(id: string) {
return this.delete<APIResponse>(this.baseURL + `/segments/${id}`);
async segmentTargetExists(segmentId: string, targetId: string) {
return this.get<APIResponse>(this.baseURL + `/segments/${segmentId}/target/${targetId}`);
}

/**
Expand Down Expand Up @@ -2987,27 +3035,6 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
return await this.post<APIResponse & TestCampaignResponse>(this.baseURL + `/campaigns/${id}/test`, { users });
}

/**
* queryRecipients - Query Campaign Recipient Results
*
*
* @return {Recipient[]} Recipients
*/
async queryRecipients(filters: RecipientFilters, options: RecipientQueryOptions = {}) {
return await this.get<{
campaigns: Record<string, Campaign>;
recipients: Recipient[];
segments: Record<string, Segment>;
channels?: Record<string, ChannelResponse<StreamChatGenerics>>;
users?: Record<string, UserResponse<StreamChatGenerics>>;
}>(this.baseURL + `/recipients`, {
payload: {
filter_conditions: filters,
...options,
},
});
}

/**
* enrichURL - Get OpenGraph data of the given link
*
Expand Down
49 changes: 28 additions & 21 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2400,22 +2400,45 @@ export type DeleteUserOptions = {
user?: DeleteType;
};

export type SegmentType = 'channel' | 'user';

export type SegmentData = {
description: string;
filter: {};
name: string;
type: 'channel' | 'user';
};

export type Segment = {
created_at: string;
deleted_at: string;
id: string;
in_use: boolean;
locked: boolean;
name: string;
size: number;
status: 'computing' | 'ready';
type: SegmentType;
updated_at: string;
} & SegmentData;

export type UpdateSegmentData = {
name: string;
add_targets?: string[];
delete_targets?: string[];
} & SegmentData;

export type SortParam = {
field: string;
direction?: AscDesc;
};

export type Pager = {
limit?: number;
next?: string;
prev?: string;
};

export type QuerySegmentsOptions = {
sort?: SortParam[];
} & Pager;

export type CampaignSortField = {
field: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -2433,12 +2456,9 @@ export type CampaignQueryOptions = {
};

export type SegmentQueryOptions = CampaignQueryOptions;
export type RecipientQueryOptions = CampaignQueryOptions;

// TODO: add better typing
export type SegmentFilters = {};
export type CampaignFilters = {};
export type RecipientFilters = {};

export type CampaignData = {
attachments: Attachment[];
Expand Down Expand Up @@ -2479,20 +2499,7 @@ export type TestCampaignResponse = {
results?: Record<string, string>;
};

export type DeleteCampaignOptions = {
recipients?: boolean;
};

export type Recipient = {
campaign_id: string;
channel_cid: string;
created_at: string;
status: 'pending' | 'sent' | 'failed';
updated_at: string;
details?: string;
message_id?: string;
receiver_id?: string;
};
export type DeleteCampaignOptions = {};

export type TaskStatus = {
created_at: string;
Expand Down
Loading