Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIM-2066] Popup #2987

Merged
merged 13 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 193 additions & 0 deletions src/main/resources/assets/styles/_popup.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
.popup-container {
background-color: #00824d;
overflow: hidden;
z-index: 9999;
position: fixed;
bottom: 25px;
right: clamp(25px, calc(400px - (3500px - 100vw) / 2), 400px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
border: 1px solid #00824d;

&.open {
width: 358px;
border-radius: 8px;
height: auto;
}

&.closed {
width: 219px;
border-radius: 2px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
}

&.scrolled {
width: 44px;
height: 44px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 2px;

.clipboard-icon {
stroke: white;
margin: 0;
display: block;
}

.closed-text {
position: absolute;
opacity: 0;
}
}

@media (max-width: 767px) {
right: 25px;
transform: none;

&.open {
left: 50%;
transform: translateX(-50%);
}

&.closed,
&.scrolled {
right: 25px;
transform: none;
}
}
}

.popup-closed {
height: 44px;
background-color: #00824d;
color: white;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
cursor: pointer;
border: none;
}

.clipboard-icon {
stroke: white;
}

.closed-text {
font-family: Roboto, sans-serif;
font-size: 16px;
font-weight: 700;
color: white;
text-align: center;
}

.popup-header {
height: 68px;
color: white;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
background-color: #00824d;
}

.header-text {
font-family: Roboto, sans-serif !important;
font-size: 16px;
margin: 0;
color: white;
}

.close-icon-wrapper {
width: 44px;
height: 44px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
border: none;
padding: 0;
outline: none;
cursor: pointer;
transition: background-color 0.2s ease-in-out;
background: none;
}

.close-icon-wrapper:hover,
.close-icon-wrapper:focus-visible {
background-color: #ecfeed;
}

.close-icon {
stroke: white;
}

.close-icon-wrapper:hover .close-icon,
.close-icon-wrapper:focus-visible .close-icon {
stroke: #00824d;
}

.popup-content {
background-color: #ecfeed;
padding: 16px 20px;
border: none;
}

.popup-content p {
font-family: 'Open Sans', sans-serif;
font-size: 14px;
color: #00824d;
font-weight: 100;
margin: 0;
line-height: 24px;
text-align: left;
}

.button-group {
padding: 16px 20px;
display: flex;
justify-content: space-between;
background-color: #ecfeed;
border-top: 1px solid #00824d;
}

.popup-button {
width: 169px;
height: 44px;
background-color: #00824d;
color: white;
font-family: Roboto, sans-serif;
font-weight: 700;
border: none;
border-radius: 2px;
cursor: pointer;
}

.popup-secondary-button {
width: 126px;
height: 44px;
background-color: #ecfeed;
color: #00824d;
font-family: Roboto, sans-serif;
font-weight: 700;
border: 2px solid #00824d;
border-radius: 2px;
cursor: pointer;
}

.popup-container:focus-visible,
.popup-button:focus-visible,
.popup-secondary-button:focus-visible {
outline: 2px solid #9272fc;
outline-offset: 2px;
border-radius: 2px;
}

@media (min-width: 768px) {
.header-text {
font-size: 20px;
}
}
1 change: 1 addition & 0 deletions src/main/resources/assets/styles/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ $container-max-widths: (
@import './statisticFigures';
@import './statisticDescription';
@import './statisticContact';
@import "./popup";

body {
-moz-osx-font-smoothing: grayscale;
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/main.es6
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ try {
feature: 'pageMap',
enabled: false,
},
{
feature: 'show-popup-survey',
enabled: false,
},
],
},
])
Expand Down
129 changes: 129 additions & 0 deletions src/main/resources/react4xp/_entries/Popup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import React, { useState, useEffect, useRef } from 'react'
import { X, Clipboard } from 'react-feather'

const Popup = () => {
const [isOpen, setIsOpen] = useState(true)
const [isVisible, setIsVisible] = useState(true)
const [isMobile, setIsMobile] = useState(window.innerWidth <= 767)
const [isScrolled, setIsScrolled] = useState(false)
const [hasUserScrolled, setHasUserScrolled] = useState(false)
const popupContainerRef = useRef<HTMLDivElement>(null)

useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth <= 767)
}

window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
}
}, [])

