@heycater/qualification-funnel 1.3.21 → 1.4.0

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.esm.js CHANGED
@@ -7732,16 +7732,6 @@ function answerInitialQuestions(state, answers) {
7732
7732
  { id: answerId, value: answerValue },
7733
7733
  { storeIfInvalid: false }
7734
7734
  );
7735
- if (state.qualification.selectedMenu) {
7736
- stateWithAnswers = answerQuestion(
7737
- stateWithAnswers,
7738
- {
7739
- id: "catering_categories",
7740
- value: state.qualification.selectedMenu.cateringCategories
7741
- },
7742
- { storeIfInvalid: false }
7743
- );
7744
- }
7745
7735
  });
7746
7736
  }
7747
7737
  const funnelHasCityQuestion = state.qualification.steps.find(
@@ -7783,16 +7773,48 @@ function answerInitialQuestions(state, answers) {
7783
7773
  }
7784
7774
  return stateWithAnswers;
7785
7775
  }
7776
+ function generateSessionId() {
7777
+ if (typeof window === "undefined") {
7778
+ return "";
7779
+ }
7780
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
7781
+ return crypto.randomUUID();
7782
+ }
7783
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
7784
+ }
7785
+ function cleanupOldTrackingSessions() {
7786
+ if (typeof window === "undefined" || typeof sessionStorage === "undefined") {
7787
+ return;
7788
+ }
7789
+ try {
7790
+ const keysToRemove = [];
7791
+ const maxAge = 24 * 60 * 60 * 1e3;
7792
+ const now2 = Date.now();
7793
+ for (let i2 = 0; i2 < sessionStorage.length; i2++) {
7794
+ const key = sessionStorage.key(i2);
7795
+ if (key && key.startsWith("funnel_started_")) {
7796
+ const timestamp = key.split("-")[1];
7797
+ if (timestamp && !isNaN(Number(timestamp))) {
7798
+ const age = now2 - Number(timestamp);
7799
+ if (age > maxAge) {
7800
+ keysToRemove.push(key);
7801
+ }
7802
+ }
7803
+ }
7804
+ }
7805
+ keysToRemove.forEach((key) => sessionStorage.removeItem(key));
7806
+ } catch (e2) {
7807
+ }
7808
+ }
7786
7809
  function initialize(state, {
7787
7810
  answers,
7788
7811
  disabledSteps,
7789
7812
  leadSource,
7790
7813
  nonSkippableQuestions,
7791
7814
  selectedCaterer,
7792
- selectedMenu,
7793
7815
  stepOrder
7794
7816
  } = {}) {
7795
- var _a2;
7817
+ var _a2, _b;
7796
7818
  const currentPageHref = typeof window === "undefined" ? void 0 : `${window.location.origin}${window.location.pathname}`;
7797
7819
  leadSource = leadSource || currentPageHref;
7798
7820
  const isUserLoggedIn = typeof window !== "undefined" && window.localStorage.getItem("token");
@@ -7801,6 +7823,7 @@ function initialize(state, {
7801
7823
  stepOrder
7802
7824
  });
7803
7825
  const firstStepId = ((_a2 = initialSteps[0]) == null ? void 0 : _a2.id) || DEFAULT_STEP_ORDER[0];
7826
+ const existingState = "qualification" in state ? state : null;
7804
7827
  const initialState = {
7805
7828
  ...state,
7806
7829
  initialOptions: {
@@ -7809,24 +7832,21 @@ function initialize(state, {
7809
7832
  status: QUALIFICATION_STATUS.answering,
7810
7833
  qualification: {
7811
7834
  leadSource,
7835
+ sessionInfo: ((_b = existingState == null ? void 0 : existingState.qualification) == null ? void 0 : _b.sessionInfo) || {
7836
+ sessionId: generateSessionId(),
7837
+ startedAt: Date.now(),
7838
+ lastActiveAt: Date.now()
7839
+ },
7812
7840
  answers: {},
7813
7841
  errors: {},
7814
7842
  steps: initialSteps.map((q2) => ({ id: q2.id })),
7815
7843
  step: { id: firstStepId },
7816
7844
  stepIndex: 0,
7817
7845
  progressPercentage: 0,
7818
- selectedMenu,
7819
7846
  selectedCaterer
7820
7847
  }
7821
7848
  };
7822
7849
  let answeredState = answerInitialQuestions(initialState, answers);
7823
- if (selectedMenu) {
7824
- answeredState = answerQuestion(answeredState, {
7825
- id: "catering_categories",
7826
- value: selectedMenu.cateringCategories
7827
- });
7828
- disableStep(answeredState, "catering_categories");
7829
- }
7830
7850
  const orderedSteps = orderStepsBasedOnAnswers({
7831
7851
  steps: answeredState.qualification.steps,
7832
7852
  answers: answeredState.qualification.answers,
@@ -8122,35 +8142,6 @@ const qualificationReducer = (state, action2) => {
8122
8142
  }
8123
8143
  return state;
8124
8144
  }
8125
- case "clearBestseller": {
8126
- if (state.status === "answering") {
8127
- const newState = answerQuestion(state, {
8128
- id: "catering_categories",
8129
- value: void 0
8130
- });
8131
- return initialize(newState, {
8132
- answers: newState.qualification.answers,
8133
- selectedCaterer: newState.qualification.selectedCaterer,
8134
- selectedMenu: void 0
8135
- });
8136
- }
8137
- return state;
8138
- }
8139
- case "selectBestseller": {
8140
- if (state.status === "answering") {
8141
- const newState = answerQuestion(state, {
8142
- id: "catering_categories",
8143
- value: void 0
8144
- });
8145
- const answers = newState.qualification.answers;
8146
- return initialize(newState, {
8147
- answers,
8148
- selectedCaterer: newState.qualification.selectedCaterer,
8149
- selectedMenu: action2.payload
8150
- });
8151
- }
8152
- return state;
8153
- }
8154
8145
  default: {
8155
8146
  return state;
8156
8147
  }
@@ -8165,8 +8156,6 @@ function getActions(dispatch) {
8165
8156
  initialize: (options) => dispatch({ type: "initialize", payload: options || {} }),
8166
8157
  nextStep: () => dispatch({ type: "nextStep" }),
8167
8158
  prevStep: () => dispatch({ type: "prevStep" }),
8168
- selectBestseller: (bestseller2) => dispatch({ type: "selectBestseller", payload: bestseller2 }),
8169
- clearBestseller: () => dispatch({ type: "clearBestseller" }),
8170
8159
  setQuestion: (questionId) => dispatch({ type: "setQuestion", payload: questionId }),
8171
8160
  setRequest: (requestFormData) => dispatch({ type: "setRequest", payload: requestFormData }),
8172
8161
  qualify: (qualified) => dispatch({ type: "qualify", payload: qualified })
@@ -10096,7 +10085,7 @@ function BudgetQuestionWithPeopleCount() {
10096
10085
  onSelect: (value) => actions.answerQuestion(questions$2.peopleCount.id, value)
10097
10086
  }
10098
10087
  ) }),
10099
- /* @__PURE__ */ jsx(Divider$1, { my: 4 }),
10088
+ /* @__PURE__ */ jsx(Divider, { my: 4 }),
10100
10089
  /* @__PURE__ */ jsx(Box, { mb: 2, children: /* @__PURE__ */ jsx(Typography, { as: "label", htmlFor: pricePerPersonQuestion.id, children: t2("common:questions.budgetProPerson") }) }),
10101
10090
  /* @__PURE__ */ jsx(Box, { mb: 2, children: /* @__PURE__ */ jsx(
10102
10091
  PriceStepperField,
@@ -10139,7 +10128,7 @@ const ErrorWrapper = styled.div`
10139
10128
  color: #F95524;
10140
10129
  font-weight: 500;
10141
10130
  `;
10142
- const Divider$1 = styled(Box)`
10131
+ const Divider = styled(Box)`
10143
10132
  height: 2px;
10144
10133
  background-color: ${({ theme }) => theme.palette.grey[100]};
10145
10134
  width: 100%;
@@ -10966,169 +10955,6 @@ const Wrapper$2 = styled.div`
10966
10955
  display: flex;
10967
10956
  flex-direction: column;
10968
10957
  `;
10969
- const CloseCircleIcon = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%3e%3cpath%20fillRule='evenodd'%20fill='white'%20clipRule='evenodd'%20d='M2%2012C2%206.47%206.47%202%2012%202C17.53%202%2022%206.47%2022%2012C22%2017.53%2017.53%2022%2012%2022C6.47%2022%202%2017.53%202%2012ZM15.59%2017L17%2015.59L13.41%2012L17%208.41L15.59%207L12%2010.59L8.41%207L7%208.41L10.59%2012L7%2015.59L8.41%2017L12%2013.41L15.59%2017Z'/%3e%3c/svg%3e";
10970
- const GreenCheckmark = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='25'%20height='24'%20viewBox='0%200%2025%2024'%20fill='none'%3e%3cpath%20d='M9.29508%2015.8749L5.12508%2011.7049L3.70508%2013.1149L9.29508%2018.7049L21.2951%206.70492L19.8851%205.29492L9.29508%2015.8749Z'%20fill='%237D8F5C'/%3e%3c/svg%3e";
10971
- const SelectedMenuCard = (props) => {
10972
- const { actions } = useQualification();
10973
- const { t: t2 } = useTranslation();
10974
- const isMobile = useBreakpointDown("sm");
10975
- if (isMobile) {
10976
- return /* @__PURE__ */ jsxs(Card, { children: [
10977
- /* @__PURE__ */ jsx(CloseButtonWrapper, { children: /* @__PURE__ */ jsx(CloseButton, { onClick: actions.clearBestseller, children: /* @__PURE__ */ jsx(CloseCircleIcon, {}) }) }),
10978
- /* @__PURE__ */ jsxs(Box, { display: "flex", children: [
10979
- /* @__PURE__ */ jsx(Box, { display: "flex", flexShrink: 0, children: /* @__PURE__ */ jsx(
10980
- MenuImage,
10981
- {
10982
- alt: "",
10983
- src: props.imageSrc,
10984
- height: 70,
10985
- width: 70
10986
- }
10987
- ) }),
10988
- /* @__PURE__ */ jsxs(
10989
- Box,
10990
- {
10991
- display: "flex",
10992
- mx: 2,
10993
- textAlign: "start",
10994
- flexDirection: "column",
10995
- alignItems: "flex-start",
10996
- justifyContent: "center",
10997
- children: [
10998
- /* @__PURE__ */ jsx(CardLabel, { children: t2("qualification:bestseller.labelShort") }),
10999
- /* @__PURE__ */ jsx(Title$1, { children: props.title })
11000
- ]
11001
- }
11002
- )
11003
- ] })
11004
- ] });
11005
- }
11006
- return /* @__PURE__ */ jsxs("div", { children: [
11007
- /* @__PURE__ */ jsx(Box, { py: 2, pb: 1, textAlign: "center", children: /* @__PURE__ */ jsx(CardLabel, { children: t2("qualification:bestseller.label") }) }),
11008
- /* @__PURE__ */ jsxs(Card, { children: [
11009
- /* @__PURE__ */ jsx(CloseButtonWrapper, { children: /* @__PURE__ */ jsx(CloseButton, { onClick: actions.clearBestseller, children: /* @__PURE__ */ jsx(CloseCircleIcon, {}) }) }),
11010
- /* @__PURE__ */ jsx(Box, { mb: 2, children: /* @__PURE__ */ jsx(MenuImage, { alt: "", src: props.imageSrc, height: 142, width: 300 }) }),
11011
- /* @__PURE__ */ jsxs(CardContent, { children: [
11012
- /* @__PURE__ */ jsx(Box, { mb: 1, children: /* @__PURE__ */ jsx(Title$1, { children: props.title }) }),
11013
- /* @__PURE__ */ jsx(Box, { as: "ul", p: 0, m: 0, mb: 2, children: props.contents.map((benefit) => /* @__PURE__ */ jsxs(
11014
- Box,
11015
- {
11016
- as: "li",
11017
- display: "flex",
11018
- alignItems: "flex-start",
11019
- children: [
11020
- /* @__PURE__ */ jsx(Box, { mr: 1, children: /* @__PURE__ */ jsx(GreenCheckmark, {}) }),
11021
- /* @__PURE__ */ jsx(Box, { mb: 1, children: benefit })
11022
- ]
11023
- },
11024
- benefit
11025
- )) }),
11026
- /* @__PURE__ */ jsx(Box, { mt: "auto", mb: 1, children: /* @__PURE__ */ jsx(Divider, {}) }),
11027
- /* @__PURE__ */ jsxs(Box, { textAlign: "center", children: [
11028
- /* @__PURE__ */ jsxs(PriceRange, { children: [
11029
- props.priceRange[0],
11030
- " - ",
11031
- props.priceRange[1],
11032
- " € p.P."
11033
- ] }),
11034
- /* @__PURE__ */ jsx(PriceRangeLabel, { children: t2("qualification:bestseller.delivery") })
11035
- ] })
11036
- ] })
11037
- ] })
11038
- ] });
11039
- };
11040
- const MenuImage = styled.img`
11041
- object-fit: cover;
11042
- `;
11043
- const CardLabel = styled(Typography)`
11044
- color: ${({ theme }) => theme.palette.secondary[500]};
11045
- font-size: 12px;
11046
- font-weight: 600;
11047
- line-height: 17px;
11048
- `;
11049
- const PriceRange = styled.div`
11050
- font-size: 16px;
11051
- font-style: normal;
11052
- font-weight: 600;
11053
- line-height: 172.5%; /* 27.6px */
11054
- `;
11055
- const CloseButton = styled.button`
11056
- border: none;
11057
- outline: none;
11058
- padding: 0;
11059
- cursor: pointer;
11060
- background-color: transparent;
11061
- position: relative;
11062
- ::before {
11063
- content: '';
11064
- position: absolute;
11065
- left: 3px;
11066
- top: 3px;
11067
- height: 18px;
11068
- width: 18px;
11069
- border-radius: 100px;
11070
- z-index: -1;
11071
- background-color: rgba(0, 0, 0, 0.5);
11072
- }
11073
- `;
11074
- const PriceRangeLabel = styled.div`
11075
- font-size: 10px;
11076
- font-style: normal;
11077
- font-weight: 400;
11078
- line-height: 17px;
11079
- letter-spacing: 0.4px;
11080
- `;
11081
- const Divider = styled.div`
11082
- display: flex;
11083
- justify-content: center;
11084
- width: 100%;
11085
- height: 1px;
11086
- background-color: rgba(0, 0, 0, 0.1);
11087
- `;
11088
- const CardContent = styled.div`
11089
- padding: ${({ theme }) => theme.spacing(0, 2, 2, 2)};
11090
- height: 100%;
11091
- display: flex;
11092
- flex-direction: column;
11093
- `;
11094
- const Card = styled.div`
11095
- flex-shrink: none;
11096
- width: 100%;
11097
- border: 1px solid ${({ theme }) => theme.palette.secondary[500]};
11098
- background-color: #f7fcfa;
11099
- box-shadow: 0px 4px 20px 0px rgba(62, 41, 29, 0.08);
11100
- position: relative;
11101
- display: flex;
11102
- height: 100%;
11103
- flex-shrink: 0;
11104
- flex-direction: column;
11105
- border-radius: ${({ theme }) => theme.spacing(0.8)}px;
11106
- overflow: hidden;
11107
- box-shadow: 0px 4px 20px 0px rgba(62, 41, 29, 0.08);
11108
-
11109
- ${({ theme }) => theme.breakpoints.up("md")} {
11110
- width: 300px;
11111
- border-radius: ${({ theme }) => theme.spacing(1.5)}px;
11112
- }
11113
- `;
11114
- const CloseButtonWrapper = styled.div`
11115
- position: absolute;
11116
- top: 8px;
11117
- right: 8px;
11118
- z-index: 2;
11119
- `;
11120
- const Title$1 = styled(Typography)`
11121
- color: #3c4340;
11122
- padding: 0;
11123
- font-size: 12px;
11124
- font-weight: 600;
11125
- line-height: 150%; /* 27px */
11126
-
11127
- ${({ theme }) => theme.breakpoints.up("md")} {
11128
- font-size: 18px;
11129
- text-align: center;
11130
- }
11131
- `;
11132
10958
  function EmployeeCateringIcon(props) {
11133
10959
  return /* @__PURE__ */ jsxs(
11134
10960
  "svg",
@@ -11188,6 +11014,20 @@ function FullServiceIcon(props) {
11188
11014
  }
11189
11015
  );
11190
11016
  }
11017
+ function getContextualProperties(state) {
11018
+ if (!("qualification" in state)) return {};
11019
+ const { sessionInfo, answers } = state.qualification;
11020
+ const props = {
11021
+ session_id: (sessionInfo == null ? void 0 : sessionInfo.sessionId) || ""
11022
+ };
11023
+ if (answers.service_type) {
11024
+ props.service_type = answers.service_type;
11025
+ }
11026
+ if (answers.city) {
11027
+ props.city = answers.city;
11028
+ }
11029
+ return props;
11030
+ }
11191
11031
  function trackFunnelEvent(action2, properties) {
11192
11032
  const eventName = `funnel_${action2}`;
11193
11033
  if (typeof window === "undefined") return;
@@ -11201,34 +11041,38 @@ function trackFunnelEvent(action2, properties) {
11201
11041
  });
11202
11042
  }
11203
11043
  }
11204
- function trackFunnelStarted(mode, totalSteps) {
11044
+ function trackFunnelStarted(mode, totalSteps, contextProps) {
11205
11045
  trackFunnelEvent("started", {
11206
11046
  funnel_mode: mode,
11207
- total_steps: totalSteps
11047
+ total_steps: totalSteps,
11048
+ ...contextProps
11208
11049
  });
11209
11050
  }
11210
- function trackStepViewed(mode, stepId, stepIndex, totalSteps) {
11051
+ function trackStepViewed(mode, stepId, stepIndex, totalSteps, contextProps) {
11211
11052
  trackFunnelEvent("step_viewed", {
11212
11053
  funnel_mode: mode,
11213
11054
  step_id: stepId,
11214
11055
  step_index: stepIndex,
11215
- total_steps: totalSteps
11056
+ total_steps: totalSteps,
11057
+ ...contextProps
11216
11058
  });
11217
11059
  }
11218
- function trackAnswerSelected(mode, stepId, questionId, value) {
11060
+ function trackAnswerSelected(mode, stepId, questionId, value, contextProps) {
11219
11061
  trackFunnelEvent("answer_selected", {
11220
11062
  funnel_mode: mode,
11221
11063
  step_id: stepId,
11222
11064
  question_id: questionId,
11223
- answer_value: value
11065
+ answer_value: value,
11066
+ ...contextProps
11224
11067
  });
11225
11068
  }
11226
- function trackStepCompleted(mode, stepId, stepIndex, totalSteps) {
11069
+ function trackStepCompleted(mode, stepId, stepIndex, totalSteps, contextProps) {
11227
11070
  trackFunnelEvent("step_completed", {
11228
11071
  funnel_mode: mode,
11229
11072
  step_id: stepId,
11230
11073
  step_index: stepIndex,
11231
- total_steps: totalSteps
11074
+ total_steps: totalSteps,
11075
+ ...contextProps
11232
11076
  });
11233
11077
  }
11234
11078
  function trackFormSubmitted(mode, properties) {
@@ -11237,9 +11081,10 @@ function trackFormSubmitted(mode, properties) {
11237
11081
  ...properties
11238
11082
  });
11239
11083
  }
11240
- function trackFunnelCompleted(mode) {
11084
+ function trackFunnelCompleted(mode, contextProps) {
11241
11085
  trackFunnelEvent("completed", {
11242
- funnel_mode: mode
11086
+ funnel_mode: mode,
11087
+ ...contextProps
11243
11088
  });
11244
11089
  }
11245
11090
  const TrackingContext = createContext(null);
@@ -11645,7 +11490,6 @@ const EmbeddedQuestion = ({
11645
11490
  var _a2, _b, _c, _d, _e;
11646
11491
  const { t: t2 } = useTranslation();
11647
11492
  const { state, actions, answerOf } = useQualification();
11648
- const selectedMenu = "qualification" in state ? state.qualification.selectedMenu : null;
11649
11493
  const getTitleContent = useCallback(
11650
11494
  (title2) => renderTitle ? renderTitle(title2) : title2,
11651
11495
  []
@@ -11663,7 +11507,7 @@ const EmbeddedQuestion = ({
11663
11507
  content: /* @__PURE__ */ jsx(Container, { size: "sm", disableGutters: true, children: /* @__PURE__ */ jsx(
11664
11508
  CityTiles,
11665
11509
  {
11666
- size: selectedMenu ? "sm" : "md",
11510
+ size: "md",
11667
11511
  variant: highlightColor,
11668
11512
  selected: answerOf("city"),
11669
11513
  onSelect: (city) => {
@@ -11671,8 +11515,7 @@ const EmbeddedQuestion = ({
11671
11515
  actions.nextStep();
11672
11516
  }
11673
11517
  }
11674
- ) }),
11675
- side: selectedMenu && /* @__PURE__ */ jsx(SelectedMenuCard, { ...selectedMenu })
11518
+ ) })
11676
11519
  }
11677
11520
  );
11678
11521
  case steps$2.cateringCategories.id: {
@@ -11696,8 +11539,7 @@ const EmbeddedQuestion = ({
11696
11539
  category
11697
11540
  )
11698
11541
  }
11699
- ),
11700
- side: selectedMenu && /* @__PURE__ */ jsx(SelectedMenuCard, { ...selectedMenu })
11542
+ )
11701
11543
  }
11702
11544
  );
11703
11545
  }
@@ -11712,8 +11554,7 @@ const EmbeddedQuestion = ({
11712
11554
  subtitle: t2(
11713
11555
  "qualification:embeddedFunnel.dietaryRestrictions.subtitle"
11714
11556
  ),
11715
- content: /* @__PURE__ */ jsx(Container, { size: MAX_WIDTH_OF_WHITE_WRAPPER, children: /* @__PURE__ */ jsx(WhiteWrapper, { children: /* @__PURE__ */ jsx(Box, { py: 3, px: 2, children: /* @__PURE__ */ jsx(DietaryDistribution, {}) }) }) }),
11716
- side: selectedMenu && /* @__PURE__ */ jsx(SelectedMenuCard, { ...selectedMenu })
11557
+ content: /* @__PURE__ */ jsx(Container, { size: MAX_WIDTH_OF_WHITE_WRAPPER, children: /* @__PURE__ */ jsx(WhiteWrapper, { children: /* @__PURE__ */ jsx(Box, { py: 3, px: 2, children: /* @__PURE__ */ jsx(DietaryDistribution, {}) }) }) })
11717
11558
  }
11718
11559
  );
11719
11560
  case steps$2.eventDateAndLeadType.id: {
@@ -11724,8 +11565,7 @@ const EmbeddedQuestion = ({
11724
11565
  wrapper: ((_c = slides == null ? void 0 : slides.dateAndLead) == null ? void 0 : _c.whiteWrapper) ? "white" : "transparent",
11725
11566
  ratings,
11726
11567
  title: getTitleContent(title),
11727
- content: /* @__PURE__ */ jsx(Container, { size: MAX_WIDTH_OF_WHITE_WRAPPER, children: /* @__PURE__ */ jsx(WhiteWrapper, { children: /* @__PURE__ */ jsx(Box, { py: 4, children: /* @__PURE__ */ jsx(DatePickerEmbedded, {}) }) }) }),
11728
- side: selectedMenu && /* @__PURE__ */ jsx(SelectedMenuCard, { ...selectedMenu })
11568
+ content: /* @__PURE__ */ jsx(Container, { size: MAX_WIDTH_OF_WHITE_WRAPPER, children: /* @__PURE__ */ jsx(WhiteWrapper, { children: /* @__PURE__ */ jsx(Box, { py: 4, children: /* @__PURE__ */ jsx(DatePickerEmbedded, {}) }) }) })
11729
11569
  }
11730
11570
  );
11731
11571
  }
@@ -11737,8 +11577,7 @@ const EmbeddedQuestion = ({
11737
11577
  wrapper: ((_d = slides == null ? void 0 : slides.budgetAndPeople) == null ? void 0 : _d.whiteWrapper) ? "white" : "transparent",
11738
11578
  ratings,
11739
11579
  title: getTitleContent(title),
11740
- content: /* @__PURE__ */ jsx(Container, { size: MAX_WIDTH_OF_WHITE_WRAPPER, children: /* @__PURE__ */ jsx(WhiteWrapper, { children: /* @__PURE__ */ jsx(Box, { py: 4, children: /* @__PURE__ */ jsx(BudgetQuestionWithPeopleCount, {}) }) }) }),
11741
- side: selectedMenu && /* @__PURE__ */ jsx(SelectedMenuCard, { ...selectedMenu })
11580
+ content: /* @__PURE__ */ jsx(Container, { size: MAX_WIDTH_OF_WHITE_WRAPPER, children: /* @__PURE__ */ jsx(WhiteWrapper, { children: /* @__PURE__ */ jsx(Box, { py: 4, children: /* @__PURE__ */ jsx(BudgetQuestionWithPeopleCount, {}) }) }) })
11742
11581
  }
11743
11582
  );
11744
11583
  case steps$2.serviceSelection.id:
@@ -11758,8 +11597,7 @@ const EmbeddedQuestion = ({
11758
11597
  actions.nextStep();
11759
11598
  }
11760
11599
  }
11761
- ) }),
11762
- side: selectedMenu && /* @__PURE__ */ jsx(SelectedMenuCard, { ...selectedMenu })
11600
+ ) })
11763
11601
  }
