@popmenu/common-ui 0.153.0 → 0.155.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.
Files changed (25) hide show
  1. package/build/cjs/components/FollowerAuthenticationDialog/FollowerAuthenticationDialogProps.d.ts +17 -2
  2. package/build/cjs/components/FollowerAuthenticationDialog/FollowerAuthenticationPrivacyPolicy.d.ts +1 -0
  3. package/build/cjs/components/FollowerAuthenticationDialog/FollowerAuthenticationUserForm.d.ts +1 -0
  4. package/build/cjs/components/FollowerAuthenticationDialog/phoneValidation.d.ts +2 -0
  5. package/build/cjs/index.js +275 -52
  6. package/build/cjs/index.js.map +1 -1
  7. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationDialogProps.d.ts +17 -2
  8. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationForm.js +28 -47
  9. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationForm.js.map +1 -1
  10. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationGraphic.js +1 -1
  11. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationGraphic.js.map +1 -1
  12. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationInfo.js +1 -1
  13. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationInfo.js.map +1 -1
  14. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationPrivacyPolicy.d.ts +1 -0
  15. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationPrivacyPolicy.js +29 -0
  16. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationPrivacyPolicy.js.map +1 -0
  17. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationUserForm.d.ts +1 -0
  18. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationUserForm.js +201 -0
  19. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationUserForm.js.map +1 -0
  20. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationVipBenefitRows.js +1 -1
  21. package/build/esm/components/FollowerAuthenticationDialog/FollowerAuthenticationVipBenefitRows.js.map +1 -1
  22. package/build/esm/components/FollowerAuthenticationDialog/phoneValidation.d.ts +2 -0
  23. package/build/esm/components/FollowerAuthenticationDialog/phoneValidation.js +32 -0
  24. package/build/esm/components/FollowerAuthenticationDialog/phoneValidation.js.map +1 -0
  25. package/package.json +2 -2
