PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.11
Yatra – Travel Booking & Tour Operator Software v3.0.11
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 / destination.js

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

460 lines 14.5 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.destinationIds);
222 if (ids.length === 0) {
223 ids = migrateNumericCsvPairToIds(
224 attributes2.destination_ids,
225 attributes2.destination
226 );
227 }
228 if (ids.length === 0) {
229 return;
230 }
231 setAttributes({
232 destinationIds: ids,
233 destination: "",
234 destination_ids: ""
235 });
236 }, [setAttributes]);
237 const destinationIds = normalizeIds(attributes2.destinationIds);
238 return /* @__PURE__ */ element.createElement(element.Fragment, null, /* @__PURE__ */ element.createElement(blockEditor.InspectorControls, null, /* @__PURE__ */ element.createElement(
239 components.PanelBody,
240 {
241 title: i18n.__("Destination Settings", "yatra"),
242 initialOpen: true
243 },
244 /* @__PURE__ */ element.createElement(
245 components.TextControl,
246 {
247 label: i18n.__("Title", "yatra"),
248 value: attributes2.title,
249 onChange: (value) => setAttributes({ title: value })
250 }
251 ),
252 /* @__PURE__ */ element.createElement(
253 components.SelectControl,
254 {
255 label: i18n.__("Order", "yatra"),
256 value: attributes2.order,
257 options: [
258 { label: i18n.__("Ascending", "yatra"), value: "asc" },
259 { label: i18n.__("Descending", "yatra"), value: "desc" }
260 ],
261 onChange: (value) => setAttributes({ order: value })
262 }
263 ),
264 /* @__PURE__ */ element.createElement(
265 components.RangeControl,
266 {
267 label: i18n.__("Number of Destinations", "yatra"),
268 value: attributes2.per_page,
269 onChange: (value) => setAttributes({
270 per_page: value !== void 0 && value !== null ? value : 10
271 }),
272 min: 1,
273 max: 50
274 }
275 ),
276 /* @__PURE__ */ element.createElement(
277 components.RangeControl,
278 {
279 label: i18n.__("Columns", "yatra"),
280 value: attributes2.columns,
281 onChange: (value) => setAttributes({
282 columns: value !== void 0 && value !== null ? value : 3
283 }),
284 min: 1,
285 max: 6
286 }
287 ),
288 /* @__PURE__ */ element.createElement(
289 components.ToggleControl,
290 {
291 label: i18n.__("Show pagination", "yatra"),
292 checked: attributes2.show_pagination,
293 onChange: (value) => setAttributes({ show_pagination: value })
294 }
295 ),
296 /* @__PURE__ */ element.createElement(
297 ClassificationMultiSelect,
298 {
299 taxonomy: "destination",
300 label: i18n.__("Destinations to show", "yatra"),
301 help: i18n.__(
302 'Pick "All published" for the full catalog; otherwise search and tick specific destinations.',
303 "yatra"
304 ),
305 value: destinationIds,
306 onChange: (ids) => setAttributes({ destinationIds: ids })
307 }
308 )
309 ), /* @__PURE__ */ element.createElement(components.PanelBody, { title: i18n.__("Display options", "yatra"), initialOpen: false }, /* @__PURE__ */ element.createElement(
310 components.ToggleControl,
311 {
312 label: i18n.__("Show trip count", "yatra"),
313 checked: attributes2.show_trip_count,
314 onChange: (value) => setAttributes({ show_trip_count: value })
315 }
316 ), /* @__PURE__ */ element.createElement(
317 components.ToggleControl,
318 {
319 label: i18n.__("Show description", "yatra"),
320 checked: attributes2.show_description,
321 onChange: (value) => setAttributes({ show_description: value })
322 }
323 ), /* @__PURE__ */ element.createElement(
324 components.ToggleControl,
325 {
326 label: i18n.__("Show image", "yatra"),
327 checked: attributes2.show_image,
328 onChange: (value) => setAttributes({ show_image: value })
329 }
330 ), /* @__PURE__ */ element.createElement(
331 components.ToggleControl,
332 {
333 label: i18n.__("Hide empty destinations", "yatra"),
334 help: i18n.__(
335 "Skip destinations that have no published trips assigned. Off by default — turn on for a tighter live catalog, leave off for editorial / onboarding views.",
336 "yatra"
337 ),
338 checked: attributes2.hide_empty,
339 onChange: (value) => setAttributes({ hide_empty: value })
340 }
341 ), /* @__PURE__ */ element.createElement(
342 components.ToggleControl,
343 {
344 label: i18n.__("Featured only (filter list)", "yatra"),
345 help: i18n.__(
346 "When on, only destinations marked as featured in Yatra → Destinations are listed.",
347 "yatra"
348 ),
349 checked: attributes2.featured_only,
350 onChange: (value) => setAttributes({ featured_only: value })
351 }
352 ))), /* @__PURE__ */ element.createElement("div", { className: "yatra-block-editor-preview" }, /* @__PURE__ */ element.createElement(
353 ServerSideRender,
354 {
355 block: "yatra/destination",
356 attributes: attributes2,
357 key: JSON.stringify(attributes2)
358 }
359 )));
360 }
361 const $schema = "https://schemas.wp.org/trunk/block.json";
362 const apiVersion = 3;
363 const name = "yatra/destination";
364 const title = "Destination";
365 const category = "yatra";
366 const icon = "location-alt";
367 const description = "Display destination listings with customizable options";
368 const keywords = [
369 "destination",
370 "place",
371 "location",
372 "yatra"
373 ];
374 const textdomain = "yatra";
375 const attributes = {
376 order: {
377 type: "string",
378 "default": "asc"
379 },
380 columns: {
381 type: "number",
382 "default": 3
383 },
384 per_page: {
385 type: "number",
386 "default": 10
387 },
388 title: {
389 type: "string",
390 "default": "Destination Showcase"
391 },
392 show_pagination: {
393 type: "boolean",
394 "default": true
395 },
396 destinationIds: {
397 type: "array",
398 "default": []
399 },
400 hide_empty: {
401 type: "boolean",
402 "default": false,
403 description: "When on, destinations with zero published trips are skipped. Off by default to preserve the historical 'show everything' behavior."
404 },
405 featured_only: {
406 type: "boolean",
407 "default": false
408 },
409 show_trip_count: {
410 type: "boolean",
411 "default": true
412 },
413 show_description: {
414 type: "boolean",
415 "default": true
416 },
417 show_image: {
418 type: "boolean",
419 "default": true
420 }
421 };
422 const supports = {
423 html: false,
424 inserter: true,
425 align: [
426 "wide",
427 "full"
428 ]
429 };
430 const editorScript = "yatra-destination-block-editor";
431 const blockMetadata = {
432 $schema,
433 apiVersion,
434 name,
435 title,
436 category,
437 icon,
438 description,
439 keywords,
440 textdomain,
441 attributes,
442 supports,
443 editorScript
444 };
445 const {
446 $schema: _$schema,
447 editorScript: _$editorScript,
448 ...metadata
449 } = blockMetadata;
450 if (blocks.getBlockType(metadata.name)) {
451 blocks.unregisterBlockType(metadata.name);
452 }
453 blocks.registerBlockType(metadata.name, {
454 ...metadata,
455 edit: Edit,
456 save: () => null
457 });
458 })(wp.element, wp.blocks, wp.blockEditor, wp.components, wp.i18n, wp.serverSideRender, wp.apiFetch);
459 //# sourceMappingURL=destination.js.map
460