Merged in feature/sas-login (pull request #1256)
First steps towards the SAS partnership * otp flow now pretends to do the linking * Update LinkAccountForm header * Update redirect times * Clean up comments * Set maxAge on sas cookies * make all SAS routes protected * Merge remote-tracking branch 'refs/remotes/origin/feature/sas-login' into feature/sas-login * Require auth for sas link flow * Fix resend otp * Add error support to OneTimePasswordForm * Add Sentry to SAS error boundary * Move SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME * Add missing translations * Merge branch 'master' of bitbucket.org:scandic-swap/web into feature/sas-login * Merge branch 'feature/sas-login' of bitbucket.org:scandic-swap/web into feature/sas-login * Add TooManyCodesError component * Refactor GenericError to support new errors * Add FailedAttemptsError * remove removed component <VWOScript/> * Merge branch 'feature/sas-login' of bitbucket.org:scandic-swap/web into feature/sas-login * remove local cookie-bot reference * Fix sas campaign logo scaling * feature toggle the SAS stuff * Merge branch 'feature/sas-login' of bitbucket.org:scandic-swap/web into feature/sas-login * fix: use env vars for SAS endpoints Approved-by: Linus Flood
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
"use client"
|
||||
|
||||
import Image from "next/image"
|
||||
import { type ReactNode, useTransition } from "react"
|
||||
import { FormProvider, useForm } from "react-hook-form"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
|
||||
import DateSelect from "@/components/TempDesignSystem/Form/Date"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import styles from "./link-sas.module.css"
|
||||
|
||||
type LinkAccountForm = {
|
||||
dateOfBirth: string | null
|
||||
termsAndConditions: boolean
|
||||
}
|
||||
export function LinkAccountForm({
|
||||
initialDateOfBirth,
|
||||
onSubmit,
|
||||
}: {
|
||||
initialDateOfBirth: string | null
|
||||
onSubmit: (dateOfBirth: string) => Promise<void>
|
||||
}) {
|
||||
let [isPending, startTransition] = useTransition()
|
||||
const intl = useIntl()
|
||||
const form = useForm<LinkAccountForm>({
|
||||
defaultValues: {
|
||||
dateOfBirth: initialDateOfBirth,
|
||||
termsAndConditions: false,
|
||||
},
|
||||
})
|
||||
|
||||
const handleSubmit = form.handleSubmit((data) => {
|
||||
startTransition(async () => {
|
||||
if (!data.dateOfBirth || !data.termsAndConditions) return
|
||||
|
||||
await onSubmit(data.dateOfBirth)
|
||||
})
|
||||
})
|
||||
|
||||
const dateOfBirth = form.watch("dateOfBirth")
|
||||
const termsAndConditions = form.watch("termsAndConditions")
|
||||
const disableSubmit = !dateOfBirth || !termsAndConditions
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<form onSubmit={handleSubmit} className={styles.form}>
|
||||
<div className={styles.titles}>
|
||||
<Image
|
||||
alt={"Scandic ❤️ SAS"}
|
||||
height={25}
|
||||
width={182}
|
||||
src="/_static/img/partner/sas/sas-campaign-logo.png"
|
||||
/>
|
||||
<Title level="h3" textTransform="regular">
|
||||
{intl.formatMessage({ id: "Link your accounts" })}
|
||||
</Title>
|
||||
</div>
|
||||
<div className={styles.dateSelect}>
|
||||
<Body>
|
||||
{intl.formatMessage({
|
||||
id: "Birth date",
|
||||
})}
|
||||
</Body>
|
||||
<DateSelect
|
||||
name="dateOfBirth"
|
||||
registerOptions={{
|
||||
required: {
|
||||
value: true,
|
||||
message: intl.formatMessage({ id: "Birth date is required" }),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Caption textAlign="left">
|
||||
{intl.formatMessage({
|
||||
id: "We require this additional information in order to match your Scandic account with your EuroBonus account.",
|
||||
})}
|
||||
</Caption>
|
||||
<div className={styles.termsAndConditions}>
|
||||
<Checkbox
|
||||
name="termsAndConditions"
|
||||
registerOptions={{
|
||||
required: {
|
||||
value: true,
|
||||
message: intl.formatMessage({
|
||||
id: "You must accept the terms and conditions",
|
||||
}),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Body>
|
||||
{intl.formatMessage({ id: "I accept the terms and conditions" })}
|
||||
</Body>
|
||||
</Checkbox>
|
||||
<Body className={styles.termsDescription}>
|
||||
{intl.formatMessage<ReactNode>(
|
||||
{
|
||||
id: "By linking your accounts you accept the <sasScandicTermsAndConditionsLink>Scandic Friends & SAS Terms and Conditions</sasScandicTermsAndConditionsLink>. You will be connected throughout the duration of your employment or until further notice, and you can opt out at any time.",
|
||||
},
|
||||
{
|
||||
sasScandicTermsAndConditionsLink: (str) => (
|
||||
<Link
|
||||
// TODO correct link
|
||||
href={"#"}
|
||||
weight="bold"
|
||||
variant="default"
|
||||
textDecoration="underline"
|
||||
>
|
||||
{str}
|
||||
</Link>
|
||||
),
|
||||
}
|
||||
)}
|
||||
</Body>
|
||||
</div>
|
||||
<div className={styles.ctaContainer}>
|
||||
<Button
|
||||
theme="base"
|
||||
fullWidth
|
||||
className={styles.ctaButton}
|
||||
type="submit"
|
||||
disabled={isPending || disableSubmit}
|
||||
>
|
||||
{intl.formatMessage({ id: "Link my accounts" })}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</FormProvider>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
.titles {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x2);
|
||||
margin-top: var(--Spacing-x3);
|
||||
}
|
||||
|
||||
.dateSelect {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x1);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.termsAndConditions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.termsDescription {
|
||||
margin-left: calc(var(--Spacing-x4) + var(--Spacing-x-half));
|
||||
}
|
||||
|
||||
.ctaContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: var(--Spacing-x3) var(--Spacing-x3) 0;
|
||||
width: calc(100% + var(--Spacing-x3) + var(--Spacing-x3));
|
||||
border-top: 1px solid var(--Base-Border-Subtle);
|
||||
}
|
||||
|
||||
.ctaButton {
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x3);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { redirect } from "next/navigation"
|
||||
import React from "react"
|
||||
|
||||
import { getProfileSafely } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import { AlreadyLinkedError } from "../components/AlreadyLinkedError"
|
||||
import { SASModal } from "../components/SASModal"
|
||||
import { LinkAccountForm } from "./LinkAccountForm"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function SASxScandicLinkPage({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
const profile = await getProfileSafely()
|
||||
|
||||
// TODO actually check if profile is already linked
|
||||
const alreadyLinked = false
|
||||
|
||||
async function handleLinkAccount(dateOfBirth: string) {
|
||||
"use server"
|
||||
|
||||
if (dateOfBirth !== profile?.dateOfBirth) {
|
||||
// TODO update users date of birth here
|
||||
console.log("updating date of birth")
|
||||
}
|
||||
|
||||
redirect(`/${params.lang}/sas-x-scandic/login?intent=link`)
|
||||
}
|
||||
|
||||
return alreadyLinked ? (
|
||||
<AlreadyLinkedError />
|
||||
) : (
|
||||
<SASModal>
|
||||
<LinkAccountForm
|
||||
initialDateOfBirth={profile?.dateOfBirth ?? null}
|
||||
onSubmit={handleLinkAccount}
|
||||
/>
|
||||
</SASModal>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from "react"
|
||||
|
||||
import CheckCircle from "@/components/Icons/CheckCircle"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import { SASModal } from "../../components/SASModal"
|
||||
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function SASxScandicLinkPage({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
const intl = await getIntl()
|
||||
|
||||
return (
|
||||
<SASModal>
|
||||
{/* <Redirect
|
||||
url={`INSERT CORRECT URL HERE`}
|
||||
timeout={3000}
|
||||
/> */}
|
||||
<CheckCircle height={64} width={64} color="uiSemanticSuccess" />
|
||||
<Title as="h2" level="h1" textAlign="center">
|
||||
{intl.formatMessage({ id: "Your accounts are connected" })}
|
||||
</Title>
|
||||
<div>
|
||||
<Body textAlign="center">
|
||||
{intl.formatMessage({
|
||||
id: "We successfully connected your accounts!",
|
||||
})}
|
||||
</Body>
|
||||
<Body textAlign="center">
|
||||
{intl.formatMessage({
|
||||
id: "Redirecting you to my pages.",
|
||||
})}
|
||||
</Body>
|
||||
</div>
|
||||
</SASModal>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user