diff --git a/components/character/CharacterGrid/index.tsx b/components/character/CharacterGrid/index.tsx index 958d374e..048ba655 100644 --- a/components/character/CharacterGrid/index.tsx +++ b/components/character/CharacterGrid/index.tsx @@ -259,6 +259,23 @@ const CharacterGrid = (props: Props) => { } } + function removeJobSkill(position: number) { + if (party.id && props.editable) { + api + .removeJobSkill({ partyId: party.id, position: position }) + .then((response) => { + // Update the current skills + const newSkills = response.data.job_skills + setJobSkills(newSkills) + appState.party.jobSkills = newSkills + }) + .catch((error) => { + const data = error.response.data + console.log(data) + }) + } + } + async function saveAccessory(accessory: JobAccessory) { const payload = { party: { @@ -506,6 +523,7 @@ const CharacterGrid = (props: Props) => { editable={props.editable} saveJob={saveJob} saveSkill={saveJobSkill} + removeSkill={removeJobSkill} saveAccessory={saveAccessory} /> (function Select( )} - + <> (function Select( /> ( onClick={openJobSelect} onOpenChange={() => setOpen(!open)} onValueChange={handleChange} + className="Job" triggerClass="Job" + overlayVisible={false} > {t('no_job')} diff --git a/components/job/JobSection/index.scss b/components/job/JobSection/index.scss index 6caa3093..03782729 100644 --- a/components/job/JobSection/index.scss +++ b/components/job/JobSection/index.scss @@ -56,6 +56,9 @@ .JobSkills { display: flex; flex-direction: column; - gap: $unit; + + &:not(.editable) { + gap: $unit; + } } } diff --git a/components/job/JobSection/index.tsx b/components/job/JobSection/index.tsx index e9e2b1b9..41258d14 100644 --- a/components/job/JobSection/index.tsx +++ b/components/job/JobSection/index.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react' import { useRouter } from 'next/router' import { useSnapshot } from 'valtio' import { useTranslation } from 'next-i18next' +import classNames from 'classnames' import JobDropdown from '~components/job/JobDropdown' import JobImage from '~components/job/JobImage' @@ -22,6 +23,7 @@ interface Props { editable: boolean saveJob: (job?: Job) => void saveSkill: (skill: JobSkill, position: number) => void + removeSkill: (position: number) => void saveAccessory: (accessory: JobAccessory) => void } @@ -48,6 +50,12 @@ const JobSection = (props: Props) => { // Refs const selectRef = React.createRef() + // Classes + const skillContainerClasses = classNames({ + JobSkills: true, + editable: props.editable, + }) + useEffect(() => { // Set current job based on ID setJob(props.job) @@ -126,9 +134,11 @@ const JobSection = (props: Props) => { return ( ) } @@ -173,10 +183,6 @@ const JobSection = (props: Props) => { ) - function jobLabel() { - return job ? filledJobLabel : emptyJobLabel - } - // Render: JSX components return (
@@ -209,7 +215,7 @@ const JobSection = (props: Props) => { )} -
    +
      {[...Array(numSkills)].map((e, i) => (
    • {canEditSkill(skills[i]) diff --git a/components/job/JobSkillItem/index.scss b/components/job/JobSkillItem/index.scss index 9a15bb62..df2fa67b 100644 --- a/components/job/JobSkillItem/index.scss +++ b/components/job/JobSkillItem/index.scss @@ -1,47 +1,81 @@ +.JobSkills { + &.editable .JobSkill { + .Info { + padding: $unit-half * 1.5; + + & > img, + & > div.placeholder { + width: $unit-4x; + height: $unit-4x; + } + } + } +} + .JobSkill { display: flex; - gap: $unit; - align-items: center; + align-items: stretch; + justify-content: space-between; + + &.editable .Info:hover { + background-color: var(--button-bg-hover); + } &.editable:hover { cursor: pointer; - & > img.editable, - & > div.placeholder.editable { - border: $hover-stroke; - box-shadow: $hover-shadow; - cursor: pointer; - transform: $scale-tall; - } + .Info { + & > img.editable, + & > div.placeholder.editable { + border: $hover-stroke; + box-shadow: $hover-shadow; + cursor: pointer; + transform: $scale-tall; + } - & p.placeholder { - color: var(--text-tertiary-hover); - } + & p.placeholder { + color: var(--text-tertiary-hover); + } - & svg { - fill: var(--icon-secondary-hover); + & svg { + fill: var(--icon-secondary-hover); + } } } - & > img, - & > div.placeholder { - background: var(--card-bg); - border-radius: calc($unit / 2); - border: 1px solid rgba(0, 0, 0, 0); - width: $unit * 5; - height: $unit * 5; - } - - & > div.placeholder { - display: flex; + .Info { align-items: center; - justify-content: center; + border-radius: $input-corner; + display: flex; + flex-grow: 1; + gap: $unit; - & > svg { - fill: var(--icon-secondary); - width: $unit * 2; - height: $unit * 2; + & > img, + & > div.placeholder { + background: var(--card-bg); + border-radius: calc($unit / 2); + border: 1px solid rgba(0, 0, 0, 0); + width: $unit-5x; + height: $unit-5x; } + + & > div.placeholder { + display: flex; + align-items: center; + justify-content: center; + + & > svg { + fill: var(--icon-secondary); + width: $unit-2x; + height: $unit-2x; + } + } + } + + & > .Button { + justify-content: center; + max-width: $unit-6x; + height: auto; } p { diff --git a/components/job/JobSkillItem/index.tsx b/components/job/JobSkillItem/index.tsx index bac8f729..a1ded0d3 100644 --- a/components/job/JobSkillItem/index.tsx +++ b/components/job/JobSkillItem/index.tsx @@ -1,21 +1,43 @@ -import React from 'react' +import React, { useState } from 'react' import { useRouter } from 'next/router' -import { useTranslation } from 'next-i18next' - +import { Trans, useTranslation } from 'next-i18next' import classNames from 'classnames' -import PlusIcon from '~public/icons/Add.svg' +import Alert from '~components/common/Alert' +import Button from '~components/common/Button' +import { + ContextMenu, + ContextMenuTrigger, + ContextMenuContent, +} from '~components/common/ContextMenu' +import ContextMenuItem from '~components/common/ContextMenuItem' + +import EllipsisIcon from '~public/icons/Ellipsis.svg' +import PlusIcon from '~public/icons/Add.svg' import './index.scss' // Props interface Props extends React.ComponentPropsWithoutRef<'div'> { skill?: JobSkill + position: number editable: boolean hasJob: boolean + removeJobSkill: (position: number) => void } const JobSkillItem = React.forwardRef( - function useJobSkillItem({ ...props }, forwardedRef) { + function useJobSkillItem( + { + skill, + position, + editable, + hasJob, + removeJobSkill: sendJobSkillToRemove, + ...props + }, + forwardedRef + ) { + // Set up translation const router = useRouter() const { t } = useTranslation('common') const locale = @@ -23,31 +45,55 @@ const JobSkillItem = React.forwardRef( ? router.locale : 'en' + // States: Component + const [alertOpen, setAlertOpen] = useState(false) + const [contextMenuOpen, setContextMenuOpen] = useState(false) + + // Classes const classes = classNames({ JobSkill: true, - editable: props.editable, + editable: editable, }) const imageClasses = classNames({ - placeholder: !props.skill, - editable: props.editable && props.hasJob, + placeholder: !skill, + editable: editable && hasJob, }) + const buttonClasses = classNames({ + Clicked: contextMenuOpen, + }) + + // Methods: Data mutation + function removeJobSkill() { + if (skill) sendJobSkillToRemove(position) + setAlertOpen(false) + } + + // Methods: Context menu + function handleButtonClicked() { + setContextMenuOpen(!contextMenuOpen) + } + + function handleContextMenuOpenChange(open: boolean) { + if (!open) setContextMenuOpen(false) + } + const skillImage = () => { let jsx: React.ReactNode - if (props.skill) { + if (skill) { jsx = ( {props.skill.name[locale]} ) } else { jsx = (
      - {props.editable && props.hasJob ? : ''} + {editable && hasJob ? : ''}
      ) } @@ -58,9 +104,9 @@ const JobSkillItem = React.forwardRef( const label = () => { let jsx: React.ReactNode - if (props.skill) { - jsx =

      {props.skill.name[locale]}

      - } else if (props.editable && props.hasJob) { + if (skill) { + jsx =

      {skill.name[locale]}

      + } else if (editable && hasJob) { jsx =

      {t('job_skills.state.selectable')}

      } else { jsx =

      {t('job_skills.state.no_skill')}

      @@ -69,10 +115,55 @@ const JobSkillItem = React.forwardRef( return jsx } + const removeAlert = () => { + return ( + setAlertOpen(false)} + cancelActionText={t('buttons.cancel')} + message={ + + Are you sure you want to remove{' '} + {{ job_skill: skill?.name[locale] }} from your + team? + + } + /> + ) + } + + const contextMenu = () => { + return ( + <> + + +