Implement dialog and notices
This implements the PartyVisibilityDialog in PartyHeader, lets the user invoke it from PartyDropdown, and adds notices so the user knows if a party is private or unlisted.
This commit is contained in:
parent
6e0973d406
commit
2cf8b028d1
4 changed files with 143 additions and 1 deletions
|
|
@ -46,6 +46,10 @@
|
|||
flex-grow: 1;
|
||||
}
|
||||
|
||||
&.no-shrink {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&.blended {
|
||||
background: transparent;
|
||||
}
|
||||
|
|
@ -304,6 +308,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.notice {
|
||||
background-color: var(--notice-button-bg);
|
||||
color: var(--notice-button-text);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--notice-button-bg-hover);
|
||||
}
|
||||
}
|
||||
|
||||
&.destructive {
|
||||
background: $error;
|
||||
color: white;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Libraries
|
||||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
|
@ -33,12 +33,14 @@ interface Props {
|
|||
editable: boolean
|
||||
deleteTeamCallback: () => void
|
||||
remixTeamCallback: () => void
|
||||
teamVisibilityCallback: () => void
|
||||
}
|
||||
|
||||
const PartyDropdown = ({
|
||||
editable,
|
||||
deleteTeamCallback,
|
||||
remixTeamCallback,
|
||||
teamVisibilityCallback,
|
||||
}: Props) => {
|
||||
// Localization
|
||||
const { t } = useTranslation('common')
|
||||
|
|
@ -81,6 +83,11 @@ const PartyDropdown = ({
|
|||
|
||||
// Methods: Event handlers
|
||||
|
||||
// Dialogs / Visibility
|
||||
function visibilityCallback() {
|
||||
teamVisibilityCallback()
|
||||
}
|
||||
|
||||
// Alerts / Delete team
|
||||
function openDeleteTeamAlert() {
|
||||
setDeleteAlertOpen(true)
|
||||
|
|
@ -125,6 +132,9 @@ const PartyDropdown = ({
|
|||
const items = (
|
||||
<>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem onClick={visibilityCallback}>
|
||||
<span>{t('dropdown.party.visibility')}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={copyToClipboard}>
|
||||
<span>{t('dropdown.party.copy')}</span>
|
||||
</DropdownMenuItem>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,41 @@
|
|||
}
|
||||
}
|
||||
|
||||
.notice {
|
||||
align-items: center;
|
||||
background: var(--notice-bg);
|
||||
border-radius: $card-corner;
|
||||
display: flex;
|
||||
gap: $unit-2x;
|
||||
font-size: $font-regular;
|
||||
justify-content: space-between;
|
||||
padding: $unit-4x;
|
||||
overflow: hidden;
|
||||
|
||||
@include breakpoint(small-tablet) {
|
||||
flex-direction: column;
|
||||
gap: $unit;
|
||||
padding: $unit-2x;
|
||||
}
|
||||
|
||||
p {
|
||||
color: var(--notice-text);
|
||||
}
|
||||
|
||||
.buttons {
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
gap: $unit;
|
||||
|
||||
@include breakpoint(small-tablet) {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ import SaveIcon from '~public/icons/Save.svg'
|
|||
import type { DetailsObject } from 'types'
|
||||
|
||||
import styles from './index.module.scss'
|
||||
import PartyVisibilityDialog from '../PartyVisibilityDialog'
|
||||
import UrlCopiedToast from '~components/toasts/UrlCopiedToast'
|
||||
|
||||
// Props
|
||||
interface Props {
|
||||
|
|
@ -50,8 +52,10 @@ const PartyHeader = (props: Props) => {
|
|||
|
||||
// State: Component
|
||||
const [detailsOpen, setDetailsOpen] = useState(false)
|
||||
const [copyToastOpen, setCopyToastOpen] = useState(false)
|
||||
const [remixAlertOpen, setRemixAlertOpen] = useState(false)
|
||||
const [remixToastOpen, setRemixToastOpen] = useState(false)
|
||||
const [visibilityDialogOpen, setVisibilityDialogOpen] = useState(false)
|
||||
|
||||
const userClass = classNames({
|
||||
[styles.user]: true,
|
||||
|
|
@ -122,12 +126,29 @@ const PartyHeader = (props: Props) => {
|
|||
setDetailsOpen(open)
|
||||
}
|
||||
|
||||
// Dialogs: Visibility
|
||||
function visibilityDialogCallback() {
|
||||
setVisibilityDialogOpen(true)
|
||||
}
|
||||
|
||||
function handleVisibilityDialogChange(open: boolean) {
|
||||
setVisibilityDialogOpen(open)
|
||||
}
|
||||
|
||||
// Actions: Remix team
|
||||
function remixTeamCallback() {
|
||||
setRemixToastOpen(true)
|
||||
props.remixCallback()
|
||||
}
|
||||
|
||||
// Actions: Copy URL
|
||||
function copyToClipboard() {
|
||||
if (router.asPath.split('/')[1] === 'p') {
|
||||
navigator.clipboard.writeText(window.location.href)
|
||||
setCopyToastOpen(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Alerts: Remix team
|
||||
function openRemixTeamAlert() {
|
||||
setRemixAlertOpen(true)
|
||||
|
|
@ -146,6 +167,15 @@ const PartyHeader = (props: Props) => {
|
|||
setRemixToastOpen(false)
|
||||
}
|
||||
|
||||
// Toasts / Copy URL
|
||||
function handleCopyToastOpenChanged(open: boolean) {
|
||||
setCopyToastOpen(!open)
|
||||
}
|
||||
|
||||
function handleCopyToastCloseClicked() {
|
||||
setCopyToastOpen(false)
|
||||
}
|
||||
|
||||
// Rendering
|
||||
|
||||
const userBlock = (username?: string, picture?: string, element?: string) => {
|
||||
|
|
@ -298,6 +328,44 @@ const PartyHeader = (props: Props) => {
|
|||
)
|
||||
}
|
||||
|
||||
// Render: Notice
|
||||
const unlistedNotice = (
|
||||
<div className={styles.notice}>
|
||||
<p>{t('party.notices.unlisted')}</p>
|
||||
<div className={styles.buttons}>
|
||||
<Button
|
||||
bound={true}
|
||||
className="notice no-shrink"
|
||||
key="copy_link"
|
||||
text={t('party.notices.buttons.copy_link')}
|
||||
onClick={copyToClipboard}
|
||||
/>
|
||||
<Button
|
||||
bound={true}
|
||||
className="notice no-shrink"
|
||||
key="change_visibility"
|
||||
text={t('party.notices.buttons.change_visibility')}
|
||||
onClick={() => handleVisibilityDialogChange(true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const privateNotice = (
|
||||
<div className={styles.notice}>
|
||||
<p>{t('party.notices.private')}</p>
|
||||
<div className={styles.buttons}>
|
||||
<Button
|
||||
bound={true}
|
||||
className="notice"
|
||||
key="change_visibility"
|
||||
text={t('party.notices.buttons.change_visibility')}
|
||||
onClick={() => handleVisibilityDialogChange(true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
// Render: Buttons
|
||||
const saveButton = () => {
|
||||
return (
|
||||
|
|
@ -358,6 +426,8 @@ const PartyHeader = (props: Props) => {
|
|||
return (
|
||||
<>
|
||||
<header className={styles.wrapper}>
|
||||
{party.visibility == 2 && unlistedNotice}
|
||||
{party.visibility == 3 && privateNotice}
|
||||
<section className={styles.info}>
|
||||
<div className={styles.left}>
|
||||
<div className={styles.header}>
|
||||
|
|
@ -399,6 +469,7 @@ const PartyHeader = (props: Props) => {
|
|||
editable={props.editable}
|
||||
deleteTeamCallback={props.deleteCallback}
|
||||
remixTeamCallback={props.remixCallback}
|
||||
teamVisibilityCallback={visibilityDialogCallback}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -412,6 +483,13 @@ const PartyHeader = (props: Props) => {
|
|||
<section className={styles.tokens}>{renderTokens()}</section>
|
||||
</header>
|
||||
|
||||
<PartyVisibilityDialog
|
||||
open={visibilityDialogOpen}
|
||||
value={party.visibility as 1 | 2 | 3}
|
||||
onOpenChange={handleVisibilityDialogChange}
|
||||
updateParty={props.updateCallback}
|
||||
/>
|
||||
|
||||
<RemixTeamAlert
|
||||
creator={props.editable}
|
||||
name={partySnapshot.name ? partySnapshot.name : t('no_title')}
|
||||
|
|
@ -426,6 +504,12 @@ const PartyHeader = (props: Props) => {
|
|||
onOpenChange={handleRemixToastOpenChanged}
|
||||
onCloseClick={handleRemixToastCloseClicked}
|
||||
/>
|
||||
|
||||
<UrlCopiedToast
|
||||
open={copyToastOpen}
|
||||
onOpenChange={handleCopyToastOpenChanged}
|
||||
onCloseClick={handleCopyToastCloseClicked}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue