fix: responsivity of fields and order of signup form

This commit is contained in:
Christel Westerberg
2024-11-18 15:07:23 +01:00
parent 9094b08345
commit d5c6b6809c
17 changed files with 264 additions and 262 deletions

View File

@@ -3,12 +3,14 @@
align-self: flex-start; align-self: flex-start;
display: grid; display: grid;
gap: var(--Spacing-x2); gap: var(--Spacing-x2);
container-name: addressContainer;
container-type: inline-size;
} }
.container { .container {
display: grid; display: grid;
gap: var(--Spacing-x2); gap: var(--Spacing-x2);
grid-template-columns: max(164px) 1fr; grid-template-columns: minmax(100px, 164px) 1fr;
} }
@media (min-width: 768px) { @media (min-width: 768px) {
@@ -16,3 +18,9 @@
display: none; display: none;
} }
} }
@container addressContainer (max-width: 350px) {
.container {
grid-template-columns: 1fr;
}
}

View File

@@ -48,7 +48,6 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) {
zipCode: "", zipCode: "",
}, },
password: "", password: "",
termsAccepted: false,
}, },
mode: "all", mode: "all",
criteriaMode: "all", criteriaMode: "all",

View File

@@ -4,14 +4,8 @@ import { useEffect, useState } from "react"
import { useWatch } from "react-hook-form" import { useWatch } from "react-hook-form"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { privacyPolicy } from "@/constants/currentWebHrefs"
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
import DateSelect from "@/components/TempDesignSystem/Form/Date" import DateSelect from "@/components/TempDesignSystem/Form/Date"
import Input from "@/components/TempDesignSystem/Form/Input" import Input from "@/components/TempDesignSystem/Form/Input"
import JoinScandicFriendsCard from "@/components/TempDesignSystem/Form/JoinScandicFriendsCard"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption" import Caption from "@/components/TempDesignSystem/Text/Caption"
import useLang from "@/hooks/useLang" import useLang from "@/hooks/useLang"
@@ -31,49 +25,27 @@ export default function Signup({ name }: { name: string }) {
setIsJoinChecked(joinValue) setIsJoinChecked(joinValue)
}, [joinValue]) }, [joinValue])
return ( return isJoinChecked ? (
<div className={styles.container}> <div className={styles.additionalFormData}>
<JoinScandicFriendsCard <Input
name={name} name="zipCode"
difference={{ price: 1000, currency: "SEK" }} label={intl.formatMessage({ id: "Zip code" })}
registerOptions={{ required: true }}
/> />
{isJoinChecked ? ( <div className={styles.dateField}>
<div className={styles.additionalFormData}> <header>
<div className={styles.dateField}> <Caption type="bold">
<header> {intl.formatMessage({ id: "Birth date" })} *
<Caption type="bold"> </Caption>
{intl.formatMessage({ id: "Birth date" })} * </header>
</Caption> <DateSelect name="dateOfBirth" registerOptions={{ required: true }} />
</header> </div>
<DateSelect
name="dateOfBirth"
registerOptions={{ required: true }}
/>
<Input
name="zipCode"
label={intl.formatMessage({ id: "Zip code" })}
registerOptions={{ required: true }}
/>
</div>
<div>
<Checkbox name="termsAccepted" registerOptions={{ required: true }}>
<Body>
{intl.formatMessage({
id: "Yes, I accept the Terms and conditions for Scandic Friends and understand that Scandic will process my personal data in accordance with",
})}{" "}
<Link
variant="underscored"
color="peach80"
target="_blank"
href={privacyPolicy[lang]}
>
{intl.formatMessage({ id: "Scandic's Privacy Policy." })}
</Link>
</Body>
</Checkbox>
</div>
</div>
) : null}
</div> </div>
) : (
<Input
label={intl.formatMessage({ id: "Membership no" })}
name="membershipNo"
type="tel"
/>
) )
} }

View File