11764
11602
  );
11765
11603
  case steps$2.teamSize.id:
@@ -11779,8 +11617,7 @@ const EmbeddedQuestion = ({
11779
11617
  placeholder: t2("qualification:embeddedFunnel.teamSize.placeholder"),
11780
11618
  suggestions: teamSizeQuestion.suggestions
11781
11619
  }
11782
- ) }) }) }),
11783
- side: selectedMenu && /* @__PURE__ */ jsx(SelectedMenuCard, { ...selectedMenu })
11620
+ ) }) }) })
11784
11621
  }
11785
11622
  );
11786
11623
  case steps$2.deliveryFrequency.id:
@@ -11803,8 +11640,7 @@ const EmbeddedQuestion = ({
11803
11640
  }
11804
11641
  ),
11805
11642
  /* @__PURE__ */ jsx(BusinessCustomerToggle, {})
11806
- ] }),
11807
- side: selectedMenu && /* @__PURE__ */ jsx(SelectedMenuCard, { ...selectedMenu })
11643
+ ] })
11808
11644
  }
11809
11645
  );
11810
11646
  case steps$2.peopleCount.id:
@@ -11824,8 +11660,7 @@ const EmbeddedQuestion = ({
11824
11660
  placeholder: t2("qualification:embeddedFunnel.peopleCount.placeholder"),
11825
11661
  suggestions: peopleCountFullServiceQuestion.suggestions
11826
11662
  }
11827
- ) }) }) }),
11828
- side: selectedMenu && /* @__PURE__ */ jsx(SelectedMenuCard, { ...selectedMenu })
11663
+ ) }) }) })
11829
11664
  }
