PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
yatra / resources / js / api / email-automation-api.ts

email-automation-api.ts in Yatra – Travel Booking & Tour Operator Software 3.0.16, at resources/js/api/email-automation-api.ts

257 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Centralized REST calls for Email Automation (Yatra Pro).
3 */
4
5 import { apiClient } from "../lib/api-client";
6 import { API_ENDPOINTS } from "../lib/api-endpoints";
7 import { unwrapApiPayload } from "../lib/unwrap-api-payload";
8
9 export type EmailTemplateVariableMap = Record<
10 string,
11 { key: string; description?: string }[]
12 >;
13
14 export type EmailPreviewPayload = {
15 subject: string;
16 body: string;
17 };
18
19 export async function fetchEmailTemplates(): Promise<unknown[]> {
20 // The list is rendered client-side in full (no server paging in the UI);
21 // ask for everything so trip-specific overrides never fall off page 1.
22 const raw = await apiClient.get(API_ENDPOINTS.EMAIL_TEMPLATES, {
23 params: { per_page: 500 },
24 });
25 const unwrapped = unwrapApiPayload<unknown>(raw);
26 return Array.isArray(unwrapped) ? unwrapped : [];
27 }
28
29 /** Trip targeting of an override template (mirrors the Pro `settings.targets`). */
30 export type EmailTemplateTargets = {
31 trips?: number[];
32 categories?: number[];
33 trip_types?: string[];
34 };
35
36 /**
37 * Create a trip-specific override of a global template (Pro Email
38 * Automation). Same event and merge tags; used instead of the global
39 * template for bookings on the targeted trips.
40 */
41 export async function createEmailTemplateOverride(
42 parentId: string | number,
43 data: {
44 targets: EmailTemplateTargets;
45 name?: string;
46 description?: string;
47 copy?: boolean;
48 },
49 ): Promise<unknown> {
50 return apiClient.post(API_ENDPOINTS.EMAIL_TEMPLATE_OVERRIDE(parentId), data);
51 }
52
53 export async function reorderEmailTemplateOverrides(
54 parentKey: string,
55 ids: number[],
56 ): Promise<unknown> {
57 return apiClient.post(API_ENDPOINTS.EMAIL_TEMPLATE_OVERRIDES_REORDER, {
58 parent_key: parentKey,
59 ids,
60 });
61 }
62
63 export type EmailTemplateResolution = {
64 trip: { id: number; trip_type: string; categories: number[] };
65 resolved: Record<
66 string,
67 {
68 id: number;
69 template_key: string;
70 name: string;
71 specificity: number;
72 reason: string;
73 } | null
74 >;
75 overridable: string[];
76 };
77
78 /** "View as a trip": which template each overridable email uses for a trip. */
79 export async function resolveEmailTemplatesForTrip(
80 tripId: number,
81 ): Promise<EmailTemplateResolution> {
82 return unwrapApiPayload<EmailTemplateResolution>(
83 await apiClient.get(API_ENDPOINTS.EMAIL_TEMPLATE_RESOLVE, {
84 params: { trip_id: tripId },
85 }),
86 );
87 }
88
89 export async function fetchEmailTemplate(
90 id: string | number,
91 ): Promise<Record<string, unknown> | null> {
92 return unwrapApiPayload<Record<string, unknown> | null>(
93 await apiClient.get(API_ENDPOINTS.EMAIL_TEMPLATE_GET(id)),
94 );
95 }
96
97 /**
98 * Fetch the merge-tag catalog for the Template Editor "Available
99 * Variables" sidebar.
100 *
101 * Pass `eventKey` to get only the variables that apply to that
102 * automation event (e.g. `booking.created` returns the booking +
103 * customer + payment tags but skips enquiry / consent). Omit it
104 * (or pass an empty string) to get the full union of all tags —
105 * matches the pre-3.0.5 behavior for callers that haven't been
106 * updated.
107 */
108 export async function fetchEmailTemplateVariables(
109 eventKey?: string,
110 ): Promise<EmailTemplateVariableMap> {
111 const url =
112 eventKey && eventKey.trim() !== ""
113 ? `${API_ENDPOINTS.EMAIL_TEMPLATE_VARIABLES}?event_key=${encodeURIComponent(eventKey.trim())}`
114 : API_ENDPOINTS.EMAIL_TEMPLATE_VARIABLES;
115 return unwrapApiPayload<EmailTemplateVariableMap>(await apiClient.get(url));
116 }
117
118 /**
119 * Live list of trigger events (key/name/description) from the server.
120 *
121 * Fetched instead of relying only on the one-time `window.yatraAdmin.emailEvents`
122 * localize snapshot: that snapshot reflects the module state at PHP render time,
123 * while the module-enabled flag is refreshed client-side (useModules), so the two
124 * can diverge — leaving the event dropdown empty when a template is created right
125 * after enabling the module (no full reload). This endpoint always reflects the
126 * current state.
127 */
128 export async function fetchEmailTemplateEvents(): Promise<
129 Array<{ key: string; name: string; description?: string }>
130 > {
131 return unwrapApiPayload<
132 Array<{ key: string; name: string; description?: string }>
133 >(await apiClient.get(API_ENDPOINTS.EMAIL_TEMPLATE_EVENTS));
134 }
135
136 export async function createEmailTemplate(data: unknown): Promise<unknown> {
137 return apiClient.post(API_ENDPOINTS.EMAIL_TEMPLATES, data);
138 }
139
140 export async function updateEmailTemplate(
141 id: string | number,
142 data: unknown,
143 ): Promise<unknown> {
144 return apiClient.put(API_ENDPOINTS.EMAIL_TEMPLATE_GET(id), data);
145 }
146
147 export async function setEmailTemplateActive(
148 id: number,
149 is_active: boolean,
150 ): Promise<unknown> {
151 return apiClient.put(API_ENDPOINTS.EMAIL_TEMPLATE_GET(id), { is_active });
152 }
153
154 export async function deleteEmailTemplate(id: number): Promise<unknown> {
155 return apiClient.delete(API_ENDPOINTS.EMAIL_TEMPLATE_GET(id));
156 }
157
158 export async function duplicateEmailTemplate(id: number): Promise<unknown> {
159 return apiClient.post(API_ENDPOINTS.EMAIL_TEMPLATE_DUPLICATE(id));
160 }
161
162 export async function previewEmailTemplate(
163 id: string | number,
164 tripId?: number | null,
165 ): Promise<EmailPreviewPayload> {
166 const response = await apiClient.post(
167 API_ENDPOINTS.EMAIL_TEMPLATE_PREVIEW(id),
168 tripId ? { trip_id: tripId } : {},
169 );
170 return unwrapApiPayload<EmailPreviewPayload>(response);
171 }
172
173 export async function sendEmailTemplateTest(
174 id: string | number,
175 email: string,
176 tripId?: number | null,
177 ): Promise<unknown> {
178 return apiClient.post(API_ENDPOINTS.EMAIL_TEMPLATE_TEST(id), {
179 email,
180 ...(tripId ? { trip_id: tripId } : {}),
181 });
182 }
183
184 export async function fetchEmailSequences(): Promise<unknown[]> {
185 const raw = await apiClient.get(API_ENDPOINTS.EMAIL_SEQUENCES);
186 const unwrapped = unwrapApiPayload<unknown>(raw);
187 return Array.isArray(unwrapped) ? unwrapped : [];
188 }
189
190 export async function fetchEmailSequence(
191 id: string | number,
192 ): Promise<unknown> {
193 return unwrapApiPayload(
194 await apiClient.get(API_ENDPOINTS.EMAIL_SEQUENCE_GET(id)),
195 );
196 }
197
198 export async function createEmailSequence(data: unknown): Promise<unknown> {
199 return apiClient.post(API_ENDPOINTS.EMAIL_SEQUENCES, data);
200 }
201
202 export async function updateEmailSequence(
203 id: string | number,
204 data: unknown,
205 ): Promise<unknown> {
206 return apiClient.put(API_ENDPOINTS.EMAIL_SEQUENCE_GET(id), data);
207 }
208
209 export async function deleteEmailSequence(id: number): Promise<unknown> {
210 return apiClient.delete(API_ENDPOINTS.EMAIL_SEQUENCE_GET(id));
211 }
212
213 export async function updateEmailSequenceStatus(
214 id: number,
215 status: string,
216 ): Promise<unknown> {
217 return apiClient.put(API_ENDPOINTS.EMAIL_SEQUENCE_GET(id), { status });
218 }
219
220 export type EmailLogsPageResult = {
221 items: unknown[];
222 total: number;
223 per_page: number;
224 current_page: number;
225 };
226
227 export async function fetchEmailLogs(params?: {
228 page?: number;
229 per_page?: number;
230 template_key?: string;
231 recipient_email?: string;
232 status?: string;
233 }): Promise<EmailLogsPageResult> {
234 const raw = await apiClient.get(API_ENDPOINTS.EMAIL_LOGS, { params });
235 if (raw !== null && typeof raw === "object") {
236 const r = raw as Record<string, unknown>;
237 if (r.success === true && "data" in r) {
238 const meta = (r.meta as Record<string, unknown>) || {};
239 const items = Array.isArray(r.data) ? r.data : [];
240 return {
241 items,
242 total: Number(meta.total) || items.length,
243 per_page: Number(meta.per_page) || params?.per_page || 20,
244 current_page: Number(meta.current_page) || params?.page || 1,
245 };
246 }
247 }
248 const fallback = unwrapApiPayload<unknown>(raw);
249 const items = Array.isArray(fallback) ? fallback : [];
250 return {
251 items,
252 total: items.length,
253 per_page: params?.per_page || 20,
254 current_page: params?.page || 1,
255 };
256 }
257