Merged in feat/LOY-486-consent-prompt-date (pull request #3221)

Feat/LOY-486 consent prompt date

* chore(LOY-486): update name on date

* chore(LOY-486): open links in new tab

* chore(LOY-486): send prompt date + refactor modal

* chore(LOY-486): update README


Approved-by: Chuma Mcphoy (We Ahead)
This commit is contained in:
Matilda Landström
2025-11-26 12:11:57 +00:00
parent f70c431a5e
commit 086319e8b1
9 changed files with 119 additions and 37 deletions

View File

@@ -1,7 +1,7 @@
"use client"
import { AnimatePresence, motion } from "motion/react"
import { useCallback, useEffect, useState } from "react"
import { useCallback, useEffect, useRef, useState } from "react"
import { Dialog, Modal, ModalOverlay } from "react-aria-components"
import { useIntl } from "react-intl"
@@ -9,6 +9,7 @@ import { Button } from "@scandic-hotels/design-system/Button"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import ScandicLogoIcon from "@scandic-hotels/design-system/Icons/ScandicLogoIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { trpc } from "@scandic-hotels/trpc/client"
import { useUpdateProfilingConsent } from "@/hooks/useUpdateProfilingConsent"
import {
@@ -35,6 +36,52 @@ type ProfilingConsentModalProps = {
const MotionModal = motion.create(Modal)
function usePromptInitialization(memberKey: string | undefined) {
const utils = trpc.useUtils()
const updateConsentPromptDate =
trpc.user.profilingConsentPromptDate.update.useMutation({
onSuccess: () => utils.user.get.invalidate(),
})
const mutationRef = useRef(updateConsentPromptDate)
mutationRef.current = updateConsentPromptDate
const [shouldOpenInitially, setShouldOpenInitially] = useState(false)
const hasSentPromptDate = useRef(false)
const sendPromptDate = useCallback((date: string) => {
mutationRef.current.mutate({
profilingConsentPromptDate: date,
})
}, [])
useEffect(() => {
if (!memberKey) return
const dismissed = readDismissed(memberKey)
const firstOpen = !dismissed
setShouldOpenInitially(firstOpen)
if (firstOpen && !hasSentPromptDate.current) {
hasSentPromptDate.current = true
sendPromptDate(new Date().toISOString())
}
}, [memberKey, sendPromptDate])
return shouldOpenInitially
}
function useModalEvents(setOpen: (s: boolean) => void) {
useEffect(() => {
const handleOpen: EventListener = () => setOpen(true)
window.addEventListener(profilingConsentOpenEvent, handleOpen)
return () =>
window.removeEventListener(profilingConsentOpenEvent, handleOpen)
}, [setOpen])
}
export default function ProfilingConsentModal({
memberKey,
content,
@@ -42,22 +89,20 @@ export default function ProfilingConsentModal({
readOnly = false,
}: ProfilingConsentModalProps) {
const intl = useIntl()
const [open, setOpen] = useState(false)
const [activeChoice, setActiveChoice] = useState<boolean | null>(null)
const shouldOpenInitially = usePromptInitialization(memberKey)
const { initiateUpdateConsent, isLoading, isSuccess } =
useUpdateProfilingConsent()
const [activeChoice, setActiveChoice] = useState<boolean | null>(null)
const handleClick = (consent: boolean) => {
setActiveChoice(consent)
initiateUpdateConsent(consent)
}
useEffect(() => {
if (!memberKey) return
setOpen(!readDismissed(memberKey))
}, [memberKey])
if (shouldOpenInitially) setOpen(true)
}, [shouldOpenInitially])
useModalEvents(setOpen)
const onClose = useCallback(() => {
if (memberKey) {
@@ -66,29 +111,22 @@ export default function ProfilingConsentModal({
setOpen(false)
}, [memberKey])
useEffect(() => {
const handleOpen: EventListener = () => setOpen(true)
window.addEventListener(profilingConsentOpenEvent, handleOpen)
return () => {
window.removeEventListener(profilingConsentOpenEvent, handleOpen)
}
}, [])
useEffect(() => {
if (isSuccess) onClose()
}, [isSuccess, onClose])
if (!memberKey && !readOnly) return null
const handleConsentClick = (consent: boolean) => {
setActiveChoice(consent)
initiateUpdateConsent(consent)
}
return (
<ModalOverlay
className={styles.overlay}
isOpen={open}
onOpenChange={(isOpen) => {
if (!isOpen) {
onClose()
}
}}
onOpenChange={(state) => !state && onClose()}
isKeyboardDismissDisabled
isDismissable={false}
>
@@ -185,7 +223,7 @@ export default function ProfilingConsentModal({
position: "modal",
name: "accept personalization",
})
handleClick(true)
handleConsentClick(true)
}}
>
{intl.formatMessage({
@@ -203,7 +241,7 @@ export default function ProfilingConsentModal({
isPending={isLoading && activeChoice === false}
onClick={() => {
trackConsentAction({ position: "modal", name: "decline" })
handleClick(false)
handleConsentClick(false)
}}
>
{intl.formatMessage({