Merged in feat/SW-1488-unlink-sas-account (pull request #1349)
Implement unlink SAS flow Approved-by: Joakim Jäderberg
This commit is contained in:
@@ -78,7 +78,10 @@ export async function GET(
|
||||
httpOnly: true,
|
||||
})
|
||||
|
||||
if (stateResult.data.intent === "link") {
|
||||
if (
|
||||
stateResult.data.intent === "link" ||
|
||||
stateResult.data.intent === "unlink"
|
||||
) {
|
||||
const [data, error] = await safeTry(
|
||||
serverClient().partner.sas.requestOtp({})
|
||||
)
|
||||
|
||||
@@ -29,7 +29,7 @@ export default async function SasXScandicLayout({
|
||||
<Link className={styles.backLink} href={profileOverview[params.lang]}>
|
||||
<ArrowLeft height={20} width={20} />
|
||||
<span className={styles.long}>
|
||||
{intl.formatMessage({ id: "Back to Scandichotels.com" })}
|
||||
{intl.formatMessage({ id: "Back to scandichotels.com" })}
|
||||
</span>
|
||||
<span className={styles.short}>
|
||||
{intl.formatMessage({ id: "Back" })}
|
||||
|
||||
@@ -18,8 +18,11 @@ import type { LangParams, PageArgs, SearchParams } from "@/types/params"
|
||||
import type { State } from "../sasUtils"
|
||||
|
||||
const searchParamsSchema = z.object({
|
||||
intent: z.enum(["link"]),
|
||||
intent: z.enum(["link", "unlink"]),
|
||||
})
|
||||
|
||||
type Intent = z.infer<typeof searchParamsSchema>["intent"]
|
||||
|
||||
export default async function SASxScandicLoginPage({
|
||||
searchParams,
|
||||
params,
|
||||
@@ -42,11 +45,19 @@ export default async function SASxScandicLoginPage({
|
||||
const clientId = env.SAS_AUTH_CLIENTID
|
||||
const sasLoginHostname = env.SAS_AUTH_ENDPOINT
|
||||
const audience = "eb-partner-api"
|
||||
// TODO check if this is correct scopes
|
||||
const scope = encodeURIComponent("openid profile email")
|
||||
|
||||
const loginLink = `${sasLoginHostname}/oauth/authorize?response_type=code&client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}&state=${urlState}&audience=${audience}`
|
||||
|
||||
const intentDescriptions: Record<Intent, string> = {
|
||||
link: intl.formatMessage({
|
||||
id: "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.",
|
||||
}),
|
||||
unlink: intl.formatMessage({
|
||||
id: "Log in to your SAS Eurobonus account to confirm account unlinking.",
|
||||
}),
|
||||
}
|
||||
|
||||
return (
|
||||
<SASModal>
|
||||
<Redirect url={loginLink} timeout={3000} />
|
||||
@@ -60,11 +71,7 @@ export default async function SASxScandicLoginPage({
|
||||
<Title as="h2" level="h1" textTransform="regular">
|
||||
{intl.formatMessage({ id: "Redirecting you to SAS" })}
|
||||
</Title>
|
||||
<Body textAlign="center">
|
||||
{intl.formatMessage({
|
||||
id: "In order to verify your account linking we will ask you to sign in to your SAS EuroBonus account.",
|
||||
})}
|
||||
</Body>
|
||||
<Body textAlign="center">{intentDescriptions[parsedParams.intent]}</Body>
|
||||
<Footnote textAlign="center">
|
||||
{intl.formatMessage<React.ReactNode>(
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ import { cookies } from "next/headers"
|
||||
import { redirect } from "next/navigation"
|
||||
import { z } from "zod"
|
||||
|
||||
import { myPages } from "@/constants/routes/myPages"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import { getIntl } from "@/i18n"
|
||||
@@ -12,17 +13,21 @@ import OneTimePasswordForm, {
|
||||
type OnSubmitHandler,
|
||||
} from "./OneTimePasswordForm"
|
||||
|
||||
import type { ReactNode } from "react"
|
||||
|
||||
import type { LangParams, PageArgs, SearchParams } from "@/types/params"
|
||||
import type { Lang } from "@/constants/languages"
|
||||
|
||||
const otpError = z.enum(["invalidCode", "expiredCode"])
|
||||
const intent = z.enum(["link", "unlink"])
|
||||
const searchParamsSchema = z.object({
|
||||
intent: z.enum(["link"]),
|
||||
intent: intent,
|
||||
to: z.string(),
|
||||
error: otpError.optional(),
|
||||
})
|
||||
|
||||
export type OtpError = z.infer<typeof otpError>
|
||||
type Intent = z.infer<typeof intent>
|
||||
|
||||
export default async function SASxScandicOneTimePasswordPage({
|
||||
searchParams,
|
||||
@@ -88,26 +93,37 @@ export default async function SASxScandicOneTimePasswordPage({
|
||||
switch (intent) {
|
||||
case "link":
|
||||
return handleLinkAccount({ lang: params.lang })
|
||||
case "unlink":
|
||||
return handleUnlinkAccount({ lang: params.lang })
|
||||
}
|
||||
}
|
||||
|
||||
const maskedContactInfo = () => (
|
||||
<>
|
||||
<br />
|
||||
<strong>{to}</strong>
|
||||
<br />
|
||||
</>
|
||||
)
|
||||
const intentDescriptions: Record<Intent, ReactNode> = {
|
||||
link: intl.formatMessage<React.ReactNode>(
|
||||
{
|
||||
id: "Please enter the code sent to <maskedContactInfo></maskedContactInfo> in order to confirm your account linking.",
|
||||
},
|
||||
{ maskedContactInfo }
|
||||
),
|
||||
unlink: intl.formatMessage<React.ReactNode>(
|
||||
{
|
||||
id: "Please enter the code sent to <maskedContactInfo></maskedContactInfo> in order to unlink your accounts.",
|
||||
},
|
||||
{ maskedContactInfo }
|
||||
),
|
||||
}
|
||||
|
||||
return (
|
||||
<OneTimePasswordForm
|
||||
heading={intl.formatMessage({ id: "Verification code" })}
|
||||
ingress={intl.formatMessage<React.ReactNode>(
|
||||
{
|
||||
id: "Please enter the code sent to <maskedContactInfo></maskedContactInfo> in order to confirm your account linking.",
|
||||
},
|
||||
{
|
||||
maskedContactInfo: () => (
|
||||
<>
|
||||
<br />
|
||||
<strong>{to}</strong>
|
||||
<br />
|
||||
</>
|
||||
),
|
||||
}
|
||||
)}
|
||||
ingress={intentDescriptions[intent]}
|
||||
footnote={intl.formatMessage({
|
||||
id: "This verifcation is needed for additional security.",
|
||||
})}
|
||||
@@ -168,3 +184,34 @@ async function handleLinkAccount({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleUnlinkAccount({
|
||||
lang,
|
||||
}: {
|
||||
lang: Lang
|
||||
}): ReturnType<OnSubmitHandler> {
|
||||
const [res, error] = await safeTry(serverClient().partner.sas.unlinkAccount())
|
||||
if (!res || error) {
|
||||
console.error("[SAS] unlink account error", error)
|
||||
return {
|
||||
url: `/${lang}/sas-x-scandic/error`,
|
||||
}
|
||||
}
|
||||
|
||||
switch (res.linkingState) {
|
||||
case "unlinked":
|
||||
return {
|
||||
url: `/${lang}/sas-x-scandic/unlink/success`,
|
||||
type: "replace",
|
||||
}
|
||||
case "notLinked":
|
||||
return {
|
||||
url: myPages[lang],
|
||||
}
|
||||
case "error":
|
||||
return {
|
||||
url: `/${lang}/sas-x-scandic/error`,
|
||||
type: "replace",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ import { z } from "zod"
|
||||
|
||||
export const SAS_TOKEN_STORAGE_KEY = "sas-x-scandic-token"
|
||||
|
||||
// TODO nonce??
|
||||
export const stateSchema = z.object({
|
||||
intent: z.literal("link"),
|
||||
intent: z.enum(["link", "unlink"]),
|
||||
})
|
||||
export type State = z.infer<typeof stateSchema>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import React from "react"
|
||||
|
||||
import { overview } from "@/constants/routes/myPages"
|
||||
|
||||
import CheckCircle from "@/components/Icons/CheckCircle"
|
||||
import { Redirect } from "@/components/Redirect"
|
||||
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 SASxScandicUnlinkSuccessPage({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
const intl = await getIntl()
|
||||
|
||||
return (
|
||||
<SASModal>
|
||||
<Redirect url={overview[params.lang]} timeout={3000} />
|
||||
<CheckCircle height={64} width={64} color="uiSemanticSuccess" />
|
||||
<Title as="h2" level="h1" textAlign="center">
|
||||
{intl.formatMessage({ id: "Your accounts are now unlinked" })}
|
||||
</Title>
|
||||
<div>
|
||||
<Body textAlign="center">
|
||||
{intl.formatMessage({
|
||||
id: "Redirecting you to My Pages.",
|
||||
})}
|
||||
</Body>
|
||||
</div>
|
||||
</SASModal>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user