Update PartyHeader and DropdownMenuItem

* Remove extraneous states and hooks from PartyHeader
* Only show PartyDropdown if we are looking at an existing party
* Add destructive prop for DropdownMenuItem
* Remove extraneous classes from PartyDropdown
* Localize dropdown contents
This commit is contained in:
Justin Edmund 2023-06-30 13:55:01 -07:00
parent 9a16574948
commit 0e10ac5a48
6 changed files with 69 additions and 114 deletions

View file

@ -50,7 +50,7 @@
}
}
& .destructive {
&.destructive {
color: $error;
&:hover {

View file

@ -3,7 +3,13 @@ import classNames from 'classnames'
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
import styles from './index.module.scss'
interface Props extends DropdownMenuPrimitive.DropdownMenuItemProps {}
interface Props extends DropdownMenuPrimitive.DropdownMenuItemProps {
destructive?: boolean
}
const defaultProps = {
destructive: false,
}
export const DropdownMenuItem = React.forwardRef<HTMLDivElement, Props>(
function dropdownMenuItem(
@ -13,6 +19,7 @@ export const DropdownMenuItem = React.forwardRef<HTMLDivElement, Props>(
const classes = classNames(props.className, {
[styles.menuItem]: true,
[styles.language]: props.className?.includes('language'),
[styles.destructive]: props.destructive,
})
return (
@ -27,4 +34,6 @@ export const DropdownMenuItem = React.forwardRef<HTMLDivElement, Props>(
}
)
DropdownMenuItem.defaultProps = defaultProps
export default DropdownMenuItem

View file

@ -1,9 +1,8 @@
// Libraries
import React, { useEffect, useState } from 'react'
import React, { useState } from 'react'
import { useRouter } from 'next/router'
import { subscribe, useSnapshot } from 'valtio'
import { useSnapshot } from 'valtio'
import { useTranslation } from 'next-i18next'
import classNames from 'classnames'
// Dependencies: Common
import Button from '~components/common/Button'
@ -11,9 +10,9 @@ import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
} from '~components/common/DropdownMenuContent'
import DropdownMenuGroup from '~components/common/DropdownMenuGroup'
import DropdownMenuItem from '~components/common/DropdownMenuItem'
// Dependencies: Toasts
import RemixedToast from '~components/toasts/RemixedToast'
@ -24,12 +23,7 @@ import DeleteTeamAlert from '~components/dialogs/DeleteTeamAlert'
import RemixTeamAlert from '~components/dialogs/RemixTeamAlert'
// Dependencies: Utils
import api from '~utils/api'
import { accountState } from '~utils/accountState'
import { appState } from '~utils/appState'
import { getLocalId } from '~utils/localId'
import { retrieveLocaleCookies } from '~utils/retrieveCookies'
import { setEditKey, storeEditKey } from '~utils/userToken'
// Dependencies: Icons
import EllipsisIcon from '~public/icons/Ellipsis.svg'
@ -51,9 +45,6 @@ const PartyDropdown = ({
// Router
const router = useRouter()
const locale =
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
const localeData = retrieveLocaleCookies()
const [open, setOpen] = useState(false)
@ -63,23 +54,9 @@ const PartyDropdown = ({
const [copyToastOpen, setCopyToastOpen] = useState(false)
const [remixToastOpen, setRemixToastOpen] = useState(false)
const [name, setName] = useState('')
const [originalName, setOriginalName] = useState('')
// Snapshots
const { account } = useSnapshot(accountState)
const { party: partySnapshot } = useSnapshot(appState)
// Subscribe to app state to listen for party name and
// unsubscribe when component is unmounted
const unsubscribe = subscribe(appState, () => {
const newName =
appState.party && appState.party.name ? appState.party.name : ''
setName(newName)
})
useEffect(() => () => unsubscribe(), [])
// Methods: Event handlers (Buttons)
function handleButtonClicked() {
setOpen(!open)
@ -145,39 +122,37 @@ const PartyDropdown = ({
remixTeamCallback()
}
const editableItems = () => {
return (
<>
<DropdownMenuGroup className="MenuGroup">
<DropdownMenuItem className="MenuItem" onClick={copyToClipboard}>
<span>Copy link to team</span>
</DropdownMenuItem>
<DropdownMenuItem className="MenuItem" onClick={openRemixTeamAlert}>
<span>Remix team</span>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuGroup className="MenuGroup">
<DropdownMenuItem className="MenuItem" onClick={openDeleteTeamAlert}>
<span className="destructive">Delete team</span>
</DropdownMenuItem>
</DropdownMenuGroup>
</>
)
}
const items = (
<>
<DropdownMenuGroup>
<DropdownMenuItem onClick={copyToClipboard}>
<span>{t('dropdown.party.copy')}</span>
</DropdownMenuItem>
<DropdownMenuItem onClick={openRemixTeamAlert}>
<span>{t('dropdown.party.remix')}</span>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuGroup>
<DropdownMenuItem destructive={true} onClick={openDeleteTeamAlert}>
<span>{t('dropdown.party.delete')}</span>
</DropdownMenuItem>
</DropdownMenuGroup>
</>
)
return (
<>
<div id="DropdownWrapper">
<div className="dropdownWrapper">
<DropdownMenu open={open} onOpenChange={handleOpenChange}>
<DropdownMenuTrigger asChild>
<Button
leftAccessoryIcon={<EllipsisIcon />}
className={classNames({ Active: open })}
active={open}
blended={true}
leftAccessoryIcon={<EllipsisIcon />}
onClick={handleButtonClicked}
/>
</DropdownMenuTrigger>
<DropdownMenuContent>{editableItems()}</DropdownMenuContent>
<DropdownMenuContent>{items}</DropdownMenuContent>
</DropdownMenu>
</div>

View file

@ -17,6 +17,9 @@ import { accountState } from '~utils/accountState'
import { appState, initialAppState } from '~utils/appState'
import { formatTimeAgo } from '~utils/timeAgo'
import RemixTeamAlert from '~components/dialogs/RemixTeamAlert'
import RemixedToast from '~components/toasts/RemixedToast'
import EditIcon from '~public/icons/Edit.svg'
import RemixIcon from '~public/icons/Remix.svg'
import SaveIcon from '~public/icons/Save.svg'
@ -24,9 +27,6 @@ import SaveIcon from '~public/icons/Save.svg'
import type { DetailsObject } from 'types'
import styles from './index.module.scss'
import RemixTeamAlert from '~components/dialogs/RemixTeamAlert'
import RemixedToast from '~components/toasts/RemixedToast'
import { set } from 'local-storage'
// Props
interface Props {
@ -45,23 +45,15 @@ const PartyHeader = (props: Props) => {
const router = useRouter()
const locale = router.locale || 'en'
const isNewParty =
router.asPath === '/' || router.asPath.split('/')[1] === 'new'
const { party: partySnapshot } = useSnapshot(appState)
// State: Component
const [remixAlertOpen, setRemixAlertOpen] = useState(false)
const [remixToastOpen, setRemixToastOpen] = useState(false)
// State: Data
const [name, setName] = useState('')
const [chargeAttack, setChargeAttack] = useState(true)
const [fullAuto, setFullAuto] = useState(false)
const [autoGuard, setAutoGuard] = useState(false)
const [autoSummon, setAutoSummon] = useState(false)
const [buttonCount, setButtonCount] = useState<number | undefined>(undefined)
const [chainCount, setChainCount] = useState<number | undefined>(undefined)
const [turnCount, setTurnCount] = useState<number | undefined>(undefined)
const [clearTime, setClearTime] = useState(0)
const userClass = classNames({
[styles.user]: true,
[styles.empty]: !party.user,
@ -76,39 +68,6 @@ const PartyHeader = (props: Props) => {
light: party && party.element == 6,
})
useEffect(() => {
if (props.party) {
setName(props.party.name)
setAutoGuard(props.party.auto_guard)
setFullAuto(props.party.full_auto)
setAutoSummon(props.party.auto_summon)
setChargeAttack(props.party.charge_attack)
setClearTime(props.party.clear_time)
if (props.party.turn_count) setTurnCount(props.party.turn_count)
if (props.party.button_count) setButtonCount(props.party.button_count)
if (props.party.chain_count) setChainCount(props.party.chain_count)
}
}, [props.party])
// Subscribe to router changes and reset state
// if the new route is a new team
useEffect(() => {
router.events.on('routeChangeStart', (url, { shallow }) => {
if (url === '/new' || url === '/') {
const party = initialAppState.party
setName(party.name ? party.name : '')
setAutoGuard(party.autoGuard)
setFullAuto(party.fullAuto)
setChargeAttack(party.chargeAttack)
setClearTime(party.clearTime)
setTurnCount(party.turnCount)
setButtonCount(party.buttonCount)
setChainCount(party.chainCount)
}
})
}, [])
// Actions: Favorites
function toggleFavorite() {
if (appState.party.favorited) unsaveFavorite()
@ -255,7 +214,7 @@ const PartyHeader = (props: Props) => {
)
const autoGuardToken = (
<Token active className="autoGuard">
<Token active={party.autoGuard} className="autoGuard">
{`${t('party.details.labels.auto_guard')} ${
party.autoGuard ? 'On' : 'Off'
}`}
@ -326,8 +285,8 @@ const PartyHeader = (props: Props) => {
{fullAutoToken}
{autoSummonToken}
{autoGuardToken}
{party.turnCount ? turnCountToken : ''}
{party.clearTime > 0 ? clearTimeToken() : ''}
{party.turnCount && turnCountToken}
{party.clearTime > 0 && clearTimeToken()}
{buttonChainToken()}
</>
)
@ -374,7 +333,7 @@ const PartyHeader = (props: Props) => {
<h1 className={party.name ? '' : 'empty'}>
{party.name ? party.name : t('no_title')}
</h1>
{party.remix && party.sourceParty ? (
{party.remix && party.sourceParty && (
<Tooltip content={t('tooltips.source')}>
<Button
blended={true}
@ -384,22 +343,18 @@ const PartyHeader = (props: Props) => {
onClick={() => goTo(party.sourceParty?.shortcode)}
/>
</Tooltip>
) : (
''
)}
</div>
<div className={styles.attribution}>
{renderUserBlock()}
{appState.party.raid ? linkedRaidBlock(appState.party.raid) : ''}
{party.created_at != '' ? (
{appState.party.raid && linkedRaidBlock(appState.party.raid)}
{party.created_at != '' && (
<time
className={styles.lastUpdated}
dateTime={new Date(party.created_at).toString()}
>
{formatTimeAgo(new Date(party.created_at), locale)}
</time>
) : (
''
)}
</div>
</div>
@ -414,11 +369,13 @@ const PartyHeader = (props: Props) => {
text={t('buttons.show_info')}
/>
</EditPartyModal>
<PartyDropdown
editable={props.editable}
deleteTeamCallback={props.deleteCallback}
remixTeamCallback={props.remixCallback}
/>
{!isNewParty && (
<PartyDropdown
editable={props.editable}
deleteTeamCallback={props.deleteCallback}
remixTeamCallback={props.remixCallback}
/>
)}
</div>
) : (
<div className={styles.right}>

View file

@ -58,6 +58,13 @@
"remove": "Remove from grid",
"remove_job_skill": "Remove class skill"
},
"dropdown": {
"party": {
"copy": "Copy link to team",
"delete": "Delete team",
"remix": "Remix team"
}
},
"elements": {
"null": "Null",
"wind": "Wind",

View file

@ -58,6 +58,13 @@
"remove": "編成から削除",
"remove_job_skill": "ジョブスキルを削除"
},
"dropdown": {
"party": {
"copy": "編成のリンクをコピー",
"delete": "編成を削除",
"remix": "編成をリミックス"
}
},
"elements": {
"null": "無",
"wind": "風",