limbo-component 1.5.2 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/limbo.es.js CHANGED
@@ -32555,15 +32555,65 @@ function useStockServices(prod = false) {
32555
32555
  return { services, loading, error, invalidateCache };
32556
32556
  }
32557
32557
  function TabStock({ prod, disabled, onSelected }) {
32558
+ const lastSearchPayloadRef = React.useRef(null);
32558
32559
  const stockServicesHook = useStockServices(prod);
32560
+ const loadSavedState = (key, defaultValue) => {
32561
+ try {
32562
+ const saved = sessionStorage.getItem(`limbo_stock_${key}`);
32563
+ return saved ? JSON.parse(saved) : defaultValue;
32564
+ } catch {
32565
+ return defaultValue;
32566
+ }
32567
+ };
32568
+ const [selectedService, setSelectedService] = useState(
32569
+ () => loadSavedState("selectedService", "")
32570
+ );
32571
+ const [dynamicForm, setDynamicForm] = useState(
32572
+ () => loadSavedState("dynamicForm", {})
32573
+ );
32574
+ const [stockImages, setStockImages] = useState(
32575
+ () => loadSavedState("stockImages", [])
32576
+ );
32577
+ const [currentPage, setCurrentPage] = useState(
32578
+ () => loadSavedState("currentPage", 1)
32579
+ );
32580
+ const [paginationInfo, setPaginationInfo] = useState(
32581
+ () => loadSavedState("paginationInfo", null)
32582
+ );
32559
32583
  const imageParamsHook = useImageParams(prod);
32560
- const [selectedService, setSelectedService] = useState("");
32561
- const [dynamicForm, setDynamicForm] = useState({});
32562
32584
  const [stockLoading, setStockLoading] = useState(false);
32563
32585
  const [stockError, setStockError] = useState(null);
32564
- const [stockImages, setStockImages] = useState([]);
32565
- const [currentPage, setCurrentPage] = useState(1);
32566
32586
  const [downloadingId, setDownloadingId] = useState(null);
32587
+ React.useEffect(() => {
32588
+ sessionStorage.setItem(
32589
+ "limbo_stock_selectedService",
32590
+ JSON.stringify(selectedService)
32591
+ );
32592
+ }, [selectedService]);
32593
+ React.useEffect(() => {
32594
+ sessionStorage.setItem(
32595
+ "limbo_stock_dynamicForm",
32596
+ JSON.stringify(dynamicForm)
32597
+ );
32598
+ }, [dynamicForm]);
32599
+ React.useEffect(() => {
32600
+ sessionStorage.setItem(
32601
+ "limbo_stock_stockImages",
32602
+ JSON.stringify(stockImages)
32603
+ );
32604
+ }, [stockImages]);
32605
+ React.useEffect(() => {
32606
+ sessionStorage.setItem(
32607
+ "limbo_stock_currentPage",
32608
+ JSON.stringify(currentPage)
32609
+ );
32610
+ }, [currentPage]);
32611
+ React.useEffect(() => {
32612
+ sessionStorage.setItem(
32613
+ "limbo_stock_paginationInfo",
32614
+ JSON.stringify(paginationInfo)
32615
+ );
32616
+ }, [paginationInfo]);
32567
32617
  const serviceLabels = {
32568
32618
  shutterstock: "Shutterstock",
32569
32619
  freepikstock: "Freepik"
@@ -32608,23 +32658,60 @@ function TabStock({ prod, disabled, onSelected }) {
32608
32658
  setStockError(null);
32609
32659
  if (page === 1) setStockImages([]);
32610
32660
  try {
32611
- const params = imageParamsHook.params?.[selectedService]?.parameters;
32612
- const formData = { ...dynamicForm };
32613
- Object.entries(params || {}).forEach(([key, cfg]) => {
32614
- if (!(key in formData)) formData[key] = cfg.default ?? "";
32615
- });
32616
- formData.service = selectedService;
32617
- formData.page = page;
32618
- const data = await searchStockImages(formData, prod);
32619
- const result = data?.result?.data || [];
32620
- setStockImages(Array.isArray(result) ? result : []);
32621
- setCurrentPage(page);
32661
+ let payload;
32662
+ if (page === 1) {
32663
+ const params = imageParamsHook.params?.[selectedService]?.parameters;
32664
+ const formData = { ...dynamicForm };
32665
+ Object.entries(params || {}).forEach(([key, cfg]) => {
32666
+ if (!(key in formData)) formData[key] = cfg.default ?? "";
32667
+ });
32668
+ formData.per_page = parseInt(formData.per_page);
32669
+ formData.service = selectedService;
32670
+ formData.page = page;
32671
+ payload = formData;
32672
+ lastSearchPayloadRef.current = { ...formData };
32673
+ } else {
32674
+ payload = { ...lastSearchPayloadRef.current, page };
32675
+ }
32676
+ const data = await searchStockImages(payload, prod);
32677
+ const result = data?.data?.images || [];
32678
+ let paginationRaw = data?.data?.pagination || null;
32679
+ let pagination = null;
32680
+ if (paginationRaw) {
32681
+ pagination = {
32682
+ total: paginationRaw.total_count ?? paginationRaw.total ?? result.length,
32683
+ per_page: paginationRaw.per_page ?? (Array.isArray(result) ? result.length : 0),
32684
+ current_page: paginationRaw.page ?? paginationRaw.current_page ?? page
32685
+ };
32686
+ }
32687
+ setStockImages(normalizeImages(Array.isArray(result) ? result : []));
32688
+ setPaginationInfo(pagination);
32689
+ setCurrentPage(pagination?.current_page || page);
32622
32690
  } catch (err) {
32623
32691
  setStockError(err.message || "Error al buscar imágenes");
32624
32692
  } finally {
32625
32693
  setStockLoading(false);
32626
32694
  }
32627
32695
  };
32696
+ const normalizeImages = (imagesRaw) => {
32697
+ const seenUrls = /* @__PURE__ */ new Set();
32698
+ const allImages = [];
32699
+ (imagesRaw || []).forEach((img, idx) => {
32700
+ const imageUrl = img.url || img.preview_url || img.full || img.preview;
32701
+ if (!imageUrl || seenUrls.has(imageUrl)) return;
32702
+ seenUrls.add(imageUrl);
32703
+ allImages.push({
32704
+ ...img,
32705
+ preview: img.preview_url || img.preview || img.url || img.full,
32706
+ full: img.url || img.full || img.preview_url,
32707
+ id: img.id || idx,
32708
+ title: img.title || img.filename || `Imagen ${idx + 1}`,
32709
+ source: img.service || selectedService,
32710
+ sourceTitle: serviceLabels?.[selectedService] || selectedService
32711
+ });
32712
+ });
32713
+ return allImages;
32714
+ };
32628
32715
  const handleDynamicFormSubmit = async (e) => {
32629
32716
  e.preventDefault();
32630
32717
  const query = dynamicForm.query || dynamicForm.search || dynamicForm.term || "";
@@ -32670,8 +32757,20 @@ function TabStock({ prod, disabled, onSelected }) {
32670
32757
  const renderDynamicForm = () => {
32671
32758
  const params = imageParamsHook.params?.[selectedService]?.parameters;
32672
32759
  if (!params) return null;
32673
- const visibleFields = Object.entries(params).filter(([_, config]) => !config.disabled);
32760
+ const visibleFields = Object.entries(params).filter(
32761
+ ([, config]) => !config.disabled
32762
+ );
32674
32763
  const useGridLayout = visibleFields.length > 3;
32764
+ const handleMultiCheckboxChange = (key, value) => {
32765
+ setDynamicForm((prev) => {
32766
+ const arr = Array.isArray(prev[key]) ? prev[key] : [];
32767
+ if (arr.includes(value)) {
32768
+ return { ...prev, [key]: arr.filter((v) => v !== value) };
32769
+ } else {
32770
+ return { ...prev, [key]: [...arr, value] };
32771
+ }
32772
+ });
32773
+ };
32675
32774
  return /* @__PURE__ */ jsxs(
32676
32775
  "form",
32677
32776
  {
@@ -32680,60 +32779,79 @@ function TabStock({ prod, disabled, onSelected }) {
32680
32779
  className: "flex flex-col gap-3 mt-4 border-t-1 pt-4 border-brand-blue-200",
32681
32780
  "aria-label": "Formulario búsqueda de imágenes de Stock",
32682
32781
  children: [
32683
- /* @__PURE__ */ jsx("div", { className: useGridLayout ? "grid grid-cols-1 md:grid-cols-2 gap-3" : "flex flex-col gap-3", children: visibleFields.map(([key, config]) => {
32684
- let placeholder = config.placeholder || "";
32685
- if (!placeholder) {
32686
- if (config.type === "integer") {
32687
- placeholder = config.minValue && config.maxValue ? `Entre ${config.minValue} y ${config.maxValue}` : config.minValue ? `Mínimo ${config.minValue}` : config.maxValue ? `Máximo ${config.maxValue}` : "Introduce un número";
32688
- } else if (key.toLowerCase().includes("query") || key.toLowerCase().includes("search") || key.toLowerCase().includes("term")) {
32689
- placeholder = "Buscar imágenes...";
32690
- } else {
32691
- placeholder = `Introduce ${(config.label || key).toLowerCase()}`;
32692
- }
32693
- }
32694
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
32695
- /* @__PURE__ */ jsxs(
32696
- "label",
32697
- {
32698
- htmlFor: `stock-${key}`,
32699
- className: "text-xs font-medium text-brand-blue-900",
32700
- children: [
32701
- config.label || key,
32702
- config.required && /* @__PURE__ */ jsx("span", { className: "text-red-600 ml-1", children: "*" })
32703
- ]
32704
- }
32705
- ),
32706
- config.options ? /* @__PURE__ */ jsx(
32707
- "select",
32708
- {
32709
- id: `stock-${key}`,
32710
- name: key,
32711
- value: dynamicForm[key] ?? "",
32712
- onChange: handleDynamicFormChange,
32713
- className: "limbo-input",
32714
- disabled,
32715
- title: config.label || key,
32716
- children: config.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt, children: opt }, opt))
32717
- }
32718
- ) : /* @__PURE__ */ jsx(
32719
- "input",
32720
- {
32721
- id: `stock-${key}`,
32722
- type: config.type === "integer" ? "number" : "text",
32723
- name: key,
32724
- value: dynamicForm[key] ?? "",
32725
- onChange: handleDynamicFormChange,
32726
- className: "limbo-input",
32727
- disabled,
32728
- required: config.required,
32729
- min: config.minValue,
32730
- max: config.maxValue,
32731
- placeholder,
32732
- title: config.label || key
32782
+ /* @__PURE__ */ jsx(
32783
+ "div",
32784
+ {
32785
+ className: useGridLayout ? "grid grid-cols-1 md:grid-cols-2 gap-3" : "flex flex-col gap-3",
32786
+ children: visibleFields.map(([key, config]) => {
32787
+ let placeholder = config.placeholder || "";
32788
+ if (!placeholder) {
32789
+ if (config.type === "integer") {
32790
+ placeholder = config.minValue && config.maxValue ? `Entre ${config.minValue} y ${config.maxValue}` : config.minValue ? `Mínimo ${config.minValue}` : config.maxValue ? `Máximo ${config.maxValue}` : "Introduce un número";
32791
+ } else if (key.toLowerCase().includes("query") || key.toLowerCase().includes("search") || key.toLowerCase().includes("term")) {
32792
+ placeholder = "Buscar imágenes...";
32793
+ } else {
32794
+ placeholder = `Introduce ${(config.label || key).toLowerCase()}`;
32795
+ }
32733
32796
  }
32734
- )
32735
- ] }, key);
32736
- }) }),
32797
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
32798
+ /* @__PURE__ */ jsxs(
32799
+ "label",
32800
+ {
32801
+ htmlFor: `stock-${key}`,
32802
+ className: "text-xs font-medium text-brand-blue-900",
32803
+ children: [
32804
+ config.label || key,
32805
+ config.required && /* @__PURE__ */ jsx("span", { className: "text-red-600 ml-1", children: "*" })
32806
+ ]
32807
+ }
32808
+ ),
32809
+ config.options && config.multiple ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 min-h-[50px] px-2 justify-between border-2 border-gray-transparent-500 rounded-lg", children: config.options.map((opt) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1", children: [
32810
+ /* @__PURE__ */ jsx(
32811
+ "input",
32812
+ {
32813
+ type: "checkbox",
32814
+ name: `stock-${key}`,
32815
+ value: opt,
32816
+ checked: Array.isArray(dynamicForm[key]) && dynamicForm[key].includes(opt),
32817
+ onChange: () => handleMultiCheckboxChange(key, opt),
32818
+ disabled
32819
+ }
32820
+ ),
32821
+ /* @__PURE__ */ jsx("span", { className: "text-xs", children: opt })
32822
+ ] }, opt)) }) : config.options ? /* @__PURE__ */ jsx(
32823
+ "select",
32824
+ {
32825
+ id: `stock-${key}`,
32826
+ name: key,
32827
+ value: dynamicForm[key] ?? "",
32828
+ onChange: handleDynamicFormChange,
32829
+ className: "limbo-input",
32830
+ disabled,
32831
+ title: config.label || key,
32832
+ children: config.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt, children: opt }, opt))
32833
+ }
32834
+ ) : /* @__PURE__ */ jsx(
32835
+ "input",
32836
+ {
32837
+ id: `stock-${key}`,
32838
+ type: config.type === "integer" ? "number" : "text",
32839
+ name: key,
32840
+ value: dynamicForm[key] ?? "",
32841
+ onChange: handleDynamicFormChange,
32842
+ className: "limbo-input",
32843
+ disabled,
32844
+ required: config.required,
32845
+ min: config.minValue,
32846
+ max: config.maxValue,
32847
+ placeholder,
32848
+ title: config.label || key
32849
+ }
32850
+ )
32851
+ ] }, key);
32852
+ })
32853
+ }
32854
+ ),
32737
32855
  /* @__PURE__ */ jsx(
32738
32856
  "button",
32739
32857
  {
@@ -32778,74 +32896,93 @@ function TabStock({ prod, disabled, onSelected }) {
32778
32896
  selectedService && renderDynamicForm(),
32779
32897
  stockError && /* @__PURE__ */ jsx("div", { className: "alert alert-danger", children: stockError }),
32780
32898
  stockImages.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
32781
- /* @__PURE__ */ jsx(
32899
+ /* @__PURE__ */ jsxs(
32782
32900
  "div",
32783
32901
  {
32784
- className: "mt-6 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4",
32902
+ className: "mt-6 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 relative",
32785
32903
  "aria-live": "polite",
32786
- children: stockImages.map((img, idx) => /* @__PURE__ */ jsxs(
32787
- "div",
32788
- {
32789
- className: "border border-brand-blue-200 rounded-lg overflow-hidden bg-white shadow-sm hover:shadow-md transition-shadow",
32790
- children: [
32791
- /* @__PURE__ */ jsxs("div", { className: "relative aspect-video bg-neutral-100", children: [
32792
- /* @__PURE__ */ jsx(
32793
- "img",
32904
+ children: [
32905
+ stockLoading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-white/80 z-10 flex items-center justify-center rounded-lg", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
32906
+ /* @__PURE__ */ jsx("span", { className: "limbo-loader" }),
32907
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-brand-blue-800", children: "Buscando imágenes..." })
32908
+ ] }) }),
32909
+ stockImages.map((img, idx) => /* @__PURE__ */ jsxs(
32910
+ "div",
32911
+ {
32912
+ className: "border border-brand-blue-200 rounded-lg overflow-hidden bg-white shadow-sm hover:shadow-md transition-shadow",
32913
+ children: [
32914
+ /* @__PURE__ */ jsxs("div", { className: "relative aspect-video bg-neutral-100", children: [
32915
+ /* @__PURE__ */ jsx(
32916
+ "img",
32917
+ {
32918
+ src: img.preview || img.thumbnail || img.url,
32919
+ alt: img.title || `Resultado ${idx + 1}`,
32920
+ className: "object-cover w-full h-full",
32921
+ loading: "lazy"
32922
+ }
32923
+ ),
32924
+ img.id && /* @__PURE__ */ jsxs("span", { className: "absolute bottom-1 right-1 bg-black/60 text-white text-xs px-2 py-1 rounded", children: [
32925
+ "ID: ",
32926
+ img.id
32927
+ ] })
32928
+ ] }),
32929
+ /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
32930
+ "button",
32794
32931
  {
32795
- src: img.preview || img.thumbnail || img.url,
32796
- alt: img.title || `Resultado ${idx + 1}`,
32797
- className: "object-cover w-full h-full",
32798
- loading: "lazy"
32932
+ className: `limbo-btn w-full text-sm ${downloadingId === img.id ? "limbo-btn-disabled cursor-not-allowed" : "limbo-btn-primary"}`,
32933
+ onClick: () => handleImageSelect(img),
32934
+ disabled: stockLoading || disabled || downloadingId === img.id,
32935
+ children: downloadingId === img.id ? /* @__PURE__ */ jsxs(Fragment, { children: [
32936
+ /* @__PURE__ */ jsx("span", { className: "limbo-loader limbo-loader--sm mr-1" }),
32937
+ "Descargando..."
32938
+ ] }) : "Seleccionar"
32799
32939
  }
32800
- ),
32801
- img.id && /* @__PURE__ */ jsxs("span", { className: "absolute bottom-1 right-1 bg-black/60 text-white text-xs px-2 py-1 rounded", children: [
32802
- "ID: ",
32803
- img.id
32804
- ] })
32805
- ] }),
32806
- /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
32807
- "button",
32808
- {
32809
- className: `limbo-btn w-full text-sm ${downloadingId === img.id ? "limbo-btn-disabled cursor-not-allowed" : "limbo-btn-primary"}`,
32810
- onClick: () => handleImageSelect(img),
32811
- disabled: stockLoading || disabled || downloadingId === img.id,
32812
- children: downloadingId === img.id ? /* @__PURE__ */ jsxs(Fragment, { children: [
32813
- /* @__PURE__ */ jsx("span", { className: "limbo-loader limbo-loader--sm mr-1" }),
32814
- "Descargando..."
32815
- ] }) : "Seleccionar"
32816
- }
32817
- ) })
32818
- ]
32819
- },
32820
- img.id || idx
32821
- ))
32940
+ ) })
32941
+ ]
32942
+ },
32943
+ img.id || idx
32944
+ ))
32945
+ ]
32822
32946
  }
