PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.17
Yatra – Travel Booking & Tour Operator Software v3.0.17
3.0.17 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 All 85 releases
← All changes | assets/dist/blocks/tripcategory.js +288 -61 3.0.3 → 3.0.17 View file →
@@ -1,7 +1,240 @@
1 -(function(element, blocks, blockEditor, components, i18n, ServerSideRender) {
1 +(function(element, blocks, blockEditor, components, i18n, ServerSideRender, apiFetch) {
2 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 + }
3 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]);
4 237 const {
5 238 order,
6 239 columns,
7 240 per_page,
@@ -6,9 +239,8 @@
6 239 columns,
7 240 per_page,
8 241 title: title2,
9 242 show_pagination,
10 - category: category2,
11 243 show_trip_count,
12 244 show_description,
13 245 show_image,
14 246 hide_empty,
@@ -13,8 +245,9 @@
13 245 show_image,
14 246 hide_empty,
15 247 featured_only
16 248 } = attributes2;
249 + const categoryIds = normalizeIds(attributes2.categoryIds);
17 250 return /* @__PURE__ */ element.createElement(element.Fragment, null, /* @__PURE__ */ element.createElement(blockEditor.InspectorControls, null, /* @__PURE__ */ element.createElement(
18 251 components.PanelBody,
19 252 {
20 253 title: i18n.__("Trip category settings", "yatra"),
@@ -28,17 +261,18 @@
28 261 onChange: (value) => setAttributes({ title: value })
29 262 }
30 263 ),
31 264 /* @__PURE__ */ element.createElement(
32 - components.TextControl,
265 + ClassificationMultiSelect,
33 266 {
34 - label: i18n.__("Categories (slugs)", "yatra"),
267 + taxonomy: "trip_category",
268 + label: i18n.__("Trip categories to show", "yatra"),
35 269 help: i18n.__(
36 - "Optional. One slug or comma-separated slugs (same as the [yatra_trip_category] category attribute). Leave empty to list all categories.",
270 + "All published lists every category; narrow with search and checkboxes. Yatra trip types only.",
37 271 "yatra"
38 272 ),
39 - value: category2,
40 - onChange: (value) => setAttributes({ category: value })
273 + value: categoryIds,
274 + onChange: (ids) => setAttributes({ categoryIds: ids })
41 275 }
42 276 ),
43 277 /* @__PURE__ */ element.createElement(
44 278 components.SelectControl,
@@ -83,59 +317,52 @@
83 317 checked: show_pagination,
84 318 onChange: (value) => setAttributes({ show_pagination: value })
85 319 }
86 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 + }
87 328 ), /* @__PURE__ */ element.createElement(
88 - components.PanelBody,
329 + components.ToggleControl,
89 330 {
90 - title: i18n.__("Display options", "yatra"),
91 - initialOpen: false
92 - },
93 - /* @__PURE__ */ element.createElement(
94 - components.ToggleControl,
95 - {
96 - label: i18n.__("Show trip count", "yatra"),
97 - checked: show_trip_count,
98 - onChange: (value) => setAttributes({ show_trip_count: value })
99 - }
100 - ),
101 - /* @__PURE__ */ element.createElement(
102 - components.ToggleControl,
103 - {
104 - label: i18n.__("Show description", "yatra"),
105 - checked: show_description,
106 - onChange: (value) => setAttributes({ show_description: value })
107 - }
108 - ),
109 - /* @__PURE__ */ element.createElement(
110 - components.ToggleControl,
111 - {
112 - label: i18n.__("Show image", "yatra"),
113 - checked: show_image,
114 - onChange: (value) => setAttributes({ show_image: value })
115 - }
116 - ),
117 - /* @__PURE__ */ element.createElement(
118 - components.ToggleControl,
119 - {
120 - label: i18n.__("Hide empty categories", "yatra"),
121 - checked: hide_empty,
122 - onChange: (value) => setAttributes({ hide_empty: value })
123 - }
124 - ),
125 - /* @__PURE__ */ element.createElement(
126 - components.ToggleControl,
127 - {
128 - label: i18n.__("Featured only (filter list)", "yatra"),
129 - help: i18n.__(
130 - "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.",
131 - "yatra"
132 - ),
133 - checked: featured_only,
134 - onChange: (value) => setAttributes({ featured_only: value })
135 - }
136 - )
137 - )), /* @__PURE__ */ element.createElement("div", { className: "yatra-block-editor-preview" }, /* @__PURE__ */ element.createElement(
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(
138 365 ServerSideRender,
139 366 {
140 367 block: "yatra/trip-category",
141 368 attributes: attributes2,
@@ -181,11 +408,11 @@
181 408 show_pagination: {
182 409 type: "boolean",
183 410 "default": true
184 411 },
185 - category: {
186 - type: "string",
187 - "default": ""
412 + categoryIds: {
413 + type: "array",
414 + "default": []
188 415 },
189 416 show_trip_count: {
190 417 type: "boolean",
191 418 "default": true
@@ -199,9 +426,9 @@
199 426 "default": true
200 427 },
201 428 hide_empty: {
202 429 type: "boolean",
203 - "default": true
430 + "default": false
204 431 },
205 432 featured_only: {
206 433 type: "boolean",
207 434 "default": false
@@ -242,6 +469,6 @@
242 469 ...metadata,
243 470 edit: Edit,
244 471 save: () => null
245 472 });
246 -})(wp.element, wp.blocks, wp.blockEditor, wp.components, wp.i18n, wp.serverSideRender);
473 +})(wp.element, wp.blocks, wp.blockEditor, wp.components, wp.i18n, wp.serverSideRender, wp.apiFetch);
247 474 //# sourceMappingURL=tripcategory.js.map