Skip to content

Commit

Permalink
Add DirectMessages Banner and Update All Banners (#3851)
Browse files Browse the repository at this point in the history
  • Loading branch information
rickyrombo committed Aug 4, 2023
1 parent e523d39 commit f9e1380
Show file tree
Hide file tree
Showing 32 changed files with 427 additions and 390 deletions.
15 changes: 15 additions & 0 deletions packages/web/src/components/banner/AppBannerWrapper.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.root {
flex-shrink: 0;
}

.root > div:first-child {
position: static;
}

.isMobile {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 15;
}
19 changes: 19 additions & 0 deletions packages/web/src/components/banner/AppBannerWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import cn from 'classnames'

import { isMobile } from 'utils/clientUtil'

import styles from './AppBannerWrapper.module.css'

/**
* Contains all the banners. Useful for mobile web to allow this to switch to fixed positioning,
* but also would like to see this control the banner list instead of App.js if it's possible to decouple some of the logic
*/
export const AppBannerWrapper = ({
children
}: {
children: React.ReactNode
}) => (
<div className={cn(styles.root, { [styles.isMobile]: isMobile() })}>
{children}
</div>
)
29 changes: 12 additions & 17 deletions packages/web/src/components/banner/Banner.module.css
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
.banner {
height: var(--banner-margin);
background: var(--page-header-gradient);
position: fixed;
min-height: 56px;
top: 0;
right: 0;
left: 0;

z-index: 14;
width: 100%;
background: var(--page-header-gradient);
display: flex;
align-items: center;
justify-content: center;
}

.banner.alert {
background: var(--accent-red-gradient);
padding: 0 var(--unit-10);
}

.banner.isElectron {
padding-left: 240px;
}

.banner.isMobile {
height: 72px;
.banner.isElectron .iconRemove {
left: calc(240px + var(--unit-4));
}

.iconRemove {
height: 24px;
width: 24px;
height: var(--unit-6);
width: var(--unit-6);
position: absolute;
left: 8px;
top: var(--unit-4);
left: var(--unit-4);
cursor: pointer;
}
.iconRemove:hover {
Expand All @@ -43,6 +38,6 @@
}

.isMobile .iconRemove {
align-self: flex-start;
margin-top: 8px;
top: var(--unit-2);
left: var(--unit-2);
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import cn from 'classnames'
import PropTypes from 'prop-types'

import { ReactComponent as IconRemove } from 'assets/img/iconRemove.svg'

import styles from './Banner.module.css'

const Banner = (props) => {
export type BannerProps = {
className?: string
onClose: () => void
isElectron?: boolean
isMobile?: boolean
children: React.ReactNode
}

export const Banner = (props: BannerProps) => {
return (
<div
className={cn(
styles.banner,
{
[styles.isElectron]: props.isElectron,
[styles.isMobile]: props.isMobile,
[styles.alert]: props.alert
[styles.isMobile]: props.isMobile
},
props.className
)}
Expand All @@ -23,17 +29,3 @@ const Banner = (props) => {
</div>
)
}

Banner.propTypes = {
className: PropTypes.string,
onClose: PropTypes.func,
isElectron: PropTypes.bool,
isMobile: PropTypes.bool,
alert: PropTypes.bool
}

Banner.defaultProps = {
alert: false
}

export default Banner
41 changes: 0 additions & 41 deletions packages/web/src/components/banner/CTABanner.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
cursor: pointer;
display: flex;
justify-content: center;
background: linear-gradient(358.41deg, #c049f9 0.17%, #8200e8 100%);
}

.ctaBanner .content {
display: flex;
align-items: center;
justify-content: center;
gap: var(--unit-4);
padding: var(--unit-4) 0;
}

.ctaBanner.isMobile .content {
gap: var(--unit-2);
}

.ctaBanner .contentSelection {
Expand All @@ -20,15 +25,16 @@
justify-content: center;
transition: all ease-in-out 0.07s;
border-bottom: 1px solid rgba(0, 0, 0, 0);
gap: var(--unit-2);
}

.ctaBanner:hover .contentSelection {
border-bottom: 1px solid var(--white);
}

.pill {
pointer-events: none;
background-color: rgba(255, 255, 255, 0.4);
margin-right: 24px;
}

.pill .pillText {
Expand All @@ -39,19 +45,25 @@

.text {
color: var(--static-white);
font-size: var(--font-m);
font-size: var(--font-l);
font-weight: var(--font-bold);
line-height: 130%;
text-align: center;
}

.celebration {
padding-right: 8px;
.isMobile .text {
font-size: var(--font-s);
}

.arrow {
padding-left: 8px;
height: 20px;
width: 20px;
height: var(--unit-5);
width: var(--unit-5);
flex-shrink: 0;
}

.isMobile .arrow {
height: var(--unit-4);
width: var(--unit-4);
}

.arrow g path {
Expand Down
76 changes: 76 additions & 0 deletions packages/web/src/components/banner/CallToActionBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { ReactNode } from 'react'

import { Client } from '@audius/common'
import { IconArrowWhite } from '@audius/stems'
import cn from 'classnames'

import { Banner, BannerProps } from 'components/banner/Banner'
import Pill from 'components/pill/Pill'
import { getClient } from 'utils/clientUtil'

import styles from './CallToActionBanner.module.css'

export type CallToActionBannerProps = Pick<
BannerProps,
'onClose' | 'className'
> & {
onAccept: () => void
emoji?: string
pill?: string
pillPosition?: 'left' | 'right'
text: ReactNode
}

export const CallToActionBanner = (props: CallToActionBannerProps) => {
const {
emoji,
pill,
pillPosition = 'left',
text,
onAccept,
...bannerProps
} = props

const client = getClient()

return (
<Banner
isElectron={client === Client.ELECTRON}
isMobile={client === Client.MOBILE}
{...bannerProps}
>
<div
className={cn(styles.ctaBanner, {
[styles.isMobile]: client === Client.MOBILE
})}
onClick={onAccept}
>
<div className={styles.content}>
{pill && pillPosition === 'left' ? (
<Pill
className={styles.pill}
textClassName={styles.pillText}
showIcon={false}
clickable={false}
text={pill}
/>
) : null}
<div className={styles.contentSelection}>
{emoji ? <i className={cn('emoji', emoji)} /> : null}
<div className={styles.text}>{text}</div>
<IconArrowWhite className={styles.arrow} />
</div>
{pill && pillPosition === 'right' ? (
<Pill
className={styles.pill}
textClassName={styles.pillText}
showIcon={false}
clickable={false}
text={pill}
/>
) : null}
</div>
</div>
</Banner>
)
}
59 changes: 59 additions & 0 deletions packages/web/src/components/banner/DirectMessagesBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useCallback, useState } from 'react'

import { Client, accountSelectors } from '@audius/common'
import { push as pushRoute } from 'connected-react-router'
import { useDispatch } from 'react-redux'

import { useSelector } from 'common/hooks/useSelector'
import { getClient } from 'utils/clientUtil'
import { CHATS_PAGE } from 'utils/route'

import { CallToActionBanner } from './CallToActionBanner'

const messages = {
text: 'Direct Messaging Now Available!',
pill: 'New'
}

const { getHasAccount } = accountSelectors

const DIRECT_MESSAGES_BANNER_LOCAL_STORAGE_KEY = 'dismissDirectMessagesBanner'

/**
* Displays a CTA Banner announcing the launch of Direct Messaging
* for logged in users on desktop web and desktop app (since logged out users can't use Direct Messages)
*/
export const DirectMessagesBanner = () => {
const dispatch = useDispatch()
const signedIn = useSelector(getHasAccount)
const isMobile = getClient() === Client.MOBILE
const hasDismissed = window.localStorage.getItem(
DIRECT_MESSAGES_BANNER_LOCAL_STORAGE_KEY
)
const [isVisible, setIsVisible] = useState(
!hasDismissed && !isMobile && signedIn
)

const handleClose = useCallback(() => {
setIsVisible(false)
window.localStorage.setItem(
DIRECT_MESSAGES_BANNER_LOCAL_STORAGE_KEY,
'true'
)
}, [])

const handleAccept = useCallback(() => {
dispatch(pushRoute(CHATS_PAGE))
handleClose()
}, [dispatch, handleClose])

return isVisible ? (
<CallToActionBanner
text={messages.text}
pill={messages.pill}
emoji={'speech-balloon'}
onClose={handleClose}
onAccept={handleAccept}
/>
) : null
}

0 comments on commit f9e1380

Please sign in to comment.