@@ -1,5 +1,14 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { IconProps } from '../Icon/IconProps';
3
+ export type SignUpFieldSetting = {
4
+ enabled?: boolean;
5
+ required?: boolean;
6
+ };
7
+ export type SignUpSetting = {
8
+ phone?: SignUpFieldSetting;
9
+ birthday?: SignUpFieldSetting;
10
+ weddingAnniversary?: SignUpFieldSetting;
11
+ };
3
12
  export type FollowerAuthenticationDialogProps = {
4
13
  open: boolean;
5
14
  state: ReducerState;
@@ -20,6 +29,7 @@ export type FollowerAuthenticationDialogProps = {
20
29
  vipBenefitRows?: FollowerAuthenticationVipBenefitRow[];
21
30
  showSubscribeEmail?: boolean;
22
31
  showSubscribeSms?: boolean;
32
+ signUpSetting?: SignUpSetting;
23
33
  onActionButtonClick: (eventType: ClickEventType, values?: Record<string, string>) => void;
24
34
  };
25
35
  export type ReducerState = {
@@ -28,11 +38,16 @@ export type ReducerState = {
28
38
  email?: string;
29
39
  phone?: string;
30
40
  name?: string;
41
+ favoriteLocationId?: number;
42
+ birthMonth?: number;
43
+ birthDay?: number;
44
+ weddingMonth?: number;
45
+ weddingDay?: number;
31
46
  };
32
47
  };
33
- export type ReducerStateValue = 'initial' | 'signUp' | 'emailFound' | 'indirectUserFound' | 'emailAuthCode' | 'emailMagicLinkSent' | 'emailPasswordSignIn' | 'phoneFound' | 'phoneAuthCode' | 'phonePasswordSignIn' | 'welcome' | 'requirePhone';
48
+ export type ReducerStateValue = 'initial' | 'signUp' | 'emailFound' | 'indirectUserFound' | 'emailAuthCode' | 'emailMagicLinkSent' | 'emailPasswordSignIn' | 'phoneFound' | 'phoneAuthCode' | 'phonePasswordSignIn' | 'welcome' | 'requirePhone' | 'completeProfile';
34
49
  export type ClickEventType = 'submit-form' | 'click-close' | 'code-sent' | 'request-auth-code-email' | 'request-auth-code-sms' | 'close' | 'use-different-account' | 'sign-in-with-password' | 'sign-in-with-facebook' | 'sign-in-with-google' | 'sign-in-with-apple' | 'open-terms-of-service' | 'open-privacy-policy';
35
- export type MessageKey = `${ReducerStateValue}Title` | `${ReducerStateValue}Info` | 'requirePhoneInputLabel' | 'requirePhoneCtaButtonLabel' | 'indirectUserFoundLabel' | 'indirectUserFoundCtaButtonLabel' | 'indirectUserFoundCtaButtonLabelAlt' | 'signUpPhoneErrorText' | 'signUpPhoneInputLabel' | 'signUpNameInputLabel' | 'signUpEmailErrorText' | 'signUpEmailInputLabel' | 'signUpLocationErrorText' | 'signUpLocationInputLabel' | 'signUpBirthdaySectionLabel' | 'signUpMonthInputLabel' | 'signUpDayInputLabel' | 'signUp' | 'signUpFinePrint' | 'emailFoundInputLabel' | 'emailFoundCtaButtonLabel' | 'phoneFoundInputLabel' | 'phoneFoundCtaButtonLabel' | 'emailAuthCodeInputLabel' | 'emailMagicLinkSentCtaButtonLabel' | 'phoneAuthCodeInputLabel' | 'resendAuthCode' | 'or' | 'popmenuLogoAlt' | 'continueWithFacebookButtonLabel' | 'continueWithGoogleButtonLabel' | 'continueWithAppleButtonLabel' | 'initialCtaButtonLabel' | 'initialInputLabel' | 'passwordInputLabel' | 'poweredBy' | 'done' | 'signIn' | 'signInWithPassword' | 'termsOfServiceButtonLabel' | 'subscribeEmailCheckboxLabel' | 'subscribeSmsCheckboxLabel' | 'privacyPolicyText' | 'privacyPolicyButtonLabel';
50
+ export type MessageKey = `${ReducerStateValue}Title` | `${ReducerStateValue}Info` | 'requirePhoneInputLabel' | 'requirePhoneCtaButtonLabel' | 'indirectUserFoundLabel' | 'indirectUserFoundCtaButtonLabel' | 'indirectUserFoundCtaButtonLabelAlt' | 'signUpPhoneErrorText' | 'signUpPhoneInputLabel' | 'signUpNameInputLabel' | 'signUpNameErrorText' | 'signUpEmailErrorText' | 'signUpEmailInputLabel' | 'signUpLocationErrorText' | 'signUpLocationInputLabel' | 'signUpBirthdaySectionLabel' | 'signUpMonthInputLabel' | 'signUpMonthJanuary' | 'signUpMonthFebruary' | 'signUpMonthMarch' | 'signUpMonthApril' | 'signUpMonthMay' | 'signUpMonthJune' | 'signUpMonthJuly' | 'signUpMonthAugust' | 'signUpMonthSeptember' | 'signUpMonthOctober' | 'signUpMonthNovember' | 'signUpMonthDecember' | 'signUpDayInputLabel' | 'signUpWeddingAnniversarySectionLabel' | 'signUp' | 'signUpFinePrint' | 'emailFoundInputLabel' | 'emailFoundCtaButtonLabel' | 'phoneFoundInputLabel' | 'phoneFoundCtaButtonLabel' | 'emailAuthCodeInputLabel' | 'emailMagicLinkSentCtaButtonLabel' | 'phoneAuthCodeInputLabel' | 'resendAuthCode' | 'or' | 'popmenuLogoAlt' | 'continueWithFacebookButtonLabel' | 'continueWithGoogleButtonLabel' | 'continueWithAppleButtonLabel' | 'initialCtaButtonLabel' | 'initialInputLabel' | 'passwordInputLabel' | 'poweredBy' | 'done' | 'signIn' | 'signInWithPassword' | 'termsOfServiceButtonLabel' | 'subscribeEmailCheckboxLabel' | 'subscribeSmsCheckboxLabel' | 'privacyPolicyText' | 'privacyPolicyButtonLabel' | 'completeProfileCtaButtonLabel';
36
51
  type LocationOption = {
37
52
  label: string;
38
53
  value: string;
@@ -0,0 +1 @@
1
+ export declare const FollowerAuthenticationPrivacyPolicy: () => JSX.Element | null;
@@ -0,0 +1 @@
1
+ export declare const FollowerAuthenticationUserForm: () => JSX.Element;
@@ -0,0 +1,2 @@
1
+ export declare const validatePhoneNumber: (phone: string) => boolean;
2
+ export declare const formatPhoneNumber: (value: string) => string;
@@ -426,7 +426,7 @@ var SemanticColors;
426
426
  SemanticColors["SECONDARY_DARK"] = "secondary.dark";
427
427
  SemanticColors["SECONDARY_LIGHT"] = "secondary.light";
428
428
  })(SemanticColors || (SemanticColors = {}));
429
- const useStyles$7 = core.makeStyles((theme) => ({
429
+ const useStyles$9 = core.makeStyles((theme) => ({
430
430
  dividerRoot: {
431
431
  gap: theme.spacing(2),
432
432
  },
@@ -463,7 +463,7 @@ const useStyles$7 = core.makeStyles((theme) => ({
463
463
  },
464
464
  }));
465
465
  const Divider = ({ TypographyProps, className, dividerColor, text, textColor, textTransform = 'lowercase', }) => {
466
- const classes = useStyles$7({ dividerColor, textColor, textTransform });
466
+ const classes = useStyles$9({ dividerColor, textColor, textTransform });
467
467
  const casingOffset = textTransform === 'lowercase' ? '.25rem' : 'unset';
468
468
  return (React.createElement(core.Box, { className: classNames([classes.dividerRoot, className]), display: "flex", alignItems: "center" },
469
469
  React.createElement(core.Box, { className: classes.dividerLine, display: "flex", flexGrow: 1, height: "1px", marginTop: casingOffset }),
@@ -483,7 +483,252 @@ const useFollowerAuthenticationDialogContext = () => {
483
483
  return context;
484
484
  };
485
485
 
486
- const useStyles$6 = core.makeStyles((theme) => ({
486
+ const northAmericanPhoneRegex = /^(\+?1[\s.-]?)?(\([2-9]\d{2}\)|[2-9]\d{2})[-\s.]?[2-9]\d{2}[-\s.]?\d{4}$/;
487
+ const ukPhoneRegex = /^((\+?44\s?|0044\s?)(\s?\d{3,5}|\(\d{3,5}\))(\s?\d{3,4})(\s?\d{3,4})$|^07\d{3}\s?\d{6}$)/;
488
+ const validatePhoneNumber = (phone) => {
489
+ if (!phone)
490
+ return false;
491
+ return northAmericanPhoneRegex.test(phone) || ukPhoneRegex.test(phone);
492
+ };
493
+ const formatPatterns = [
494
+ { pattern: /^(1)([2-9]\d{2})(\d{3})(\d{4})$/, format: '+{1} ({2}) {3}-{4}', international: true },
495
+ { pattern: /^([2-9]\d{2})(\d{3})(\d{4})$/, format: '({1}) {2}-{3}', international: false },
496
+ { pattern: /^(44)(\d{4})(\d{6})$/, format: '+{1} {2} {3}', international: true },
497
+ { pattern: /^(07\d{3})(\d{6})$/, format: '{1} {2}', international: false },
498
+ ];
499
+ const formatPhoneNumber = (value) => {
500
+ if (!value)
501
+ return '';
502
+ const isInternational = value.startsWith('+');
503
+ const digits = value.replace(/\D/g, '');
504
+ if (!digits)
505
+ return isInternational ? '+' : '';
506
+ for (const { pattern, format, international } of formatPatterns) {
507
+ if (isInternational && !international)
508
+ continue;
509
+ const m = digits.match(pattern);
510
+ if (m)
511
+ return m.slice(1).reduce((result, match, i) => result.replace(`{${i + 1}}`, match), format);
512
+ }
513
+ return isInternational ? `+${digits}` : digits;
514
+ };
515
+
516
+ const useStyles$8 = core.makeStyles((theme) => ({
517
+ button: {
518
+ fontSize: '0.75rem',
519
+ margin: theme.spacing(0, 0.5),
520
+ padding: 0,
521
+ textDecoration: 'underline',
522
+ width: 'auto',
523
+ },
524
+ text: {
525
+ fontSize: '0.75rem',
526
+ textAlign: 'center',
527
+ },
528
+ }));
529
+ const FollowerAuthenticationPrivacyPolicy = () => {
530
+ const classes = useStyles$8();
531
+ const { messages, onActionButtonClick, showV2 } = useFollowerAuthenticationDialogContext();
532
+ if (!showV2 || !messages.privacyPolicyText)
533
+ return null;
534
+ return (React.createElement(core.Typography, { className: classes.text },
535
+ messages.privacyPolicyText,
536
+ React.createElement(core.Button, { className: classes.button, onClick: () => onActionButtonClick('open-privacy-policy'), variant: "text" }, messages.privacyPolicyButtonLabel)));
537
+ };
538
+
539
+ const getDaysInMonth = (month) => {
540
+ const m = parseInt(month, 10);
541
+ if (!m)
542
+ return 31;
543
+ // Allow 29 for Feb to support leap year birthdays/anniversaries
544
+ const days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
545
+ return days[m - 1];
546
+ };
547
+ const useStyles$7 = core.makeStyles((theme) => ({
548
+ form: {
549
+ alignItems: 'center',
550
+ display: 'flex',
551
+ flexDirection: 'column',
552
+ gridGap: 16,
553
+ width: '100%',
554
+ },
555
+ sectionLabel: {
556
+ alignSelf: 'start',
557
+ fontSize: '0.75rem',
558
+ },
559
+ divider: {
560
+ width: '100%',
561
+ },
562
+ pickerContainer: {
563
+ display: 'flex',
564
+ flexDirection: 'column',
565
+ gridGap: theme.spacing(1),
566
+ width: '100%',
567
+ },
568
+ pickerFieldsRow: {
569
+ display: 'flex',
570
+ gridGap: theme.spacing(2),
571
+ width: '100%',
572
+ },
573
+ pickerField: {
574
+ flex: 1,
575
+ },
576
+ }));
577
+ const MonthDayPicker = ({ sectionLabel, monthLabel, dayLabel, monthId, dayId, monthName, dayName, monthValue, dayValue, onMonthChange, onDayChange, required, disabled, monthOptions, }) => {
578
+ const classes = useStyles$7();
579
+ const dayOptions = React.useMemo(() => Array.from({ length: getDaysInMonth(monthValue) }, (_, i) => ({ label: String(i + 1), value: String(i + 1) })), [monthValue]);
580
+ return (React.createElement(core.Box, { className: classes.pickerContainer },
581
+ React.createElement(core.Typography, { className: classes.sectionLabel }, sectionLabel),
582
+ React.createElement(core.Box, { className: classes.pickerFieldsRow },
583
+ React.createElement(core.TextField, { disabled: disabled, select: true, label: monthLabel, id: monthId, name: monthName, value: monthValue, onChange: (e) => {
584
+ const newMonth = e.target.value;
585
+ onMonthChange(newMonth);
586
+ if (dayValue && parseInt(dayValue, 10) > getDaysInMonth(newMonth)) {
587
+ onDayChange('');
588
+ }
589
+ }, required: required || Boolean(dayValue), className: classes.pickerField }, monthOptions.map((option) => (React.createElement(core.MenuItem, { key: option.value, value: option.value }, option.label)))),
590
+ React.createElement(core.TextField, { disabled: disabled, select: true, label: dayLabel, id: dayId, name: dayName, value: dayValue, onChange: (e) => onDayChange(e.target.value), required: required || Boolean(monthValue), className: classes.pickerField }, dayOptions.map((option) => (React.createElement(core.MenuItem, { key: option.value, value: option.value }, option.label)))))));
591
+ };
592
+ const FollowerAuthenticationUserForm = () => {
593
+ const { state, messages, locationOptions, onActionButtonClick, loading, signUpSetting } = useFollowerAuthenticationDialogContext();
594
+ const showPhone = signUpSetting?.phone?.enabled !== false;
595
+ const phoneRequired = signUpSetting?.phone?.required ?? false;
596
+ const showBirthday = signUpSetting?.birthday?.enabled !== false;
597
+ const birthdayRequired = signUpSetting?.birthday?.required ?? false;
598
+ const showWeddingAnniversary = signUpSetting?.weddingAnniversary?.enabled !== false;
599
+ const weddingAnniversaryRequired = signUpSetting?.weddingAnniversary?.required ?? false;
600
+ const classes = useStyles$7();
601
+ const formRef = React.useRef(null);
602
+ const [showNameErrorText, setShowNameErrorText] = React.useState(false);
603
+ const [showEmailErrorText, setShowEmailErrorText] = React.useState(false);
604
+ const [showPhoneErrorText, setShowPhoneErrorText] = React.useState(false);
605
+ const [showLocationErrorText, setShowLocationErrorText] = React.useState(false);
606
+ const [nameValue, setNameValue] = React.useState(state.context.name || '');
607
+ const [emailValue, setEmailValue] = React.useState(state.context.email || '');
608
+ const [phoneValue, setPhoneValue] = React.useState(formatPhoneNumber(state.context.phone || ''));
609
+ const [locationValue, setLocationValue] = React.useState(state.context.favoriteLocationId ? String(state.context.favoriteLocationId) : '');
610
+ const [selectedBirthMonth, setSelectedBirthMonth] = React.useState(state.context.birthMonth ? String(state.context.birthMonth) : '');
611
+ const [selectedBirthDay, setSelectedBirthDay] = React.useState(state.context.birthDay ? String(state.context.birthDay) : '');
612
+ const [selectedWeddingMonth, setSelectedWeddingMonth] = React.useState(state.context.weddingMonth ? String(state.context.weddingMonth) : '');
613
+ const [selectedWeddingDay, setSelectedWeddingDay] = React.useState(state.context.weddingDay ? String(state.context.weddingDay) : '');
614
+ const checkFieldValidity = (e) => {
615
+ const fieldName = e.target.name;
616
+ const fieldValue = e.target.value;
617
+ switch (fieldName) {
618
+ case 'name': {
619
+ setNameValue(fieldValue);
620
+ setShowNameErrorText(fieldValue.length === 0);
621
+ break;
622
+ }
623
+ case 'email': {
624
+ const emailField = formRef.current?.elements.namedItem(fieldName);
625
+ const isEmailValid = emailField?.validity.valid ?? false;
626
+ setEmailValue(fieldValue);
627
+ setShowEmailErrorText(!isEmailValid && fieldValue.length > 0);
628
+ break;
629
+ }
630
+ case 'phone': {
631
+ const formatted = formatPhoneNumber(fieldValue);
632
+ setPhoneValue(formatted);
633
+ setShowPhoneErrorText(formatted.length > 0 && !validatePhoneNumber(formatted));
634
+ break;
635
+ }
636
+ case 'location': {
637
+ setLocationValue(fieldValue);
638
+ setShowLocationErrorText(!fieldValue);
639
+ break;
640
+ }
641
+ }
642
+ };
643
+ const isFormValid = React.useMemo(() => {
644
+ const hasValidName = Boolean(nameValue) && !showNameErrorText;
645
+ const hasValidEmail = Boolean(emailValue) && !showEmailErrorText;
646
+ const hasValidPhone = showPhone
647
+ ? state.context.phone
648
+ ? true
649
+ : phoneRequired
650
+ ? validatePhoneNumber(phoneValue)
651
+ : !phoneValue || validatePhoneNumber(phoneValue)
652
+ : true;
653
+ const hasValidLocation = locationOptions.length > 0 ? Boolean(locationValue) : true;
654
+ // A partial date (only month or only day) requires completing the pair
655
+ const hasValidBirthday = !showBirthday ||
656
+ (birthdayRequired || selectedBirthMonth || selectedBirthDay
657
+ ? Boolean(selectedBirthMonth) && Boolean(selectedBirthDay)
658
+ : true);
659
+ const hasValidWeddingAnniversary = !showWeddingAnniversary ||
660
+ (weddingAnniversaryRequired || selectedWeddingMonth || selectedWeddingDay
661
+ ? Boolean(selectedWeddingMonth) && Boolean(selectedWeddingDay)
662
+ : true);
663
+ return (hasValidName &&
664
+ hasValidEmail &&
665
+ hasValidPhone &&
666
+ hasValidLocation &&
667
+ hasValidBirthday &&
668
+ hasValidWeddingAnniversary);
669
+ }, [
670
+ nameValue,
671
+ emailValue,
672
+ phoneValue,
673
+ state.context.phone,
674
+ locationValue,
675
+ locationOptions.length,
676
+ showNameErrorText,
677
+ showEmailErrorText,
678
+ showPhone,
679
+ phoneRequired,
680
+ showBirthday,
681
+ birthdayRequired,
682
+ selectedBirthMonth,
683
+ selectedBirthDay,
684
+ showWeddingAnniversary,
685
+ weddingAnniversaryRequired,
686
+ selectedWeddingMonth,
687
+ selectedWeddingDay,
688
+ ]);
689
+ const monthOptions = React.useMemo(() => [
690
+ { label: messages.signUpMonthJanuary, value: '1' },
691
+ { label: messages.signUpMonthFebruary, value: '2' },
692
+ { label: messages.signUpMonthMarch, value: '3' },
693
+ { label: messages.signUpMonthApril, value: '4' },
694
+ { label: messages.signUpMonthMay, value: '5' },
695
+ { label: messages.signUpMonthJune, value: '6' },
696
+ { label: messages.signUpMonthJuly, value: '7' },
697
+ { label: messages.signUpMonthAugust, value: '8' },
698
+ { label: messages.signUpMonthSeptember, value: '9' },
699
+ { label: messages.signUpMonthOctober, value: '10' },
700
+ { label: messages.signUpMonthNovember, value: '11' },
701
+ { label: messages.signUpMonthDecember, value: '12' },
702
+ ], [messages]);
703
+ const handleSubmit = (e) => {
704
+ e.preventDefault();
705
+ const formData = new FormData(e.target);
706
+ const values = Object.fromEntries(formData.entries());
707
+ // Disabled fields are excluded from FormData — restore pre-filled values from context
708
+ if (state.context.email && !values.email)
709
+ values.email = state.context.email;
710
+ if (state.context.phone && !values.phone)
711
+ values.phone = state.context.phone;
712
+ // Strip display formatting so the submitted value is consistent with the disabled-field path
713
+ if (values.phone) {
714
+ values.phone = values.phone.replace(/[^\d+]/g, '');
715
+ }
716
+ onActionButtonClick('submit-form', values);
717
+ };
718
+ return (React.createElement("form", { ref: formRef, id: "follower-authentication-user-form", className: classes.form, onSubmit: handleSubmit, onInvalid: (e) => e.preventDefault() },
719
+ React.createElement(core.TextField, { disabled: loading || Boolean(state.context.email), label: messages.signUpEmailInputLabel, id: "email-input", name: "email", onChange: checkFieldValidity, error: showEmailErrorText, helperText: showEmailErrorText && messages.signUpEmailErrorText, inputProps: { type: 'email', required: true }, value: emailValue, fullWidth: true }),
720
+ React.createElement(Divider, { className: classes.divider }),
721
+ React.createElement(core.TextField, { disabled: loading, label: messages.signUpNameInputLabel, id: "name-input", name: "name", onChange: checkFieldValidity, error: showNameErrorText, helperText: showNameErrorText && messages.signUpNameErrorText, inputProps: { required: true }, value: nameValue, fullWidth: true }),
722
+ showPhone && (React.createElement(core.TextField, { disabled: loading || Boolean(state.context.phone), label: messages.signUpPhoneInputLabel, id: "phone-input", name: "phone", onChange: checkFieldValidity, error: showPhoneErrorText, helperText: showPhoneErrorText && messages.signUpPhoneErrorText, inputProps: { required: phoneRequired }, value: phoneValue, fullWidth: true })),
723
+ locationOptions.length > 0 && (React.createElement(core.TextField, { disabled: loading, select: true, onChange: checkFieldValidity, label: messages.signUpLocationInputLabel, error: showLocationErrorText, helperText: showLocationErrorText && messages.signUpLocationErrorText, id: "location-input", name: "location", value: locationValue, fullWidth: true }, locationOptions.map((option) => (React.createElement(core.MenuItem, { "data-cy": "option", key: option.value, value: option.value }, option.label))))),
724
+ (showBirthday || showWeddingAnniversary) && React.createElement(Divider, { className: classes.divider }),
725
+ showBirthday && (React.createElement(MonthDayPicker, { sectionLabel: messages.signUpBirthdaySectionLabel, monthLabel: messages.signUpMonthInputLabel, dayLabel: messages.signUpDayInputLabel, monthId: "birthday-month-input", dayId: "birthday-date-input", monthName: "birthMonth", dayName: "birthDay", monthValue: selectedBirthMonth, dayValue: selectedBirthDay, onMonthChange: setSelectedBirthMonth, onDayChange: setSelectedBirthDay, required: birthdayRequired, disabled: loading, monthOptions: monthOptions })),
726
+ showWeddingAnniversary && (React.createElement(MonthDayPicker, { sectionLabel: messages.signUpWeddingAnniversarySectionLabel, monthLabel: messages.signUpMonthInputLabel, dayLabel: messages.signUpDayInputLabel, monthId: "wedding-month-input", dayId: "wedding-date-input", monthName: "weddingMonth", dayName: "weddingDay", monthValue: selectedWeddingMonth, dayValue: selectedWeddingDay, onMonthChange: setSelectedWeddingMonth, onDayChange: setSelectedWeddingDay, required: weddingAnniversaryRequired, disabled: loading, monthOptions: monthOptions })),
727
+ React.createElement(FollowerAuthenticationPrivacyPolicy, null),
728
+ React.createElement(core.Button, { disabled: loading || !isFormValid, type: "submit" }, messages.completeProfileCtaButtonLabel)));
729
+ };
730
+
731
+ const useStyles$6 = core.makeStyles({
487
732
  checkboxLabel: {
488
733
  '& > a': {
489
734
  textDecoration: 'underline',
@@ -501,18 +746,7 @@ const useStyles$6 = core.makeStyles((theme) => ({
501
746
  alignSelf: 'start',
502
747
  fontSize: '0.85rem',
503
748
  },
504
- privacyPolicyButton: {
505
- fontSize: '0.75rem',
506
- margin: theme.spacing(0, 0.5),
507
- padding: 0,
508
- textDecoration: 'underline',
509
- width: 'auto',
510
- },
511
- privacyPolicyText: {
512
- fontSize: '0.75rem',
513
- textAlign: 'center',
514
- },
515
- }));
749
+ });
516
750
  function LocationAndBirthday({ checkFieldValidity, classes, loading, locationOptions, messages, showLocationErrorText, showV2, }) {
517
751
  const locationSelect = (React.createElement(core.TextField, { disabled: loading, select: true, onChange: checkFieldValidity, label: messages.signUpLocationInputLabel, error: showLocationErrorText, helperText: showLocationErrorText && messages.signUpLocationErrorText, id: "location-input", inputProps: { required: true }, name: "location" }, locationOptions.map((locationOption) => (React.createElement(core.MenuItem, { "data-cy": 'option', key: locationOption.value, value: locationOption.value }, locationOption.label)))));
518
752
  if (showV2) {
@@ -530,13 +764,6 @@ function LocationAndBirthday({ checkFieldValidity, classes, loading, locationOpt
530
764
  React.createElement(core.TextField, { disabled: loading, label: messages.signUpMonthInputLabel, id: "birthday-month-input", name: "birthdayMonth" }),
531
765
  React.createElement(core.TextField, { disabled: loading, label: messages.signUpDayInputLabel, id: "birthday-date-input", name: "birthdayDate" })));
532
766
  }
533
- const northAmericanPhoneRegex = /^(\()?[2-9]{1}\d{2}(\))?[-\s.]?[2-9]{1}\d{2}[-\s.]?\d{4}$/;
534
- const ukPhoneRegex = /^((\+?44\s?|0044\s?)(\s?\d{3,5}|\(\d{3,5}\))(\s?\d{3,4})(\s?\d{3,4})$|^07\d{9}$)/;
535
- const validatePhoneNumber = (phone) => {
536
- if (!phone)
537
- return false;
538
- return northAmericanPhoneRegex.test(phone) || ukPhoneRegex.test(phone);
539
- };
540
767
  const FollowerAuthenticationForm = () => {
541
768
  const { state, messages, locationOptions, onActionButtonClick, loading, showV2, showSubscribeEmail, showSubscribeSms, } = useFollowerAuthenticationDialogContext();
542
769
  const classes = useStyles$6();
@@ -623,6 +850,7 @@ const FollowerAuthenticationForm = () => {
623
850
  onActionButtonClick('submit-form', values);
624
851
  };
625
852
  const formProps = {
853
+ key: state.value,
626
854
  id: 'follower-authentication-form',
627
855
  className: classes.form,
628
856
  onSubmit: handleSubmit,
@@ -630,17 +858,17 @@ const FollowerAuthenticationForm = () => {
630
858
  switch (state.value) {
631
859
  case 'initial':
632
860
  return (React.createElement("form", { ...formProps },
633
- React.createElement(core.TextField, { disabled: loading, label: messages.initialInputLabel, key: "identifier-input", id: "identifier-input", name: "identifier" }),
861
+ React.createElement(core.TextField, { disabled: loading, label: messages.initialInputLabel, id: "identifier-input", name: "identifier" }),
634
862
  React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.initialCtaButtonLabel)));
635
863
  case 'signUp':
636
864
  return (React.createElement("form", { ref: formRef, ...formProps, onInvalid: (e) => {
637
865
  e.preventDefault();
638
866
  } },
639
- React.createElement(core.TextField, { disabled: loading, label: messages.signUpPhoneInputLabel, key: "phone-input", id: "phone-input", name: "phone", onChange: checkFieldValidity, error: showPhoneErrorText, helperText: showPhoneErrorText && messages.signUpPhoneErrorText, inputProps: {
867
+ React.createElement(core.TextField, { disabled: loading, label: messages.signUpPhoneInputLabel, id: "phone-input", name: "phone", onChange: checkFieldValidity, error: showPhoneErrorText, helperText: showPhoneErrorText && messages.signUpPhoneErrorText, inputProps: {
640
868
  required: showV2 || !signUpEmailValue,
641
869
  }, defaultValue: state.context.phone }),
642
- React.createElement(core.TextField, { disabled: loading, label: messages.signUpNameInputLabel, key: "name-input", id: "name-input", name: "name", onChange: checkFieldValidity, error: showNameErrorText, inputProps: { required: true }, defaultValue: state.context.name }),
643
- React.createElement(core.TextField, { disabled: loading, label: messages.signUpEmailInputLabel, key: "email-input", id: "email-input", name: "email", error: showEmailErrorText, helperText: showEmailErrorText && messages.signUpEmailErrorText, onChange: checkFieldValidity, inputProps: {
870
+ React.createElement(core.TextField, { disabled: loading, label: messages.signUpNameInputLabel, id: "name-input", name: "name", onChange: checkFieldValidity, error: showNameErrorText, inputProps: { required: true }, defaultValue: state.context.name }),
871
+ React.createElement(core.TextField, { disabled: loading, label: messages.signUpEmailInputLabel, id: "email-input", name: "email", error: showEmailErrorText, helperText: showEmailErrorText && messages.signUpEmailErrorText, onChange: checkFieldValidity, inputProps: {
644
872
  required: showV2 || !signUpPhoneValue,
645
873
  type: 'email',
646
874
  }, defaultValue: state.context.email }),
@@ -648,58 +876,53 @@ const FollowerAuthenticationForm = () => {
648
876
  React.createElement(core.Box, { display: "flex", flexDirection: "column", alignItems: "flex-start", gridGap: 2, width: "100%" },
649
877
  showSubscribeEmail && (React.createElement(core.FormControlLabel, { style: { alignItems: 'flex-start' }, control: React.createElement(core.Checkbox, { id: "subscribe-email", name: "subscribeEmail", disabled: loading, color: "primary" }), label: React.createElement(core.Typography, { className: classes.checkboxLabel }, messages.subscribeEmailCheckboxLabel) })),
650
878
  showSubscribeSms && (React.createElement(core.FormControlLabel, { style: { alignItems: 'flex-start' }, control: React.createElement(core.Checkbox, { id: "subscribe-sms", name: "subscribeSms", disabled: loading, color: "primary" }), label: React.createElement(core.Typography, { className: classes.checkboxLabel }, messages.subscribeSmsCheckboxLabel) }))),
651
- showV2 && messages.privacyPolicyText && (React.createElement(core.Typography, { className: classes.privacyPolicyText },
652
- messages.privacyPolicyText,
653
- React.createElement(core.Button, { className: classes.privacyPolicyButton, onClick: () => onActionButtonClick('open-privacy-policy'), variant: "text" }, messages.privacyPolicyButtonLabel))),
879
+ React.createElement(FollowerAuthenticationPrivacyPolicy, null),
654
880
  React.createElement(core.Button, { disabled: loading || !formValidity, type: "submit" }, messages.signUp)));
655
881
  case 'emailFound':
656
882
  return (React.createElement("form", { ...formProps },
657
- React.createElement(core.TextField, { disabled: loading, label: messages.emailFoundInputLabel, key: "email-input", id: "email-input", name: "email", value: state.context.email }),
883
+ React.createElement(core.TextField, { disabled: loading, label: messages.emailFoundInputLabel, id: "email-input", name: "email", value: state.context.email }),
658
884
  React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.emailFoundCtaButtonLabel)));
659
885
  case 'emailAuthCode':
660
886
  return (React.createElement("form", { ...formProps },
661
- React.createElement(core.TextField, { disabled: loading, label: messages.emailAuthCodeInputLabel, key: "code-input", id: "code-input", name: "code" }),
887
+ React.createElement(core.TextField, { disabled: loading, label: messages.emailAuthCodeInputLabel, id: "code-input", name: "code" }),
662
888
  React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.signIn)));
663
889
  case 'emailMagicLinkSent':
664
890
  return (React.createElement(core.Button, { disabled: loading, onClick: () => {
665
891
  onActionButtonClick('close');
666
892
  } }, messages.emailMagicLinkSentCtaButtonLabel));
667
893
  case 'indirectUserFound': {
668
- if (state.context.email) {
669
- return (React.createElement("form", { ...formProps },
670
- React.createElement(core.TextField, { disabled: loading, label: messages.emailFoundInputLabel, key: "email-input", id: "email-input", name: "email", value: state.context.email }),
671
- React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.indirectUserFoundCtaButtonLabel)));
672
- }
673
- else if (state.context.phone) {
674
- return (React.createElement("form", { ...formProps },
675
- React.createElement(core.TextField, { disabled: loading, label: messages.phoneFoundInputLabel, key: "phone-input", id: "phone-input", name: "phone", value: state.context.phone }),
676
- React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.indirectUserFoundCtaButtonLabel)));
677
- }
678
- else
894
+ const isEmail = Boolean(state.context.email);
895
+ const isPhone = Boolean(state.context.phone);
896
+ if (!isEmail && !isPhone)
679
897
  return null;
898
+ return (React.createElement("form", { ...formProps },
899
+ React.createElement(core.TextField, { disabled: loading, label: isEmail ? messages.emailFoundInputLabel : messages.phoneFoundInputLabel, id: isEmail ? 'email-input' : 'phone-input', name: isEmail ? 'email' : 'phone', value: isEmail ? state.context.email : state.context.phone }),
900
+ React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.indirectUserFoundCtaButtonLabel)));
680
901
  }
681
902
  case 'emailPasswordSignIn':
682
903
  return (React.createElement("form", { ...formProps },
683
- React.createElement(core.TextField, { disabled: loading, label: messages.emailFoundInputLabel, key: "email-input", id: "email-input", name: "email", value: state.context.email, InputLabelProps: { shrink: true } }),
684
- React.createElement(core.TextField, { disabled: loading, label: messages.passwordInputLabel, key: "password-input", id: "password-input", name: "password", inputProps: { type: 'password' } }),
904
+ React.createElement(core.TextField, { disabled: loading, label: messages.emailFoundInputLabel, id: "email-input", name: "email", value: state.context.email, InputLabelProps: { shrink: true } }),
905
+ React.createElement(core.TextField, { disabled: loading, label: messages.passwordInputLabel, id: "password-input", name: "password", inputProps: { type: 'password' } }),
685
906
  React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.signIn)));
686
907
  case 'phoneFound':
687
908
  return (React.createElement("form", { ...formProps },
688
- React.createElement(core.TextField, { disabled: loading, label: messages.phoneFoundInputLabel, key: "phone-input", id: "phone-input", name: "phone", value: state.context.phone }),
909
+ React.createElement(core.TextField, { disabled: loading, label: messages.phoneFoundInputLabel, id: "phone-input", name: "phone", value: state.context.phone }),
689
910
  React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.phoneFoundCtaButtonLabel)));
690
911
  case 'phoneAuthCode':
691
912
  return (React.createElement("form", { ...formProps },
692
- React.createElement(core.TextField, { disabled: loading, label: messages.phoneAuthCodeInputLabel, key: "code-input", id: "code-input", name: "code", autoComplete: "one-time-code" }),
913
+ React.createElement(core.TextField, { disabled: loading, label: messages.phoneAuthCodeInputLabel, id: "code-input", name: "code", autoComplete: "one-time-code" }),
693
914
  React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.signIn)));
694
915
  case 'phonePasswordSignIn':
695
916
  return (React.createElement("form", { ...formProps },
696
- React.createElement(core.TextField, { disabled: loading, label: messages.phoneFoundInputLabel, key: "phone-input", id: "phone-input", name: "phone", value: state.context.phone, InputLabelProps: { shrink: true } }),
697
- React.createElement(core.TextField, { disabled: loading, label: messages.passwordInputLabel, key: "password-input", id: "password-input", name: "password", inputProps: { type: 'password' } }),
917
+ React.createElement(core.TextField, { disabled: loading, label: messages.phoneFoundInputLabel, id: "phone-input", name: "phone", value: state.context.phone, InputLabelProps: { shrink: true } }),
918
+ React.createElement(core.TextField, { disabled: loading, label: messages.passwordInputLabel, id: "password-input", name: "password", inputProps: { type: 'password' } }),
698
919
  React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.signIn)));
699
920
  case 'requirePhone':
700
921
  return (React.createElement("form", { ...formProps },
701
- React.createElement(core.TextField, { disabled: loading, label: messages.requirePhoneInputLabel, key: "phone-input", id: "phone-input", name: "phone", value: state.context.phone }),
922
+ React.createElement(core.TextField, { disabled: loading, label: messages.requirePhoneInputLabel, id: "phone-input", name: "phone", value: state.context.phone }),
702
923
  React.createElement(core.Button, { disabled: loading, type: "submit" }, messages.requirePhoneCtaButtonLabel)));
924
+ case 'completeProfile':
925
+ return React.createElement(FollowerAuthenticationUserForm, null);
703
926
  case 'welcome':
704
927
  return null;
705
928
  default:
@@ -858,7 +1081,7 @@ const FollowerAuthenticationFooter = () => {
858
1081
 
859
1082
  const FollowerAuthenticationGraphic = () => {
860
1083
  const { state, graphics, showV2 } = useFollowerAuthenticationDialogContext();
861
- if (showV2 && state.value === 'signUp')
1084
+ if (showV2 && (state.value === 'signUp' || state.value === 'completeProfile'))
862
1085
  return null;
863
1086
  const graphic = graphics[state.value];
864
1087
  if (!graphic)
@@ -869,7 +1092,7 @@ const FollowerAuthenticationGraphic = () => {
869
1092
 
870
1093
  const FollowerAuthenticationInfo = () => {
871
1094
  const { state, messages, showV2 } = useFollowerAuthenticationDialogContext();
872
- if (showV2 && state.value === 'signUp')
1095
+ if (showV2 && (state.value === 'signUp' || state.value === 'completeProfile'))
873
1096
  return null;
874
1097
  const info = messages[`${state.value}Info`];
875
1098
  const last4Digits = state.context.phone?.slice(-4);
@@ -930,7 +1153,7 @@ const useStyles$1 = core.makeStyles((theme) => ({
930
1153
  const FollowerAuthenticationVipBenefitRows = () => {
931
1154
  const classes = useStyles$1();
932
1155
  const { vipBenefitRows, showV2, state } = useFollowerAuthenticationDialogContext();
933
- const isInitialOrSignUpState = state.value === 'initial' || state.value === 'signUp';
1156
+ const isInitialOrSignUpState = state.value === 'initial' || state.value === 'signUp' || state.value === 'completeProfile';
934
1157
  if (!showV2 || !vipBenefitRows || !isInitialOrSignUpState)
935
1158
  return null;
936
1159
  return (React.createElement(core.Box, { className: classes.main }, vipBenefitRows.map((row, index) => (React.createElement(core.Box, { key: index, className: classes.vipBenefitRows },