@@ -1,34 +1,30 @@
.form { .form {
display: grid; display: grid;
gap: var(--Spacing-x1); gap: var(--Spacing-x3);
padding: var(--Spacing-x3) 0px; margin-bottom: var(--Spacing-x3);
} }
.container { .container {
display: grid; display: grid;
gap: var(--Spacing-x1); gap: var(--Spacing-x2);
grid-template-columns: 1fr 1fr;
width: min(100%, 600px); width: min(100%, 600px);
} }
.header,
.country, .country,
.email, .email,
.membershipNo, .signup,
.phone { .phone {
grid-column: 1/-1; grid-column: 1/-1;
} }
.footer { .footer {
display: grid;
gap: var(--Spacing-x3);
justify-items: flex-start;
margin-top: var(--Spacing-x1); margin-top: var(--Spacing-x1);
} }
@media screen and (min-width: 1367px) { @media screen and (min-width: 768px) {
.form { .form {
gap: var(--Spacing-x2); gap: var(--Spacing-x3);
padding: var(--Spacing-x3) 0px;
} }
.container { .container {
@@ -36,18 +32,4 @@
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
width: min(100%, 600px); width: min(100%, 600px);
} }
.country,
.email,
.membershipNo,
.phone {
grid-column: 1/-1;
}
.footer {
display: grid;
gap: var(--Spacing-x3);
justify-items: flex-start;
margin-top: var(--Spacing-x1);
}
} }

View File

@@ -10,6 +10,7 @@ import { useStepsStore } from "@/stores/steps"
import Button from "@/components/TempDesignSystem/Button" import Button from "@/components/TempDesignSystem/Button"
import CountrySelect from "@/components/TempDesignSystem/Form/Country" import CountrySelect from "@/components/TempDesignSystem/Form/Country"
import Input from "@/components/TempDesignSystem/Form/Input" import Input from "@/components/TempDesignSystem/Form/Input"
import JoinScandicFriendsCard from "@/components/TempDesignSystem/Form/JoinScandicFriendsCard"
import Phone from "@/components/TempDesignSystem/Form/Phone" import Phone from "@/components/TempDesignSystem/Form/Phone"
import Footnote from "@/components/TempDesignSystem/Text/Footnote" import Footnote from "@/components/TempDesignSystem/Text/Footnote"
@@ -35,7 +36,6 @@ export default function Details({ user }: DetailsProps) {
join: state.data.join, join: state.data.join,
dateOfBirth: state.data.dateOfBirth, dateOfBirth: state.data.dateOfBirth,
zipCode: state.data.zipCode, zipCode: state.data.zipCode,
termsAccepted: state.data.termsAccepted,
membershipNo: state.data.membershipNo, membershipNo: state.data.membershipNo,
})) }))
@@ -52,7 +52,6 @@ export default function Details({ user }: DetailsProps) {
join: initialData.join, join: initialData.join,
dateOfBirth: initialData.dateOfBirth, dateOfBirth: initialData.dateOfBirth,
zipCode: initialData.zipCode, zipCode: initialData.zipCode,
termsAccepted: initialData.termsAccepted,
membershipNo: initialData.membershipNo, membershipNo: initialData.membershipNo,
}, },
criteriaMode: "all", criteriaMode: "all",
@@ -69,6 +68,7 @@ export default function Details({ user }: DetailsProps) {
[completeStep, updateDetails] [completeStep, updateDetails]
) )
const joinValue = methods.watch("join")
return ( return (
<FormProvider {...methods}> <FormProvider {...methods}>
<form <form
@@ -76,15 +76,21 @@ export default function Details({ user }: DetailsProps) {
id={formID} id={formID}
onSubmit={methods.handleSubmit(onSubmit)} onSubmit={methods.handleSubmit(onSubmit)}
> >
{user ? null : <Signup name="join" />} {user ? null : (
<Footnote <JoinScandicFriendsCard
color="uiTextHighContrast" name="join"
textTransform="uppercase" difference={{ price: 1000, currency: "SEK" }}
type="label" />
> )}
{intl.formatMessage({ id: "Guest information" })}
</Footnote>
<div className={styles.container}> <div className={styles.container}>
<Footnote
color="uiTextHighContrast"
textTransform="uppercase"
type="label"
className={styles.header}
>
{intl.formatMessage({ id: "Guest information" })}
</Footnote>
<Input <Input
label={intl.formatMessage({ id: "First name" })} label={intl.formatMessage({ id: "First name" })}
name="firstName" name="firstName"
@@ -118,13 +124,10 @@ export default function Details({ user }: DetailsProps) {
readOnly={!!user} readOnly={!!user}
registerOptions={{ required: true }} registerOptions={{ required: true }}
/> />
{user || methods.watch("join") ? null : ( {user ? null : (
<Input <div className={styles.signup}>
className={styles.membershipNo} <Signup name="join" />
label={intl.formatMessage({ id: "Membership no" })} </div>
name="membershipNo"
type="tel"
/>
)} )}
</div> </div>
<footer className={styles.footer}> <footer className={styles.footer}>

View File

@@ -15,7 +15,6 @@ export const notJoinDetailsSchema = baseDetailsSchema.merge(
join: z.literal<boolean>(false), join: z.literal<boolean>(false),
zipCode: z.string().optional(), zipCode: z.string().optional(),
dateOfBirth: z.string().optional(), dateOfBirth: z.string().optional(),
termsAccepted: z.boolean().default(false),
membershipNo: z membershipNo: z
.string() .string()
.optional() .optional()
@@ -39,15 +38,6 @@ export const joinDetailsSchema = baseDetailsSchema.merge(
join: z.literal<boolean>(true), join: z.literal<boolean>(true),
zipCode: z.string().min(1, { message: "Zip code is required" }), zipCode: z.string().min(1, { message: "Zip code is required" }),
dateOfBirth: z.string().min(1, { message: "Date of birth is required" }), dateOfBirth: z.string().min(1, { message: "Date of birth is required" }),
termsAccepted: z.literal<boolean>(true, {
errorMap: (err, ctx) => {
switch (err.code) {
case "invalid_literal":
return { message: "You must accept the terms and conditions" }
}
return { message: ctx.defaultError }
},
}),
membershipNo: z.string().optional(), membershipNo: z.string().optional(),
}) })
) )