32823
32947
  ),
32824
- /* @__PURE__ */ jsxs("div", { className: "mt-6 flex items-center justify-center gap-2", children: [
32948
+ paginationInfo && /* @__PURE__ */ jsxs("div", { className: "mt-6 flex items-center justify-center gap-2", children: [
32825
32949
  /* @__PURE__ */ jsxs(
32826
32950
  "button",
32827
32951
  {
32828
- onClick: () => handlePageChange(currentPage - 1),
32829
- disabled: currentPage === 1 || stockLoading,
32830
- className: "limbo-btn limbo-btn-secondary px-4 py-2 disabled:opacity-50",
32952
+ onClick: () => handlePageChange(paginationInfo.current_page - 1),
32953
+ disabled: paginationInfo.current_page <= 1 || stockLoading,
32954
+ className: "limbo-btn limbo-btn-secondary px-4 py-2 disabled:opacity-25" + (paginationInfo.current_page <= 1 || stockLoading ? " pointer-events-none cursor-default" : " limbo-btn-primary"),
32831
32955
  children: [
32832
32956
  /* @__PURE__ */ jsx("span", { className: "icon icon-arrow-left-white icon--sm" }),
32833
- " Anterior"
32957
+ " ",
32958
+ "Anterior"
32834
32959
  ]
32835
32960
  }
32836
32961
  ),
32837
32962
  /* @__PURE__ */ jsxs("span", { className: "px-4 py-2 text-sm text-neutral-700", children: [
32838
32963
  "Página ",
32839
- currentPage
32964
+ paginationInfo.current_page,
32965
+ " de",
32966
+ " ",
32967
+ Math.max(
32968
+ 1,
32969
+ Math.ceil(paginationInfo.total / paginationInfo.per_page)
32970
+ ),
32971
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-neutral-500 block", children: [
32972
+ "(",
32973
+ paginationInfo.total,
32974
+ " imágenes totales)"
32975
+ ] })
32840
32976
  ] }),
32841
32977
  /* @__PURE__ */ jsxs(
32842
32978
  "button",
32843
32979
  {
32844
- onClick: () => handlePageChange(currentPage + 1),
32845
- disabled: stockLoading || stockImages.length === 0,
32846
- className: "limbo-btn limbo-btn-secondary px-4 py-2 disabled:opacity-50",
32980
+ onClick: () => handlePageChange(paginationInfo.current_page + 1),
32981
+ disabled: stockLoading || paginationInfo.current_page >= Math.ceil(paginationInfo.total / paginationInfo.per_page),
32982
+ className: "limbo-btn limbo-btn-secondary px-4 py-2 disabled:opacity-25" + (stockLoading || paginationInfo.current_page >= Math.ceil(paginationInfo.total / paginationInfo.per_page) ? " pointer-events-none cursor-default" : " limbo-btn-primary"),
32847
32983
  children: [
32848
- "Siguiente ",
32984
+ "Siguiente",
32985
+ " ",
32849
32986
  /* @__PURE__ */ jsx("span", { className: "icon icon-arrow-right-white icon--sm" })
32850
32987
  ]
32851
32988
  }
@@ -32948,6 +33085,7 @@ const ValidatedImage = ({ src, alt, className, onError }) => {
32948
33085
  );
32949
33086
  };
32950
33087
  function TabPortals({ prod, disabled, onSelected }) {
33088
+ const lastSearchPayloadRef = React.useRef(null);
32951
33089
  const portalSourcesHook = usePortalSources(prod);
32952
33090
  const loadSavedState = (key, defaultValue) => {
32953
33091
  try {
@@ -32957,38 +33095,63 @@ function TabPortals({ prod, disabled, onSelected }) {
32957
33095
  return defaultValue;
32958
33096
  }
32959
33097
  };
32960
- const [selectedPortals, setSelectedPortals] = useState(() => loadSavedState("selectedPortals", []));
32961
- const [searchName, setSearchName] = useState(() => loadSavedState("searchName", ""));
33098
+ const [selectedPortals, setSelectedPortals] = useState(
33099
+ () => loadSavedState("selectedPortals", [])
33100
+ );
33101
+ const [searchName, setSearchName] = useState(
33102
+ () => loadSavedState("searchName", "")
33103
+ );
32962
33104
  const [limit, setLimit] = useState(() => loadSavedState("limit", 20));
32963
- const [currentPage, setCurrentPage] = useState(() => loadSavedState("currentPage", 1));
33105
+ const [currentPage, setCurrentPage] = useState(
33106
+ () => loadSavedState("currentPage", 1)
33107
+ );
32964
33108
  const [loading, setLoading] = useState(false);
32965
33109
  const [error, setError] = useState(null);
32966
33110
  const [images, setImages] = useState(() => loadSavedState("images", []));
32967
- const [portalResults, setPortalResults] = useState(() => loadSavedState("portalResults", {}));
32968
- const [paginationInfo, setPaginationInfo] = useState(() => loadSavedState("paginationInfo", null));
33111
+ const [portalResults, setPortalResults] = useState(
33112
+ () => loadSavedState("portalResults", {})
33113
+ );
33114
+ const [paginationInfo, setPaginationInfo] = useState(
33115
+ () => loadSavedState("paginationInfo", null)
33116
+ );
32969
33117
  const [downloadingUrl, setDownloadingUrl] = useState(null);
32970
33118
  const searchCacheRef = useRef({});
32971
33119
  const [failedImages, setFailedImages] = useState(/* @__PURE__ */ new Set());
32972
33120
  React.useEffect(() => {
32973
- sessionStorage.setItem("limbo_portals_selectedPortals", JSON.stringify(selectedPortals));
33121
+ sessionStorage.setItem(
33122
+ "limbo_portals_selectedPortals",
33123
+ JSON.stringify(selectedPortals)
33124
+ );
32974
33125
  }, [selectedPortals]);
32975
33126
  React.useEffect(() => {
32976
- sessionStorage.setItem("limbo_portals_searchName", JSON.stringify(searchName));
33127
+ sessionStorage.setItem(
33128
+ "limbo_portals_searchName",
33129
+ JSON.stringify(searchName)
33130
+ );
32977
33131
  }, [searchName]);
32978
33132
  React.useEffect(() => {
32979
33133
  sessionStorage.setItem("limbo_portals_limit", JSON.stringify(limit));
32980
33134
  }, [limit]);
32981
33135
  React.useEffect(() => {
32982
- sessionStorage.setItem("limbo_portals_currentPage", JSON.stringify(currentPage));
33136
+ sessionStorage.setItem(
33137
+ "limbo_portals_currentPage",
33138
+ JSON.stringify(currentPage)
33139
+ );
32983
33140
  }, [currentPage]);
32984
33141
  React.useEffect(() => {
32985
33142
  sessionStorage.setItem("limbo_portals_images", JSON.stringify(images));
32986
33143
  }, [images]);
32987
33144
  React.useEffect(() => {
32988
- sessionStorage.setItem("limbo_portals_portalResults", JSON.stringify(portalResults));
33145
+ sessionStorage.setItem(
33146
+ "limbo_portals_portalResults",
33147
+ JSON.stringify(portalResults)
33148
+ );
32989
33149
  }, [portalResults]);
32990
33150
  React.useEffect(() => {
32991
- sessionStorage.setItem("limbo_portals_paginationInfo", JSON.stringify(paginationInfo));
33151
+ sessionStorage.setItem(
33152
+ "limbo_portals_paginationInfo",
33153
+ JSON.stringify(paginationInfo)
33154
+ );
32992
33155
  }, [paginationInfo]);
32993
33156
  const getCacheKey = (portals, name, limitVal, page) => {
32994
33157
  return `${portals.sort().join(",")}_${name}_${limitVal}_${page}`;
@@ -33033,14 +33196,19 @@ function TabPortals({ prod, disabled, onSelected }) {
33033
33196
  setPaginationInfo(null);
33034
33197
  }
33035
33198
  try {
33036
- const params = {
33037
- sources: selectedPortals,
33038
- // Ya son strings de IDs
33039
- limit,
33040
- page,
33041
- name: searchName.trim()
33042
- };
33043
- const data = await getExternalImages(params, prod);
33199
+ let payload;
33200
+ if (page === 1) {
33201
+ payload = {
33202
+ sources: selectedPortals,
33203
+ limit,
33204
+ page,
33205
+ name: searchName.trim()
33206
+ };
33207
+ lastSearchPayloadRef.current = { ...payload };
33208
+ } else {
33209
+ payload = { ...lastSearchPayloadRef.current, page };
33210
+ }
33211
+ const data = await getExternalImages(payload, prod);
33044
33212
  const sources = data?.data?.sources || {};
33045
33213
  const allImages = [];
33046
33214
  const newPortalResults = {};
@@ -33110,7 +33278,9 @@ function TabPortals({ prod, disabled, onSelected }) {
33110
33278
  throw new Error("No se encontró URL de la imagen");
33111
33279
  }
33112
33280
  const apiBaseUrl = getBaseUrl({ prod });
33113
- const proxyUrl = `${apiBaseUrl}/api/atenea/proxy?url=${encodeURIComponent(imageUrl)}`;
33281
+ const proxyUrl = `${apiBaseUrl}/api/atenea/proxy?url=${encodeURIComponent(
33282
+ imageUrl
33283
+ )}`;
33114
33284
  const response = await fetch(proxyUrl);
33115
33285
  if (!response.ok) {
33116
33286
  throw new Error(`Error al descargar: ${response.status}`);
@@ -33344,7 +33514,7 @@ function TabPortals({ prod, disabled, onSelected }) {
33344
33514
  {
33345
33515
  onClick: () => handlePageChange(currentPage - 1),
33346
33516
  disabled: currentPage === 1 || loading,
33347
- className: "limbo-btn limbo-btn-secondary px-4 py-2 disabled:opacity-50" + (currentPage === 1 || loading ? " pointer-events-none cursor-default" : " limbo-btn-primary"),
33517
+ className: "limbo-btn limbo-btn-secondary px-4 py-2 disabled:opacity-25" + (currentPage === 1 || loading ? " pointer-events-none cursor-default" : " limbo-btn-primary"),
33348
33518
  children: [
33349
33519
  /* @__PURE__ */ jsx("span", { className: "icon icon-arrow-left-white icon--sm" }),
33350
33520
  " ",
@@ -33371,7 +33541,7 @@ function TabPortals({ prod, disabled, onSelected }) {
33371
33541
  {
33372
33542
  onClick: () => handlePageChange(currentPage + 1),
33373
33543
  disabled: loading || paginationInfo && currentPage >= paginationInfo.pages,
33374
- className: "limbo-btn limbo-btn-secondary px-4 py-2 disabled:opacity-50" + (loading || paginationInfo && currentPage >= paginationInfo.pages ? " pointer-events-none cursor-default" : " limbo-btn-primary"),
33544
+ className: "limbo-btn limbo-btn-secondary px-4 py-2 disabled:opacity-25" + (loading || paginationInfo && currentPage >= paginationInfo.pages ? " pointer-events-none cursor-default" : " limbo-btn-primary"),
33375
33545
  children: [
33376
33546
  "Siguiente",
33377
33547
  " ",
@@ -38167,6 +38337,17 @@ function App({
38167
38337
  itemsPerPage = 10
38168
38338
  // Número de elementos por página
38169
38339
  }) {
38340
+ sessionStorage.removeItem("limbo_stock_selectedService");
38341
+ sessionStorage.removeItem("limbo_stock_dynamicForm");
38342
+ sessionStorage.removeItem("limbo_stock_stockImages");
38343
+ sessionStorage.removeItem("limbo_stock_currentPage");
38344
+ sessionStorage.removeItem("limbo_stock_paginationInfo");
38345
+ sessionStorage.removeItem("limbo_portals_searchName");
38346
+ sessionStorage.removeItem("limbo_portals_limit");
38347
+ sessionStorage.removeItem("limbo_portals_currentPage");
38348
+ sessionStorage.removeItem("limbo_portals_images");
38349
+ sessionStorage.removeItem("limbo_portals_portalResults");
38350
+ sessionStorage.removeItem("limbo_portals_paginationInfo");
38170
38351
  const getFilteredFeatures = () => {
38171
38352
  switch (modeUI) {
38172
38353
  case "gallery-only":
@@ -38193,10 +38374,7 @@ function App({
38193
38374
  const [activeTab, setActiveTab] = useState(getInitialTab());
38194
38375
  const [selectedImage, setSelectedImage] = useState(null);
38195
38376
  const [currentPage, setCurrentPage] = useState(1);
38196
- const {
38197
- isTokenExpired,
38198
- handleTokenExpiredClose
38199
- } = useTokenExpiration();
38377
+ const { isTokenExpired, handleTokenExpiredClose } = useTokenExpiration();
38200
38378
  const handlePageChange = (newPage) => {
38201
38379
  setCurrentPage(newPage);
38202
38380
  };
@@ -38240,7 +38418,9 @@ function App({
38240
38418
  feature: "cropper"
38241
38419
  }
38242
38420
  ];
38243
- const tabs = availableTabs.filter((tab) => activeFeatures.includes(tab.feature));
38421
+ const tabs = availableTabs.filter(
38422
+ (tab) => activeFeatures.includes(tab.feature)
38423
+ );
38244
38424
  const handleUpload = async (file) => {
38245
38425
  const result = await upload(file);
38246
38426
  if (result) {
@@ -41705,9 +41885,7 @@ if (typeof window !== "undefined" && document.querySelector("#root")) {
41705
41885
  Limbo.configure({
41706
41886
  prod: false,
41707
41887
  publicKey: PUBLIC_KEY,
41708
- authMode: "session",
41709
- tokenEndpoint: "/auth/token"
41710
- // Endpoint que acepta solo public_key
41888
+ authMode: "session"
41711
41889
  });
41712
41890
  Limbo.create({
41713
41891
  container: "#root",