Fix party details
* Populate from SSR * Hide button to edit empty anonymous grids
This commit is contained in:
parent
67aa814b27
commit
5a797f0d14
3 changed files with 313 additions and 278 deletions
|
|
@ -156,6 +156,11 @@ const Party = (props: Props) => {
|
||||||
// Methods: Storing party data
|
// Methods: Storing party data
|
||||||
const storeParty = function (party: Party) {
|
const storeParty = function (party: Party) {
|
||||||
// Store the important party and state-keeping values
|
// Store the important party and state-keeping values
|
||||||
|
appState.party.name = party.name
|
||||||
|
appState.party.description = party.description
|
||||||
|
appState.party.raid = party.raid
|
||||||
|
appState.party.updated_at = party.updated_at
|
||||||
|
|
||||||
appState.party.id = party.id
|
appState.party.id = party.id
|
||||||
appState.party.extra = party.extra
|
appState.party.extra = party.extra
|
||||||
appState.party.user = party.user
|
appState.party.user = party.user
|
||||||
|
|
|
||||||
|
|
@ -1,317 +1,346 @@
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from "react"
|
||||||
import Head from 'next/head'
|
import Head from "next/head"
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from "next/router"
|
||||||
import { useSnapshot } from 'valtio'
|
import { useSnapshot } from "valtio"
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from "next-i18next"
|
||||||
|
|
||||||
import Linkify from 'react-linkify'
|
import Linkify from "react-linkify"
|
||||||
import classNames from 'classnames'
|
import classNames from "classnames"
|
||||||
|
|
||||||
import * as AlertDialog from '@radix-ui/react-alert-dialog'
|
import * as AlertDialog from "@radix-ui/react-alert-dialog"
|
||||||
import CrossIcon from '~public/icons/Cross.svg'
|
import CrossIcon from "~public/icons/Cross.svg"
|
||||||
|
|
||||||
import Button from '~components/Button'
|
import Button from "~components/Button"
|
||||||
import CharLimitedFieldset from '~components/CharLimitedFieldset'
|
import CharLimitedFieldset from "~components/CharLimitedFieldset"
|
||||||
import RaidDropdown from '~components/RaidDropdown'
|
import RaidDropdown from "~components/RaidDropdown"
|
||||||
import TextFieldset from '~components/TextFieldset'
|
import TextFieldset from "~components/TextFieldset"
|
||||||
|
|
||||||
import { accountState } from '~utils/accountState'
|
import { accountState } from "~utils/accountState"
|
||||||
import { appState } from '~utils/appState'
|
import { appState } from "~utils/appState"
|
||||||
|
|
||||||
import './index.scss'
|
import "./index.scss"
|
||||||
import Link from 'next/link'
|
import Link from "next/link"
|
||||||
import { formatTimeAgo } from '~utils/timeAgo'
|
import { formatTimeAgo } from "~utils/timeAgo"
|
||||||
|
|
||||||
const emptyRaid: Raid = {
|
const emptyRaid: Raid = {
|
||||||
id: '',
|
id: "",
|
||||||
name: {
|
name: {
|
||||||
en: '',
|
en: "",
|
||||||
ja: ''
|
ja: "",
|
||||||
},
|
},
|
||||||
slug: '',
|
slug: "",
|
||||||
level: 0,
|
level: 0,
|
||||||
group: 0,
|
group: 0,
|
||||||
element: 0
|
element: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
interface Props {
|
interface Props {
|
||||||
editable: boolean
|
editable: boolean
|
||||||
updateCallback: (name?: string, description?: string, raid?: Raid) => void
|
updateCallback: (name?: string, description?: string, raid?: Raid) => void
|
||||||
deleteCallback: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
|
deleteCallback: (
|
||||||
|
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
|
||||||
|
) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const PartyDetails = (props: Props) => {
|
const PartyDetails = (props: Props) => {
|
||||||
const { party, raids } = useSnapshot(appState)
|
const { party, raids } = useSnapshot(appState)
|
||||||
const { account } = useSnapshot(accountState)
|
const { account } = useSnapshot(accountState)
|
||||||
|
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation("common")
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const locale = router.locale || 'en'
|
const locale = router.locale || "en"
|
||||||
|
|
||||||
const nameInput = React.createRef<HTMLInputElement>()
|
const nameInput = React.createRef<HTMLInputElement>()
|
||||||
const descriptionInput = React.createRef<HTMLTextAreaElement>()
|
const descriptionInput = React.createRef<HTMLTextAreaElement>()
|
||||||
const raidSelect = React.createRef<HTMLSelectElement>()
|
const raidSelect = React.createRef<HTMLSelectElement>()
|
||||||
|
|
||||||
const readOnlyClasses = classNames({
|
const readOnlyClasses = classNames({
|
||||||
'PartyDetails': true,
|
PartyDetails: true,
|
||||||
'ReadOnly': true,
|
ReadOnly: true,
|
||||||
'Visible': !party.detailsVisible
|
Visible: !party.detailsVisible,
|
||||||
})
|
})
|
||||||
|
|
||||||
const editableClasses = classNames({
|
const editableClasses = classNames({
|
||||||
'PartyDetails': true,
|
PartyDetails: true,
|
||||||
'Editable': true,
|
Editable: true,
|
||||||
'Visible': party.detailsVisible
|
Visible: party.detailsVisible,
|
||||||
})
|
})
|
||||||
|
|
||||||
const emptyClasses = classNames({
|
const emptyClasses = classNames({
|
||||||
'EmptyDetails': true,
|
EmptyDetails: true,
|
||||||
'Visible': !party.detailsVisible
|
Visible: !party.detailsVisible,
|
||||||
})
|
})
|
||||||
|
|
||||||
const userClass = classNames({
|
const userClass = classNames({
|
||||||
'user': true,
|
user: true,
|
||||||
'empty': !party.user
|
empty: !party.user,
|
||||||
})
|
})
|
||||||
|
|
||||||
const linkClass = classNames({
|
const linkClass = classNames({
|
||||||
'wind': party && party.element == 1,
|
wind: party && party.element == 1,
|
||||||
'fire': party && party.element == 2,
|
fire: party && party.element == 2,
|
||||||
'water': party && party.element == 3,
|
water: party && party.element == 3,
|
||||||
'earth': party && party.element == 4,
|
earth: party && party.element == 4,
|
||||||
'dark': party && party.element == 5,
|
dark: party && party.element == 5,
|
||||||
'light': party && party.element == 6
|
light: party && party.element == 6,
|
||||||
})
|
})
|
||||||
|
|
||||||
const [errors, setErrors] = useState<{ [key: string]: string }>({
|
const [errors, setErrors] = useState<{ [key: string]: string }>({
|
||||||
name: '',
|
name: "",
|
||||||
description: ''
|
description: "",
|
||||||
})
|
})
|
||||||
|
|
||||||
function handleInputChange(event: React.ChangeEvent<HTMLInputElement>) {
|
function handleInputChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
const { name, value } = event.target
|
const { name, value } = event.target
|
||||||
let newErrors = errors
|
let newErrors = errors
|
||||||
|
|
||||||
setErrors(newErrors)
|
setErrors(newErrors)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTextAreaChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
|
function handleTextAreaChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
const { name, value } = event.target
|
const { name, value } = event.target
|
||||||
let newErrors = errors
|
let newErrors = errors
|
||||||
|
|
||||||
setErrors(newErrors)
|
setErrors(newErrors)
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleDetails() {
|
function toggleDetails() {
|
||||||
appState.party.detailsVisible = !appState.party.detailsVisible
|
appState.party.detailsVisible = !appState.party.detailsVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDetails(event: React.MouseEvent) {
|
function updateDetails(event: React.MouseEvent) {
|
||||||
const nameValue = nameInput.current?.value
|
const nameValue = nameInput.current?.value
|
||||||
const descriptionValue = descriptionInput.current?.value
|
const descriptionValue = descriptionInput.current?.value
|
||||||
const raid = raids.find(raid => raid.slug === raidSelect.current?.value)
|
const raid = raids.find((raid) => raid.slug === raidSelect.current?.value)
|
||||||
|
|
||||||
props.updateCallback(nameValue, descriptionValue, raid)
|
props.updateCallback(nameValue, descriptionValue, raid)
|
||||||
toggleDetails()
|
toggleDetails()
|
||||||
}
|
}
|
||||||
|
|
||||||
const userImage = () => {
|
const userImage = () => {
|
||||||
if (party.user)
|
if (party.user)
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
alt={party.user.picture.picture}
|
alt={party.user.picture.picture}
|
||||||
className={`profile ${party.user.picture.element}`}
|
className={`profile ${party.user.picture.element}`}
|
||||||
srcSet={`/profile/${party.user.picture.picture}.png,
|
srcSet={`/profile/${party.user.picture.picture}.png,
|
||||||
/profile/${party.user.picture.picture}@2x.png 2x`}
|
/profile/${party.user.picture.picture}@2x.png 2x`}
|
||||||
src={`/profile/${party.user.picture.picture}.png`}
|
src={`/profile/${party.user.picture.picture}.png`}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
else
|
else return <div className="no-user" />
|
||||||
return (<div className="no-user" />)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const userBlock = () => {
|
|
||||||
return (
|
|
||||||
<div className={userClass}>
|
|
||||||
{ userImage() }
|
|
||||||
{ (party.user) ? party.user.username : t('no_user') }
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const linkedUserBlock = (user: User) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Link href={`/${user.username}`} passHref>
|
|
||||||
<a className={linkClass}>{userBlock()}</a>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const linkedRaidBlock = (raid: Raid) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Link href={`/teams?raid=${raid.slug}`} passHref>
|
|
||||||
<a className={`Raid ${linkClass}`}>
|
|
||||||
{raid.name[locale]}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const deleteButton = () => {
|
|
||||||
if (party.editable) {
|
|
||||||
return (
|
|
||||||
<AlertDialog.Root>
|
|
||||||
<AlertDialog.Trigger className="Button destructive">
|
|
||||||
<span className='icon'>
|
|
||||||
<CrossIcon />
|
|
||||||
</span>
|
|
||||||
<span className="text">{t('buttons.delete')}</span>
|
|
||||||
</AlertDialog.Trigger>
|
|
||||||
<AlertDialog.Portal>
|
|
||||||
<AlertDialog.Overlay className="Overlay" />
|
|
||||||
<AlertDialog.Content className="Dialog">
|
|
||||||
<AlertDialog.Title className="DialogTitle">
|
|
||||||
{t('modals.delete_team.title')}
|
|
||||||
</AlertDialog.Title>
|
|
||||||
<AlertDialog.Description className="DialogDescription">
|
|
||||||
{t('modals.delete_team.description')}
|
|
||||||
</AlertDialog.Description>
|
|
||||||
<div className="actions">
|
|
||||||
<AlertDialog.Cancel className="Button modal">{t('modals.delete_team.buttons.cancel')}</AlertDialog.Cancel>
|
|
||||||
<AlertDialog.Action className="Button modal destructive" onClick={(e) => props.deleteCallback(e)}>{t('modals.delete_team.buttons.confirm')}</AlertDialog.Action>
|
|
||||||
</div>
|
|
||||||
</AlertDialog.Content>
|
|
||||||
</AlertDialog.Portal>
|
|
||||||
</AlertDialog.Root>
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return ('')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const editable = (
|
|
||||||
<section className={editableClasses}>
|
|
||||||
<CharLimitedFieldset
|
|
||||||
fieldName="name"
|
|
||||||
placeholder="Name your team"
|
|
||||||
value={party.name}
|
|
||||||
limit={50}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
error={errors.name}
|
|
||||||
ref={nameInput}
|
|
||||||
/>
|
|
||||||
<RaidDropdown
|
|
||||||
showAllRaidsOption={false}
|
|
||||||
currentRaid={party.raid?.slug || ''}
|
|
||||||
ref={raidSelect}
|
|
||||||
/>
|
|
||||||
<TextFieldset
|
|
||||||
fieldName="name"
|
|
||||||
placeholder={"Write your notes here\n\n\nWatch out for the 50% trigger!\nMake sure to click Fediel’s 1 first\nGood luck with RNG!"}
|
|
||||||
value={party.description}
|
|
||||||
onChange={handleTextAreaChange}
|
|
||||||
error={errors.description}
|
|
||||||
ref={descriptionInput}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="bottom">
|
|
||||||
<div className="left">
|
|
||||||
{ (router.pathname !== '/new') ? deleteButton() : '' }
|
|
||||||
</div>
|
|
||||||
<div className="right">
|
|
||||||
<Button
|
|
||||||
active={true}
|
|
||||||
onClick={toggleDetails}>
|
|
||||||
{t('buttons.cancel')}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
active={true}
|
|
||||||
icon="check"
|
|
||||||
onClick={updateDetails}>
|
|
||||||
{t('buttons.save_info')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
|
|
||||||
const readOnly = (
|
|
||||||
<section className={readOnlyClasses}>
|
|
||||||
<div className="info">
|
|
||||||
<div className="left">
|
|
||||||
{ (party.name) ? <h1>{party.name}</h1> : '' }
|
|
||||||
<div className="attribution">
|
|
||||||
{ (party.user) ? linkedUserBlock(party.user) : userBlock() }
|
|
||||||
{ (party.raid) ? linkedRaidBlock(party.raid) : '' }
|
|
||||||
{ (party.created_at != undefined)
|
|
||||||
? <time
|
|
||||||
className="last-updated"
|
|
||||||
dateTime={new Date(party.created_at).toString()}>
|
|
||||||
{formatTimeAgo(new Date(party.created_at), locale)}
|
|
||||||
</time>
|
|
||||||
: '' }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="right">
|
|
||||||
{ (party.editable)
|
|
||||||
? <Button active={true} icon="edit" onClick={toggleDetails}>{t('buttons.show_info')}</Button>
|
|
||||||
: <div /> }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{ (party.description) ? <p><Linkify>{party.description}</Linkify></p> : '' }
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
|
|
||||||
const emptyDetails = (
|
|
||||||
<div className={emptyClasses}>
|
|
||||||
<Button active={true} icon="edit" onClick={toggleDetails}>{t('buttons.show_info')}</Button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const generateTitle = () => {
|
|
||||||
let title = ''
|
|
||||||
|
|
||||||
const username = (party.user != null) ? `@${party.user?.username}` : 'Anonymous'
|
|
||||||
|
|
||||||
if (party.name != null)
|
|
||||||
title = `${party.name} by ${username}`
|
|
||||||
else if (party.name == null && party.editable && router.route === '/new')
|
|
||||||
title = "New Team"
|
|
||||||
else
|
|
||||||
title = `Untitled team by ${username}`
|
|
||||||
|
|
||||||
return title
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const userBlock = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={userClass}>
|
||||||
<Head>
|
{userImage()}
|
||||||
<title>{generateTitle()}</title>
|
{party.user ? party.user.username : t("no_user")}
|
||||||
|
</div>
|
||||||
<meta property="og:title" content={generateTitle()} />
|
|
||||||
<meta property="og:description" content={ (party.description) ? party.description : '' } />
|
|
||||||
<meta property="og:url" content="https://app.granblue.team" />
|
|
||||||
<meta property="og:type" content="website" />
|
|
||||||
|
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
|
||||||
<meta property="twitter:domain" content="app.granblue.team" />
|
|
||||||
<meta name="twitter:title" content={generateTitle()} />
|
|
||||||
<meta name="twitter:description" content={ (party.description) ? party.description : '' } />
|
|
||||||
</Head>
|
|
||||||
{ (editable && (party.name || party.description || party.raid)) ? readOnly : emptyDetails}
|
|
||||||
{editable}
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkedUserBlock = (user: User) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Link href={`/${user.username}`} passHref>
|
||||||
|
<a className={linkClass}>{userBlock()}</a>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkedRaidBlock = (raid: Raid) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Link href={`/teams?raid=${raid.slug}`} passHref>
|
||||||
|
<a className={`Raid ${linkClass}`}>{raid.name[locale]}</a>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteButton = () => {
|
||||||
|
if (party.editable) {
|
||||||
|
return (
|
||||||
|
<AlertDialog.Root>
|
||||||
|
<AlertDialog.Trigger className="Button destructive">
|
||||||
|
<span className="icon">
|
||||||
|
<CrossIcon />
|
||||||
|
</span>
|
||||||
|
<span className="text">{t("buttons.delete")}</span>
|
||||||
|
</AlertDialog.Trigger>
|
||||||
|
<AlertDialog.Portal>
|
||||||
|
<AlertDialog.Overlay className="Overlay" />
|
||||||
|
<AlertDialog.Content className="Dialog">
|
||||||
|
<AlertDialog.Title className="DialogTitle">
|
||||||
|
{t("modals.delete_team.title")}
|
||||||
|
</AlertDialog.Title>
|
||||||
|
<AlertDialog.Description className="DialogDescription">
|
||||||
|
{t("modals.delete_team.description")}
|
||||||
|
</AlertDialog.Description>
|
||||||
|
<div className="actions">
|
||||||
|
<AlertDialog.Cancel className="Button modal">
|
||||||
|
{t("modals.delete_team.buttons.cancel")}
|
||||||
|
</AlertDialog.Cancel>
|
||||||
|
<AlertDialog.Action
|
||||||
|
className="Button modal destructive"
|
||||||
|
onClick={(e) => props.deleteCallback(e)}
|
||||||
|
>
|
||||||
|
{t("modals.delete_team.buttons.confirm")}
|
||||||
|
</AlertDialog.Action>
|
||||||
|
</div>
|
||||||
|
</AlertDialog.Content>
|
||||||
|
</AlertDialog.Portal>
|
||||||
|
</AlertDialog.Root>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const editable = (
|
||||||
|
<section className={editableClasses}>
|
||||||
|
<CharLimitedFieldset
|
||||||
|
fieldName="name"
|
||||||
|
placeholder="Name your team"
|
||||||
|
value={party.name}
|
||||||
|
limit={50}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
error={errors.name}
|
||||||
|
ref={nameInput}
|
||||||
|
/>
|
||||||
|
<RaidDropdown
|
||||||
|
showAllRaidsOption={false}
|
||||||
|
currentRaid={party.raid?.slug || ""}
|
||||||
|
ref={raidSelect}
|
||||||
|
/>
|
||||||
|
<TextFieldset
|
||||||
|
fieldName="name"
|
||||||
|
placeholder={
|
||||||
|
"Write your notes here\n\n\nWatch out for the 50% trigger!\nMake sure to click Fediel’s 1 first\nGood luck with RNG!"
|
||||||
|
}
|
||||||
|
value={party.description}
|
||||||
|
onChange={handleTextAreaChange}
|
||||||
|
error={errors.description}
|
||||||
|
ref={descriptionInput}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="bottom">
|
||||||
|
<div className="left">
|
||||||
|
{router.pathname !== "/new" ? deleteButton() : ""}
|
||||||
|
</div>
|
||||||
|
<div className="right">
|
||||||
|
<Button active={true} onClick={toggleDetails}>
|
||||||
|
{t("buttons.cancel")}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button active={true} icon="check" onClick={updateDetails}>
|
||||||
|
{t("buttons.save_info")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
|
||||||
|
const readOnly = (
|
||||||
|
<section className={readOnlyClasses}>
|
||||||
|
<div className="info">
|
||||||
|
<div className="left">
|
||||||
|
{party.name ? <h1>{party.name}</h1> : ""}
|
||||||
|
<div className="attribution">
|
||||||
|
{party.user ? linkedUserBlock(party.user) : userBlock()}
|
||||||
|
{party.raid ? linkedRaidBlock(party.raid) : ""}
|
||||||
|
{party.created_at != undefined ? (
|
||||||
|
<time
|
||||||
|
className="last-updated"
|
||||||
|
dateTime={new Date(party.created_at).toString()}
|
||||||
|
>
|
||||||
|
{formatTimeAgo(new Date(party.created_at), locale)}
|
||||||
|
</time>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="right">
|
||||||
|
{party.editable ? (
|
||||||
|
<Button active={true} icon="edit" onClick={toggleDetails}>
|
||||||
|
{t("buttons.show_info")}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<div />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{party.description ? (
|
||||||
|
<p>
|
||||||
|
<Linkify>{party.description}</Linkify>
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
|
||||||
|
const emptyDetails = (
|
||||||
|
<div className={emptyClasses}>
|
||||||
|
{party.editable ? (
|
||||||
|
<Button active={true} icon="edit" onClick={toggleDetails}>
|
||||||
|
{t("buttons.show_info")}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<div />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
const generateTitle = () => {
|
||||||
|
let title = ""
|
||||||
|
|
||||||
|
const username =
|
||||||
|
party.user != null ? `@${party.user?.username}` : "Anonymous"
|
||||||
|
|
||||||
|
if (party.name != null) title = `${party.name} by ${username}`
|
||||||
|
else if (party.name == null && party.editable && router.route === "/new")
|
||||||
|
title = "New Team"
|
||||||
|
else title = `Untitled team by ${username}`
|
||||||
|
|
||||||
|
return title
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Head>
|
||||||
|
<title>{generateTitle()}</title>
|
||||||
|
|
||||||
|
<meta property="og:title" content={generateTitle()} />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content={party.description ? party.description : ""}
|
||||||
|
/>
|
||||||
|
<meta property="og:url" content="https://app.granblue.team" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta property="twitter:domain" content="app.granblue.team" />
|
||||||
|
<meta name="twitter:title" content={generateTitle()} />
|
||||||
|
<meta
|
||||||
|
name="twitter:description"
|
||||||
|
content={party.description ? party.description : ""}
|
||||||
|
/>
|
||||||
|
</Head>
|
||||||
|
{editable && (party.name || party.description || party.raid)
|
||||||
|
? readOnly
|
||||||
|
: emptyDetails}
|
||||||
|
{editable}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PartyDetails
|
export default PartyDetails
|
||||||
|
|
|
||||||
1
types/Party.d.ts
vendored
1
types/Party.d.ts
vendored
|
|
@ -1,6 +1,7 @@
|
||||||
interface Party {
|
interface Party {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
|
description: string
|
||||||
raid: Raid
|
raid: Raid
|
||||||
shortcode: string
|
shortcode: string
|
||||||
extra: boolean
|
extra: boolean
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue