Quality pass (#326)
* Move min-width to RaidCombobox, not Popover This fixes #318 * Use snapshots to make tokens reactive This fixes #319 * Revert ChatGPT refactor of this method Oops. This code was nice, but it didn't actually assign `false` to keys to be sent to the server. We will revisit this, but it needs to be fixed right now. This fixes #325 * Ignore gacha directory We will probably scrape these images soon. * Add translation for Auto Summon token * Add auto summon token to app state * Set battle settings in state on update Also renames PartyDetails to PartyFooter and makes description reactive * Stop 1password icon from appearing in name field * Use snapshot for reactive Edit party modal * Fix Edit modal placeholder colors * Fix bug with RaidCombobox and Farming Selecting farming then opening the raid combobox *twice* consecutively would put you in no segment, so no raids appeared Fixes #323 * Fix values staying in Edit team even if not saved The values a user entered in the Edit team modal would persist even if the user hit cancel to close the modal. They wouldn't save to the server, but very confusing nonetheless. Now fixed. * Fix unreadable colors in ElementToggle * Fix button alignment in weapon modal * Add text to filters button on small screens The FilterBar showed a left aligned filter icon on mobile for months and it was driving me insane * Remove extraneous code from Header Including the party name, since it's at the top now * Fix Alert at small sizes * Make copy link toast work again * Remove stylesheet links * Fix remix toasts and alerts from both locations The remix toast and alert was barely hooked up and not showing up when invoked from PartyHeader. It now shows up whether you remix your own team (from PartyDropdown) or if you remix another person's team (from PartyHeader).
This commit is contained in:
parent
73b98db85e
commit
103ef7e1a2
26 changed files with 384 additions and 369 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -58,6 +58,7 @@ public/images/mastery*
|
||||||
public/images/updates*
|
public/images/updates*
|
||||||
public/images/guidebooks*
|
public/images/guidebooks*
|
||||||
public/images/raids*
|
public/images/raids*
|
||||||
|
public/images/gacha*
|
||||||
|
|
||||||
# Typescript v1 declaration files
|
# Typescript v1 declaration files
|
||||||
typings/
|
typings/
|
||||||
|
|
|
||||||
|
|
@ -47,32 +47,32 @@
|
||||||
|
|
||||||
&.fire {
|
&.fire {
|
||||||
background: var(--fire-bg);
|
background: var(--fire-bg);
|
||||||
color: var(--fire-text);
|
color: var(--fire-hover-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.water {
|
&.water {
|
||||||
background: var(--water-bg);
|
background: var(--water-bg);
|
||||||
color: var(--water-text);
|
color: var(--water-hover-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.earth {
|
&.earth {
|
||||||
background: var(--earth-bg);
|
background: var(--earth-bg);
|
||||||
color: var(--earth-text);
|
color: var(--earth-hover-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.wind {
|
&.wind {
|
||||||
background: var(--wind-bg);
|
background: var(--wind-bg);
|
||||||
color: var(--wind-text);
|
color: var(--wind-hover-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.dark {
|
&.dark {
|
||||||
background: var(--dark-bg);
|
background: var(--dark-bg);
|
||||||
color: var(--dark-text);
|
color: var(--dark-hover-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.light {
|
&.light {
|
||||||
background: var(--light-bg);
|
background: var(--light-bg);
|
||||||
color: var(--light-text);
|
color: var(--light-hover-text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Filter.Button {
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.Text {
|
||||||
|
display: none;
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
@include breakpoint(tablet) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include breakpoint(phone) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.UserInfo {
|
.UserInfo {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,7 @@ const FilterBar = (props: Props) => {
|
||||||
className={filterButtonClasses}
|
className={filterButtonClasses}
|
||||||
blended={true}
|
blended={true}
|
||||||
leftAccessoryIcon={<FilterIcon />}
|
leftAccessoryIcon={<FilterIcon />}
|
||||||
|
text={t('filters.name')}
|
||||||
onClick={() => setFilterModalOpen(true)}
|
onClick={() => setFilterModalOpen(true)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import classNames from 'classnames'
|
||||||
import clonedeep from 'lodash.clonedeep'
|
import clonedeep from 'lodash.clonedeep'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
import api from '~utils/api'
|
|
||||||
import { accountState, initialAccountState } from '~utils/accountState'
|
import { accountState, initialAccountState } from '~utils/accountState'
|
||||||
import { appState, initialAppState } from '~utils/appState'
|
import { appState, initialAppState } from '~utils/appState'
|
||||||
import { getLocalId } from '~utils/localId'
|
import { getLocalId } from '~utils/localId'
|
||||||
|
|
@ -32,11 +31,8 @@ import Tooltip from '~components/common/Tooltip'
|
||||||
import * as Switch from '@radix-ui/react-switch'
|
import * as Switch from '@radix-ui/react-switch'
|
||||||
|
|
||||||
import ChevronIcon from '~public/icons/Chevron.svg'
|
import ChevronIcon from '~public/icons/Chevron.svg'
|
||||||
import LinkIcon from '~public/icons/Link.svg'
|
|
||||||
import MenuIcon from '~public/icons/Menu.svg'
|
import MenuIcon from '~public/icons/Menu.svg'
|
||||||
import RemixIcon from '~public/icons/Remix.svg'
|
|
||||||
import PlusIcon from '~public/icons/Add.svg'
|
import PlusIcon from '~public/icons/Add.svg'
|
||||||
import SaveIcon from '~public/icons/Save.svg'
|
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
|
|
@ -51,7 +47,6 @@ const Header = () => {
|
||||||
const localeData = retrieveLocaleCookies()
|
const localeData = retrieveLocaleCookies()
|
||||||
|
|
||||||
// State management
|
// State management
|
||||||
const [copyToastOpen, setCopyToastOpen] = useState(false)
|
|
||||||
const [remixToastOpen, setRemixToastOpen] = useState(false)
|
const [remixToastOpen, setRemixToastOpen] = useState(false)
|
||||||
const [loginModalOpen, setLoginModalOpen] = useState(false)
|
const [loginModalOpen, setLoginModalOpen] = useState(false)
|
||||||
const [signupModalOpen, setSignupModalOpen] = useState(false)
|
const [signupModalOpen, setSignupModalOpen] = useState(false)
|
||||||
|
|
@ -64,7 +59,6 @@ const Header = () => {
|
||||||
const [originalName, setOriginalName] = useState('')
|
const [originalName, setOriginalName] = useState('')
|
||||||
|
|
||||||
// Snapshots
|
// Snapshots
|
||||||
const { account } = useSnapshot(accountState)
|
|
||||||
const { party: partySnapshot } = useSnapshot(appState)
|
const { party: partySnapshot } = useSnapshot(appState)
|
||||||
|
|
||||||
// Subscribe to app state to listen for party name and
|
// Subscribe to app state to listen for party name and
|
||||||
|
|
@ -108,15 +102,6 @@ const Header = () => {
|
||||||
setRightMenuOpen(false)
|
setRightMenuOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods: Event handlers (Copy toast)
|
|
||||||
function handleCopyToastOpenChanged(open: boolean) {
|
|
||||||
setCopyToastOpen(open)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCopyToastCloseClicked() {
|
|
||||||
setCopyToastOpen(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Methods: Event handlers (Remix toasts)
|
// Methods: Event handlers (Remix toasts)
|
||||||
function handleRemixToastOpenChanged(open: boolean) {
|
function handleRemixToastOpenChanged(open: boolean) {
|
||||||
setRemixToastOpen(open)
|
setRemixToastOpen(open)
|
||||||
|
|
@ -142,23 +127,6 @@ const Header = () => {
|
||||||
router.push(router.asPath, undefined, { locale: language })
|
router.push(router.asPath, undefined, { locale: language })
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyToClipboard() {
|
|
||||||
const path = router.asPath.split('/')[1]
|
|
||||||
|
|
||||||
if (path === 'p') {
|
|
||||||
const el = document.createElement('input')
|
|
||||||
el.value = window.location.href
|
|
||||||
el.id = 'url-input'
|
|
||||||
document.body.appendChild(el)
|
|
||||||
|
|
||||||
el.select()
|
|
||||||
document.execCommand('copy')
|
|
||||||
el.remove()
|
|
||||||
|
|
||||||
setCopyToastOpen(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
// Close menu
|
// Close menu
|
||||||
closeRightMenu()
|
closeRightMenu()
|
||||||
|
|
@ -188,84 +156,6 @@ const Header = () => {
|
||||||
router.push('/new')
|
router.push('/new')
|
||||||
}
|
}
|
||||||
|
|
||||||
function remixTeam() {
|
|
||||||
setOriginalName(partySnapshot.name ? partySnapshot.name : t('no_title'))
|
|
||||||
|
|
||||||
if (partySnapshot.shortcode) {
|
|
||||||
const body = getLocalId()
|
|
||||||
api
|
|
||||||
.remix({ shortcode: partySnapshot.shortcode, body: body })
|
|
||||||
.then((response) => {
|
|
||||||
const remix = response.data.party
|
|
||||||
|
|
||||||
// Store the edit key in local storage
|
|
||||||
if (remix.edit_key) {
|
|
||||||
storeEditKey(remix.id, remix.edit_key)
|
|
||||||
setEditKey(remix.id, remix.user)
|
|
||||||
}
|
|
||||||
|
|
||||||
router.push(`/p/${remix.shortcode}`)
|
|
||||||
setRemixToastOpen(true)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleFavorite() {
|
|
||||||
if (partySnapshot.favorited) unsaveFavorite()
|
|
||||||
else saveFavorite()
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveFavorite() {
|
|
||||||
if (partySnapshot.id)
|
|
||||||
api.saveTeam({ id: partySnapshot.id }).then((response) => {
|
|
||||||
if (response.status == 201) appState.party.favorited = true
|
|
||||||
})
|
|
||||||
else console.error('Failed to save team: No party ID')
|
|
||||||
}
|
|
||||||
|
|
||||||
function unsaveFavorite() {
|
|
||||||
if (partySnapshot.id)
|
|
||||||
api.unsaveTeam({ id: partySnapshot.id }).then((response) => {
|
|
||||||
if (response.status == 200) appState.party.favorited = false
|
|
||||||
})
|
|
||||||
else console.error('Failed to unsave team: No party ID')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rendering: Elements
|
|
||||||
const pageTitle = () => {
|
|
||||||
let title = ''
|
|
||||||
let hasAccessory = false
|
|
||||||
|
|
||||||
const path = router.asPath.split('/')[1]
|
|
||||||
if (path === 'p') {
|
|
||||||
hasAccessory = true
|
|
||||||
if (appState.party && appState.party.name) {
|
|
||||||
title = appState.party.name
|
|
||||||
} else {
|
|
||||||
title = t('no_title')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
title = ''
|
|
||||||
}
|
|
||||||
|
|
||||||
return title !== '' ? (
|
|
||||||
<Tooltip content={t('tooltips.copy_url')}>
|
|
||||||
<Button
|
|
||||||
blended={true}
|
|
||||||
rightAccessoryIcon={
|
|
||||||
path === 'p' && hasAccessory ? (
|
|
||||||
<LinkIcon className="stroke" />
|
|
||||||
) : undefined
|
|
||||||
}
|
|
||||||
text={title}
|
|
||||||
onClick={copyToClipboard}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const profileImage = () => {
|
const profileImage = () => {
|
||||||
let image
|
let image
|
||||||
|
|
||||||
|
|
@ -310,21 +200,6 @@ const Header = () => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rendering: Toasts
|
|
||||||
const urlCopyToast = () => {
|
|
||||||
return (
|
|
||||||
<Toast
|
|
||||||
altText={t('toasts.copied')}
|
|
||||||
open={copyToastOpen}
|
|
||||||
duration={2400}
|
|
||||||
type="foreground"
|
|
||||||
content={t('toasts.copied')}
|
|
||||||
onOpenChange={handleCopyToastOpenChanged}
|
|
||||||
onCloseClick={handleCopyToastCloseClicked}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const remixToast = () => {
|
const remixToast = () => {
|
||||||
return (
|
return (
|
||||||
<Toast
|
<Toast
|
||||||
|
|
@ -394,7 +269,6 @@ const Header = () => {
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
{!appState.errorCode ? pageTitle() : ''}
|
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -564,8 +438,6 @@ const Header = () => {
|
||||||
<nav id="Header">
|
<nav id="Header">
|
||||||
{left()}
|
{left()}
|
||||||
{right()}
|
{right()}
|
||||||
{urlCopyToast()}
|
|
||||||
{remixToast()}
|
|
||||||
{settingsModal()}
|
{settingsModal()}
|
||||||
{loginModal()}
|
{loginModal()}
|
||||||
{signupModal()}
|
{signupModal()}
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,14 @@
|
||||||
max-width: 30vw;
|
max-width: 30vw;
|
||||||
padding: $unit * 4;
|
padding: $unit * 4;
|
||||||
|
|
||||||
|
@include breakpoint(tablet) {
|
||||||
|
max-width: inherit;
|
||||||
|
max-width: 60vw;
|
||||||
|
}
|
||||||
|
|
||||||
@include breakpoint(phone) {
|
@include breakpoint(phone) {
|
||||||
max-width: inherit;
|
max-width: inherit;
|
||||||
width: 60vw;
|
width: 70vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.description {
|
.description {
|
||||||
|
|
@ -41,5 +46,15 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-self: flex-end;
|
align-self: flex-end;
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
|
|
||||||
|
@include breakpoint(phone) {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
align-self: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.Button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
.Joined .Input::placeholder {
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
|
|
@ -56,6 +56,7 @@ const CharLimitedFieldset: ForwardRefRenderFunction<HTMLInputElement, Props> = (
|
||||||
<div className={classNames({ Joined: true }, props.className)}>
|
<div className={classNames({ Joined: true }, props.className)}>
|
||||||
<input
|
<input
|
||||||
{...props}
|
{...props}
|
||||||
|
data-1p-ignore
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
className="Input"
|
className="Input"
|
||||||
type={props.type}
|
type={props.type}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,6 @@
|
||||||
|
|
||||||
.Input::placeholder {
|
.Input::placeholder {
|
||||||
/* Chrome, Firefox, Opera, Safari 10.1+ */
|
/* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||||
color: var(--text-secondary) !important;
|
color: var(--text-secondary);
|
||||||
opacity: 1; /* Firefox */
|
opacity: 1; /* Firefox */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
padding: $unit;
|
padding: $unit;
|
||||||
transform-origin: var(--radix-popover-content-transform-origin);
|
transform-origin: var(--radix-popover-content-transform-origin);
|
||||||
width: var(--radix-popover-trigger-width);
|
width: var(--radix-popover-trigger-width);
|
||||||
min-width: 440px;
|
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
|
|
||||||
@include breakpoint(phone) {
|
@include breakpoint(phone) {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@
|
||||||
color: var(--full-auto-text);
|
color: var(--full-auto-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.AutoGuard.On {
|
&.AutoGuard.On,
|
||||||
|
&.AutoSummon.On {
|
||||||
background: var(--auto-guard-bg);
|
background: var(--auto-guard-bg);
|
||||||
color: var(--auto-guard-text);
|
color: var(--auto-guard-text);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ const RemixTeamAlert = ({
|
||||||
<Trans i18nKey="modals.remix_team.description.viewer">
|
<Trans i18nKey="modals.remix_team.description.viewer">
|
||||||
Remixing a team makes a copy of it in your account so you can make
|
Remixing a team makes a copy of it in your account so you can make
|
||||||
your own changes.\n\nWould you like to remix{' '}
|
your own changes.\n\nWould you like to remix{' '}
|
||||||
<strong>{{ name: 'HEY' }}</strong>?
|
<strong>{{ name: name }}</strong>?
|
||||||
</Trans>
|
</Trans>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
import { useSnapshot } from 'valtio'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -22,6 +23,8 @@ import TableField from '~components/common/TableField'
|
||||||
import type { DetailsObject } from 'types'
|
import type { DetailsObject } from 'types'
|
||||||
import type { DialogProps } from '@radix-ui/react-dialog'
|
import type { DialogProps } from '@radix-ui/react-dialog'
|
||||||
|
|
||||||
|
import { appState } from '~utils/appState'
|
||||||
|
|
||||||
import CheckIcon from '~public/icons/Check.svg'
|
import CheckIcon from '~public/icons/Check.svg'
|
||||||
import CrossIcon from '~public/icons/Cross.svg'
|
import CrossIcon from '~public/icons/Cross.svg'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
@ -31,14 +34,16 @@ interface Props extends DialogProps {
|
||||||
updateCallback: (details: DetailsObject) => void
|
updateCallback: (details: DetailsObject) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const EditPartyModal = ({ party, updateCallback, ...props }: Props) => {
|
const EditPartyModal = ({ updateCallback, ...props }: Props) => {
|
||||||
// Set up router
|
// Set up router
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const locale = router.locale
|
|
||||||
|
|
||||||
// Set up translation
|
// Set up translation
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
|
|
||||||
|
// Set up reactive state
|
||||||
|
const { party } = useSnapshot(appState)
|
||||||
|
|
||||||
// Refs
|
// Refs
|
||||||
const headerRef = React.createRef<HTMLDivElement>()
|
const headerRef = React.createRef<HTMLDivElement>()
|
||||||
const footerRef = React.createRef<HTMLDivElement>()
|
const footerRef = React.createRef<HTMLDivElement>()
|
||||||
|
|
@ -54,6 +59,7 @@ const EditPartyModal = ({ party, updateCallback, ...props }: Props) => {
|
||||||
|
|
||||||
// States: Data
|
// States: Data
|
||||||
const [name, setName] = useState('')
|
const [name, setName] = useState('')
|
||||||
|
const [description, setDescription] = useState('')
|
||||||
const [raid, setRaid] = useState<Raid>()
|
const [raid, setRaid] = useState<Raid>()
|
||||||
const [extra, setExtra] = useState(false)
|
const [extra, setExtra] = useState(false)
|
||||||
const [chargeAttack, setChargeAttack] = useState(true)
|
const [chargeAttack, setChargeAttack] = useState(true)
|
||||||
|
|
@ -68,24 +74,15 @@ const EditPartyModal = ({ party, updateCallback, ...props }: Props) => {
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!party) return
|
persistFromState()
|
||||||
|
|
||||||
setName(party.name)
|
|
||||||
setRaid(party.raid)
|
|
||||||
setAutoGuard(party.auto_guard)
|
|
||||||
setAutoSummon(party.auto_summon)
|
|
||||||
setFullAuto(party.full_auto)
|
|
||||||
setChargeAttack(party.charge_attack)
|
|
||||||
setClearTime(party.clear_time)
|
|
||||||
if (party.turn_count) setTurnCount(party.turn_count)
|
|
||||||
if (party.button_count) setButtonCount(party.button_count)
|
|
||||||
if (party.chain_count) setChainCount(party.chain_count)
|
|
||||||
}, [party])
|
}, [party])
|
||||||
|
|
||||||
// Methods: Event handlers (Dialog)
|
// Methods: Event handlers (Dialog)
|
||||||
function openChange() {
|
function openChange() {
|
||||||
if (open) {
|
if (open) {
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
|
setCurrentSegment(0)
|
||||||
|
persistFromState()
|
||||||
if (props.onOpenChange) props.onOpenChange(false)
|
if (props.onOpenChange) props.onOpenChange(false)
|
||||||
} else {
|
} else {
|
||||||
setOpen(true)
|
setOpen(true)
|
||||||
|
|
@ -176,6 +173,21 @@ const EditPartyModal = ({ party, updateCallback, ...props }: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods: Data methods
|
// Methods: Data methods
|
||||||
|
function persistFromState() {
|
||||||
|
if (!party) return
|
||||||
|
setName(party.name ? party.name : '')
|
||||||
|
setDescription(party.description ? party.description : '')
|
||||||
|
setRaid(party.raid)
|
||||||
|
setAutoGuard(party.autoGuard)
|
||||||
|
setAutoSummon(party.autoSummon)
|
||||||
|
setFullAuto(party.fullAuto)
|
||||||
|
setChargeAttack(party.chargeAttack)
|
||||||
|
setClearTime(party.clearTime)
|
||||||
|
if (party.turnCount) setTurnCount(party.turnCount)
|
||||||
|
if (party.buttonCount) setButtonCount(party.buttonCount)
|
||||||
|
if (party.chainCount) setChainCount(party.chainCount)
|
||||||
|
}
|
||||||
|
|
||||||
function updateDetails(event: React.MouseEvent) {
|
function updateDetails(event: React.MouseEvent) {
|
||||||
const descriptionValue = descriptionInput.current?.value
|
const descriptionValue = descriptionInput.current?.value
|
||||||
const details: DetailsObject = {
|
const details: DetailsObject = {
|
||||||
|
|
@ -272,9 +284,8 @@ const EditPartyModal = ({ party, updateCallback, ...props }: Props) => {
|
||||||
}
|
}
|
||||||
onChange={handleTextAreaChanged}
|
onChange={handleTextAreaChanged}
|
||||||
ref={descriptionInput}
|
ref={descriptionInput}
|
||||||
>
|
defaultValue={description}
|
||||||
{party ? party.description : ''}
|
/>
|
||||||
</textarea>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import clonedeep from 'lodash.clonedeep'
|
||||||
|
|
||||||
import Alert from '~components/common/Alert'
|
import Alert from '~components/common/Alert'
|
||||||
import PartySegmentedControl from '~components/party/PartySegmentedControl'
|
import PartySegmentedControl from '~components/party/PartySegmentedControl'
|
||||||
import PartyDetails from '~components/party/PartyDetails'
|
import PartyFooter from '~components/party/PartyFooter'
|
||||||
import PartyHeader from '~components/party/PartyHeader'
|
import PartyHeader from '~components/party/PartyHeader'
|
||||||
import WeaponGrid from '~components/weapon/WeaponGrid'
|
import WeaponGrid from '~components/weapon/WeaponGrid'
|
||||||
import SummonGrid from '~components/summon/SummonGrid'
|
import SummonGrid from '~components/summon/SummonGrid'
|
||||||
|
|
@ -145,37 +145,27 @@ const Party = (props: Props) => {
|
||||||
function formatDetailsObject(details: DetailsObject) {
|
function formatDetailsObject(details: DetailsObject) {
|
||||||
const payload: { [key: string]: any } = {}
|
const payload: { [key: string]: any } = {}
|
||||||
|
|
||||||
const mappings: { [key: string]: string } = {
|
if (details.name) payload.name = details.name
|
||||||
name: 'name',
|
if (details.description) payload.description = details.description
|
||||||
description: 'description',
|
|
||||||
chargeAttack: 'charge_attack',
|
|
||||||
fullAuto: 'full_auto',
|
|
||||||
autoGuard: 'auto_guard',
|
|
||||||
autoSummon: 'auto_summon',
|
|
||||||
clearTime: 'clear_time',
|
|
||||||
buttonCount: 'button_count',
|
|
||||||
chainCount: 'chain_count',
|
|
||||||
turnCount: 'turn_count',
|
|
||||||
extra: 'extra',
|
|
||||||
job: 'job_id',
|
|
||||||
guidebook1_id: 'guidebook1_id',
|
|
||||||
guidebook2_id: 'guidebook2_id',
|
|
||||||
guidebook3_id: 'guidebook3_id',
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.entries(mappings).forEach(([key, value]) => {
|
|
||||||
if (details[key]) {
|
|
||||||
payload[value] = details[key]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (details.raid) payload.raid_id = details.raid.id
|
if (details.raid) payload.raid_id = details.raid.id
|
||||||
|
if (details.chargeAttack != undefined)
|
||||||
|
payload.charge_attack = details.chargeAttack
|
||||||
|
if (details.fullAuto != undefined) payload.full_auto = details.fullAuto
|
||||||
|
if (details.autoGuard != undefined) payload.auto_guard = details.autoGuard
|
||||||
|
if (details.autoSummon != undefined)
|
||||||
|
payload.auto_summon = details.autoSummon
|
||||||
|
if (details.clearTime) payload.clear_time = details.clearTime
|
||||||
|
if (details.buttonCount) payload.button_count = details.buttonCount
|
||||||
|
if (details.chainCount) payload.chain_count = details.chainCount
|
||||||
|
if (details.turnCount) payload.turn_count = details.turnCount
|
||||||
|
if (details.extra != undefined) payload.extra = details.extra
|
||||||
|
if (details.job) payload.job_id = details.job.id
|
||||||
|
if (details.guidebook1_id) payload.guidebook1_id = details.guidebook1_id
|
||||||
|
if (details.guidebook2_id) payload.guidebook2_id = details.guidebook2_id
|
||||||
|
if (details.guidebook3_id) payload.guidebook3_id = details.guidebook3_id
|
||||||
|
|
||||||
if (Object.keys(payload).length >= 1) {
|
if (Object.keys(payload).length >= 1) return { party: payload }
|
||||||
return { party: payload }
|
else return {}
|
||||||
} else {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelAlert() {
|
function cancelAlert() {
|
||||||
|
|
@ -275,6 +265,15 @@ const Party = (props: Props) => {
|
||||||
appState.party.jobSkills = team.job_skills
|
appState.party.jobSkills = team.job_skills
|
||||||
appState.party.accessory = team.accessory
|
appState.party.accessory = team.accessory
|
||||||
|
|
||||||
|
appState.party.chargeAttack = team.charge_attack
|
||||||
|
appState.party.fullAuto = team.full_auto
|
||||||
|
appState.party.autoGuard = team.auto_guard
|
||||||
|
appState.party.autoSummon = team.auto_summon
|
||||||
|
appState.party.clearTime = team.clear_time
|
||||||
|
appState.party.buttonCount = team.button_count
|
||||||
|
appState.party.chainCount = team.chain_count
|
||||||
|
appState.party.turnCount = team.turn_count
|
||||||
|
|
||||||
appState.party.id = team.id
|
appState.party.id = team.id
|
||||||
appState.party.shortcode = team.shortcode
|
appState.party.shortcode = team.shortcode
|
||||||
appState.party.extra = team.extra
|
appState.party.extra = team.extra
|
||||||
|
|
@ -455,7 +454,7 @@ const Party = (props: Props) => {
|
||||||
|
|
||||||
<section id="Party">{currentGrid()}</section>
|
<section id="Party">{currentGrid()}</section>
|
||||||
|
|
||||||
<PartyDetails
|
<PartyFooter
|
||||||
party={props.team}
|
party={props.team}
|
||||||
new={props.new || false}
|
new={props.new || false}
|
||||||
editable={party.editable}
|
editable={party.editable}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { subscribe, useSnapshot } from 'valtio'
|
import { subscribe, useSnapshot } from 'valtio'
|
||||||
import { Trans, useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import Link from 'next/link'
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
// Dependencies: Common
|
// Dependencies: Common
|
||||||
|
|
@ -125,22 +124,27 @@ const PartyDropdown = ({
|
||||||
|
|
||||||
// Toasts / Copy URL
|
// Toasts / Copy URL
|
||||||
function handleCopyToastOpenChanged(open: boolean) {
|
function handleCopyToastOpenChanged(open: boolean) {
|
||||||
setCopyToastOpen(open)
|
setCopyToastOpen(!open)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCopyToastCloseClicked() {
|
function handleCopyToastCloseClicked() {
|
||||||
setCopyToastOpen(false)
|
setCopyToastOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toasts / Remix team
|
// Toasts: Remix team
|
||||||
function handleRemixToastOpenChanged(open: boolean) {
|
function handleRemixToastOpenChanged(open: boolean) {
|
||||||
setRemixToastOpen(open)
|
setRemixToastOpen(!open)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRemixToastCloseClicked() {
|
function handleRemixToastCloseClicked() {
|
||||||
setRemixToastOpen(false)
|
setRemixToastOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function remixCallback() {
|
||||||
|
setRemixToastOpen(true)
|
||||||
|
remixTeamCallback()
|
||||||
|
}
|
||||||
|
|
||||||
const editableItems = () => {
|
const editableItems = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -185,10 +189,23 @@ const PartyDropdown = ({
|
||||||
|
|
||||||
<RemixTeamAlert
|
<RemixTeamAlert
|
||||||
creator={editable}
|
creator={editable}
|
||||||
name={partySnapshot.name ? partySnapshot.name : t('no_title')}
|
name={partySnapshot.name || t('no_title')}
|
||||||
open={remixAlertOpen}
|
open={remixAlertOpen}
|
||||||
onOpenChange={handleRemixTeamAlertChange}
|
onOpenChange={handleRemixTeamAlertChange}
|
||||||
remixCallback={remixTeamCallback}
|
remixCallback={remixCallback}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<RemixedToast
|
||||||
|
open={remixToastOpen}
|
||||||
|
partyName={partySnapshot.name || t('no_title')}
|
||||||
|
onOpenChange={handleRemixToastOpenChanged}
|
||||||
|
onCloseClick={handleRemixToastCloseClicked}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<UrlCopiedToast
|
||||||
|
open={copyToastOpen}
|
||||||
|
onOpenChange={handleCopyToastOpenChanged}
|
||||||
|
onCloseClick={handleCopyToastCloseClicked}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
.DetailsWrapper {
|
.FooterWrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $unit-2x;
|
gap: $unit-2x;
|
||||||
|
|
@ -16,10 +16,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.PartyDetails {
|
.PartyFooter {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: none;
|
line-height: 1.4;
|
||||||
|
white-space: pre-wrap;
|
||||||
margin: 0 auto $unit-2x;
|
margin: 0 auto $unit-2x;
|
||||||
|
margin-bottom: $unit-12x;
|
||||||
|
min-height: 10vh;
|
||||||
max-width: $unit * 94;
|
max-width: $unit * 94;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -27,11 +30,6 @@
|
||||||
@include breakpoint(phone) {
|
@include breakpoint(phone) {
|
||||||
padding: 0 $unit;
|
padding: 0 $unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.Visible {
|
|
||||||
// margin-bottom: $unit-12x;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.Editable {
|
&.Editable {
|
||||||
gap: $unit;
|
gap: $unit;
|
||||||
|
|
||||||
|
|
@ -174,11 +172,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ReadOnly {
|
|
||||||
box-sizing: border-box;
|
|
||||||
line-height: 1.4;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
|
|
||||||
&.Visible {
|
&.Visible {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
@ -285,7 +278,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.PartyInfo {
|
.PartyInfo {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
import { useSnapshot } from 'valtio'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import clonedeep from 'lodash.clonedeep'
|
import clonedeep from 'lodash.clonedeep'
|
||||||
|
|
||||||
|
|
@ -27,10 +28,12 @@ interface Props {
|
||||||
updateCallback: (details: DetailsObject) => void
|
updateCallback: (details: DetailsObject) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const PartyDetails = (props: Props) => {
|
const PartyFooter = (props: Props) => {
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
const { party } = useSnapshot(appState)
|
||||||
|
|
||||||
const youtubeUrlRegex =
|
const youtubeUrlRegex =
|
||||||
/(?:https:\/\/www\.youtube\.com\/watch\?v=|https:\/\/youtu\.be\/)([\w-]+)/g
|
/(?:https:\/\/www\.youtube\.com\/watch\?v=|https:\/\/youtu\.be\/)([\w-]+)/g
|
||||||
|
|
||||||
|
|
@ -40,16 +43,10 @@ const PartyDetails = (props: Props) => {
|
||||||
const [embeddedDescription, setEmbeddedDescription] =
|
const [embeddedDescription, setEmbeddedDescription] =
|
||||||
useState<React.ReactNode>()
|
useState<React.ReactNode>()
|
||||||
|
|
||||||
const readOnlyClasses = classNames({
|
|
||||||
PartyDetails: true,
|
|
||||||
ReadOnly: true,
|
|
||||||
Visible: !open,
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Extract the video IDs from the description
|
// Extract the video IDs from the description
|
||||||
if (appState.party.description) {
|
if (party.description) {
|
||||||
const videoIds = extractYoutubeVideoIds(appState.party.description)
|
const videoIds = extractYoutubeVideoIds(party.description)
|
||||||
|
|
||||||
// Fetch the video titles for each ID
|
// Fetch the video titles for each ID
|
||||||
const fetchPromises = videoIds.map(({ id }) => fetchYoutubeData(id))
|
const fetchPromises = videoIds.map(({ id }) => fetchYoutubeData(id))
|
||||||
|
|
@ -58,7 +55,7 @@ const PartyDetails = (props: Props) => {
|
||||||
Promise.all(fetchPromises).then((videoTitles) => {
|
Promise.all(fetchPromises).then((videoTitles) => {
|
||||||
// Replace the video URLs in the description with LiteYoutubeEmbed elements
|
// Replace the video URLs in the description with LiteYoutubeEmbed elements
|
||||||
const newDescription = reactStringReplace(
|
const newDescription = reactStringReplace(
|
||||||
appState.party.description,
|
party.description,
|
||||||
youtubeUrlRegex,
|
youtubeUrlRegex,
|
||||||
(match, i) => (
|
(match, i) => (
|
||||||
<LiteYouTubeEmbed
|
<LiteYouTubeEmbed
|
||||||
|
|
@ -77,7 +74,7 @@ const PartyDetails = (props: Props) => {
|
||||||
} else {
|
} else {
|
||||||
setEmbeddedDescription('')
|
setEmbeddedDescription('')
|
||||||
}
|
}
|
||||||
}, [appState.party.description])
|
}, [party.description])
|
||||||
|
|
||||||
async function fetchYoutubeData(videoId: string) {
|
async function fetchYoutubeData(videoId: string) {
|
||||||
return await youtube
|
return await youtube
|
||||||
|
|
@ -173,14 +170,6 @@ const PartyDetails = (props: Props) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const readOnly = () => {
|
|
||||||
return (
|
|
||||||
<section className={readOnlyClasses}>
|
|
||||||
<Linkify>{embeddedDescription}</Linkify>
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const remixSection = () => {
|
const remixSection = () => {
|
||||||
return (
|
return (
|
||||||
<section className="Remixes">
|
<section className="Remixes">
|
||||||
|
|
@ -192,10 +181,14 @@ const PartyDetails = (props: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<section className="DetailsWrapper">{readOnly()}</section>
|
<section className="FooterWrapper">
|
||||||
|
<section className="PartyFooter">
|
||||||
|
<Linkify>{embeddedDescription}</Linkify>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
{remixes && remixes.length > 0 ? remixSection() : ''}
|
{remixes && remixes.length > 0 ? remixSection() : ''}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PartyDetails
|
export default PartyFooter
|
||||||
|
|
@ -12,6 +12,7 @@ import Token from '~components/common/Token'
|
||||||
import EditPartyModal from '~components/party/EditPartyModal'
|
import EditPartyModal from '~components/party/EditPartyModal'
|
||||||
import PartyDropdown from '~components/party/PartyDropdown'
|
import PartyDropdown from '~components/party/PartyDropdown'
|
||||||
|
|
||||||
|
import api from '~utils/api'
|
||||||
import { accountState } from '~utils/accountState'
|
import { accountState } from '~utils/accountState'
|
||||||
import { appState, initialAppState } from '~utils/appState'
|
import { appState, initialAppState } from '~utils/appState'
|
||||||
import { formatTimeAgo } from '~utils/timeAgo'
|
import { formatTimeAgo } from '~utils/timeAgo'
|
||||||
|
|
@ -23,7 +24,9 @@ import SaveIcon from '~public/icons/Save.svg'
|
||||||
import type { DetailsObject } from 'types'
|
import type { DetailsObject } from 'types'
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
import api from '~utils/api'
|
import RemixTeamAlert from '~components/dialogs/RemixTeamAlert'
|
||||||
|
import RemixedToast from '~components/toasts/RemixedToast'
|
||||||
|
import { set } from 'local-storage'
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -44,12 +47,16 @@ const PartyHeader = (props: Props) => {
|
||||||
|
|
||||||
const { party: partySnapshot } = useSnapshot(appState)
|
const { party: partySnapshot } = useSnapshot(appState)
|
||||||
|
|
||||||
const [name, setName] = useState('')
|
// State: Component
|
||||||
|
const [remixAlertOpen, setRemixAlertOpen] = useState(false)
|
||||||
|
const [remixToastOpen, setRemixToastOpen] = useState(false)
|
||||||
|
|
||||||
|
// State: Data
|
||||||
|
const [name, setName] = useState('')
|
||||||
const [chargeAttack, setChargeAttack] = useState(true)
|
const [chargeAttack, setChargeAttack] = useState(true)
|
||||||
const [fullAuto, setFullAuto] = useState(false)
|
const [fullAuto, setFullAuto] = useState(false)
|
||||||
const [autoGuard, setAutoGuard] = useState(false)
|
const [autoGuard, setAutoGuard] = useState(false)
|
||||||
|
const [autoSummon, setAutoSummon] = useState(false)
|
||||||
const [buttonCount, setButtonCount] = useState<number | undefined>(undefined)
|
const [buttonCount, setButtonCount] = useState<number | undefined>(undefined)
|
||||||
const [chainCount, setChainCount] = useState<number | undefined>(undefined)
|
const [chainCount, setChainCount] = useState<number | undefined>(undefined)
|
||||||
const [turnCount, setTurnCount] = useState<number | undefined>(undefined)
|
const [turnCount, setTurnCount] = useState<number | undefined>(undefined)
|
||||||
|
|
@ -78,6 +85,7 @@ const PartyHeader = (props: Props) => {
|
||||||
setName(props.party.name)
|
setName(props.party.name)
|
||||||
setAutoGuard(props.party.auto_guard)
|
setAutoGuard(props.party.auto_guard)
|
||||||
setFullAuto(props.party.full_auto)
|
setFullAuto(props.party.full_auto)
|
||||||
|
setAutoSummon(props.party.auto_summon)
|
||||||
setChargeAttack(props.party.charge_attack)
|
setChargeAttack(props.party.charge_attack)
|
||||||
setClearTime(props.party.clear_time)
|
setClearTime(props.party.clear_time)
|
||||||
if (props.party.turn_count) setTurnCount(props.party.turn_count)
|
if (props.party.turn_count) setTurnCount(props.party.turn_count)
|
||||||
|
|
@ -155,6 +163,32 @@ const PartyHeader = (props: Props) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Actions: Remix team
|
||||||
|
function remixTeamCallback() {
|
||||||
|
setRemixToastOpen(true)
|
||||||
|
props.remixCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alerts: Remix team
|
||||||
|
function openRemixTeamAlert() {
|
||||||
|
setRemixAlertOpen(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRemixTeamAlertChange(open: boolean) {
|
||||||
|
setRemixAlertOpen(open)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toasts: Remix team
|
||||||
|
function handleRemixToastOpenChanged(open: boolean) {
|
||||||
|
setRemixToastOpen(!open)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRemixToastCloseClicked() {
|
||||||
|
setRemixToastOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
|
||||||
const userBlock = (username?: string, picture?: string, element?: string) => {
|
const userBlock = (username?: string, picture?: string, element?: string) => {
|
||||||
return (
|
return (
|
||||||
<div className={userClass}>
|
<div className={userClass}>
|
||||||
|
|
@ -212,12 +246,12 @@ const PartyHeader = (props: Props) => {
|
||||||
<Token
|
<Token
|
||||||
className={classNames({
|
className={classNames({
|
||||||
ChargeAttack: true,
|
ChargeAttack: true,
|
||||||
On: chargeAttack,
|
On: party.chargeAttack,
|
||||||
Off: !chargeAttack,
|
Off: !party.chargeAttack,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{`${t('party.details.labels.charge_attack')} ${
|
{`${t('party.details.labels.charge_attack')} ${
|
||||||
chargeAttack ? 'On' : 'Off'
|
party.chargeAttack ? 'On' : 'Off'
|
||||||
}`}
|
}`}
|
||||||
</Token>
|
</Token>
|
||||||
)
|
)
|
||||||
|
|
@ -226,11 +260,13 @@ const PartyHeader = (props: Props) => {
|
||||||
<Token
|
<Token
|
||||||
className={classNames({
|
className={classNames({
|
||||||
FullAuto: true,
|
FullAuto: true,
|
||||||
On: fullAuto,
|
On: party.fullAuto,
|
||||||
Off: !fullAuto,
|
Off: !party.fullAuto,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{`${t('party.details.labels.full_auto')} ${fullAuto ? 'On' : 'Off'}`}
|
{`${t('party.details.labels.full_auto')} ${
|
||||||
|
party.fullAuto ? 'On' : 'Off'
|
||||||
|
}`}
|
||||||
</Token>
|
</Token>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -238,37 +274,57 @@ const PartyHeader = (props: Props) => {
|
||||||
<Token
|
<Token
|
||||||
className={classNames({
|
className={classNames({
|
||||||
AutoGuard: true,
|
AutoGuard: true,
|
||||||
On: autoGuard,
|
On: party.autoGuard,
|
||||||
Off: !autoGuard,
|
Off: !party.autoGuard,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{`${t('party.details.labels.auto_guard')} ${autoGuard ? 'On' : 'Off'}`}
|
{`${t('party.details.labels.auto_guard')} ${
|
||||||
|
party.autoGuard ? 'On' : 'Off'
|
||||||
|
}`}
|
||||||
|
</Token>
|
||||||
|
)
|
||||||
|
|
||||||
|
const autoSummonToken = (
|
||||||
|
<Token
|
||||||
|
className={classNames({
|
||||||
|
AutoSummon: true,
|
||||||
|
On: party.autoSummon,
|
||||||
|
Off: !party.autoSummon,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{`${t('party.details.labels.auto_summon')} ${
|
||||||
|
party.autoSummon ? 'On' : 'Off'
|
||||||
|
}`}
|
||||||
</Token>
|
</Token>
|
||||||
)
|
)
|
||||||
|
|
||||||
const turnCountToken = (
|
const turnCountToken = (
|
||||||
<Token>
|
<Token>
|
||||||
{t('party.details.turns.with_count', {
|
{t('party.details.turns.with_count', {
|
||||||
count: turnCount,
|
count: party.turnCount,
|
||||||
})}
|
})}
|
||||||
</Token>
|
</Token>
|
||||||
)
|
)
|
||||||
|
|
||||||
const buttonChainToken = () => {
|
const buttonChainToken = () => {
|
||||||
if (buttonCount || chainCount) {
|
if (party.buttonCount || party.chainCount) {
|
||||||
let string = ''
|
let string = ''
|
||||||
|
|
||||||
if (buttonCount && buttonCount > 0) {
|
if (party.buttonCount && party.buttonCount > 0) {
|
||||||
string += `${buttonCount}b`
|
string += `${party.buttonCount}b`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!buttonCount && chainCount && chainCount > 0) {
|
if (!party.buttonCount && party.chainCount && party.chainCount > 0) {
|
||||||
string += `0${t('party.details.suffix.buttons')}${chainCount}${t(
|
string += `0${t('party.details.suffix.buttons')}${party.chainCount}${t(
|
||||||
'party.details.suffix.chains'
|
'party.details.suffix.chains'
|
||||||
)}`
|
)}`
|
||||||
} else if (buttonCount && chainCount && chainCount > 0) {
|
} else if (
|
||||||
string += `${chainCount}${t('party.details.suffix.chains')}`
|
party.buttonCount &&
|
||||||
} else if (buttonCount && !chainCount) {
|
party.chainCount &&
|
||||||
|
party.chainCount > 0
|
||||||
|
) {
|
||||||
|
string += `${party.chainCount}${t('party.details.suffix.chains')}`
|
||||||
|
} else if (party.buttonCount && !party.chainCount) {
|
||||||
string += `0${t('party.details.suffix.chains')}`
|
string += `0${t('party.details.suffix.chains')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -277,8 +333,8 @@ const PartyHeader = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearTimeToken = () => {
|
const clearTimeToken = () => {
|
||||||
const minutes = Math.floor(clearTime / 60)
|
const minutes = Math.floor(party.clearTime / 60)
|
||||||
const seconds = clearTime - minutes * 60
|
const seconds = party.clearTime - minutes * 60
|
||||||
|
|
||||||
let string = ''
|
let string = ''
|
||||||
if (minutes > 0)
|
if (minutes > 0)
|
||||||
|
|
@ -296,8 +352,9 @@ const PartyHeader = (props: Props) => {
|
||||||
{chargeAttackToken}
|
{chargeAttackToken}
|
||||||
{fullAutoToken}
|
{fullAutoToken}
|
||||||
{autoGuardToken}
|
{autoGuardToken}
|
||||||
{turnCount ? turnCountToken : ''}
|
{autoSummonToken}
|
||||||
{clearTime > 0 ? clearTimeToken() : ''}
|
{party.turnCount ? turnCountToken : ''}
|
||||||
|
{party.clearTime > 0 ? clearTimeToken() : ''}
|
||||||
{buttonChainToken()}
|
{buttonChainToken()}
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
|
|
@ -329,7 +386,7 @@ const PartyHeader = (props: Props) => {
|
||||||
leftAccessoryIcon={<RemixIcon />}
|
leftAccessoryIcon={<RemixIcon />}
|
||||||
className="Remix"
|
className="Remix"
|
||||||
text={t('buttons.remix')}
|
text={t('buttons.remix')}
|
||||||
onClick={props.remixCallback}
|
onClick={openRemixTeamAlert}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
|
|
@ -341,8 +398,8 @@ const PartyHeader = (props: Props) => {
|
||||||
<div className="PartyInfo">
|
<div className="PartyInfo">
|
||||||
<div className="Left">
|
<div className="Left">
|
||||||
<div className="Header">
|
<div className="Header">
|
||||||
<h1 className={name ? '' : 'empty'}>
|
<h1 className={party.name ? '' : 'empty'}>
|
||||||
{name ? name : t('no_title')}
|
{party.name ? party.name : t('no_title')}
|
||||||
</h1>
|
</h1>
|
||||||
{party.remix && party.sourceParty ? (
|
{party.remix && party.sourceParty ? (
|
||||||
<Tooltip content={t('tooltips.source')}>
|
<Tooltip content={t('tooltips.source')}>
|
||||||
|
|
@ -398,6 +455,21 @@ const PartyHeader = (props: Props) => {
|
||||||
</div>
|
</div>
|
||||||
<section className={classes}>{renderTokens()}</section>
|
<section className={classes}>{renderTokens()}</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<RemixTeamAlert
|
||||||
|
creator={props.editable}
|
||||||
|
name={partySnapshot.name ? partySnapshot.name : t('no_title')}
|
||||||
|
open={remixAlertOpen}
|
||||||
|
onOpenChange={handleRemixTeamAlertChange}
|
||||||
|
remixCallback={remixTeamCallback}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<RemixedToast
|
||||||
|
open={remixToastOpen}
|
||||||
|
partyName={props.party?.name || t('no_title')}
|
||||||
|
onOpenChange={handleRemixToastOpenChanged}
|
||||||
|
onCloseClick={handleRemixToastCloseClicked}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.Combobox.Raid {
|
.Combobox.Raid {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
min-width: 440px;
|
||||||
|
|
||||||
.Header {
|
.Header {
|
||||||
background: var(--dialog-bg);
|
background: var(--dialog-bg);
|
||||||
|
|
@ -184,6 +185,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.SelectTrigger.Raid .Value.Empty {
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
.Filters .SelectTrigger.Raid {
|
.Filters .SelectTrigger.Raid {
|
||||||
& > span {
|
& > span {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
|
||||||
|
|
@ -105,19 +105,25 @@ const RaidCombobox = (props: Props) => {
|
||||||
|
|
||||||
// Set current raid and section when the component mounts
|
// Set current raid and section when the component mounts
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (appState.party.raid) {
|
// if (appState.party.raid) {
|
||||||
setCurrentRaid(appState.party.raid)
|
// setCurrentRaid(appState.party.raid)
|
||||||
setCurrentSection(appState.party.raid.group.section)
|
// if (appState.party.raid.group.section > 0) {
|
||||||
} else if (props.showAllRaidsOption && !currentRaid) {
|
// setCurrentSection(appState.party.raid.group.section)
|
||||||
setCurrentRaid(allRaidsOption)
|
// } else {
|
||||||
}
|
// setCurrentSection(1)
|
||||||
|
// }
|
||||||
|
// } else if (props.showAllRaidsOption && !currentRaid) {
|
||||||
|
// setCurrentRaid(allRaidsOption)
|
||||||
|
// }
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// Set current raid and section when the current raid changes
|
// Set current raid and section when the current raid changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.currentRaid) {
|
if (props.currentRaid) {
|
||||||
setCurrentRaid(props.currentRaid)
|
setCurrentRaid(props.currentRaid)
|
||||||
|
if (appState.party.raid && appState.party.raid.group.section > 0)
|
||||||
setCurrentSection(props.currentRaid.group.section)
|
setCurrentSection(props.currentRaid.group.section)
|
||||||
|
else setCurrentSection(1)
|
||||||
}
|
}
|
||||||
}, [props.currentRaid])
|
}, [props.currentRaid])
|
||||||
|
|
||||||
|
|
@ -260,7 +266,11 @@ const RaidCombobox = (props: Props) => {
|
||||||
// Toggle the open state of the combobox
|
// Toggle the open state of the combobox
|
||||||
function toggleOpen() {
|
function toggleOpen() {
|
||||||
if (open) {
|
if (open) {
|
||||||
if (currentRaid && currentRaid.slug !== 'all') {
|
if (
|
||||||
|
currentRaid &&
|
||||||
|
currentRaid.slug !== 'all' &&
|
||||||
|
currentRaid.group.section > 0
|
||||||
|
) {
|
||||||
setCurrentSection(currentRaid.group.section)
|
setCurrentSection(currentRaid.group.section)
|
||||||
}
|
}
|
||||||
setScrolled(false)
|
setScrolled(false)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import Toast from '~components/common/Toast'
|
import Toast from '~components/common/Toast'
|
||||||
import { Trans, useTranslation } from 'next-i18next'
|
import { Trans, useTranslation } from 'next-i18next'
|
||||||
|
|
||||||
import './index.scss'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
partyName: string
|
partyName: string
|
||||||
open: boolean
|
open: boolean
|
||||||
|
|
@ -19,7 +17,9 @@ const RemixedToast = ({
|
||||||
onCloseClick,
|
onCloseClick,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(partyName)
|
||||||
|
}, [])
|
||||||
// Methods: Event handlers
|
// Methods: Event handlers
|
||||||
function handleOpenChange() {
|
function handleOpenChange() {
|
||||||
onOpenChange(open)
|
onOpenChange(open)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Toast from '~components/common/Toast'
|
import Toast from '~components/common/Toast'
|
||||||
|
|
||||||
import './index.scss'
|
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,7 @@ const WeaponModal = ({
|
||||||
{gridWeapon.object.awakenings ? awakeningSelect() : ''}
|
{gridWeapon.object.awakenings ? awakeningSelect() : ''}
|
||||||
</div>
|
</div>
|
||||||
<div className="DialogFooter" ref={footerRef}>
|
<div className="DialogFooter" ref={footerRef}>
|
||||||
|
<div className="actions">
|
||||||
<Button
|
<Button
|
||||||
contained={true}
|
contained={true}
|
||||||
onClick={updateWeapon}
|
onClick={updateWeapon}
|
||||||
|
|
@ -401,6 +402,7 @@ const WeaponModal = ({
|
||||||
text={t('modals.weapon.buttons.confirm')}
|
text={t('modals.weapon.buttons.confirm')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@
|
||||||
"unauthorized": "You don't have permission to perform that action"
|
"unauthorized": "You don't have permission to perform that action"
|
||||||
},
|
},
|
||||||
"filters": {
|
"filters": {
|
||||||
|
"name": "Filter",
|
||||||
"labels": {
|
"labels": {
|
||||||
"element": "Element",
|
"element": "Element",
|
||||||
"series": "Series",
|
"series": "Series",
|
||||||
|
|
@ -383,6 +384,7 @@
|
||||||
"charge_attack": "Charge Attack",
|
"charge_attack": "Charge Attack",
|
||||||
"full_auto": "Full Auto",
|
"full_auto": "Full Auto",
|
||||||
"auto_guard": "Auto Guard",
|
"auto_guard": "Auto Guard",
|
||||||
|
"auto_summon": "Auto Summon",
|
||||||
"turn_count": "Turn count",
|
"turn_count": "Turn count",
|
||||||
"button_chain": "Buttons/Chains",
|
"button_chain": "Buttons/Chains",
|
||||||
"clear_time": "Clear time"
|
"clear_time": "Clear time"
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@
|
||||||
"unauthorized": "行ったアクションを実行する権限がありません"
|
"unauthorized": "行ったアクションを実行する権限がありません"
|
||||||
},
|
},
|
||||||
"filters": {
|
"filters": {
|
||||||
|
"name": "フィルター",
|
||||||
"labels": {
|
"labels": {
|
||||||
"element": "属性",
|
"element": "属性",
|
||||||
"series": "シリーズ",
|
"series": "シリーズ",
|
||||||
|
|
@ -380,6 +381,7 @@
|
||||||
"charge_attack": "奥義",
|
"charge_attack": "奥義",
|
||||||
"full_auto": "フルオート",
|
"full_auto": "フルオート",
|
||||||
"auto_guard": "オートガード",
|
"auto_guard": "オートガード",
|
||||||
|
"auto_summon": "オート召喚",
|
||||||
"turn_count": "経過ターン",
|
"turn_count": "経過ターン",
|
||||||
"button_chain": "ポチチェイン",
|
"button_chain": "ポチチェイン",
|
||||||
"clear_time": "討伐時間"
|
"clear_time": "討伐時間"
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ interface AppState {
|
||||||
element: number
|
element: number
|
||||||
fullAuto: boolean
|
fullAuto: boolean
|
||||||
autoGuard: boolean
|
autoGuard: boolean
|
||||||
|
autoSummon: boolean
|
||||||
chargeAttack: boolean
|
chargeAttack: boolean
|
||||||
clearTime: number
|
clearTime: number
|
||||||
buttonCount?: number
|
buttonCount?: number
|
||||||
|
|
@ -110,6 +111,7 @@ export const initialAppState: AppState = {
|
||||||
raid: undefined,
|
raid: undefined,
|
||||||
fullAuto: false,
|
fullAuto: false,
|
||||||
autoGuard: false,
|
autoGuard: false,
|
||||||
|
autoSummon: false,
|
||||||
chargeAttack: true,
|
chargeAttack: true,
|
||||||
clearTime: 0,
|
clearTime: 0,
|
||||||
buttonCount: undefined,
|
buttonCount: undefined,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue