Skip to content

Commit

Permalink
[PAY-1255] [PAY-1245] DMs: Add confirmation modals (#3424)
Browse files Browse the repository at this point in the history
  • Loading branch information
rickyrombo committed May 25, 2023
1 parent 07e36d5 commit 1c33185
Show file tree
Hide file tree
Showing 18 changed files with 405 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ root {
--white: #ffffff;

--accent-red: #d0021b;
--accent-red-dark-1: #aa0115;
--accent-red-dark-1: #bb0218;
--accent-red-light-1: #d51b32;

--accent-green: #0ba400;
Expand Down Expand Up @@ -109,7 +109,7 @@ root {
--static-white: #ffffff;

--static-accent-red: #d0021b;
--static-accent-red-dark-1: #aa0115;
--static-accent-red-dark-1: #bb0218;
--static-accent-red-light-1: #d51b32;

--static-accent-green: #0ba400;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,3 +453,44 @@
.textButton:hover .icon path {
fill: var(--secondary);
}

/** Destructive buttons **/
.destructive {
background: transparent;
border: 1px solid var(--accent-red);
border-radius: var(--unit-1);
}

.destructive .textLabel {
font-size: var(--font-l);
font-weight: var(--font-bold);
color: var(--accent-red);
}

.destructive .icon path {
fill: var(--accent-red);
}

/** destructive hover **/
.destructive.includeHoverAnimations:hover:enabled {
transform: var(--grow);
background-color: var(--accent-red);
}

.destructive.includeHoverAnimations:active:enabled {
transform: perspective(1px) scale3d(0.99, 0.99, 0.99);
background-color: var(--accent-red-dark-1);
}

.destructive.includeHoverAnimations:hover:enabled .textLabel {
color: white;
}

.destructive.includeHoverAnimations:hover:enabled .icon path {
fill: var(--static-white);
}

/** destructive disabled **/
.destructive:disabled {
opacity: 0.45;
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,7 @@ White.args = { type: Type.WHITE }
// Text
export const Text = Template.bind({})
Text.args = { type: Type.TEXT }

// Destructive
export const Destructive = Template.bind({})
Destructive.args = { type: Type.DESTRUCTIVE }
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const TYPE_STYLE_MAP = {
[Type.DISABLED]: styles.disabled,
[Type.GLASS]: styles.glass,
[Type.WHITE]: styles.white,
[Type.TEXT]: styles.textButton
[Type.TEXT]: styles.textButton,
[Type.DESTRUCTIVE]: styles.destructive
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export enum Type {
DISABLED = 'disabled',
GLASS = 'glass',
WHITE = 'white',
TEXT = 'text'
TEXT = 'text',
DESTRUCTIVE = 'destructive'
}

export enum Size {
Expand Down
13 changes: 6 additions & 7 deletions apps/audius-client/packages/stems/src/components/Modal/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { HTMLAttributes, ReactNode } from 'react'
import * as React from 'react'

import { ScrollbarProps } from 'components/Scrollbar'

Expand Down Expand Up @@ -44,7 +43,7 @@ export type ModalProps = {
/**
* @deprecated in favor of composability - use ModalHeader sub-component instead.
*/
title?: React.ReactNode
title?: ReactNode
/**
* @deprecated in favor of composability - use ModalHeader sub-component instead.
*/
Expand Down Expand Up @@ -128,16 +127,16 @@ export type ModalHeaderProps = HTMLAttributes<HTMLDivElement> & {
dismissButtonClassName?: string
showDismissButton?: boolean
onClose?: () => void
children: React.ReactNode
children: ReactNode
}

export type ModalTitleProps = HTMLAttributes<HTMLDivElement> & {
export type ModalTitleProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> & {
subtitleClassName?: string
icon?: React.ReactNode
icon?: ReactNode
iconClassName?: string
title: React.ReactNode
title: ReactNode
titleClassName?: string
subtitle?: React.ReactNode
subtitle?: ReactNode
titleId?: string
subtitleId?: string
}
Expand Down
4 changes: 2 additions & 2 deletions apps/audius-client/packages/web/src/assets/styles/colors.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
--accent-blue: #1ba1f1;

--accent-red: #d0021b;
--accent-red-dark-1: #aa0115;
--accent-red-dark-1: #bb0218;
--accent-red-light-1: #d51b32;

--accent-green: #0ba400;
Expand Down Expand Up @@ -222,7 +222,7 @@
--static-white: #ffffff;

--static-accent-red: #d0021b;
--static-accent-red-dark-1: #aa0115;
--static-accent-red-dark-1: #bb0218;
--static-accent-red-light-1: #d51b32;

--static-accent-green: #0ba400;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
border-radius: var(--unit-2);
}

.icon {
.icon,
.icon svg {
width: var(--unit-6);
height: var(--unit-6);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import { ReactComponent as IconQuestionCircle } from 'assets/img/iconQuestionCir
import styles from './HelpCallout.module.css'

export const HelpCallout = ({
icon = <IconQuestionCircle />,
content,
className
}: {
icon?: ReactNode
content: ReactNode
className?: string
}) => {
return (
<div className={cn(styles.root, className)}>
<IconQuestionCircle className={styles.icon} />
<div className={styles.icon}>{icon}</div>
<div className={styles.content}>{content}</div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.root {
max-width: 488px;
}

.icon path {
fill: var(--neutral-light-2);
}

.button {
flex: 1;
}

.content > div {
line-height: 150%;
font-weight: var(--font-medium);
font-size: var(--font-l);
display: flex;
flex-direction: column;
gap: var(--unit-4);
}

.footer {
display: flex;
gap: var(--unit-4);
padding: 0 var(--unit-6) var(--unit-6) var(--unit-6);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { useCallback } from 'react'

import { User, chatActions } from '@audius/common'
import {
Button,
ButtonType,
IconBlockMessages,
IconInfo,
Modal,
ModalContent,
ModalFooter,
ModalHeader,
ModalTitle
} from '@audius/stems'
import { useDispatch } from 'react-redux'

import { HelpCallout } from 'components/help-callout/HelpCallout'
import { UserNameAndBadges } from 'components/user-name-and-badges/UserNameAndBadges'

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

const { blockUser } = chatActions

const messages = {
title: 'Are you sure?',
confirm: 'Block User',
cancel: 'Cancel',
content: (user: User) => (
<>
Are you sure you want to block <UserNameAndBadges user={user} /> from
sending messages to your inbox?
</>
),
callout:
'This will not affect their ability to view your profile or interact with your content.'
}

type BlockUserConfirmationModalProps = {
isVisible: boolean
onClose: () => void
user: User
}

export const BlockUserConfirmationModal = ({
isVisible,
onClose,
user
}: BlockUserConfirmationModalProps) => {
const dispatch = useDispatch()
const handleConfirmClicked = useCallback(() => {
dispatch(blockUser({ userId: user.user_id }))
onClose()
}, [dispatch, onClose, user])

return (
<Modal bodyClassName={styles.root} isOpen={isVisible} onClose={onClose}>
<ModalHeader>
<ModalTitle
title={messages.title}
icon={<IconBlockMessages />}
iconClassName={styles.icon}
/>
</ModalHeader>
<ModalContent className={styles.content}>
<div>{messages.content(user)}</div>
<HelpCallout icon={<IconInfo />} content={messages.callout} />
</ModalContent>
<ModalFooter className={styles.footer}>
<Button
className={styles.button}
type={ButtonType.PRIMARY}
text={messages.cancel}
onClick={onClose}
/>
<Button
className={styles.button}
type={ButtonType.DESTRUCTIVE}
text={messages.confirm}
onClick={handleConfirmClicked}
/>
</ModalFooter>
</Modal>
)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { forwardRef, useCallback } from 'react'
import { forwardRef, useCallback, useState } from 'react'

import {
useProxySelector,
chatSelectors,
chatActions,
User
} from '@audius/common'
import { useProxySelector, chatSelectors, User } from '@audius/common'
import {
IconButton,
IconCompose,
Expand All @@ -23,8 +18,11 @@ import { useDispatch, useSelector } from 'react-redux'
import { useModalState } from 'common/hooks/useModalState'
import { profilePage } from 'utils/route'

import { BlockUserConfirmationModal } from './BlockUserConfirmationModal'
import styles from './ChatHeader.module.css'
import { ChatUser } from './ChatUser'
import { DeleteChatConfirmationModal } from './DeleteChatConfirmationModal'
import { UnblockUserConfirmationModal } from './UnblockUserConfirmationModal'

const messages = {
header: 'Messages',
Expand All @@ -38,7 +36,6 @@ const messages = {
}

const { getOtherChatUsers, getBlockees } = chatSelectors
const { blockUser, unblockUser, deleteChat } = chatActions

type ChatHeaderProps = { currentChatId?: string }

Expand All @@ -47,6 +44,12 @@ export const ChatHeader = forwardRef<HTMLDivElement, ChatHeaderProps>(
const dispatch = useDispatch()
const [, setCreateChatVisible] = useModalState('CreateChat')
const [, setInboxSettingsVisible] = useModalState('InboxSettings')
const [isUnblockUserModalVisible, setIsUnblockUserModalVisible] =
useState(false)
const [isBlockUserModalVisible, setIsBlockUserModalVisible] =
useState(false)
const [isDeleteChatModalVisible, setIsDeleteChatModalVisible] =
useState(false)
const users = useProxySelector(
(state) => getOtherChatUsers(state, currentChatId),
[currentChatId]
Expand All @@ -64,22 +67,20 @@ export const ChatHeader = forwardRef<HTMLDivElement, ChatHeaderProps>(
}, [setInboxSettingsVisible])

const handleUnblockClicked = useCallback(() => {
dispatch(unblockUser({ userId: user.user_id }))
}, [dispatch, user])
setIsUnblockUserModalVisible(true)
}, [setIsUnblockUserModalVisible])

const handleBlockClicked = useCallback(() => {
dispatch(blockUser({ userId: user.user_id }))
}, [dispatch, user])
setIsBlockUserModalVisible(true)
}, [setIsBlockUserModalVisible])

const handleVisitClicked = useCallback(() => {
dispatch(pushRoute(profilePage(user.handle)))
}, [dispatch, user])

const handleDeleteClicked = useCallback(() => {
if (currentChatId) {
dispatch(deleteChat({ chatId: currentChatId }))
}
}, [dispatch, currentChatId])
setIsDeleteChatModalVisible(true)
}, [setIsDeleteChatModalVisible])

const overflowItems = [
isBlocked
Expand Down Expand Up @@ -139,6 +140,21 @@ export const ChatHeader = forwardRef<HTMLDivElement, ChatHeaderProps>(
/>
)}
/>
<UnblockUserConfirmationModal
user={user}
isVisible={isUnblockUserModalVisible}
onClose={() => setIsUnblockUserModalVisible(false)}
/>
<BlockUserConfirmationModal
user={user}
isVisible={isBlockUserModalVisible}
onClose={() => setIsBlockUserModalVisible(false)}
/>
<DeleteChatConfirmationModal
chatId={currentChatId}
isVisible={isDeleteChatModalVisible}
onClose={() => setIsDeleteChatModalVisible(false)}
/>
</div>
) : null}
</div>
Expand Down
Loading

0 comments on commit 1c33185

Please sign in to comment.