PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.6
Yatra – Travel Booking & Tour Operator Software v3.0.6
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 / assets / dist / blocks / tripcategory.js

tripcategory.js in Yatra – Travel Booking & Tour Operator Software 3.0.6, at assets/dist/blocks/tripcategory.js

475 lines 14.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function(element, blocks, blockEditor, components, i18n, ServerSideRender, apiFetch) {
2 "use strict";
3 const listWrapStyle = {
4 maxHeight: 220,
5 overflowY: "auto",
6 marginTop: 8,
7 padding: "4px 0",
8 border: "1px solid #94949451",
9 borderRadius: 2
10 };
11 function ClassificationMultiSelect({
12 taxonomy,
13 label,
14 help,
15 value,
16 onChange
17 }) {
18 const [items, setItems] = element.useState([]);
19 const [loading, setLoading] = element.useState(true);
20 const [loadError, setLoadError] = element.useState(false);
21 const [search, setSearch] = element.useState("");
22 const [scope, setScope] = element.useState(
23 () => value.length > 0 ? "narrow" : "all"
24 );
25 element.useEffect(() => {
26 if (value.length > 0) {
27 setScope("narrow");
28 }
29 }, [value.length]);
30 element.useEffect(() => {
31 let cancelled = false;
32 setLoading(true);
33 setLoadError(false);
34 apiFetch({
35 path: `/yatra/v1/block-editor/taxonomy-choices?taxonomy=${encodeURIComponent(
36 taxonomy
37 )}`
38 }).then((response) => {
39 if (!cancelled) {
40 setItems(response.items ?? []);
41 }
42 }).catch(() => {
43 if (!cancelled) {
44 setItems([]);
45 setLoadError(true);
46 }
47 }).finally(() => {
48 if (!cancelled) {
49 setLoading(false);
50 }
51 });
52 return () => {
53 cancelled = true;
54 };
55 }, [taxonomy]);
56 const filteredItems = element.useMemo(() => {
57 const q = search.trim().toLowerCase();
58 if (q === "") {
59 return items;
60 }
61 return items.filter((i) => i.name.toLowerCase().includes(q));
62 }, [items, search]);
63 const selectedSet = element.useMemo(() => new Set(value), [value]);
64 const toggleId = (id, checked) => {
65 const next = new Set(selectedSet);
66 if (checked) {
67 next.add(id);
68 } else {
69 next.delete(id);
70 }
71 onChange([...next].sort((a, b) => a - b));
72 };
73 const onScopeChange = (next) => {
74 if (next === "all") {
75 setScope("all");
76 onChange([]);
77 setSearch("");
78 } else {
79 setScope("narrow");
80 }
81 };
82 if (loading) {
83 return /* @__PURE__ */ element.createElement(
84 "fieldset",
85 {
86 className: "yatra-block-taxonomy-field",
87 style: { margin: "0 0 16px", border: "none", padding: 0 }
88 },
89 /* @__PURE__ */ element.createElement(
90 "legend",
91 {
92 className: "components-base-control__label",
93 style: { padding: 0 }
94 },
95 label
96 ),
97 /* @__PURE__ */ element.createElement(components.Spinner, null)
98 );
99 }
100 return /* @__PURE__ */ element.createElement(
101 "fieldset",
102 {
103 className: "yatra-block-taxonomy-field",
104 style: { margin: "0 0 16px", border: "none", padding: 0 }
105 },
106 /* @__PURE__ */ element.createElement("legend", { className: "components-base-control__label", style: { padding: 0 } }, label),
107 /* @__PURE__ */ element.createElement(
108 "p",
109 {
110 className: "components-base-control__help",
111 style: { marginTop: 4, marginBottom: 10 }
112 },
113 help
114 ),
115 loadError && /* @__PURE__ */ element.createElement("p", { style: { color: "#b32d2e", fontSize: 12, marginBottom: 8 } }, i18n.__(
116 "Could not load options. Confirm you can edit posts and Yatra REST is available.",
117 "yatra"
118 )),
119 /* @__PURE__ */ element.createElement(
120 components.RadioControl,
121 {
122 label: i18n.__("Listing scope", "yatra"),
123 selected: scope,
124 options: [
125 {
126 label: i18n.__("All published (no restriction)", "yatra"),
127 value: "all"
128 },
129 {
130 label: i18n.__("Only selected (search below)", "yatra"),
131 value: "narrow"
132 }
133 ],
134 onChange: onScopeChange
135 }
136 ),
137 scope === "all" && /* @__PURE__ */ element.createElement("p", { className: "components-base-control__help", style: { marginTop: 4 } }, i18n.__(
138 "The frontend will include every matching published item.",
139 "yatra"
140 )),
141 scope === "narrow" && /* @__PURE__ */ element.createElement(element.Fragment, null, /* @__PURE__ */ element.createElement(
142 components.SearchControl,
143 {
144 label: i18n.sprintf(
145 /* translators: %d = number of loaded taxonomy items */
146 i18n.__("Filter items (%d loaded)", "yatra"),
147 items.length
148 ),
149 hideLabelFromVision: true,
150 placeholder: i18n.__("Type to filter the list…", "yatra"),
151 value: search,
152 onChange: (s) => setSearch(s),
153 __nextHasNoMarginBottom: true
154 }
155 ), value.length > 0 && /* @__PURE__ */ element.createElement(
156 "p",
157 {
158 className: "components-base-control__help",
159 style: { marginTop: 4 }
160 },
161 i18n.sprintf(
162 /* translators: %d = number of selected taxonomy items */
163 i18n.__("%d selected", "yatra"),
164 value.length
165 )
166 ), items.length === 0 && !loadError ? /* @__PURE__ */ element.createElement("p", { className: "components-base-control__help" }, i18n.__("No published items of this type yet.", "yatra")) : /* @__PURE__ */ element.createElement("div", { role: "group", "aria-label": label, style: listWrapStyle }, filteredItems.length === 0 ? /* @__PURE__ */ element.createElement("p", { style: { padding: "8px 12px", margin: 0, fontSize: 12 } }, i18n.__("No matching items.", "yatra")) : filteredItems.map((item) => {
167 const cid = Number(item.id);
168 return /* @__PURE__ */ element.createElement("div", { key: cid, style: { padding: "2px 8px" } }, /* @__PURE__ */ element.createElement(
169 components.CheckboxControl,
170 {
171 label: `${item.name} (${cid})`,
172 checked: selectedSet.has(cid),
173 onChange: (checked) => toggleId(cid, checked === true),
174 __nextHasNoMarginBottom: true
175 }
176 ));
177 })), value.length > 0 && /* @__PURE__ */ element.createElement(
178 components.Button,
179 {
180 variant: "link",
181 style: { paddingLeft: 0, marginTop: 6 },
182 onClick: () => onChange([])
183 },
184 i18n.__("Clear selected", "yatra")
185 ), /* @__PURE__ */ element.createElement("p", { className: "components-base-control__help", style: { marginTop: 6 } }, i18n.__(
186 "If none are checked, the block behaves like “All” (no taxonomy filter).",
187 "yatra"
188 )))
189 );
190 }
191 function migrateNumericCsvPairToIds(legacyA, legacyB) {
192 const raw = [legacyA ?? "", legacyB ?? ""].find(
193 (s) => String(s).trim() !== ""
194 );
195 if (raw === void 0) {
196 return [];
197 }
198 const parts = String(raw).split(",").map((s) => s.trim()).filter(Boolean);
199 const ids = [];
200 for (const p of parts) {
201 if (!/^\d+$/.test(p)) {
202 return [];
203 }
204 const n = parseInt(p, 10);
205 if (n > 0) {
206 ids.push(n);
207 }
208 }
209 return [...new Set(ids)];
210 }
211 function normalizeIds(arr) {
212 return Array.isArray(arr) ? [...new Set(arr.map((n) => parseInt(String(n), 10)).filter((n) => n > 0))] : [];
213 }
214 function Edit({ attributes: attributes2, setAttributes }) {
215 const migratedOnce = element.useRef(false);
216 element.useEffect(() => {
217 if (migratedOnce.current) {
218 return;
219 }
220 migratedOnce.current = true;
221 let ids = normalizeIds(attributes2.categoryIds);
222 if (ids.length === 0) {
223 ids = migrateNumericCsvPairToIds(
224 attributes2.category_ids,
225 attributes2.category
226 );
227 }
228 if (ids.length === 0) {
229 return;
230 }
231 setAttributes({
232 categoryIds: ids,
233 category: "",
234 category_ids: ""
235 });
236 }, [setAttributes]);
237 const {
238 order,
239 columns,
240 per_page,
241 title: title2,
242 show_pagination,
243 show_trip_count,
244 show_description,
245 show_image,
246 hide_empty,
247 featured_only
248 } = attributes2;
249 const categoryIds = normalizeIds(attributes2.categoryIds);
250 return /* @__PURE__ */ element.createElement(element.Fragment, null, /* @__PURE__ */ element.createElement(blockEditor.InspectorControls, null, /* @__PURE__ */ element.createElement(
251 components.PanelBody,
252 {
253 title: i18n.__("Trip category settings", "yatra"),
254 initialOpen: true
255 },
256 /* @__PURE__ */ element.createElement(
257 components.TextControl,
258 {
259 label: i18n.__("Title", "yatra"),
260 value: title2,
261 onChange: (value) => setAttributes({ title: value })
262 }
263 ),
264 /* @__PURE__ */ element.createElement(
265 ClassificationMultiSelect,
266 {
267 taxonomy: "trip_category",
268 label: i18n.__("Trip categories to show", "yatra"),
269 help: i18n.__(
270 "All published lists every category; narrow with search and checkboxes. Yatra trip types only.",
271 "yatra"
272 ),
273 value: categoryIds,
274 onChange: (ids) => setAttributes({ categoryIds: ids })
275 }
276 ),
277 /* @__PURE__ */ element.createElement(
278 components.SelectControl,
279 {
280 label: i18n.__("Order", "yatra"),
281 value: order,
282 options: [
283 { label: i18n.__("Ascending", "yatra"), value: "asc" },
284 { label: i18n.__("Descending", "yatra"), value: "desc" }
285 ],
286 onChange: (value) => setAttributes({ order: value })
287 }
288 ),
289 /* @__PURE__ */ element.createElement(
290 components.RangeControl,
291 {
292 label: i18n.__("Number of categories", "yatra"),
293 value: per_page,
294 onChange: (value) => setAttributes({
295 per_page: value !== void 0 && value !== null ? value : 10
296 }),
297 min: 1,
298 max: 50
299 }
300 ),
301 /* @__PURE__ */ element.createElement(
302 components.RangeControl,
303 {
304 label: i18n.__("Columns", "yatra"),
305 value: columns,
306 onChange: (value) => setAttributes({
307 columns: value !== void 0 && value !== null ? value : 3
308 }),
309 min: 1,
310 max: 6
311 }
312 ),
313 /* @__PURE__ */ element.createElement(
314 components.ToggleControl,
315 {
316 label: i18n.__("Show pagination", "yatra"),
317 checked: show_pagination,
318 onChange: (value) => setAttributes({ show_pagination: value })
319 }
320 )
321 ), /* @__PURE__ */ element.createElement(components.PanelBody, { title: i18n.__("Display options", "yatra"), initialOpen: false }, /* @__PURE__ */ element.createElement(
322 components.ToggleControl,
323 {
324 label: i18n.__("Show trip count", "yatra"),
325 checked: show_trip_count,
326 onChange: (value) => setAttributes({ show_trip_count: value })
327 }
328 ), /* @__PURE__ */ element.createElement(
329 components.ToggleControl,
330 {
331 label: i18n.__("Show description", "yatra"),
332 checked: show_description,
333 onChange: (value) => setAttributes({ show_description: value })
334 }
335 ), /* @__PURE__ */ element.createElement(
336 components.ToggleControl,
337 {
338 label: i18n.__("Show image", "yatra"),
339 checked: show_image,
340 onChange: (value) => setAttributes({ show_image: value })
341 }
342 ), /* @__PURE__ */ element.createElement(
343 components.ToggleControl,
344 {
345 label: i18n.__("Hide empty categories", "yatra"),
346 help: i18n.__(
347 "Skip categories that have no published trips assigned. Off by default — turn on for a tighter live catalog, leave off for editorial / onboarding views.",
348 "yatra"
349 ),
350 checked: hide_empty,
351 onChange: (value) => setAttributes({ hide_empty: value })
352 }
353 ), /* @__PURE__ */ element.createElement(
354 components.ToggleControl,
355 {
356 label: i18n.__("Featured only (filter list)", "yatra"),
357 help: i18n.__(
358 "When on, only categories with “Featured category” enabled in Yatra → Trips → Categories are listed. The red “Featured” badge on each card is controlled per category there—not by this toggle.",
359 "yatra"
360 ),
361 checked: featured_only,
362 onChange: (value) => setAttributes({ featured_only: value })
363 }
364 ))), /* @__PURE__ */ element.createElement("div", { className: "yatra-block-editor-preview" }, /* @__PURE__ */ element.createElement(
365 ServerSideRender,
366 {
367 block: "yatra/trip-category",
368 attributes: attributes2,
369 key: JSON.stringify(attributes2)
370 }
371 )));
372 }
373 const $schema = "https://schemas.wp.org/trunk/block.json";
374 const apiVersion = 3;
375 const name = "yatra/trip-category";
376 const title = "Trip categories";
377 const category = "yatra";
378 const icon = "category";
379 const description = "Display trip category cards with trip counts and pricing (same layout as destinations).";
380 const keywords = [
381 "category",
382 "trip",
383 "taxonomy",
384 "yatra"
385 ];
386 const textdomain = "yatra";
387 const attributes = {
388 align: {
389 type: "string",
390 "default": ""
391 },
392 order: {
393 type: "string",
394 "default": "desc"
395 },
396 columns: {
397 type: "number",
398 "default": 3
399 },
400 per_page: {
401 type: "number",
402 "default": 10
403 },
404 title: {
405 type: "string",
406 "default": "Trip Categories"
407 },
408 show_pagination: {
409 type: "boolean",
410 "default": true
411 },
412 categoryIds: {
413 type: "array",
414 "default": []
415 },
416 show_trip_count: {
417 type: "boolean",
418 "default": true
419 },
420 show_description: {
421 type: "boolean",
422 "default": true
423 },
424 show_image: {
425 type: "boolean",
426 "default": true
427 },
428 hide_empty: {
429 type: "boolean",
430 "default": false
431 },
432 featured_only: {
433 type: "boolean",
434 "default": false
435 }
436 };
437 const supports = {
438 html: false,
439 inserter: true,
440 align: [
441 "wide",
442 "full"
443 ]
444 };
445 const editorScript = "yatra-trip-category-block-editor";
446 const blockMetadata = {
447 $schema,
448 apiVersion,
449 name,
450 title,
451 category,
452 icon,
453 description,
454 keywords,
455 textdomain,
456 attributes,
457 supports,
458 editorScript
459 };
460 const {
461 $schema: _$schema,
462 editorScript: _$editorScript,
463 ...metadata
464 } = blockMetadata;
465 if (blocks.getBlockType(metadata.name)) {
466 blocks.unregisterBlockType(metadata.name);
467 }
468 blocks.registerBlockType(metadata.name, {
469 ...metadata,
470 edit: Edit,
471 save: () => null
472 });
473 })(wp.element, wp.blocks, wp.blockEditor, wp.components, wp.i18n, wp.serverSideRender, wp.apiFetch);
474 //# sourceMappingURL=tripcategory.js.map
475