View File

@@ -66,7 +66,7 @@ export default function SectionAccordion({
const textColor = const textColor =
isComplete || isOpen ? "uiTextHighContrast" : "baseTextDisabled" isComplete || isOpen ? "uiTextHighContrast" : "baseTextDisabled"
return ( return (
<section className={styles.wrapper} data-open={isOpen} data-step={step}> <div className={styles.main} data-open={isOpen} data-step={step}>
<div className={styles.iconWrapper}> <div className={styles.iconWrapper}>
<div className={styles.circle} data-checked={isComplete}> <div className={styles.circle} data-checked={isComplete}>
{isComplete ? ( {isComplete ? (
@@ -74,31 +74,27 @@ export default function SectionAccordion({
) : null} ) : null}
</div> </div>
</div> </div>
<div className={styles.main}> <header className={styles.header}>
<header> <button onClick={onModify} className={styles.modifyButton}>
<button onClick={onModify} className={styles.modifyButton}> <Footnote
<Footnote className={styles.title}
className={styles.title} asChild
asChild textTransform="uppercase"
textTransform="uppercase" type="label"
type="label" color={textColor}
color={textColor} >
> <h2>{header}</h2>
<h2>{header}</h2> </Footnote>
</Footnote> <Subtitle className={styles.selection} type="two" color={textColor}>
<Subtitle className={styles.selection} type="two" color={textColor}> {title}
{title} </Subtitle>
</Subtitle>
{isComplete && !isOpen && ( {isComplete && !isOpen && (
<ChevronDownIcon className={styles.button} color="burgundy" /> <ChevronDownIcon className={styles.button} color="burgundy" />
)} )}
</button> </button>
</header> </header>
<div className={styles.content}> <div className={styles.content}>{children}</div>
<div className={styles.contentWrapper}>{children}</div> </div>
</div>
</div>
</section>
) )
} }

View File

@@ -1,15 +1,25 @@
.wrapper { .main {
position: relative; gap: var(--Spacing-x3);
display: flex; width: 100%;
flex-direction: row;
gap: var(--Spacing-x-one-and-half);
padding-top: var(--Spacing-x3); padding-top: var(--Spacing-x3);
transition: 0.4s ease-out;
display: grid;
grid-template-areas: "circle header" "content content";
grid-template-columns: auto 1fr;
grid-template-rows: 2.4em 0fr;
column-gap: var(--Spacing-x-one-and-half);
} }
.wrapper:last-child .main { .main:last-child .main {
border-bottom: none; border-bottom: none;
} }
.header {
grid-area: header;
}
.modifyButton { .modifyButton {
display: grid; display: grid;
grid-template-areas: "title button" "selection button"; grid-template-areas: "title button" "selection button";
@@ -17,6 +27,7 @@
background-color: transparent; background-color: transparent;
border: none; border: none;
width: 100%; width: 100%;
padding: 0;
} }
.title { .title {
@@ -29,15 +40,6 @@
justify-self: flex-end; justify-self: flex-end;
} }
.main {
display: grid;
width: 100%;
border-bottom: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
padding-bottom: var(--Spacing-x3);
transition: 0.4s ease-out;
grid-template-rows: 2em 0fr;
}
.selection { .selection {
font-weight: 450; font-weight: 450;
font-size: var(--typography-Title-4-fontSize); font-size: var(--typography-Title-4-fontSize);
@@ -46,6 +48,7 @@
.iconWrapper { .iconWrapper {
position: relative; position: relative;
grid-area: circle;
} }
.circle { .circle {
@@ -63,42 +66,42 @@
background-color: var(--UI-Input-Controls-Fill-Selected); background-color: var(--UI-Input-Controls-Fill-Selected);
} }
.wrapper[data-open="true"] .circle[data-checked="false"] { .main[data-open="true"] .circle[data-checked="false"] {
background-color: var(--UI-Text-Placeholder); background-color: var(--UI-Text-Placeholder);
} }
.wrapper[data-open="false"] .circle[data-checked="false"] { .main[data-open="false"] .circle[data-checked="false"] {
background-color: var(--Base-Surface-Subtle-Hover); background-color: var(--Base-Surface-Subtle-Hover);
} }
.wrapper[data-open="true"] .main { .main[data-open="true"] {
grid-template-rows: 2em 1fr; grid-template-rows: 2.4em 1fr;
gap: var(--Spacing-x3);
} }
.content { .content {
overflow: hidden; overflow: hidden;
grid-area: content;
border-bottom: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
} }
.contentWrapper { @media screen and (min-width: 768px) {
padding-top: var(--Spacing-x3); .main {
}
@media screen and (min-width: 1367px) {
.wrapper {
gap: var(--Spacing-x3); gap: var(--Spacing-x3);
grid-template-areas: "circle header" "circle content";
} }
.iconWrapper { .iconWrapper {
top: var(--Spacing-x1); top: var(--Spacing-x1);
} }
.wrapper:not(:last-child)::after { .main:not(:last-child) .iconWrapper::after {
position: absolute; position: absolute;
left: 12px; left: 12px;
bottom: 0; bottom: calc(0px - var(--Spacing-x7));
top: var(--Spacing-x7); top: 24px;
height: 100%;
content: ""; content: "";
border-left: 1px solid var(--Primary-Light-On-Surface-Divider-subtle); border-left: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
} }
} }

View File

@@ -63,7 +63,7 @@
justify-content: flex-start; justify-content: flex-start;
} }
@media screen and (min-width: 1367px) { @media screen and (min-width: 768px) {
.wrapper { .wrapper {
gap: var(--Spacing-x3); gap: var(--Spacing-x3);
padding-top: var(--Spacing-x3); padding-top: var(--Spacing-x3);

View File

@@ -9,6 +9,7 @@
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2); padding: var(--Spacing-x-one-and-half) var(--Spacing-x2);
transition: all 200ms ease; transition: all 200ms ease;
width: min(100%, 600px); width: min(100%, 600px);
height: 100%;
} }
.label:hover { .label:hover {

View File

@@ -1,4 +1,8 @@
/* Leaving, will most likely get deleted */ /* Leaving, will most likely get deleted */
.datePicker {
container-name: datePickerContainer;
container-type: inline-size;
}
.container { .container {
display: grid; display: grid;
gap: var(--Spacing-x2); gap: var(--Spacing-x2);
@@ -27,3 +31,10 @@
.year.invalid > div > div { .year.invalid > div > div {
border-color: var(--Scandic-Red-60); border-color: var(--Scandic-Red-60);
} }
@container datePickerContainer (max-width: 350px) {
.container {
display: flex;
flex-direction: column;
}
}

View File

@@ -115,6 +115,7 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
ref={field.ref} ref={field.ref}
value={dateValue} value={dateValue}
data-testid={name} data-testid={name}
className={styles.datePicker}
> >
<Group> <Group>
<DateInput className={styles.container}> <DateInput className={styles.container}>

View File

@@ -35,43 +35,41 @@ export default function JoinScandicFriendsCard({
return ( return (
<div className={styles.cardContainer}> <div className={styles.cardContainer}>
<header className={styles.header}> <Checkbox name={name} className={styles.checkBox}>
<Checkbox name={name} className={styles.checkBox}> <div>
<div> <Caption type="label" textTransform="uppercase" color="red">
<Caption type="label" textTransform="uppercase" color="red"> {intl.formatMessage(
{intl.formatMessage( {
{ id: "Only pay {amount} {currency}",
id: "Only pay {amount} {currency}", },
}, {
{ amount: intl.formatNumber(difference.price),
amount: intl.formatNumber(difference.price), currency: difference.currency,
currency: difference.currency, }
} )}
)} </Caption>
</Caption> <Caption
<Caption type="label"
type="label" textTransform="uppercase"
textTransform="uppercase" color="uiTextHighContrast"
color="uiTextHighContrast"
>
{intl.formatMessage({ id: "Join Scandic Friends" })}
</Caption>
</div>
</Checkbox>
<Footnote color="uiTextHighContrast">
{intl.formatMessage({ id: "Already a friend?" })}{" "}
<LoginButton
color="burgundy"
position="enter details"
trackingId="join-scandic-friends-enter-details"
variant="breadcrumb"
target="_blank"
> >
{intl.formatMessage({ id: "Log in" })} {intl.formatMessage({ id: "Join Scandic Friends" })}
</LoginButton> </Caption>
</Footnote> </div>
</header> </Checkbox>
<Footnote color="uiTextHighContrast" className={styles.login}>
{intl.formatMessage({ id: "Already a friend?" })}{" "}
<LoginButton
color="burgundy"
position="enter details"
trackingId="join-scandic-friends-enter-details"
variant="breadcrumb"
target="_blank"
>
{intl.formatMessage({ id: "Log in" })}
</LoginButton>
</Footnote>
<div className={styles.list}> <div className={styles.list}>
{list.map((item) => ( {list.map((item) => (
@@ -84,7 +82,7 @@ export default function JoinScandicFriendsCard({
</Caption> </Caption>
))} ))}
</div> </div>
<Footnote color="uiTextPlaceholder"> <Footnote color="uiTextPlaceholder" className={styles.terms}>
{intl.formatMessage<React.ReactNode>( {intl.formatMessage<React.ReactNode>(
{ {
id: "signup.terms", id: "signup.terms",

View File

@@ -4,26 +4,52 @@
border: 1px solid var(--Base-Border-Subtle); border: 1px solid var(--Base-Border-Subtle);
border-radius: var(--Corner-radius-Large); border-radius: var(--Corner-radius-Large);
display: grid; display: grid;
gap: var(--Spacing-x2); gap: var(--Spacing-x-one-and-half);
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2); padding: var(--Spacing-x-one-and-half) var(--Spacing-x2);
grid-template-areas:
"checkbox"
"list"
"login"
"terms";
width: min(100%, 600px); width: min(100%, 600px);
} }
.header { .login {
display: grid; grid-area: login;
gap: var(--Spacing-x-one-and-half);
grid-template-columns: 1fr auto;
} }
.checkBox { .checkBox {
align-self: center; align-self: center;
grid-area: checkbox;
} }
.list { .list {
display: flex; display: grid;
grid-area: list;
gap: var(--Spacing-x1); gap: var(--Spacing-x1);
} }
.listItem { .listItem {
display: flex; display: flex;
} }
.terms {
border-top: 1px solid var(--Base-Border-Normal);
grid-area: terms;
padding-top: var(--Spacing-x1);
}
@media screen and (min-width: 768px) {
.cardContainer {
grid-template-columns: 1fr auto;
gap: var(--Spacing-x2);
grid-template-areas:
"checkbox login"
"list list"
"terms terms";
}
.list {
display: flex;
gap: var(--Spacing-x1);
}
}

View File

@@ -78,67 +78,69 @@ export default function Phone({
} }
return ( return (
<div className={`${styles.phone} ${className}`}> <div className={`${styles.wrapper} ${className}`}>
<CountrySelector <div className={styles.phone}>
disabled={readOnly} <CountrySelector
dropdownArrowClassName={styles.arrow} disabled={readOnly}
flagClassName={styles.flag} dropdownArrowClassName={styles.arrow}
onSelect={handleSelectCountry} flagClassName={styles.flag}
preferredCountries={["de", "dk", "fi", "no", "se", "gb"]} onSelect={handleSelectCountry}
selectedCountry={country.iso2} preferredCountries={["de", "dk", "fi", "no", "se", "gb"]}
renderButtonWrapper={(props) => ( selectedCountry={country.iso2}
<button renderButtonWrapper={(props) => (
{...props.rootProps} <button
className={styles.select} {...props.rootProps}
tabIndex={0} className={styles.select}
type="button" tabIndex={0}
data-testid="country-selector" type="button"
> data-testid="country-selector"
<Label required={!!registerOptions.required} size="small"> >
{intl.formatMessage({ id: "Country code" })} <Label required={!!registerOptions.required} size="small">
</Label> {intl.formatMessage({ id: "Country code" })}
<span className={styles.selectContainer}> </Label>
{props.children} <span className={styles.selectContainer}>
<Body asChild fontOnly> {props.children}
<DialCodePreview <Body asChild fontOnly>
className={styles.dialCode} <DialCodePreview
dialCode={country.dialCode} className={styles.dialCode}
prefix="+" dialCode={country.dialCode}
prefix="+"
/>
</Body>
<ChevronDownIcon
className={styles.chevron}
color="grey80"
height={18}
width={18}
/> />
</Body> </span>
<ChevronDownIcon </button>
className={styles.chevron} )}
color="grey80"
height={18}
width={18}
/>
</span>
</button>
)}
/>
<TextField
aria-label={ariaLabel}
defaultValue={field.value}
isDisabled={disabled ?? field.disabled}
isInvalid={fieldState.invalid}
isRequired={!!registerOptions?.required}
isReadOnly={readOnly}
name={field.name}
type="tel"
>
<AriaInputWithLabel
{...field}
id={field.name}
label={label}
onChange={handleChange}
placeholder={placeholder}
readOnly={readOnly}
required={!!registerOptions.required}
type="tel"
value={inputValue}
/> />
<ErrorMessage errors={formState.errors} name={field.name} /> <TextField
</TextField> aria-label={ariaLabel}
defaultValue={field.value}
isDisabled={disabled ?? field.disabled}
isInvalid={fieldState.invalid}
isRequired={!!registerOptions?.required}
isReadOnly={readOnly}
name={field.name}
type="tel"
>
<AriaInputWithLabel
{...field}
id={field.name}
label={label}
onChange={handleChange}
placeholder={placeholder}
readOnly={readOnly}
required={!!registerOptions.required}
type="tel"
value={inputValue}
/>
<ErrorMessage errors={formState.errors} name={field.name} />
</TextField>
</div>
</div> </div>
) )
} }

View File

@@ -1,3 +1,7 @@
.wrapper {
container-name: phoneContainer;
container-type: inline-size;
}
.phone { .phone {
display: grid; display: grid;
gap: var(--Spacing-x2); gap: var(--Spacing-x2);
@@ -100,3 +104,10 @@
justify-self: flex-start; justify-self: flex-start;
padding: 0; padding: 0;
} }
@container phoneContainer (max-width: 350px) {
.phone {
display: flex;
flex-direction: column;
}
}

View File

@@ -94,7 +94,6 @@ export function createDetailsStore(
state.data.membershipNo = data.membershipNo state.data.membershipNo = data.membershipNo
} }
state.data.phoneNumber = data.phoneNumber state.data.phoneNumber = data.phoneNumber
state.data.termsAccepted = data.termsAccepted
state.data.zipCode = data.zipCode state.data.zipCode = data.zipCode
}) })
) )