useEffect(() => {
const handleScroll = () => {
if (!isOpen && isMobile && hasUserScrolled) {
setIsScrolled(true)
}
}
const onManualScroll = () => {
setHasUserScrolled(true)
}

if (isMobile && !isOpen) {
setTimeout(() => {
window.addEventListener('scroll', handleScroll)
window.addEventListener('scroll', onManualScroll)
}, 500)
}

return () => {
window.removeEventListener('scroll', handleScroll)
window.removeEventListener('scroll', onManualScroll)
}
}, [isMobile, isOpen, hasUserScrolled])

const toggleOpen = () => {
setIsOpen(!isOpen)
setIsScrolled(false)
setHasUserScrolled(false)
if (!isOpen && popupContainerRef.current) {
popupContainerRef.current.focus()
}
}

const closePopup = () => {
setIsVisible(false)
const date = new Date()
date.setTime(date.getTime() + 7 * 24 * 60 * 60 * 1000)
const expires = `expires=${date.toUTCString()}`
document.cookie = `hidePopup=true; ${expires}; path=/; SameSite=Lax`
}

const handlePrimaryButtonClick = () => {
closePopup()
window.open(
'https://forms.office.com/Pages/ResponsePage.aspx?id=knAhx0CyHU69YfqXupdcvJkAFGNmKDFCsjsXHsjRxlJUNjkzSVZRVDdaOFpEWlJOOE1PNUJLMVdFMS4u&embed=true',
'_blank',
'noopener,noreferrer'
)
}

const handleClosedButtonKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
toggleOpen()
}
}

if (!isVisible || isOpen === null) return null

return (
<div
className={`popup-container ${isOpen ? 'open' : isScrolled ? 'scrolled' : 'closed'}`}
ref={popupContainerRef}
tabIndex={isOpen ? -1 : 0}
onKeyDown={!isOpen ? handleClosedButtonKeyDown : undefined}
>
{!isOpen ? (
<button className='popup-closed' tabIndex={-1} onClick={toggleOpen} onKeyDown={handleClosedButtonKeyDown}>
<Clipboard className='clipboard-icon' size={20} focusable='false' />
<span className='closed-text'>Undersøkelse ssb.no</span>
</button>
) : (
<>
<div className='popup-header' role='presentation'>
<h4 className='header-text'>Hvordan opplever du ssb.no?</h4>
<button className='close-icon-wrapper' tabIndex={0} onClick={closePopup}>
<X className='close-icon' size={24} />
</button>
</div>
<div className='popup-content' role='presentation'>
<p>
Hjelp oss å gjøre opplevelsen din på ssb.no bedre. Det tar omtrent 6 minutter å svare på vår årlige
brukerundersøkelse.
</p>
</div>
<div className='button-group'>
<button
className='popup-secondary-button'
onClick={() => {
toggleOpen()
if (popupContainerRef.current) {
popupContainerRef.current.focus()
}
}}
>
Svar senere
</button>
<button className='popup-button' onClick={handlePrimaryButtonClick}>
Til undersøkelsen
</button>
</div>
</>
)}
</div>
)
}

export default (props: {}) => <Popup {...props} />
2 changes: 1 addition & 1 deletion src/main/resources/site/pages/default/default.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
[(${pageMap})]
</div>


<div id="popup" data-th-if="${popupBody}"></div>

<!-- Metainfo to make the page searchable -->
<div id="metainfo-container" data-th-if="${addMetaInfoSearch}"
Expand Down
15 changes: 15 additions & 0 deletions src/main/resources/site/pages/default/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,19 @@ export function get(req: XP.Request): XP.Response {
pageContributions = footer.pageContributions
}

const hidePopupCookie = req.cookies ? req.cookies['hidePopup'] : undefined

const isPopupEnabled = isEnabled('show-popup-survey', false, 'ssb')

const popupComponent =
isPopupEnabled && hidePopupCookie !== 'true'
? r4xpRender('Popup', {}, req, { id: 'popup', body: '<div id="popup"></div>', pageContributions })
: undefined

if (popupComponent) {
pageContributions = popupComponent.pageContributions
}

let municipality: MunicipalityWithCounty | undefined
if (req.params.selfRequest) {
municipality = getMunicipality(req as RequestWithCode)
Expand Down Expand Up @@ -266,6 +279,7 @@ export function get(req: XP.Request): XP.Response {
hideHeader,
hideBreadcrumb,
tableView: page.type === 'mimir:table',
popupBody: popupComponent?.body,
}

const thymeleafRenderBody = render(view, model)
Expand Down Expand Up @@ -733,4 +747,5 @@ interface DefaultModel {
hideHeader: boolean
hideBreadcrumb: boolean
tableView: boolean
popupBody: string | undefined // Added for Popup component
}
Loading