@inploi/plugin-job-search 0.23.0 → 0.23.2

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/index.cjs CHANGED
@@ -1563,7 +1563,7 @@ const getFilterValue = (filterValue) => {
1563
1563
  return null;
1564
1564
  return filterValue;
1565
1565
  };
1566
- const filtersToPayload = (filters) => {
1566
+ const filtersToPayload$1 = (filters) => {
1567
1567
  return Object.fromEntries(
1568
1568
  Object.entries(filters).map(([key, filter]) => {
1569
1569
  return [key, getFilterValue(filter == null ? void 0 : filter.value)];
@@ -1580,7 +1580,7 @@ const getAvailableFilters = async ({
1580
1580
  try {
1581
1581
  const searchParams = new URLSearchParams(
1582
1582
  stringify({
1583
- filters: filtersToPayload(filters),
1583
+ filters: filtersToPayload$1(filters),
1584
1584
  query: keyword
1585
1585
  })
1586
1586
  );
@@ -1609,7 +1609,7 @@ const getJobSearchResults = async ({
1609
1609
  try {
1610
1610
  const searchParams = new URLSearchParams(
1611
1611
  stringify({
1612
- filters: filtersToPayload(filters)
1612
+ filters: filtersToPayload$1(filters)
1613
1613
  })
1614
1614
  );
1615
1615
  searchParams.set("page", page.toString());
@@ -2690,6 +2690,48 @@ const cacheKey = (value) => {
2690
2690
  ).join("&");
2691
2691
  return `${value.baseKey}::${filterString}::${value.keyword ?? ""}`;
2692
2692
  };
2693
+ const useMediaQuery = (query) => {
2694
+ const [matches, setMatches] = h$1(false);
2695
+ y$1(() => {
2696
+ if (typeof window === "undefined")
2697
+ return;
2698
+ const mediaQuery = window.matchMedia(query);
2699
+ const updateMatches = () => setMatches(mediaQuery.matches);
2700
+ updateMatches();
2701
+ mediaQuery.addEventListener("change", updateMatches);
2702
+ return () => mediaQuery.removeEventListener("change", updateMatches);
2703
+ }, [query]);
2704
+ return matches;
2705
+ };
2706
+ const useViewTracking = (elementRef, { minViewTime = 1e3, visibilityThreshold = 0, onView }) => {
2707
+ const [viewed, setViewed] = h$1(false);
2708
+ y$1(() => {
2709
+ if (viewed)
2710
+ return;
2711
+ if (!elementRef.current)
2712
+ return;
2713
+ let timeout;
2714
+ const observer = new IntersectionObserver(
2715
+ (entries) => entries.forEach((entry) => {
2716
+ clearTimeout(timeout);
2717
+ if (entry.isIntersecting) {
2718
+ timeout = setTimeout(() => {
2719
+ setViewed(true);
2720
+ onView();
2721
+ }, minViewTime);
2722
+ }
2723
+ }),
2724
+ {
2725
+ threshold: visibilityThreshold
2726
+ }
2727
+ );
2728
+ observer.observe(elementRef.current);
2729
+ return () => {
2730
+ observer.disconnect();
2731
+ clearTimeout(timeout);
2732
+ };
2733
+ }, [elementRef, minViewTime, visibilityThreshold, onView, viewed]);
2734
+ };
2693
2735
  const jobSearch = "";
2694
2736
  const getFilterValues = (appliedFilters) => {
2695
2737
  const entries = Object.entries(appliedFilters).map(([key, value]) => {
@@ -4246,19 +4288,6 @@ const CurrentValueTag = ({ query, property, selectedValues }) => {
4246
4288
  exhaustive(query);
4247
4289
  }
4248
4290
  };
4249
- const useMediaQuery = (query) => {
4250
- const [matches, setMatches] = h$1(false);
4251
- y$1(() => {
4252
- if (typeof window === "undefined")
4253
- return;
4254
- const mediaQuery = window.matchMedia(query);
4255
- const updateMatches = () => setMatches(mediaQuery.matches);
4256
- updateMatches();
4257
- mediaQuery.addEventListener("change", updateMatches);
4258
- return () => mediaQuery.removeEventListener("change", updateMatches);
4259
- }, [query]);
4260
- return matches;
4261
- };
4262
4291
  const TAG_HEIGHT = 44;
4263
4292
  const LINE_COUNT = 6;
4264
4293
  const SUGGESTIONS_COUNT_THRESHOLD = 12;
@@ -5446,8 +5475,12 @@ const JobCardLogo = ({
5446
5475
  };
5447
5476
  const asArray = (value) => Array.isArray(value) ? value : [value];
5448
5477
  const ONE_DAY_MS = 1e3 * 60 * 60 * 24 * 7;
5449
- const JobCard = ({ job, config }) => {
5450
- var _a, _b, _c, _d;
5478
+ const JobCard = ({
5479
+ job,
5480
+ config,
5481
+ onJobClick
5482
+ }) => {
5483
+ var _a, _b, _c;
5451
5484
  const subheading = config.subheading ? getDisplayableProperty({ job, property: config.subheading }) : null;
5452
5485
  const tags = config.infoTags.flatMap((infoTag) => asArray(getDisplayableProperty({ job, property: infoTag }))).filter(Boolean);
5453
5486
  const salary = asArray(
@@ -5457,11 +5490,16 @@ const JobCard = ({ job, config }) => {
5457
5490
  const href = ((_b = config.overrides) == null ? void 0 : _b.baseUrl) ? config.overrides.baseUrl(job.id.toString()) : job.href;
5458
5491
  const newUnderDays = config.newUnderDays ?? 7;
5459
5492
  const isNew = job.createdAt ? new Date(job.createdAt).getTime() > Date.now() - newUnderDays * ONE_DAY_MS : false;
5493
+ const handleClick = (e2) => {
5494
+ var _a2, _b2;
5495
+ onJobClick == null ? void 0 : onJobClick(job);
5496
+ (_b2 = (_a2 = config.overrides) == null ? void 0 : _a2.onClick) == null ? void 0 : _b2.call(_a2, e2);
5497
+ };
5460
5498
  return /* @__PURE__ */ u$2(
5461
5499
  "a",
5462
5500
  {
5463
5501
  onMouseEnter: (_c = config.overrides) == null ? void 0 : _c.onMouseEnter,
5464
- onClick: (_d = config.overrides) == null ? void 0 : _d.onClick,
5502
+ onClick: handleClick,
5465
5503
  href,
5466
5504
  target: config.openJob === "redirect-new-tab" ? "_blank" : void 0,
5467
5505
  class: wrapperClass(),
@@ -5548,16 +5586,19 @@ const LoadMore = ({
5548
5586
  state,
5549
5587
  fetchNextPage,
5550
5588
  config,
5551
- analytics
5589
+ remainingItems
5552
5590
  }) => {
5591
+ const itemsToLoad = Math.min(PAGE_SIZE, remainingItems);
5553
5592
  if (state === "revalidating") {
5554
5593
  return /* @__PURE__ */ u$2("ul", { class: "flex flex-col gap-3", "aria-hidden": true, children: Array.from({ length: PAGE_SIZE }).map((_2, i2) => /* @__PURE__ */ u$2("li", { children: /* @__PURE__ */ u$2(JobCardSkeleton, { seed: i2, animationDelay: (i2 - 4) * 0.1, config }) }, i2)) });
5555
5594
  } else {
5556
- const handleClick = () => {
5557
- analytics.log({ event: "SEARCH_PAGINATE" });
5558
- fetchNextPage();
5559
- };
5560
- return /* @__PURE__ */ u$2("button", { class: btnClass({ variant: "neutral", class: "py-2" }), onClick: handleClick, children: "Load More" });
5595
+ return /* @__PURE__ */ u$2("button", { class: btnClass({ variant: "neutral", class: "py-2" }), onClick: fetchNextPage, children: [
5596
+ "Load ",
5597
+ itemsToLoad,
5598
+ " more of ",
5599
+ remainingItems,
5600
+ " remaining"
5601
+ ] });
5561
5602
  }
5562
5603
  };
5563
5604
  const getResultsCount = ({ pagination }) => {
@@ -5572,7 +5613,9 @@ const ResultsSection = ({
5572
5613
  logger,
5573
5614
  jobCardConfig,
5574
5615
  initialData,
5575
- analytics
5616
+ onResultsUpdate,
5617
+ onJobClick,
5618
+ onPaginate
5576
5619
  }) => {
5577
5620
  const [page, setPage] = h$1(1);
5578
5621
  return /* @__PURE__ */ u$2(k$3, { children: Array.from({ length: page }).map((_2, index) => {
@@ -5586,10 +5629,14 @@ const ResultsSection = ({
5586
5629
  page: index + 1,
5587
5630
  isFirst: index === 0,
5588
5631
  isLast,
5589
- fetchNextPage: () => setPage(page + 1),
5632
+ fetchNextPage: () => {
5633
+ setPage(page + 1);
5634
+ onPaginate(page + 1);
5635
+ },
5590
5636
  jobCardConfig,
5591
5637
  initialData,
5592
- analytics
5638
+ onResultsUpdate,
5639
+ onJobClick
5593
5640
  },
5594
5641
  index
5595
5642
  ) }, index);
@@ -5605,7 +5652,8 @@ const ResultsPage = ({
5605
5652
  fetchNextPage,
5606
5653
  jobCardConfig,
5607
5654
  initialData,
5608
- analytics
5655
+ onResultsUpdate,
5656
+ onJobClick
5609
5657
  }) => {
5610
5658
  const fallbackData = page === 1 ? initialData : void 0;
5611
5659
  const { keyword$ } = store;
@@ -5622,6 +5670,13 @@ const ResultsPage = ({
5622
5670
  { ...SWR_SETTINGS, fallbackData }
5623
5671
  )
5624
5672
  );
5673
+ y$1(() => {
5674
+ if (data && isFirst && onResultsUpdate) {
5675
+ onResultsUpdate({
5676
+ totalCount: data.pagination.total
5677
+ });
5678
+ }
5679
+ }, [data, isFirst, onResultsUpdate]);
5625
5680
  switch (state) {
5626
5681
  case "loading":
5627
5682
  return /* @__PURE__ */ u$2(k$3, { children: [
@@ -5649,6 +5704,8 @@ const ResultsPage = ({
5649
5704
  ] })
5650
5705
  ] });
5651
5706
  const hasMore = data.pagination.last_page !== data.pagination.current_page;
5707
+ const alreadyDisplayedItems = page * PAGE_SIZE;
5708
+ const remainingItems = Math.max(data.pagination.total - alreadyDisplayedItems, 0);
5652
5709
  return /* @__PURE__ */ u$2(k$3, { children: [
5653
5710
  isFirst && /* @__PURE__ */ u$2("p", { class: "text-copy-neutral-lowcontrast text-style-tag m-0 p-0 text-center", children: getResultsCount({ pagination: data.pagination }) }),
5654
5711
  /* @__PURE__ */ u$2("ul", { "aria-label": `Page ${page}`, class: "flex flex-col gap-3", children: data.results.map((job) => {
@@ -5657,12 +5714,20 @@ const ResultsPage = ({
5657
5714
  {
5658
5715
  class: "ease-expo-out duration-slow transition-opacity",
5659
5716
  style: { opacity: state === "revalidating" ? 0.33 : 1 },
5660
- children: /* @__PURE__ */ u$2(JobCard, { job, config: jobCardConfig })
5717
+ children: /* @__PURE__ */ u$2(JobCard, { job, onJobClick, config: jobCardConfig })
5661
5718
  },
5662
5719
  job.id
5663
5720
  );
5664
5721
  }) }),
5665
- hasMore && isLast && /* @__PURE__ */ u$2(LoadMore, { state, fetchNextPage, config: jobCardConfig, analytics })
5722
+ hasMore && isLast && /* @__PURE__ */ u$2(
5723
+ LoadMore,
5724
+ {
5725
+ state,
5726
+ fetchNextPage,
5727
+ config: jobCardConfig,
5728
+ remainingItems
5729
+ }
5730
+ )
5666
5731
  ] });
5667
5732
  }
5668
5733
  default:
@@ -5694,6 +5759,17 @@ const getFilterDefaults = (properties, field = "value") => properties.reduce(
5694
5759
  },
5695
5760
  {}
5696
5761
  );
5762
+ const filtersToPayload = (filters) => {
5763
+ return Object.fromEntries(
5764
+ Object.entries(filters).map(([key, filter]) => {
5765
+ const value = filter == null ? void 0 : filter.value;
5766
+ return [
5767
+ key,
5768
+ Array.isArray(value) ? value : value ? [value] : []
5769
+ ];
5770
+ }).filter(([, value]) => value !== void 0 && value.length > 0)
5771
+ );
5772
+ };
5697
5773
  const JobSearch = ({
5698
5774
  apiClient,
5699
5775
  logger,
@@ -5706,30 +5782,64 @@ const JobSearch = ({
5706
5782
  params
5707
5783
  }) => {
5708
5784
  const appRef = A$1(null);
5785
+ const defaultFilters = getFilterDefaults(properties, "defaultValue");
5709
5786
  const [appliedFilters, setAppliedFilters] = h$1(() => ({
5710
5787
  default: true,
5711
- filters: getFilterDefaults(properties, "defaultValue")
5788
+ filters: defaultFilters
5712
5789
  }));
5790
+ const [totalCount, setTotalCount] = h$1(0);
5713
5791
  const { keyword$ } = store;
5792
+ const defaultFiltersPayload = filtersToPayload(defaultFilters);
5793
+ const currentFiltersPayload = filtersToPayload(appliedFilters.filters);
5794
+ const getSearchProperties = q$1(
5795
+ () => ({
5796
+ query: keyword$.value || void 0,
5797
+ filters: currentFiltersPayload,
5798
+ default_filters: defaultFiltersPayload,
5799
+ total_count: totalCount,
5800
+ page_size: PAGE_SIZE
5801
+ }),
5802
+ [keyword$.value, currentFiltersPayload, defaultFiltersPayload, totalCount]
5803
+ );
5804
+ useViewTracking(appRef, {
5805
+ minViewTime: 2e3,
5806
+ onView: () => {
5807
+ analytics.log({ event: "VIEW_SEARCH", properties: null });
5808
+ }
5809
+ });
5714
5810
  y$1(() => {
5715
5811
  const timer = window.setTimeout(() => {
5716
- console.log("settling");
5717
- const formattedFilters = filtersToPayload(appliedFilters.filters);
5718
- const hasInteracted = appliedFilters.default !== true;
5719
- if (!keyword$.value && !hasInteracted)
5812
+ const shouldSkipAnalytics = appliedFilters.default === true && !keyword$.value || !keyword$.value && !Object.keys(currentFiltersPayload).length || totalCount === 0;
5813
+ if (shouldSkipAnalytics)
5720
5814
  return;
5721
5815
  analytics.log({
5722
5816
  event: "SEARCH_SETTLE",
5723
- properties: {
5724
- query: keyword$.value || void 0,
5725
- filters: hasInteracted ? formattedFilters : void 0
5726
- }
5817
+ properties: getSearchProperties()
5727
5818
  });
5728
5819
  }, 5e3);
5729
5820
  return () => {
5730
5821
  clearTimeout(timer);
5731
5822
  };
5732
- }, [appliedFilters.filters, keyword$.value, analytics, appliedFilters.default]);
5823
+ }, [analytics, appliedFilters.default, currentFiltersPayload, getSearchProperties, keyword$.value, totalCount]);
5824
+ const onJobClick = (job) => {
5825
+ analytics.log({
5826
+ event: "SEARCH_JOB_CLICK",
5827
+ properties: {
5828
+ job_id: job.id,
5829
+ ...getSearchProperties()
5830
+ }
5831
+ });
5832
+ };
5833
+ const onPaginate = (page) => {
5834
+ analytics.log({
5835
+ event: "SEARCH_PAGINATE",
5836
+ properties: {
5837
+ page,
5838
+ ...getSearchProperties()
5839
+ }
5840
+ });
5841
+ console.log("onPaginate", page, getSearchProperties());
5842
+ };
5733
5843
  return /* @__PURE__ */ u$2("div", { ref: appRef, class: className, id: JOB_SEARCH_SCOPE_ELEMENT_ID, children: /* @__PURE__ */ u$2("div", { class: "ijs-app bg-app rounded-app font-family-default font-weight-default font-style-default mx-auto flex min-h-screen max-w-screen-lg flex-col gap-4 py-4 md:grid md:grid-cols-3 md:px-4", children: [
5734
5844
  /* @__PURE__ */ u$2(ErrorBoundary, { Fallback: ErrorView, children: /* @__PURE__ */ u$2("div", { class: "flex flex-col gap-2", children: [
5735
5845
  params.enableKeywordSearch && /* @__PURE__ */ u$2(KeywordSearch, { onKeywordChange }),
@@ -5768,7 +5878,11 @@ const JobSearch = ({
5768
5878
  apiClient,
5769
5879
  jobCardConfig: params.jobCard,
5770
5880
  initialData: appliedFilters.default ? initialData == null ? void 0 : initialData.jobs : void 0,
5771
- analytics
5881
+ onResultsUpdate: (data) => {
5882
+ setTotalCount(data.totalCount);
5883
+ },
5884
+ onJobClick,
5885
+ onPaginate
5772
5886
  },
5773
5887
  cacheKey({ filter: appliedFilters.filters, baseKey: "resultsSection", keyword: keyword$.value })
5774
5888
  ) }) }) })
package/dist/index.js CHANGED
@@ -1561,7 +1561,7 @@ const getFilterValue = (filterValue) => {
1561
1561
  return null;
1562
1562
  return filterValue;
1563
1563
  };
1564
- const filtersToPayload = (filters) => {
1564
+ const filtersToPayload$1 = (filters) => {
1565
1565
  return Object.fromEntries(
1566
1566
  Object.entries(filters).map(([key, filter]) => {
1567
1567
  return [key, getFilterValue(filter == null ? void 0 : filter.value)];
@@ -1578,7 +1578,7 @@ const getAvailableFilters = async ({
1578
1578
  try {
1579
1579
  const searchParams = new URLSearchParams(
1580
1580
  stringify({
1581
- filters: filtersToPayload(filters),
1581
+ filters: filtersToPayload$1(filters),
1582
1582
  query: keyword
1583
1583
  })
1584
1584
  );
@@ -1607,7 +1607,7 @@ const getJobSearchResults = async ({
1607
1607
  try {
1608
1608
  const searchParams = new URLSearchParams(
1609
1609
  stringify({
1610
- filters: filtersToPayload(filters)
1610
+ filters: filtersToPayload$1(filters)
1611
1611
  })
1612
1612
  );
1613
1613
  searchParams.set("page", page.toString());
@@ -2688,6 +2688,48 @@ const cacheKey = (value) => {
2688
2688
  ).join("&");
2689
2689
  return `${value.baseKey}::${filterString}::${value.keyword ?? ""}`;
2690
2690
  };
2691
+ const useMediaQuery = (query) => {
2692
+ const [matches, setMatches] = h$1(false);
2693
+ y$1(() => {
2694
+ if (typeof window === "undefined")
2695
+ return;
2696
+ const mediaQuery = window.matchMedia(query);
2697
+ const updateMatches = () => setMatches(mediaQuery.matches);
2698
+ updateMatches();
2699
+ mediaQuery.addEventListener("change", updateMatches);
2700
+ return () => mediaQuery.removeEventListener("change", updateMatches);
2701
+ }, [query]);
2702
+ return matches;
2703
+ };
2704
+ const useViewTracking = (elementRef, { minViewTime = 1e3, visibilityThreshold = 0, onView }) => {
2705
+ const [viewed, setViewed] = h$1(false);
2706
+ y$1(() => {
2707
+ if (viewed)
2708
+ return;
2709
+ if (!elementRef.current)
2710
+ return;
2711
+ let timeout;
2712
+ const observer = new IntersectionObserver(
2713
+ (entries) => entries.forEach((entry) => {
2714
+ clearTimeout(timeout);
2715
+ if (entry.isIntersecting) {
2716
+ timeout = setTimeout(() => {
2717
+ setViewed(true);
2718
+ onView();
2719
+ }, minViewTime);
2720
+ }
2721
+ }),
2722
+ {
2723
+ threshold: visibilityThreshold
2724
+ }
2725
+ );
2726
+ observer.observe(elementRef.current);
2727
+ return () => {
2728
+ observer.disconnect();
2729
+ clearTimeout(timeout);
2730
+ };
2731
+ }, [elementRef, minViewTime, visibilityThreshold, onView, viewed]);
2732
+ };
2691
2733
  const jobSearch = "";
2692
2734
  const getFilterValues = (appliedFilters) => {
2693
2735
  const entries = Object.entries(appliedFilters).map(([key, value]) => {
@@ -4244,19 +4286,6 @@ const CurrentValueTag = ({ query, property, selectedValues }) => {
4244
4286
  exhaustive(query);
4245
4287
  }
4246
4288
  };
4247
- const useMediaQuery = (query) => {
4248
- const [matches, setMatches] = h$1(false);
4249
- y$1(() => {
4250
- if (typeof window === "undefined")
4251
- return;
4252
- const mediaQuery = window.matchMedia(query);
4253
- const updateMatches = () => setMatches(mediaQuery.matches);
4254
- updateMatches();
4255
- mediaQuery.addEventListener("change", updateMatches);
4256
- return () => mediaQuery.removeEventListener("change", updateMatches);
4257
- }, [query]);
4258
- return matches;
4259
- };
4260
4289
  const TAG_HEIGHT = 44;
4261
4290
  const LINE_COUNT = 6;
4262
4291
  const SUGGESTIONS_COUNT_THRESHOLD = 12;
@@ -5444,8 +5473,12 @@ const JobCardLogo = ({
5444
5473
  };
5445
5474
  const asArray = (value) => Array.isArray(value) ? value : [value];
5446
5475
  const ONE_DAY_MS = 1e3 * 60 * 60 * 24 * 7;
5447
- const JobCard = ({ job, config }) => {
5448
- var _a, _b, _c, _d;
5476
+ const JobCard = ({
5477
+ job,
5478
+ config,
5479
+ onJobClick
5480
+ }) => {
5481
+ var _a, _b, _c;
5449
5482
  const subheading = config.subheading ? getDisplayableProperty({ job, property: config.subheading }) : null;
5450
5483
  const tags = config.infoTags.flatMap((infoTag) => asArray(getDisplayableProperty({ job, property: infoTag }))).filter(Boolean);
5451
5484
  const salary = asArray(
@@ -5455,11 +5488,16 @@ const JobCard = ({ job, config }) => {
5455
5488
  const href = ((_b = config.overrides) == null ? void 0 : _b.baseUrl) ? config.overrides.baseUrl(job.id.toString()) : job.href;
5456
5489
  const newUnderDays = config.newUnderDays ?? 7;
5457
5490
  const isNew = job.createdAt ? new Date(job.createdAt).getTime() > Date.now() - newUnderDays * ONE_DAY_MS : false;
5491
+ const handleClick = (e2) => {
5492
+ var _a2, _b2;
5493
+ onJobClick == null ? void 0 : onJobClick(job);
5494
+ (_b2 = (_a2 = config.overrides) == null ? void 0 : _a2.onClick) == null ? void 0 : _b2.call(_a2, e2);
5495
+ };
5458
5496
  return /* @__PURE__ */ u$2(
5459
5497
  "a",
5460
5498
  {
5461
5499
  onMouseEnter: (_c = config.overrides) == null ? void 0 : _c.onMouseEnter,
5462
- onClick: (_d = config.overrides) == null ? void 0 : _d.onClick,
5500
+ onClick: handleClick,
5463
5501
  href,
5464
5502
  target: config.openJob === "redirect-new-tab" ? "_blank" : void 0,
5465
5503
  class: wrapperClass(),
@@ -5546,16 +5584,19 @@ const LoadMore = ({
5546
5584
  state,
5547
5585
  fetchNextPage,
5548
5586
  config,
5549
- analytics
5587
+ remainingItems
5550
5588
  }) => {
5589
+ const itemsToLoad = Math.min(PAGE_SIZE, remainingItems);
5551
5590
  if (state === "revalidating") {
5552
5591
  return /* @__PURE__ */ u$2("ul", { class: "flex flex-col gap-3", "aria-hidden": true, children: Array.from({ length: PAGE_SIZE }).map((_2, i2) => /* @__PURE__ */ u$2("li", { children: /* @__PURE__ */ u$2(JobCardSkeleton, { seed: i2, animationDelay: (i2 - 4) * 0.1, config }) }, i2)) });
5553
5592
  } else {
5554
- const handleClick = () => {
5555
- analytics.log({ event: "SEARCH_PAGINATE" });
5556
- fetchNextPage();
5557
- };
5558
- return /* @__PURE__ */ u$2("button", { class: btnClass({ variant: "neutral", class: "py-2" }), onClick: handleClick, children: "Load More" });
5593
+ return /* @__PURE__ */ u$2("button", { class: btnClass({ variant: "neutral", class: "py-2" }), onClick: fetchNextPage, children: [
5594
+ "Load ",
5595
+ itemsToLoad,
5596
+ " more of ",
5597
+ remainingItems,
5598
+ " remaining"
5599
+ ] });
5559
5600
  }
5560
5601
  };
5561
5602
  const getResultsCount = ({ pagination }) => {
@@ -5570,7 +5611,9 @@ const ResultsSection = ({
5570
5611
  logger,
5571
5612
  jobCardConfig,
5572
5613
  initialData,
5573
- analytics
5614
+ onResultsUpdate,
5615
+ onJobClick,
5616
+ onPaginate
5574
5617
  }) => {
5575
5618
  const [page, setPage] = h$1(1);
5576
5619
  return /* @__PURE__ */ u$2(k$3, { children: Array.from({ length: page }).map((_2, index) => {
@@ -5584,10 +5627,14 @@ const ResultsSection = ({
5584
5627
  page: index + 1,
5585
5628
  isFirst: index === 0,
5586
5629
  isLast,
5587
- fetchNextPage: () => setPage(page + 1),
5630
+ fetchNextPage: () => {
5631
+ setPage(page + 1);
5632
+ onPaginate(page + 1);
5633
+ },
5588
5634
  jobCardConfig,
5589
5635
  initialData,
5590
- analytics
5636
+ onResultsUpdate,
5637
+ onJobClick
5591
5638
  },
5592
5639
  index
5593
5640
  ) }, index);
@@ -5603,7 +5650,8 @@ const ResultsPage = ({
5603
5650
  fetchNextPage,
5604
5651
  jobCardConfig,
5605
5652
  initialData,
5606
- analytics
5653
+ onResultsUpdate,
5654
+ onJobClick
5607
5655
  }) => {
5608
5656
  const fallbackData = page === 1 ? initialData : void 0;
5609
5657
  const { keyword$ } = store;
@@ -5620,6 +5668,13 @@ const ResultsPage = ({
5620
5668
  { ...SWR_SETTINGS, fallbackData }
5621
5669
  )
5622
5670
  );
5671
+ y$1(() => {
5672
+ if (data && isFirst && onResultsUpdate) {
5673
+ onResultsUpdate({
5674
+ totalCount: data.pagination.total
5675
+ });
5676
+ }
5677
+ }, [data, isFirst, onResultsUpdate]);
5623
5678
  switch (state) {
5624
5679
  case "loading":
5625
5680
  return /* @__PURE__ */ u$2(k$3, { children: [
@@ -5647,6 +5702,8 @@ const ResultsPage = ({
5647
5702
  ] })
5648
5703
  ] });
5649
5704
  const hasMore = data.pagination.last_page !== data.pagination.current_page;
5705
+ const alreadyDisplayedItems = page * PAGE_SIZE;
5706
+ const remainingItems = Math.max(data.pagination.total - alreadyDisplayedItems, 0);
5650
5707
  return /* @__PURE__ */ u$2(k$3, { children: [
5651
5708
  isFirst && /* @__PURE__ */ u$2("p", { class: "text-copy-neutral-lowcontrast text-style-tag m-0 p-0 text-center", children: getResultsCount({ pagination: data.pagination }) }),
5652
5709
  /* @__PURE__ */ u$2("ul", { "aria-label": `Page ${page}`, class: "flex flex-col gap-3", children: data.results.map((job) => {
@@ -5655,12 +5712,20 @@ const ResultsPage = ({
5655
5712
  {
5656
5713
  class: "ease-expo-out duration-slow transition-opacity",
5657
5714
  style: { opacity: state === "revalidating" ? 0.33 : 1 },
5658
- children: /* @__PURE__ */ u$2(JobCard, { job, config: jobCardConfig })
5715
+ children: /* @__PURE__ */ u$2(JobCard, { job, onJobClick, config: jobCardConfig })
5659
5716
  },
5660
5717
  job.id
5661
5718
  );
5662
5719
  }) }),
5663
- hasMore && isLast && /* @__PURE__ */ u$2(LoadMore, { state, fetchNextPage, config: jobCardConfig, analytics })
5720
+ hasMore && isLast && /* @__PURE__ */ u$2(
5721
+ LoadMore,
5722
+ {
5723
+ state,
5724
+ fetchNextPage,
5725
+ config: jobCardConfig,
5726
+ remainingItems
5727
+ }
5728
+ )
5664
5729
  ] });
5665
5730
  }
5666
5731
  default:
@@ -5692,6 +5757,17 @@ const getFilterDefaults = (properties, field = "value") => properties.reduce(
5692
5757
  },
5693
5758
  {}
5694
5759
  );
5760
+ const filtersToPayload = (filters) => {
5761
+ return Object.fromEntries(
5762
+ Object.entries(filters).map(([key, filter]) => {
5763
+ const value = filter == null ? void 0 : filter.value;
5764
+ return [
5765
+ key,
5766
+ Array.isArray(value) ? value : value ? [value] : []
5767
+ ];
5768
+ }).filter(([, value]) => value !== void 0 && value.length > 0)
5769
+ );
5770
+ };
5695
5771
  const JobSearch = ({
5696
5772
  apiClient,
5697
5773
  logger,
@@ -5704,30 +5780,64 @@ const JobSearch = ({
5704
5780
  params
5705
5781
  }) => {
5706
5782
  const appRef = A$1(null);
5783
+ const defaultFilters = getFilterDefaults(properties, "defaultValue");
5707
5784
  const [appliedFilters, setAppliedFilters] = h$1(() => ({
5708
5785
  default: true,
5709
- filters: getFilterDefaults(properties, "defaultValue")
5786
+ filters: defaultFilters
5710
5787
  }));
5788
+ const [totalCount, setTotalCount] = h$1(0);
5711
5789
  const { keyword$ } = store;
5790
+ const defaultFiltersPayload = filtersToPayload(defaultFilters);
5791
+ const currentFiltersPayload = filtersToPayload(appliedFilters.filters);
5792
+ const getSearchProperties = q$1(
5793
+ () => ({
5794
+ query: keyword$.value || void 0,
5795
+ filters: currentFiltersPayload,
5796
+ default_filters: defaultFiltersPayload,
5797
+ total_count: totalCount,
5798
+ page_size: PAGE_SIZE
5799
+ }),
5800
+ [keyword$.value, currentFiltersPayload, defaultFiltersPayload, totalCount]
5801
+ );
5802
+ useViewTracking(appRef, {
5803
+ minViewTime: 2e3,
5804
+ onView: () => {
5805
+ analytics.log({ event: "VIEW_SEARCH", properties: null });
5806
+ }
5807
+ });
5712
5808
  y$1(() => {
5713
5809
  const timer = window.setTimeout(() => {
5714
- console.log("settling");
5715
- const formattedFilters = filtersToPayload(appliedFilters.filters);
5716
- const hasInteracted = appliedFilters.default !== true;
5717
- if (!keyword$.value && !hasInteracted)
5810
+ const shouldSkipAnalytics = appliedFilters.default === true && !keyword$.value || !keyword$.value && !Object.keys(currentFiltersPayload).length || totalCount === 0;
5811
+ if (shouldSkipAnalytics)
5718
5812
  return;
5719
5813
  analytics.log({
5720
5814
  event: "SEARCH_SETTLE",
5721
- properties: {
5722
- query: keyword$.value || void 0,
5723
- filters: hasInteracted ? formattedFilters : void 0
5724
- }
5815
+ properties: getSearchProperties()
5725
5816
  });
5726
5817
  }, 5e3);
5727
5818
  return () => {
5728
5819
  clearTimeout(timer);
5729
5820
  };
5730
- }, [appliedFilters.filters, keyword$.value, analytics, appliedFilters.default]);
5821
+ }, [analytics, appliedFilters.default, currentFiltersPayload, getSearchProperties, keyword$.value, totalCount]);
5822
+ const onJobClick = (job) => {
5823
+ analytics.log({
5824
+ event: "SEARCH_JOB_CLICK",
5825
+ properties: {
5826
+ job_id: job.id,
5827
+ ...getSearchProperties()
5828
+ }
5829
+ });
5830
+ };
5831
+ const onPaginate = (page) => {
5832
+ analytics.log({
5833
+ event: "SEARCH_PAGINATE",
5834
+ properties: {
5835
+ page,
5836
+ ...getSearchProperties()
5837
+ }
5838
+ });
5839
+ console.log("onPaginate", page, getSearchProperties());
5840
+ };
5731
5841
  return /* @__PURE__ */ u$2("div", { ref: appRef, class: className, id: JOB_SEARCH_SCOPE_ELEMENT_ID, children: /* @__PURE__ */ u$2("div", { class: "ijs-app bg-app rounded-app font-family-default font-weight-default font-style-default mx-auto flex min-h-screen max-w-screen-lg flex-col gap-4 py-4 md:grid md:grid-cols-3 md:px-4", children: [
5732
5842
  /* @__PURE__ */ u$2(ErrorBoundary, { Fallback: ErrorView, children: /* @__PURE__ */ u$2("div", { class: "flex flex-col gap-2", children: [
5733
5843
  params.enableKeywordSearch && /* @__PURE__ */ u$2(KeywordSearch, { onKeywordChange }),
@@ -5766,7 +5876,11 @@ const JobSearch = ({
5766
5876
  apiClient,
5767
5877
  jobCardConfig: params.jobCard,
5768
5878
  initialData: appliedFilters.default ? initialData == null ? void 0 : initialData.jobs : void 0,
5769
- analytics
5879
+ onResultsUpdate: (data) => {
5880
+ setTotalCount(data.totalCount);
5881
+ },
5882
+ onJobClick,
5883
+ onPaginate
5770
5884
  },
5771
5885
  cacheKey({ filter: appliedFilters.filters, baseKey: "resultsSection", keyword: keyword$.value })
5772
5886
  ) }) }) })