11830
11665
  );
11831
11666
  case steps$2.budgetRange.id:
@@ -11848,8 +11683,7 @@ const EmbeddedQuestion = ({
11848
11683
  }
11849
11684
  ),
11850
11685
  /* @__PURE__ */ jsx(BusinessCustomerToggle, {})
11851
- ] }),
11852
- side: selectedMenu && /* @__PURE__ */ jsx(SelectedMenuCard, { ...selectedMenu })
11686
+ ] })
11853
11687
  }
11854
11688
  );
11855
11689
  case steps$2.contactForm.id:
@@ -26375,13 +26209,17 @@ function PhoneField({ label, name, formik, helperText }) {
26375
26209
  const StyledInput = styled(Input)`
26376
26210
  border-color: ${(props) => props.$hasError ? props.theme.palette.error.main : "transparent"};
26377
26211
  `;
26378
- function Success() {
26212
+ function Success({ isUkLead = false }) {
26379
26213
  const { actions } = useQualification();
26380
26214
  const router = useRouter();
26381
26215
  const { t: t2 } = useTranslation("qualification");
26382
26216
  const handleClose = () => {
26383
26217
  actions.initialize();
26384
- router.push("/en/catering-london");
26218
+ if (isUkLead) {
26219
+ router.push("/en/catering-london");
26220
+ } else {
26221
+ router.push(`/${router.locale}`);
26222
+ }
26385
26223
  };
26386
26224
  return /* @__PURE__ */ jsxs(Fragment, { children: [
26387
26225
  /* @__PURE__ */ jsx(Box, { display: "flex", justifyContent: "end", children: /* @__PURE__ */ jsx(Box, { px: 2, children: /* @__PURE__ */ jsx(IconButton$2, { onClick: handleClose, "aria-label": "back", component: "span", children: /* @__PURE__ */ jsx(CloseIcon$1, {}) }) }) }),
@@ -26606,7 +26444,7 @@ function useRequestForm() {
26606
26444
  const { funnelCheckout } = useFunnelCheckout();
26607
26445
  const { createQfLead } = useQfLeadCreator();
26608
26446
  const buildOpportunityPayload = (values2) => {
26609
- var _a2, _b, _c, _d, _e;
26447
+ var _a2, _b, _c, _d;
26610
26448
  const deliveryAddressStreetAndNumberValue = `${values2.deliveryAddressStreet} ${values2.deliveryAddressStreetNumber}`;
26611
26449
  const { street, postalCode, city, country } = ((_b = (_a2 = currentUserAccount == null ? void 0 : currentUserAccount.owner) == null ? void 0 : _a2.salesforceCustomer) == null ? void 0 : _b.billingAddress) || {
26612
26450
  street: deliveryAddressStreetAndNumberValue,
@@ -26627,7 +26465,6 @@ function useRequestForm() {
26627
26465
  catererSlug: (_d = qualification == null ? void 0 : qualification.selectedCaterer) == null ? void 0 : _d.slug,
26628
26466
  landingPageSource: qualification.leadSource,
26629
26467
  billingAddressStreetAndNumber: street || "",
26630
- inspiredByMenuId: (_e = qualification == null ? void 0 : qualification.selectedMenu) == null ? void 0 : _e.id,
26631
26468
  billingAddressPostalCode: postalCode || "",
26632
26469
  billingAddressCity: city || "",
26633
26470
  billingCountry: country || "",
@@ -26661,7 +26498,7 @@ function useRequestForm() {
26661
26498
  });
26662
26499
  return {
26663
26500
  success,
26664
- isUkLead: true
26501
+ isUkLead
26665
26502
  };
26666
26503
  } else {
26667
26504
  const {
@@ -26709,6 +26546,7 @@ const getValidationSchema = ({
26709
26546
  function RequestForm({ header = null }) {
26710
26547
  var _a2, _b, _c;
26711
26548
  const [showLeadSuccess, setShowLeadSuccess] = useState(false);
26549
+ const [isActualUkLead, setIsActualUkLead] = useState(false);
26712
26550
  const { t: t2 } = useTranslation("qualification");
26713
26551
  const { submitAsNewCustomer, submitAsExistingCustomer } = useRequestForm();
26714
26552
  const pillValues = useAnswerPills({ display: "all-answers" });
@@ -26719,7 +26557,7 @@ function RequestForm({ header = null }) {
26719
26557
  cacheValidations
26720
26558
  });
26721
26559
  const isFloating = mobile && isNotInView;
26722
- const qualification = "qualification" in state ? state.qualification : null;
26560
+ "qualification" in state ? state.qualification : null;
26723
26561
  const { actions } = useQualification();
26724
26562
  const { currentUserAccount } = useCurrentUser();
26725
26563
  const router = useRouter();
@@ -26772,13 +26610,15 @@ function RequestForm({ header = null }) {
26772
26610
  isUkLead,
26773
26611
  success
26774
26612
  } = await submitAsNewCustomer(values2);
26775
- if (success && isUkLead) {
26613
+ if (success) {
26614
+ setIsActualUkLead(isUkLead);
26776
26615
  setShowLeadSuccess(true);
26616
+ const contextProps2 = getContextualProperties(state);
26777
26617
  trackFormSubmitted(mode, {
26778
- is_uk_lead: true,
26779
- has_bestseller: !!(qualification == null ? void 0 : qualification.selectedMenu)
26618
+ is_uk_lead: isUkLead,
26619
+ ...contextProps2
26780
26620
  });
26781
- trackFunnelCompleted(mode);
26621
+ trackFunnelCompleted(mode, contextProps2);
26782
26622
  return;
26783
26623
  }
26784
26624
  if (signInToken) {
@@ -26787,11 +26627,12 @@ function RequestForm({ header = null }) {
26787
26627
  redirectRoute = `/${router.locale}/account/external/requests/${opportunity.id}`;
26788
26628
  }
26789
26629
  }
26630
+ const contextProps = getContextualProperties(state);
26790
26631
  trackFormSubmitted(mode, {
26791
26632
  is_logged_in: !!currentUserAccount,
26792
- has_bestseller: !!(qualification == null ? void 0 : qualification.selectedMenu)
26633
+ ...contextProps
26793
26634
  });
26794
- trackFunnelCompleted(mode);
26635
+ trackFunnelCompleted(mode, contextProps);
26795
26636
  actions.setRequest(values2);
26796
26637
  redirectToCustomerAccountRequest(redirectRoute);
26797
26638
  };
@@ -26850,7 +26691,7 @@ function RequestForm({ header = null }) {
26850
26691
  phone: ((_c = (_b = currentUserAccount == null ? void 0 : currentUserAccount.owner) == null ? void 0 : _b.salesforceCustomer) == null ? void 0 : _c.phoneNumber) || ""
26851
26692
  };
26852
26693
  const isLoggedIn = !!currentUserAccount;
26853
- if (showLeadSuccess) return /* @__PURE__ */ jsx(Success, {});
26694
+ if (showLeadSuccess) return /* @__PURE__ */ jsx(Success, { isUkLead: isActualUkLead });
26854
26695
  return /* @__PURE__ */ jsxs(FeedbackMessageProvider, { children: [
26855
26696
  header,
26856
26697
  /* @__PURE__ */ jsx(
@@ -29873,6 +29714,55 @@ const LoadingIndicator = ({ variant }) => {
29873
29714
  const WrapperBox = styled(Box)`
29874
29715
  color: var(--embedded-text-color, inherit);
29875
29716
  `;
29717
+ function useAbandonmentTracking(mode, state) {
29718
+ var _a2, _b;
29719
+ const hasTrackedAbandonmentRef = useRef(false);
29720
+ const hasCompletedRef = useRef(false);
29721
+ useEffect(() => {
29722
+ if (state.status === QUALIFICATION_STATUS.answered || state.status === QUALIFICATION_STATUS.qualifiedForRequest || state.status === QUALIFICATION_STATUS.qualifiedForMarketplace || state.status === QUALIFICATION_STATUS.qualifiedForCate) {
29723
+ hasCompletedRef.current = true;
29724
+ return;
29725
+ }
29726
+ if (state.status !== QUALIFICATION_STATUS.answering) {
29727
+ hasTrackedAbandonmentRef.current = false;
29728
+ return;
29729
+ }
29730
+ if (!("qualification" in state)) return;
29731
+ const stateSnapshot = {
29732
+ stepId: state.qualification.step.id,
29733
+ stepIndex: state.qualification.stepIndex,
29734
+ totalSteps: state.qualification.steps.filter((s3) => !s3.disabled).length,
29735
+ contextProps: getContextualProperties(state)
29736
+ };
29737
+ const handleAbandonment = () => {
29738
+ if (hasTrackedAbandonmentRef.current) return;
29739
+ if (hasCompletedRef.current) return;
29740
+ trackFunnelEvent("abandoned", {
29741
+ funnel_mode: mode,
29742
+ step_id: stateSnapshot.stepId,
29743
+ step_index: stateSnapshot.stepIndex,
29744
+ total_steps: stateSnapshot.totalSteps,
29745
+ ...stateSnapshot.contextProps
29746
+ });
29747
+ hasTrackedAbandonmentRef.current = true;
29748
+ };
29749
+ window.addEventListener("beforeunload", handleAbandonment);
29750
+ let invisibilityTimeout;
29751
+ const handleVisibilityChange2 = () => {
29752
+ if (document.hidden) {
29753
+ invisibilityTimeout = setTimeout(handleAbandonment, 3e4);
29754
+ } else {
29755
+ clearTimeout(invisibilityTimeout);
29756
+ }
29757
+ };
29758
+ document.addEventListener("visibilitychange", handleVisibilityChange2);
29759
+ return () => {
29760
+ window.removeEventListener("beforeunload", handleAbandonment);
29761
+ document.removeEventListener("visibilitychange", handleVisibilityChange2);
29762
+ clearTimeout(invisibilityTimeout);
29763
+ };
29764
+ }, [state.status, (_b = (_a2 = state.qualification) == null ? void 0 : _a2.step) == null ? void 0 : _b.id, mode]);
29765
+ }
29876
29766
  const EmbeddedFunnel = React__default.forwardRef(
29877
29767
  ({
29878
29768
  onBackground,
@@ -29885,44 +29775,62 @@ const EmbeddedFunnel = React__default.forwardRef(
29885
29775
  mode = "embedded",
29886
29776
  onCancel
29887
29777
  }, ref2) => {
29888
- var _a2, _b, _c, _d, _e, _f, _g;
29778
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
29889
29779
  const scrollHelperRef = useRef(null);
29890
- const hasTrackedStart = useRef(false);
29891
29780
  const previousStepRef = useRef(null);
29892
- const onQuestionChange = useCallback(
29893
- (step2, stepIndex, totalSteps) => {
29894
- if (scrollHelperRef && (scrollHelperRef == null ? void 0 : scrollHelperRef.current)) {
29895
- scrollHelperRef.current.scrollIntoView({
29896
- inline: "nearest",
29897
- block: "nearest",
29898
- behavior: "smooth"
29899
- });
29900
- }
29901
- if (step2 && typeof totalSteps === "number") {
29902
- if (previousStepRef.current && previousStepRef.current !== step2.id && typeof stepIndex === "number" && stepIndex > 0) {
29903
- trackStepCompleted(
29904
- mode,
29905
- previousStepRef.current,
29906
- stepIndex - 1,
29907
- totalSteps
29908
- );
29909
- }
29910
- trackStepViewed(mode, step2.id, stepIndex ?? 0, totalSteps);
29911
- previousStepRef.current = step2.id;
29781
+ const { state, actions, canContinue } = useQualification({});
29782
+ useEffect(() => {
29783
+ cleanupOldTrackingSessions();
29784
+ }, []);
29785
+ useEffect(() => {
29786
+ if (state.status !== QUALIFICATION_STATUS.answering) {
29787
+ return;
29788
+ }
29789
+ const step2 = state.qualification.step;
29790
+ const stepIndex = state.qualification.stepIndex;
29791
+ const totalSteps = state.qualification.steps.filter((s3) => !s3.disabled).length;
29792
+ if (scrollHelperRef && (scrollHelperRef == null ? void 0 : scrollHelperRef.current)) {
29793
+ scrollHelperRef.current.scrollIntoView({
29794
+ inline: "nearest",
29795
+ block: "nearest",
29796
+ behavior: "smooth"
29797
+ });
29798
+ }
29799
+ if (step2 && previousStepRef.current !== step2.id) {
29800
+ const contextProps = getContextualProperties(state);
29801
+ if (previousStepRef.current && stepIndex > 0) {
29802
+ trackStepCompleted(
29803
+ mode,
29804
+ previousStepRef.current,
29805
+ stepIndex - 1,
29806
+ totalSteps,
29807
+ contextProps
29808
+ );
29912
29809
  }
29913
- },
29914
- [mode]
29915
- );
29916
- const { state, actions, canContinue } = useQualification({
29917
- onQuestionChange
29918
- });
29810
+ trackStepViewed(mode, step2.id, stepIndex, totalSteps, contextProps);
29811
+ previousStepRef.current = step2.id;
29812
+ }
29813
+ }, [state.status, (_b = (_a2 = state.qualification) == null ? void 0 : _a2.step) == null ? void 0 : _b.id, mode]);
29919
29814
  useEffect(() => {
29920
- if (!hasTrackedStart.current && state.status === QUALIFICATION_STATUS.answering) {
29815
+ var _a3, _b2;
29816
+ const sessionId = "qualification" in state ? (_b2 = (_a3 = state.qualification) == null ? void 0 : _a3.sessionInfo) == null ? void 0 : _b2.sessionId : null;
29817
+ if (!sessionId) return;
29818
+ const trackingKey = `funnel_started_${sessionId}`;
29819
+ let alreadyTracked = false;
29820
+ try {
29821
+ alreadyTracked = sessionStorage.getItem(trackingKey) === "true";
29822
+ } catch (e2) {
29823
+ }
29824
+ if (!alreadyTracked && "qualification" in state) {
29921
29825
  const enabledSteps2 = state.qualification.steps.filter((s3) => !s3.disabled);
29922
- trackFunnelStarted(mode, enabledSteps2.length);
29923
- hasTrackedStart.current = true;
29826
+ const contextProps = getContextualProperties(state);
29827
+ trackFunnelStarted(mode, enabledSteps2.length, contextProps);
29828
+ try {
29829
+ sessionStorage.setItem(trackingKey, "true");
29830
+ } catch (e2) {
29831
+ }
29924
29832
  }
29925
- }, [state.status, mode]);
29833
+ }, [(_d = (_c = state.qualification) == null ? void 0 : _c.sessionInfo) == null ? void 0 : _d.sessionId, mode]);
29926
29834
  useEffect(() => {
29927
29835
  if (scrollHelperRef && (scrollHelperRef == null ? void 0 : scrollHelperRef.current)) {
29928
29836
  scrollHelperRef.current.scrollIntoView({
@@ -29932,6 +29840,31 @@ const EmbeddedFunnel = React__default.forwardRef(
29932
29840
  });
29933
29841
  }
29934
29842
  }, [state.status]);
29843
+ const previousStatusRef = useRef(state.status);
29844
+ const lastAnsweringStateRef = useRef(null);
29845
+ useEffect(() => {
29846
+ if (state.status === QUALIFICATION_STATUS.answering && "qualification" in state) {
29847
+ lastAnsweringStateRef.current = {
29848
+ stepId: state.qualification.step.id,
29849
+ stepIndex: state.qualification.stepIndex
29850
+ };
29851
+ }
29852
+ }, [state.status, (_f = (_e = state.qualification) == null ? void 0 : _e.step) == null ? void 0 : _f.id, (_g = state.qualification) == null ? void 0 : _g.stepIndex]);
29853
+ useEffect(() => {
29854
+ if (previousStatusRef.current === QUALIFICATION_STATUS.answering && state.status === QUALIFICATION_STATUS.answered && lastAnsweringStateRef.current && "qualification" in state) {
29855
+ const totalSteps = state.qualification.steps.filter((s3) => !s3.disabled).length;
29856
+ const contextProps = getContextualProperties(state);
29857
+ trackStepCompleted(
29858
+ mode,
29859
+ lastAnsweringStateRef.current.stepId,
29860
+ lastAnsweringStateRef.current.stepIndex,
29861
+ totalSteps,
29862
+ contextProps
29863
+ );
29864
+ }
29865
+ previousStatusRef.current = state.status;
29866
+ }, [state.status, mode]);
29867
+ useAbandonmentTracking(mode, state);
29935
29868
  const toNextStep2 = useCallback(() => {
29936
29869
  actions.nextStep();
29937
29870
  }, [actions]);
@@ -29948,7 +29881,7 @@ const EmbeddedFunnel = React__default.forwardRef(
29948
29881
  if (state.status !== QUALIFICATION_STATUS.answered && state.status !== QUALIFICATION_STATUS.answering && state.status !== QUALIFICATION_STATUS.qualifiedForRequest) {
29949
29882
  return null;
29950
29883
  }
29951
- const stepId = state.status === "answering" && ((_a2 = state.qualification.step) == null ? void 0 : _a2.id) || "";
29884
+ const stepId = state.status === "answering" && ((_h = state.qualification.step) == null ? void 0 : _h.id) || "";
29952
29885
  const onKeyPress = (event) => {
29953
29886
  if (event.key === "Enter" && canContinue) {
29954
29887
  event.preventDefault();
@@ -29959,22 +29892,22 @@ const EmbeddedFunnel = React__default.forwardRef(
29959
29892
  return /* @__PURE__ */ jsx(EmbeddedRequestPage, { ratings });
29960
29893
  }
29961
29894
  let textColor = onBackground === "light" ? "dark" : "light";
29962
- if (stepId.includes("customer-") && ((_b = slides == null ? void 0 : slides.customerTier) == null ? void 0 : _b.whiteWrapper)) {
29895
+ if (stepId.includes("customer-") && ((_i = slides == null ? void 0 : slides.customerTier) == null ? void 0 : _i.whiteWrapper)) {
29963
29896
  textColor = "dark";
29964
29897
  }
29965
- if (stepId === "city" && ((_c = slides == null ? void 0 : slides.city) == null ? void 0 : _c.whiteWrapper)) {
29898
+ if (stepId === "city" && ((_j = slides == null ? void 0 : slides.city) == null ? void 0 : _j.whiteWrapper)) {
29966
29899
  textColor = "dark";
29967
29900
  }
29968
- if (stepId === "catering_categories" && ((_d = slides == null ? void 0 : slides.category) == null ? void 0 : _d.whiteWrapper)) {
29901
+ if (stepId === "catering_categories" && ((_k = slides == null ? void 0 : slides.category) == null ? void 0 : _k.whiteWrapper)) {
29969
29902
  textColor = "dark";
29970
29903
  }
29971
- if (stepId === "people_count_and_budget" && ((_e = slides == null ? void 0 : slides.budgetAndPeople) == null ? void 0 : _e.whiteWrapper)) {
29904
+ if (stepId === "people_count_and_budget" && ((_l = slides == null ? void 0 : slides.budgetAndPeople) == null ? void 0 : _l.whiteWrapper)) {
29972
29905
  textColor = "dark";
29973
29906
  }
29974
- if (stepId === "dietary_restrictions" && ((_f = slides == null ? void 0 : slides.dietaryRestriction) == null ? void 0 : _f.whiteWrapper)) {
29907
+ if (stepId === "dietary_restrictions" && ((_m = slides == null ? void 0 : slides.dietaryRestriction) == null ? void 0 : _m.whiteWrapper)) {
29975
29908
  textColor = "dark";
29976
29909
  }
29977
- if (stepId === "event_date" && ((_g = slides == null ? void 0 : slides.dateAndLead) == null ? void 0 : _g.whiteWrapper)) {
29910
+ if (stepId === "event_date" && ((_n = slides == null ? void 0 : slides.dateAndLead) == null ? void 0 : _n.whiteWrapper)) {
29978
29911
  textColor = "dark";
29979
29912
  }
29980
29913
  const isFullscreen = mode === "fullscreen";
@@ -30525,4 +30458,3 @@ function QualificationFunnel({
30525
30458
  export {
30526
30459
  QualificationFunnel
30527
30460
  };
30528
- //# sourceMappingURL=index.esm.js.map