From f197ef41c1b41804190d218b48d7f81cb234eb6b Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 25 Jan 2022 23:14:18 -0800 Subject: [PATCH 01/34] Add new uncap icons --- public/icons/uncap/blue.svg | 44 +++++++++++++++++++++++++++++++++++ public/icons/uncap/empty.svg | 25 ++++++++++++++++++++ public/icons/uncap/purple.svg | 44 +++++++++++++++++++++++++++++++++++ public/icons/uncap/red.svg | 44 +++++++++++++++++++++++++++++++++++ public/icons/uncap/yellow.svg | 44 +++++++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 public/icons/uncap/blue.svg create mode 100644 public/icons/uncap/empty.svg create mode 100644 public/icons/uncap/purple.svg create mode 100644 public/icons/uncap/red.svg create mode 100644 public/icons/uncap/yellow.svg diff --git a/public/icons/uncap/blue.svg b/public/icons/uncap/blue.svg new file mode 100644 index 00000000..2469d0de --- /dev/null +++ b/public/icons/uncap/blue.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/empty.svg b/public/icons/uncap/empty.svg new file mode 100644 index 00000000..9aad37c9 --- /dev/null +++ b/public/icons/uncap/empty.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/purple.svg b/public/icons/uncap/purple.svg new file mode 100644 index 00000000..93a1147c --- /dev/null +++ b/public/icons/uncap/purple.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/red.svg b/public/icons/uncap/red.svg new file mode 100644 index 00000000..c5da53d5 --- /dev/null +++ b/public/icons/uncap/red.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/yellow.svg b/public/icons/uncap/yellow.svg new file mode 100644 index 00000000..70b8ece3 --- /dev/null +++ b/public/icons/uncap/yellow.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From ccb0951a3597f9fe42a1d30c80aa837b639031e5 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 25 Jan 2022 23:14:58 -0800 Subject: [PATCH 02/34] Update WeaponUnit Flips text and uncap stars and makes the modal click target the image instead of the whole unit --- components/WeaponUnit/index.scss | 1 + components/WeaponUnit/index.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/WeaponUnit/index.scss b/components/WeaponUnit/index.scss index 93c26597..10d9818d 100644 --- a/components/WeaponUnit/index.scss +++ b/components/WeaponUnit/index.scss @@ -11,6 +11,7 @@ display: flex; align-items: center; justify-content: center; + margin-bottom: 2px; overflow: hidden; transition: all 0.18s ease-in-out; } diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index 17e231dc..adf5e5b5 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -54,13 +54,13 @@ const WeaponUnit = (props: Props) => { {weapon?.name.en} { (props.editable) ? : '' } +

{weapon?.name.en}

-

{weapon?.name.en}

) From 1c9c98b1c35fae8c698389532dc5a93d335e7f0c Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 25 Jan 2022 23:18:01 -0800 Subject: [PATCH 03/34] Implement new stars --- components/UncapIndicator/index.scss | 4 ++++ components/UncapIndicator/index.tsx | 12 ++++++----- components/UncapStar/index.scss | 32 ++++++++++++++++++++++++---- components/UncapStar/index.tsx | 18 +++++++++++++--- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/components/UncapIndicator/index.scss b/components/UncapIndicator/index.scss index ceafd8d2..431f20d1 100644 --- a/components/UncapIndicator/index.scss +++ b/components/UncapIndicator/index.scss @@ -7,4 +7,8 @@ list-style: none; margin: 0; padding: 0; + + &:hover { + cursor: pointer; + } } \ No newline at end of file diff --git a/components/UncapIndicator/index.tsx b/components/UncapIndicator/index.tsx index ee74c9d5..ef8c00ab 100644 --- a/components/UncapIndicator/index.tsx +++ b/components/UncapIndicator/index.tsx @@ -1,5 +1,4 @@ -import React from 'react' -import classnames from 'classnames' +import React, { useState } from 'react' import UncapStar from '~components/UncapStar' import './index.scss' @@ -36,11 +35,14 @@ const UncapIndicator = (props: Props) => {
    { Array.from(Array(numStars)).map((x, i) => { - if (props.type === 'character' && i > 3 || + if (props.type === 'character' && i > 4) { + return + } else if ( + props.type === 'character' && i == 4 || props.type !== 'character' && i > 2) { - return + return } else { - return + return } }) } diff --git a/components/UncapStar/index.scss b/components/UncapStar/index.scss index 7014dbef..e0cab927 100644 --- a/components/UncapStar/index.scss +++ b/components/UncapStar/index.scss @@ -1,7 +1,31 @@ .UncapStar { - color: #FFA15E; -} + background-repeat: no-repeat; + background-size: 18px 18px; + display: block; + height: 18px; + width: 18px; -.UncapStar.uncap { - color: #65DAFF; + &:hover { + transform: scale(1.2); + } + + &.empty { + background: url('/icons/uncap/empty.svg'); + } + + &.mlb { + background: url('/icons/uncap/yellow.svg') + } + + &.special { + background: url('/icons/uncap/red.svg') + } + + &.flb { + background: url('/icons/uncap/blue.svg') + } + + &.ulb { + background: url('/icons/uncap/purple.svg') + } } \ No newline at end of file diff --git a/components/UncapStar/index.tsx b/components/UncapStar/index.tsx index 6cc0d45e..74c76dea 100644 --- a/components/UncapStar/index.tsx +++ b/components/UncapStar/index.tsx @@ -4,13 +4,19 @@ import classnames from 'classnames' import './index.scss' interface Props { - uncap: boolean + special: boolean + flb: boolean + ulb: boolean } const UncapStar = (props: Props) => { const classes = classnames({ - UncapStar: true, - 'uncap': props.uncap + UncapStar: true, + 'special': props.special, + 'mlb': !props.special, + 'flb': props.flb, + 'ulb': props.ulb + }) return ( @@ -18,4 +24,10 @@ const UncapStar = (props: Props) => { ) } +UncapStar.defaultProps = { + special: false, + flb: false, + ulb: false +} + export default UncapStar \ No newline at end of file From 7c96b5c836724de2cbb2b4b9450e44adff556c29 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 25 Jan 2022 23:25:18 -0800 Subject: [PATCH 04/34] Adjust hover transforms It was too aggressive --- components/CharacterUnit/index.scss | 2 +- components/SummonUnit/index.scss | 7 ++++++- components/WeaponUnit/index.scss | 6 +++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/CharacterUnit/index.scss b/components/CharacterUnit/index.scss index 45aa6f99..4cab997f 100644 --- a/components/CharacterUnit/index.scss +++ b/components/CharacterUnit/index.scss @@ -22,7 +22,7 @@ border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 14px; cursor: pointer; - transform: scale(1.1, 1.1); + transform: scale(1.025, 1.025); } .CharacterUnit.filled h3 { diff --git a/components/SummonUnit/index.scss b/components/SummonUnit/index.scss index 614b482e..d7e87d3a 100644 --- a/components/SummonUnit/index.scss +++ b/components/SummonUnit/index.scss @@ -33,7 +33,12 @@ border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 14px; cursor: pointer; - transform: scale(1.1, 1.1); + transform: scale(1.05, 1.05); + } + + &.main.editable .SummonImage:hover, + &.friend.editable .SummonImage:hover { + transform: scale(1.025, 1.025); } &.filled h3 { diff --git a/components/WeaponUnit/index.scss b/components/WeaponUnit/index.scss index 10d9818d..34c5ae00 100644 --- a/components/WeaponUnit/index.scss +++ b/components/WeaponUnit/index.scss @@ -20,7 +20,11 @@ border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 14px; cursor: pointer; - transform: scale(1.1, 1.1); + transform: scale(1.05, 1.05); +} + +.WeaponUnit.mainhand.editable .WeaponImage:hover { + transform: scale(1.025, 1.025); } .WeaponUnit.filled h3 { From 3a1ef5d685832c74755478458aa821531f0bfb16 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 26 Jan 2022 00:12:02 -0800 Subject: [PATCH 05/34] Allow user to set uncap level doesn't save to server yet --- components/UncapIndicator/index.tsx | 15 ++++++++++++--- components/UncapStar/index.scss | 6 +++++- components/UncapStar/index.tsx | 9 +++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/components/UncapIndicator/index.tsx b/components/UncapIndicator/index.tsx index ef8c00ab..ae10bd71 100644 --- a/components/UncapIndicator/index.tsx +++ b/components/UncapIndicator/index.tsx @@ -15,6 +15,8 @@ interface Props { const UncapIndicator = (props: Props) => { let numStars + const [uncap, setUncap] = useState(props.uncapLevel) + if (props.type === 'character') { if (props.flb) { numStars = 5 @@ -31,18 +33,25 @@ const UncapIndicator = (props: Props) => { } } + function toggleStar(index: number, empty: boolean) { + if (empty) + setUncap(index + 1) + else + setUncap(index) + } + return (
      { Array.from(Array(numStars)).map((x, i) => { if (props.type === 'character' && i > 4) { - return + return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> } else if ( props.type === 'character' && i == 4 || props.type !== 'character' && i > 2) { - return + return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> } else { - return + return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> } }) } diff --git a/components/UncapStar/index.scss b/components/UncapStar/index.scss index e0cab927..144de4c9 100644 --- a/components/UncapStar/index.scss +++ b/components/UncapStar/index.scss @@ -9,7 +9,11 @@ transform: scale(1.2); } - &.empty { + &.empty, + &.empty.mlb, + &.empty.flb, + &.empty.ulb, + &.empty.special { background: url('/icons/uncap/empty.svg'); } diff --git a/components/UncapStar/index.tsx b/components/UncapStar/index.tsx index 74c76dea..bd20d45c 100644 --- a/components/UncapStar/index.tsx +++ b/components/UncapStar/index.tsx @@ -4,14 +4,18 @@ import classnames from 'classnames' import './index.scss' interface Props { + empty: boolean special: boolean flb: boolean ulb: boolean + index: number + onClick: (index: number, empty: boolean) => void } const UncapStar = (props: Props) => { const classes = classnames({ UncapStar: true, + 'empty': props.empty, 'special': props.special, 'mlb': !props.special, 'flb': props.flb, @@ -19,12 +23,17 @@ const UncapStar = (props: Props) => { }) + function clicked() { + props.onClick(props.index, props.empty) + } + return (
    • ) } UncapStar.defaultProps = { + empty: false, special: false, flb: false, ulb: false From ae857c19a176597fd335c5a87960991e6ccede97 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 25 Jan 2022 23:14:18 -0800 Subject: [PATCH 06/34] Add new uncap icons --- public/icons/uncap/blue.svg | 44 +++++++++++++++++++++++++++++++++++ public/icons/uncap/empty.svg | 25 ++++++++++++++++++++ public/icons/uncap/purple.svg | 44 +++++++++++++++++++++++++++++++++++ public/icons/uncap/red.svg | 44 +++++++++++++++++++++++++++++++++++ public/icons/uncap/yellow.svg | 44 +++++++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 public/icons/uncap/blue.svg create mode 100644 public/icons/uncap/empty.svg create mode 100644 public/icons/uncap/purple.svg create mode 100644 public/icons/uncap/red.svg create mode 100644 public/icons/uncap/yellow.svg diff --git a/public/icons/uncap/blue.svg b/public/icons/uncap/blue.svg new file mode 100644 index 00000000..2469d0de --- /dev/null +++ b/public/icons/uncap/blue.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/empty.svg b/public/icons/uncap/empty.svg new file mode 100644 index 00000000..9aad37c9 --- /dev/null +++ b/public/icons/uncap/empty.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/purple.svg b/public/icons/uncap/purple.svg new file mode 100644 index 00000000..93a1147c --- /dev/null +++ b/public/icons/uncap/purple.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/red.svg b/public/icons/uncap/red.svg new file mode 100644 index 00000000..c5da53d5 --- /dev/null +++ b/public/icons/uncap/red.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/yellow.svg b/public/icons/uncap/yellow.svg new file mode 100644 index 00000000..70b8ece3 --- /dev/null +++ b/public/icons/uncap/yellow.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b2daead1d5da05cb3ab7c8502a0ce5f378ca7a1d Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 25 Jan 2022 23:14:58 -0800 Subject: [PATCH 07/34] Update WeaponUnit Flips text and uncap stars and makes the modal click target the image instead of the whole unit --- components/WeaponUnit/index.scss | 1 + components/WeaponUnit/index.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/WeaponUnit/index.scss b/components/WeaponUnit/index.scss index 93c26597..10d9818d 100644 --- a/components/WeaponUnit/index.scss +++ b/components/WeaponUnit/index.scss @@ -11,6 +11,7 @@ display: flex; align-items: center; justify-content: center; + margin-bottom: 2px; overflow: hidden; transition: all 0.18s ease-in-out; } diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index 17e231dc..adf5e5b5 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -54,13 +54,13 @@ const WeaponUnit = (props: Props) => { {weapon?.name.en} { (props.editable) ? : '' } +

      {weapon?.name.en}

      -

      {weapon?.name.en}

      ) From e2ff4fd4322201ef2ab9bf826f943bebbe26beba Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 25 Jan 2022 23:18:01 -0800 Subject: [PATCH 08/34] Implement new stars --- components/UncapIndicator/index.scss | 4 ++++ components/UncapIndicator/index.tsx | 12 ++++++----- components/UncapStar/index.scss | 32 ++++++++++++++++++++++++---- components/UncapStar/index.tsx | 18 +++++++++++++--- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/components/UncapIndicator/index.scss b/components/UncapIndicator/index.scss index ceafd8d2..431f20d1 100644 --- a/components/UncapIndicator/index.scss +++ b/components/UncapIndicator/index.scss @@ -7,4 +7,8 @@ list-style: none; margin: 0; padding: 0; + + &:hover { + cursor: pointer; + } } \ No newline at end of file diff --git a/components/UncapIndicator/index.tsx b/components/UncapIndicator/index.tsx index ee74c9d5..ef8c00ab 100644 --- a/components/UncapIndicator/index.tsx +++ b/components/UncapIndicator/index.tsx @@ -1,5 +1,4 @@ -import React from 'react' -import classnames from 'classnames' +import React, { useState } from 'react' import UncapStar from '~components/UncapStar' import './index.scss' @@ -36,11 +35,14 @@ const UncapIndicator = (props: Props) => {
        { Array.from(Array(numStars)).map((x, i) => { - if (props.type === 'character' && i > 3 || + if (props.type === 'character' && i > 4) { + return + } else if ( + props.type === 'character' && i == 4 || props.type !== 'character' && i > 2) { - return + return } else { - return + return } }) } diff --git a/components/UncapStar/index.scss b/components/UncapStar/index.scss index 7014dbef..e0cab927 100644 --- a/components/UncapStar/index.scss +++ b/components/UncapStar/index.scss @@ -1,7 +1,31 @@ .UncapStar { - color: #FFA15E; -} + background-repeat: no-repeat; + background-size: 18px 18px; + display: block; + height: 18px; + width: 18px; -.UncapStar.uncap { - color: #65DAFF; + &:hover { + transform: scale(1.2); + } + + &.empty { + background: url('/icons/uncap/empty.svg'); + } + + &.mlb { + background: url('/icons/uncap/yellow.svg') + } + + &.special { + background: url('/icons/uncap/red.svg') + } + + &.flb { + background: url('/icons/uncap/blue.svg') + } + + &.ulb { + background: url('/icons/uncap/purple.svg') + } } \ No newline at end of file diff --git a/components/UncapStar/index.tsx b/components/UncapStar/index.tsx index 6cc0d45e..74c76dea 100644 --- a/components/UncapStar/index.tsx +++ b/components/UncapStar/index.tsx @@ -4,13 +4,19 @@ import classnames from 'classnames' import './index.scss' interface Props { - uncap: boolean + special: boolean + flb: boolean + ulb: boolean } const UncapStar = (props: Props) => { const classes = classnames({ - UncapStar: true, - 'uncap': props.uncap + UncapStar: true, + 'special': props.special, + 'mlb': !props.special, + 'flb': props.flb, + 'ulb': props.ulb + }) return ( @@ -18,4 +24,10 @@ const UncapStar = (props: Props) => { ) } +UncapStar.defaultProps = { + special: false, + flb: false, + ulb: false +} + export default UncapStar \ No newline at end of file From 928273a836da4ec39c93f1966aa985d2e897365b Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 25 Jan 2022 23:25:18 -0800 Subject: [PATCH 09/34] Adjust hover transforms It was too aggressive --- components/CharacterUnit/index.scss | 2 +- components/SummonUnit/index.scss | 7 ++++++- components/WeaponUnit/index.scss | 6 +++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/CharacterUnit/index.scss b/components/CharacterUnit/index.scss index 45aa6f99..4cab997f 100644 --- a/components/CharacterUnit/index.scss +++ b/components/CharacterUnit/index.scss @@ -22,7 +22,7 @@ border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 14px; cursor: pointer; - transform: scale(1.1, 1.1); + transform: scale(1.025, 1.025); } .CharacterUnit.filled h3 { diff --git a/components/SummonUnit/index.scss b/components/SummonUnit/index.scss index 614b482e..d7e87d3a 100644 --- a/components/SummonUnit/index.scss +++ b/components/SummonUnit/index.scss @@ -33,7 +33,12 @@ border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 14px; cursor: pointer; - transform: scale(1.1, 1.1); + transform: scale(1.05, 1.05); + } + + &.main.editable .SummonImage:hover, + &.friend.editable .SummonImage:hover { + transform: scale(1.025, 1.025); } &.filled h3 { diff --git a/components/WeaponUnit/index.scss b/components/WeaponUnit/index.scss index 10d9818d..34c5ae00 100644 --- a/components/WeaponUnit/index.scss +++ b/components/WeaponUnit/index.scss @@ -20,7 +20,11 @@ border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 14px; cursor: pointer; - transform: scale(1.1, 1.1); + transform: scale(1.05, 1.05); +} + +.WeaponUnit.mainhand.editable .WeaponImage:hover { + transform: scale(1.025, 1.025); } .WeaponUnit.filled h3 { From c18c594d0547b957731aa0bc60ad76e0d6706c86 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 26 Jan 2022 00:12:02 -0800 Subject: [PATCH 10/34] Allow user to set uncap level doesn't save to server yet --- components/UncapIndicator/index.tsx | 15 ++++++++++++--- components/UncapStar/index.scss | 6 +++++- components/UncapStar/index.tsx | 9 +++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/components/UncapIndicator/index.tsx b/components/UncapIndicator/index.tsx index ef8c00ab..ae10bd71 100644 --- a/components/UncapIndicator/index.tsx +++ b/components/UncapIndicator/index.tsx @@ -15,6 +15,8 @@ interface Props { const UncapIndicator = (props: Props) => { let numStars + const [uncap, setUncap] = useState(props.uncapLevel) + if (props.type === 'character') { if (props.flb) { numStars = 5 @@ -31,18 +33,25 @@ const UncapIndicator = (props: Props) => { } } + function toggleStar(index: number, empty: boolean) { + if (empty) + setUncap(index + 1) + else + setUncap(index) + } + return (
          { Array.from(Array(numStars)).map((x, i) => { if (props.type === 'character' && i > 4) { - return + return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> } else if ( props.type === 'character' && i == 4 || props.type !== 'character' && i > 2) { - return + return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> } else { - return + return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> } }) } diff --git a/components/UncapStar/index.scss b/components/UncapStar/index.scss index e0cab927..144de4c9 100644 --- a/components/UncapStar/index.scss +++ b/components/UncapStar/index.scss @@ -9,7 +9,11 @@ transform: scale(1.2); } - &.empty { + &.empty, + &.empty.mlb, + &.empty.flb, + &.empty.ulb, + &.empty.special { background: url('/icons/uncap/empty.svg'); } diff --git a/components/UncapStar/index.tsx b/components/UncapStar/index.tsx index 74c76dea..bd20d45c 100644 --- a/components/UncapStar/index.tsx +++ b/components/UncapStar/index.tsx @@ -4,14 +4,18 @@ import classnames from 'classnames' import './index.scss' interface Props { + empty: boolean special: boolean flb: boolean ulb: boolean + index: number + onClick: (index: number, empty: boolean) => void } const UncapStar = (props: Props) => { const classes = classnames({ UncapStar: true, + 'empty': props.empty, 'special': props.special, 'mlb': !props.special, 'flb': props.flb, @@ -19,12 +23,17 @@ const UncapStar = (props: Props) => { }) + function clicked() { + props.onClick(props.index, props.empty) + } + return (
        • ) } UncapStar.defaultProps = { + empty: false, special: false, flb: false, ulb: false From a471a494bca0e8d401377387f91da6c8c813c381 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 01:47:05 -0800 Subject: [PATCH 11/34] Remove img so background-image works --- components/UncapStar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/UncapStar/index.tsx b/components/UncapStar/index.tsx index bd20d45c..a9459ecc 100644 --- a/components/UncapStar/index.tsx +++ b/components/UncapStar/index.tsx @@ -28,7 +28,7 @@ const UncapStar = (props: Props) => { } return ( -
        • +
        • ) } From e70a7afab7d884e4daf4dc1c11dfc9b186df0465 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 01:47:27 -0800 Subject: [PATCH 12/34] Pull weapon uncap level from server --- components/WeaponUnit/index.tsx | 2 +- pages/p/[party].tsx | 7 +++++-- types/GridWeapon.d.ts | 1 + types/Weapon.d.ts | 1 + 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index adf5e5b5..9bf3249e 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -59,7 +59,7 @@ const WeaponUnit = (props: Props) => { type="weapon" ulb={weapon?.uncap.ulb || false} flb={weapon?.uncap.flb || false} - uncapLevel={3} + uncapLevel={weapon?.uncap_level!} /> diff --git a/pages/p/[party].tsx b/pages/p/[party].tsx index 8be0e297..a47a8c12 100644 --- a/pages/p/[party].tsx +++ b/pages/p/[party].tsx @@ -87,10 +87,13 @@ const PartyRoute: React.FC = () => { let weapons: GridArray = {} list.forEach((object: GridWeapon) => { + const weapon = object.weapon + weapon.uncap_level = object.uncapLevel + if (object.mainhand) - setMainWeapon(object.weapon) + setMainWeapon(weapon) else if (!object.mainhand && object.position != null) - weapons[object.position] = object.weapon + weapons[object.position] = weapon }) return weapons diff --git a/types/GridWeapon.d.ts b/types/GridWeapon.d.ts index 2c329833..af920b85 100644 --- a/types/GridWeapon.d.ts +++ b/types/GridWeapon.d.ts @@ -3,4 +3,5 @@ interface GridWeapon { mainhand: boolean position: number | null weapon: Weapon + uncapLevel: number | null } \ No newline at end of file diff --git a/types/Weapon.d.ts b/types/Weapon.d.ts index 295543ef..4e8baf58 100644 --- a/types/Weapon.d.ts +++ b/types/Weapon.d.ts @@ -25,5 +25,6 @@ interface Weapon { flb: boolean ulb: boolean } + uncap_level: number | null position?: number } \ No newline at end of file From 86657e133a5f4131fda305d29617efa655a302cd Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 05:03:12 -0800 Subject: [PATCH 13/34] Add endpoint for updating uncap levels --- utils/api.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/utils/api.tsx b/utils/api.tsx index a5490811..60fd68f3 100644 --- a/utils/api.tsx +++ b/utils/api.tsx @@ -58,12 +58,22 @@ class Api { return axios.get(url) } - check(resource: string, value: string) { + check(resource: 'username'|'email', value: string) { const resourceUrl = `${this.url}/check/${resource}` return axios.post(resourceUrl, { [resource]: value }) } + + updateUncap(resource: 'characters'|'weapons'|'summons', id: string, value: number) { + const resourceUrl = `${this.url}/${resource}/update_uncap` + return axios.post(resourceUrl, { + [resource]: { + id: id, + uncap_level: value + } + }) + } } const api: Api = new Api({ url: process.env.NEXT_PUBLIC_SIERO_API_URL || 'https://localhost:3000/api/v1'}) From 7f96b4c9a9b43eec0ed78d362a826eed52718ccb Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 05:03:26 -0800 Subject: [PATCH 14/34] Added lodash debounce dep --- package-lock.json | 32 ++++++++++++++++++++++++++++++++ package.json | 2 ++ 2 files changed, 34 insertions(+) diff --git a/package-lock.json b/package-lock.json index 26a22fd7..efd90a14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@svgr/webpack": "^6.2.0", "axios": "^0.25.0", "classnames": "^2.3.1", + "lodash.debounce": "^4.0.8", "meyer-reset-scss": "^2.0.4", "next": "12.0.8", "react": "17.0.2", @@ -23,6 +24,7 @@ "sass": "^1.49.0" }, "devDependencies": { + "@types/lodash.debounce": "^4.0.6", "@types/node": "17.0.11", "@types/react": "17.0.38", "@types/react-dom": "^17.0.11", @@ -3000,6 +3002,21 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.14.178", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", + "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==", + "dev": true + }, + "node_modules/@types/lodash.debounce": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz", + "integrity": "sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/node": { "version": "17.0.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.11.tgz", @@ -8757,6 +8774,21 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/lodash": { + "version": "4.14.178", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", + "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==", + "dev": true + }, + "@types/lodash.debounce": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz", + "integrity": "sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/node": { "version": "17.0.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.11.tgz", diff --git a/package.json b/package.json index f3d377f4..f7d84b90 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@svgr/webpack": "^6.2.0", "axios": "^0.25.0", "classnames": "^2.3.1", + "lodash.debounce": "^4.0.8", "meyer-reset-scss": "^2.0.4", "next": "12.0.8", "react": "17.0.2", @@ -28,6 +29,7 @@ "sass": "^1.49.0" }, "devDependencies": { + "@types/lodash.debounce": "^4.0.6", "@types/node": "17.0.11", "@types/react": "17.0.38", "@types/react-dom": "^17.0.11", From 3b252f99ed824f51ea094e2e0cb2e55ea5c25d37 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 05:03:40 -0800 Subject: [PATCH 15/34] Removed uncap_level from Weapon type --- types/Weapon.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/types/Weapon.d.ts b/types/Weapon.d.ts index 4e8baf58..295543ef 100644 --- a/types/Weapon.d.ts +++ b/types/Weapon.d.ts @@ -25,6 +25,5 @@ interface Weapon { flb: boolean ulb: boolean } - uncap_level: number | null position?: number } \ No newline at end of file From 7a50c4bce510265148b0d05ef0cd0957401e8cca Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 05:06:27 -0800 Subject: [PATCH 16/34] Pass down GridWeapon instead of Weapon Previously, we stripped the Weapon out of the GridWeapon for simplicity. However, now that we need to display and manipulate data on the GridWeapon (unique data), we need to pass that down instead. --- components/ExtraWeapons/index.tsx | 7 +++--- components/Party/index.tsx | 30 ++++++++++++++--------- components/UncapIndicator/index.tsx | 37 ++++++++++++++++++----------- components/WeaponGrid/index.tsx | 15 ++++++------ components/WeaponUnit/index.tsx | 12 +++++----- pages/p/[party].tsx | 13 ++++------ 6 files changed, 65 insertions(+), 49 deletions(-) diff --git a/components/ExtraWeapons/index.tsx b/components/ExtraWeapons/index.tsx index 97bab025..65792741 100644 --- a/components/ExtraWeapons/index.tsx +++ b/components/ExtraWeapons/index.tsx @@ -13,12 +13,13 @@ export enum GridType { // Props interface Props { - grid: GridArray + grid: GridArray editable: boolean exists: boolean found?: boolean offset: number onClick: (position: number) => void + updateUncap: (id: string, uncap: number) => void } const ExtraWeapons = (props: Props) => { @@ -34,10 +35,10 @@ const ExtraWeapons = (props: Props) => {
        • { props.onClick(props.offset + i)}} position={props.offset + i} unitType={1} - weapon={props.grid[props.offset + i]} + gridWeapon={props.grid[props.offset + i]} + onClick={() => { props.onClick(props.offset + i)}} />
        • ) diff --git a/components/Party/index.tsx b/components/Party/index.tsx index 3499bda4..71c89bc9 100644 --- a/components/Party/index.tsx +++ b/components/Party/index.tsx @@ -23,11 +23,11 @@ import './index.scss' interface Props { partyId?: string - mainWeapon?: Weapon + mainWeapon?: GridWeapon mainSummon?: Summon friendSummon?: Summon characters?: GridArray - weapons?: GridArray + weapons?: GridArray summons?: GridArray extra: boolean editable: boolean @@ -46,10 +46,10 @@ const Party = (props: Props) => { // Grid data const [characters, setCharacters] = useState>({}) - const [weapons, setWeapons] = useState>({}) + const [weapons, setWeapons] = useState>({}) const [summons, setSummons] = useState>({}) - const [mainWeapon, setMainWeapon] = useState() + const [mainWeapon, setMainWeapon] = useState() const [mainSummon, setMainSummon] = useState() const [friendSummon, setFriendSummon] = useState() @@ -178,8 +178,8 @@ const Party = (props: Props) => { case GridType.Weapon: const weapon = item as Weapon saveWeapon(weapon, position, partyId) - .then(() => { - storeWeapon(weapon, position) + .then((response) => { + storeWeapon(response.data.grid_weapon) }) break case GridType.Summon: @@ -193,24 +193,32 @@ const Party = (props: Props) => { } // Weapons - function storeWeapon(weapon: Weapon, position: number) { - if (position == -1) { + function storeWeapon(weapon: GridWeapon) { + if (weapon.position == -1) { setMainWeapon(weapon) } else { // Store the grid unit weapon at the correct position let newWeapons = Object.assign({}, weapons) - newWeapons[position] = weapon + newWeapons[weapon.position!] = weapon setWeapons(newWeapons) } } async function saveWeapon(weapon: Weapon, position: number, party: string) { - await api.endpoints.weapons.create({ + let uncapLevel = 3 + + if (weapon.uncap.ulb) + uncapLevel = 5 + else if (weapon.uncap.flb) + uncapLevel = 4 + + return await api.endpoints.weapons.create({ 'weapon': { 'party_id': party, 'weapon_id': weapon.id, 'position': position, - 'mainhand': (position == -1) + 'mainhand': (position == -1), + 'uncap_level': uncapLevel } }, headers) } diff --git a/components/UncapIndicator/index.tsx b/components/UncapIndicator/index.tsx index ae10bd71..d19fbb40 100644 --- a/components/UncapIndicator/index.tsx +++ b/components/UncapIndicator/index.tsx @@ -10,30 +10,39 @@ interface Props { uncapLevel: number flb: boolean ulb?: boolean + updateUncap: (uncap: number) => void } const UncapIndicator = (props: Props) => { - let numStars - const [uncap, setUncap] = useState(props.uncapLevel) - if (props.type === 'character') { - if (props.flb) { - numStars = 5 + const numStars = setNumStars() + + function setNumStars() { + let numStars + + if (props.type === 'character') { + if (props.flb) { + numStars = 5 + } else { + numStars = 4 + } } else { - numStars = 4 - } - } else { - if (props.ulb) { - numStars = 5 - } else if (props.flb) { - numStars = 4 - } else { - numStars = 3 + if (props.ulb) { + numStars = 5 + } else if (props.flb) { + numStars = 4 + } else { + numStars = 3 + } } + + return numStars } function toggleStar(index: number, empty: boolean) { + console.log("Toggling star!") + if (empty) setUncap(index + 1) else diff --git a/components/WeaponGrid/index.tsx b/components/WeaponGrid/index.tsx index ef7b6a46..cfd01ef8 100644 --- a/components/WeaponGrid/index.tsx +++ b/components/WeaponGrid/index.tsx @@ -19,8 +19,8 @@ export enum GridType { interface Props { userId?: string partyId?: string - mainhand?: Weapon | undefined - grid: GridArray + mainhand?: GridWeapon | undefined + grid: GridArray extra: boolean editable: boolean exists: boolean @@ -33,6 +33,7 @@ const WeaponGrid = (props: Props) => { const [searchPosition, setSearchPosition] = useState(0) const numWeapons: number = 9 + const searchGrid: GridArray = Object.values(props.grid).map((o) => o.weapon) const extraGrid = ( {
          { openSearchModal(-1) }} editable={props.editable} key="grid_mainhand" position={-1} unitType={0} - weapon={props.mainhand} + gridWeapon={props.mainhand} + onClick={() => { openSearchModal(-1) }} />
            @@ -81,11 +82,11 @@ const WeaponGrid = (props: Props) => { return (
          • { openSearchModal(i) }} editable={props.editable} position={i} unitType={1} - weapon={props.grid[i]} + gridWeapon={props.grid[i]} + onClick={() => { openSearchModal(i) }} />
          • ) @@ -102,7 +103,7 @@ const WeaponGrid = (props: Props) => { {open ? ( void - weapon: Weapon | undefined + gridWeapon: GridWeapon | undefined position: number editable: boolean unitType: 0 | 1 @@ -24,10 +24,10 @@ const WeaponUnit = (props: Props) => { 'mainhand': props.unitType == 0, 'grid': props.unitType == 1, 'editable': props.editable, - 'filled': (props.weapon !== undefined) + 'filled': (props.gridWeapon !== undefined) }) - const weapon = props.weapon + const weapon = props.gridWeapon?.weapon useEffect(() => { generateImageUrl() @@ -35,8 +35,8 @@ const WeaponUnit = (props: Props) => { function generateImageUrl() { let imgSrc = "" - if (props.weapon) { - const weapon = props.weapon! + if (props.gridWeapon) { + const weapon = props.gridWeapon.weapon! if (props.unitType == 0) imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${weapon.granblue_id}.jpg` @@ -59,7 +59,7 @@ const WeaponUnit = (props: Props) => { type="weapon" ulb={weapon?.uncap.ulb || false} flb={weapon?.uncap.flb || false} - uncapLevel={weapon?.uncap_level!} + uncapLevel={props.gridWeapon?.uncap_level!} />
          diff --git a/pages/p/[party].tsx b/pages/p/[party].tsx index a47a8c12..6d002c8a 100644 --- a/pages/p/[party].tsx +++ b/pages/p/[party].tsx @@ -23,10 +23,10 @@ const PartyRoute: React.FC = () => { const [editable, setEditable] = useState(false) const [characters, setCharacters] = useState>({}) - const [weapons, setWeapons] = useState>({}) + const [weapons, setWeapons] = useState>({}) const [summons, setSummons] = useState>({}) - const [mainWeapon, setMainWeapon] = useState() + const [mainWeapon, setMainWeapon] = useState() const [mainSummon, setMainSummon] = useState() const [friendSummon, setFriendSummon] = useState() @@ -84,16 +84,13 @@ const PartyRoute: React.FC = () => { } function populateWeapons(list: [GridWeapon]) { - let weapons: GridArray = {} + let weapons: GridArray = {} list.forEach((object: GridWeapon) => { - const weapon = object.weapon - weapon.uncap_level = object.uncapLevel - if (object.mainhand) - setMainWeapon(weapon) + setMainWeapon(object) else if (!object.mainhand && object.position != null) - weapons[object.position] = weapon + weapons[object.position] = object }) return weapons From dd974fde2e9aa84f42c44aa446eb4136daec8bd5 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 05:07:52 -0800 Subject: [PATCH 17/34] WIP: Use debounce to intelligently send uncap level to server We are using debounce to send the uncap level to the server without making a ton of requests if the user is feeling clicky. This is a WIP because it doesn't send to the server yet. I'm having issues setting the correct initial state from the props. --- components/ExtraWeapons/index.tsx | 1 + components/UncapIndicator/index.tsx | 15 ++++++++++++++- components/WeaponGrid/index.tsx | 7 +++++++ components/WeaponUnit/index.tsx | 7 +++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/components/ExtraWeapons/index.tsx b/components/ExtraWeapons/index.tsx index 65792741..de72c162 100644 --- a/components/ExtraWeapons/index.tsx +++ b/components/ExtraWeapons/index.tsx @@ -39,6 +39,7 @@ const ExtraWeapons = (props: Props) => { unitType={1} gridWeapon={props.grid[props.offset + i]} onClick={() => { props.onClick(props.offset + i)}} + updateUncap={updateUncap} /> ) diff --git a/components/UncapIndicator/index.tsx b/components/UncapIndicator/index.tsx index d19fbb40..a0971315 100644 --- a/components/UncapIndicator/index.tsx +++ b/components/UncapIndicator/index.tsx @@ -1,6 +1,8 @@ -import React, { useState } from 'react' +import React, { useCallback, useMemo, useState } from 'react' import UncapStar from '~components/UncapStar' +import debounce from 'lodash.debounce' + import './index.scss' @@ -16,6 +18,15 @@ interface Props { const UncapIndicator = (props: Props) => { const [uncap, setUncap] = useState(props.uncapLevel) + const debouncedAction = debounce(() => { + console.log("Debouncing...") + props.updateUncap(numStars) + }, 1000) + + const delayedAction = useCallback(() => { + debouncedAction() + }, []) + const numStars = setNumStars() function setNumStars() { @@ -47,6 +58,8 @@ const UncapIndicator = (props: Props) => { setUncap(index + 1) else setUncap(index) + + delayedAction() } return ( diff --git a/components/WeaponGrid/index.tsx b/components/WeaponGrid/index.tsx index cfd01ef8..7e1ea5d7 100644 --- a/components/WeaponGrid/index.tsx +++ b/components/WeaponGrid/index.tsx @@ -42,6 +42,7 @@ const WeaponGrid = (props: Props) => { exists={false} offset={numWeapons} onClick={openSearchModal} + updateUncap={updateUncap} /> ) @@ -64,6 +65,10 @@ const WeaponGrid = (props: Props) => { openModal() } + function updateUncap(id: string, uncap: number) { + console.log(`${id} is now ${uncap} stars`) + } + return (
          @@ -74,6 +79,7 @@ const WeaponGrid = (props: Props) => { unitType={0} gridWeapon={props.mainhand} onClick={() => { openSearchModal(-1) }} + updateUncap={updateUncap} />
            @@ -87,6 +93,7 @@ const WeaponGrid = (props: Props) => { unitType={1} gridWeapon={props.grid[i]} onClick={() => { openSearchModal(i) }} + updateUncap={updateUncap} /> ) diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index a7f7b1d1..dc99d4c6 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -10,6 +10,7 @@ import './index.scss' interface Props { onClick: () => void + updateUncap: (id: string, uncap: number) => void gridWeapon: GridWeapon | undefined position: number editable: boolean @@ -47,6 +48,11 @@ const WeaponUnit = (props: Props) => { setImageUrl(imgSrc) } + function passUncapData(uncap: number) { + if (props.gridWeapon) + props.updateUncap(props.gridWeapon.id, uncap) + } + return (
            @@ -60,6 +66,7 @@ const WeaponUnit = (props: Props) => { ulb={weapon?.uncap.ulb || false} flb={weapon?.uncap.flb || false} uncapLevel={props.gridWeapon?.uncap_level!} + updateUncap={passUncapData} />
            From 67d5ada59445f1ae8ceb695e7b44564289cb0746 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 05:29:03 -0800 Subject: [PATCH 18/34] Add variables for the hover scale effects --- components/CharacterUnit/index.scss | 2 +- components/SummonUnit/index.scss | 4 ++-- components/WeaponUnit/index.scss | 4 ++-- styles/variables.scss | 6 +++++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/components/CharacterUnit/index.scss b/components/CharacterUnit/index.scss index 4cab997f..2d104efc 100644 --- a/components/CharacterUnit/index.scss +++ b/components/CharacterUnit/index.scss @@ -22,7 +22,7 @@ border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 14px; cursor: pointer; - transform: scale(1.025, 1.025); + transform: $scale-tall; } .CharacterUnit.filled h3 { diff --git a/components/SummonUnit/index.scss b/components/SummonUnit/index.scss index d7e87d3a..1f1492be 100644 --- a/components/SummonUnit/index.scss +++ b/components/SummonUnit/index.scss @@ -33,12 +33,12 @@ border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 14px; cursor: pointer; - transform: scale(1.05, 1.05); + transform: $scale-wide; } &.main.editable .SummonImage:hover, &.friend.editable .SummonImage:hover { - transform: scale(1.025, 1.025); + transform: $scale-tall; } &.filled h3 { diff --git a/components/WeaponUnit/index.scss b/components/WeaponUnit/index.scss index 34c5ae00..0b3fc9d4 100644 --- a/components/WeaponUnit/index.scss +++ b/components/WeaponUnit/index.scss @@ -20,11 +20,11 @@ border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: rgba(0, 0, 0, 0.14) 0px 0px 14px; cursor: pointer; - transform: scale(1.05, 1.05); + transform: $scale-wide; } .WeaponUnit.mainhand.editable .WeaponImage:hover { - transform: scale(1.025, 1.025); + transform: $scale-tall; } .WeaponUnit.filled h3 { diff --git a/styles/variables.scss b/styles/variables.scss index b5caf4c7..cb23afef 100644 --- a/styles/variables.scss +++ b/styles/variables.scss @@ -26,4 +26,8 @@ $bold: 600; $font-small: 12px; $font-regular: 14px; $font-large: 18px; -$font-xlarge: 21px; \ No newline at end of file +$font-xlarge: 21px; + +// Scale factors +$scale-wide: scale(1.05, 1.05); +$scale-tall: scale(1.012, 1.012); \ No newline at end of file From d1962a5cfa9fcdced2804850d73988965687c6c9 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 05:30:52 -0800 Subject: [PATCH 19/34] Fix incorrect references --- components/ExtraWeapons/index.tsx | 2 +- components/WeaponUnit/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/ExtraWeapons/index.tsx b/components/ExtraWeapons/index.tsx index de72c162..752a94be 100644 --- a/components/ExtraWeapons/index.tsx +++ b/components/ExtraWeapons/index.tsx @@ -39,7 +39,7 @@ const ExtraWeapons = (props: Props) => { unitType={1} gridWeapon={props.grid[props.offset + i]} onClick={() => { props.onClick(props.offset + i)}} - updateUncap={updateUncap} + updateUncap={props.updateUncap} /> ) diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index dc99d4c6..93f7ee2d 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -65,7 +65,7 @@ const WeaponUnit = (props: Props) => { type="weapon" ulb={weapon?.uncap.ulb || false} flb={weapon?.uncap.flb || false} - uncapLevel={props.gridWeapon?.uncap_level!} + uncapLevel={props.gridWeapon?.uncapLevel!} updateUncap={passUncapData} />
          From ca42f4b718a701aee0db5714fc3aca020582d4c5 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 05:51:15 -0800 Subject: [PATCH 20/34] Add hover states for stars These aren't quite right yet --- components/UncapStar/index.scss | 28 +++++++++++++++--- public/icons/uncap/blue-hover.svg | 44 +++++++++++++++++++++++++++++ public/icons/uncap/empty-hover.svg | 25 ++++++++++++++++ public/icons/uncap/purple-hover.svg | 44 +++++++++++++++++++++++++++++ public/icons/uncap/red-hover.svg | 44 +++++++++++++++++++++++++++++ public/icons/uncap/yellow-hover.svg | 44 +++++++++++++++++++++++++++++ 6 files changed, 225 insertions(+), 4 deletions(-) create mode 100644 public/icons/uncap/blue-hover.svg create mode 100644 public/icons/uncap/empty-hover.svg create mode 100644 public/icons/uncap/purple-hover.svg create mode 100644 public/icons/uncap/red-hover.svg create mode 100644 public/icons/uncap/yellow-hover.svg diff --git a/components/UncapStar/index.scss b/components/UncapStar/index.scss index 144de4c9..4386c5ea 100644 --- a/components/UncapStar/index.scss +++ b/components/UncapStar/index.scss @@ -15,21 +15,41 @@ &.empty.ulb, &.empty.special { background: url('/icons/uncap/empty.svg'); + + &:hover { + background: url('/icons/uncap/empty-hover.svg'); + } } &.mlb { - background: url('/icons/uncap/yellow.svg') + background: url('/icons/uncap/yellow.svg'); + + &:hover { + background: url('/icons/uncap/yellow-hover.svg'); + } } &.special { - background: url('/icons/uncap/red.svg') + background: url('/icons/uncap/red.svg'); + + &:hover { + background: url('/icons/uncap/red-hover.svg'); + } } &.flb { - background: url('/icons/uncap/blue.svg') + background: url('/icons/uncap/blue.svg'); + + &:hover { + background: url('/icons/uncap/blue-hover.svg'); + } } &.ulb { - background: url('/icons/uncap/purple.svg') + background: url('/icons/uncap/purple.svg'); + + &:hover { + background: url('/icons/uncap/purple-hover.svg'); + } } } \ No newline at end of file diff --git a/public/icons/uncap/blue-hover.svg b/public/icons/uncap/blue-hover.svg new file mode 100644 index 00000000..cb846567 --- /dev/null +++ b/public/icons/uncap/blue-hover.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/empty-hover.svg b/public/icons/uncap/empty-hover.svg new file mode 100644 index 00000000..6debb5dd --- /dev/null +++ b/public/icons/uncap/empty-hover.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/purple-hover.svg b/public/icons/uncap/purple-hover.svg new file mode 100644 index 00000000..b4d08a3e --- /dev/null +++ b/public/icons/uncap/purple-hover.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/red-hover.svg b/public/icons/uncap/red-hover.svg new file mode 100644 index 00000000..3ed4a968 --- /dev/null +++ b/public/icons/uncap/red-hover.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icons/uncap/yellow-hover.svg b/public/icons/uncap/yellow-hover.svg new file mode 100644 index 00000000..c6a6d5dd --- /dev/null +++ b/public/icons/uncap/yellow-hover.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 39549f0b947518bbcadba34d5187eec2d2b006a0 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 11:40:06 -0800 Subject: [PATCH 21/34] Move debounce to WeaponGrid --- components/UncapIndicator/index.tsx | 33 +++++++----------- components/WeaponGrid/index.tsx | 53 ++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/components/UncapIndicator/index.tsx b/components/UncapIndicator/index.tsx index a0971315..0bc82fb0 100644 --- a/components/UncapIndicator/index.tsx +++ b/components/UncapIndicator/index.tsx @@ -1,11 +1,8 @@ -import React, { useCallback, useMemo, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import UncapStar from '~components/UncapStar' -import debounce from 'lodash.debounce' - import './index.scss' - interface Props { type: 'character' | 'weapon' | 'summon' rarity?: number @@ -16,19 +13,19 @@ interface Props { } const UncapIndicator = (props: Props) => { + const firstUpdate = useRef(true) const [uncap, setUncap] = useState(props.uncapLevel) - const debouncedAction = debounce(() => { - console.log("Debouncing...") - props.updateUncap(numStars) - }, 1000) - - const delayedAction = useCallback(() => { - debouncedAction() - }, []) + useEffect(() => { + if (firstUpdate.current) { + firstUpdate.current = false + return + } + + props.updateUncap(uncap) + }, [uncap]) const numStars = setNumStars() - function setNumStars() { let numStars @@ -52,14 +49,8 @@ const UncapIndicator = (props: Props) => { } function toggleStar(index: number, empty: boolean) { - console.log("Toggling star!") - - if (empty) - setUncap(index + 1) - else - setUncap(index) - - delayedAction() + if (empty) setUncap(index + 1) + else setUncap(index) } return ( diff --git a/components/WeaponGrid/index.tsx b/components/WeaponGrid/index.tsx index 7e1ea5d7..5f172192 100644 --- a/components/WeaponGrid/index.tsx +++ b/components/WeaponGrid/index.tsx @@ -1,11 +1,15 @@ -import React, { useState } from 'react' +import React, { useCallback, useMemo, useState } from 'react' import { useModal as useModal } from '~utils/useModal' +import debounce from 'lodash.debounce' + import SearchModal from '~components/SearchModal' import WeaponUnit from '~components/WeaponUnit' import ExtraWeapons from '~components/ExtraWeapons' import './index.scss' +import { delay } from 'lodash' +import api from '~utils/api' // GridType export enum GridType { @@ -35,17 +39,6 @@ const WeaponGrid = (props: Props) => { const numWeapons: number = 9 const searchGrid: GridArray = Object.values(props.grid).map((o) => o.weapon) - const extraGrid = ( - - ) - function receiveWeapon(weapon: Weapon, position: number) { props.onSelect(GridType.Weapon, weapon, position) } @@ -65,10 +58,38 @@ const WeaponGrid = (props: Props) => { openModal() } - function updateUncap(id: string, uncap: number) { - console.log(`${id} is now ${uncap} stars`) + async function updateUncap(id: string, level: number) { + console.log(id, level) + await api.updateUncap('weapon', id, level) + .then(response => { + console.log(response.data) + }) + .catch(error => { + console.log(error) + }) } + const initiateUncapUpdate = (id: string, uncapLevel: number) => { + debouncedAction(id, uncapLevel) + } + + const debouncedAction = useCallback( + () => debounce((id, number) => { + updateUncap(id, number) + }, 1000), [] + )() + + const extraGrid = ( + + ) + return (
          @@ -79,7 +100,7 @@ const WeaponGrid = (props: Props) => { unitType={0} gridWeapon={props.mainhand} onClick={() => { openSearchModal(-1) }} - updateUncap={updateUncap} + updateUncap={initiateUncapUpdate} />
            @@ -93,7 +114,7 @@ const WeaponGrid = (props: Props) => { unitType={1} gridWeapon={props.grid[i]} onClick={() => { openSearchModal(i) }} - updateUncap={updateUncap} + updateUncap={initiateUncapUpdate} /> ) From 0dbcc7854b5bdc6977044e8b6334dd9c37935492 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 11:42:29 -0800 Subject: [PATCH 22/34] Update api.tsx --- utils/api.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/api.tsx b/utils/api.tsx index 60fd68f3..11391545 100644 --- a/utils/api.tsx +++ b/utils/api.tsx @@ -65,8 +65,9 @@ class Api { }) } - updateUncap(resource: 'characters'|'weapons'|'summons', id: string, value: number) { - const resourceUrl = `${this.url}/${resource}/update_uncap` + updateUncap(resource: 'character'|'weapon'|'summon', id: string, value: number) { + const pluralized = resource + 's' + const resourceUrl = `${this.url}/${pluralized}/update_uncap` return axios.post(resourceUrl, { [resource]: { id: id, From 41f6dcb6157eb7627854d88a47bb984e5e8b7670 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 14:15:38 -0800 Subject: [PATCH 23/34] Fix uncap level display bug This bug was caused primarily by us using the wrong key in the type definition. --- components/WeaponUnit/index.tsx | 2 +- types/GridWeapon.d.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index 93f7ee2d..d67fa680 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -65,9 +65,9 @@ const WeaponUnit = (props: Props) => { type="weapon" ulb={weapon?.uncap.ulb || false} flb={weapon?.uncap.flb || false} - uncapLevel={props.gridWeapon?.uncapLevel!} updateUncap={passUncapData} /> + uncapLevel={gridWeapon.uncap_level}
          ) diff --git a/types/GridWeapon.d.ts b/types/GridWeapon.d.ts index af920b85..3a6c2aa4 100644 --- a/types/GridWeapon.d.ts +++ b/types/GridWeapon.d.ts @@ -1,7 +1,7 @@ interface GridWeapon { id: string mainhand: boolean - position: number | null + position: number weapon: Weapon - uncapLevel: number | null + uncap_level: number } \ No newline at end of file From 4f0844c3781b22df2e634f08671e38258ee1fd20 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 14:19:44 -0800 Subject: [PATCH 24/34] Cleanup and refactoring --- components/UncapIndicator/index.tsx | 26 +++++++++++++++++--------- components/WeaponGrid/index.tsx | 11 +++-------- components/WeaponUnit/index.tsx | 25 +++++++++++++++---------- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/components/UncapIndicator/index.tsx b/components/UncapIndicator/index.tsx index 0bc82fb0..6073e583 100644 --- a/components/UncapIndicator/index.tsx +++ b/components/UncapIndicator/index.tsx @@ -13,15 +13,9 @@ interface Props { } const UncapIndicator = (props: Props) => { - const firstUpdate = useRef(true) const [uncap, setUncap] = useState(props.uncapLevel) useEffect(() => { - if (firstUpdate.current) { - firstUpdate.current = false - return - } - props.updateUncap(uncap) }, [uncap]) @@ -53,18 +47,32 @@ const UncapIndicator = (props: Props) => { else setUncap(index) } + const transcendence = (i: number) => { + return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> + } + + const flb = (i: number) => { + return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> + } + + const mlb = (i: number) => { + return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> + } + + + return (
            { Array.from(Array(numStars)).map((x, i) => { if (props.type === 'character' && i > 4) { - return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> + return transcendence(i) } else if ( props.type === 'character' && i == 4 || props.type !== 'character' && i > 2) { - return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> + return flb(i) } else { - return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> + return mlb(i) } }) } diff --git a/components/WeaponGrid/index.tsx b/components/WeaponGrid/index.tsx index 5f172192..c3e80c6c 100644 --- a/components/WeaponGrid/index.tsx +++ b/components/WeaponGrid/index.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo, useState } from 'react' +import React, { useCallback, useState } from 'react' import { useModal as useModal } from '~utils/useModal' import debounce from 'lodash.debounce' @@ -7,9 +7,8 @@ import SearchModal from '~components/SearchModal' import WeaponUnit from '~components/WeaponUnit' import ExtraWeapons from '~components/ExtraWeapons' -import './index.scss' -import { delay } from 'lodash' import api from '~utils/api' +import './index.scss' // GridType export enum GridType { @@ -59,13 +58,9 @@ const WeaponGrid = (props: Props) => { } async function updateUncap(id: string, level: number) { - console.log(id, level) await api.updateUncap('weapon', id, level) - .then(response => { - console.log(response.data) - }) .catch(error => { - console.log(error) + console.error(error) }) } diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index d67fa680..bf342704 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -1,9 +1,7 @@ import React, { useEffect, useState } from 'react' - import classnames from 'classnames' import UncapIndicator from '~components/UncapIndicator' - import PlusIcon from '~public/icons/plus.svg' import './index.scss' @@ -28,7 +26,8 @@ const WeaponUnit = (props: Props) => { 'filled': (props.gridWeapon !== undefined) }) - const weapon = props.gridWeapon?.weapon + const gridWeapon = props.gridWeapon + const weapon = gridWeapon?.weapon useEffect(() => { generateImageUrl() @@ -53,21 +52,27 @@ const WeaponUnit = (props: Props) => { props.updateUncap(props.gridWeapon.id, uncap) } + function imageClickHandler() { + if (props.editable) props.onClick + } + return (
            -
            {} }> +
            {weapon?.name.en} { (props.editable) ? : '' }

            {weapon?.name.en}

            - + { (gridWeapon) ? + : '' + }
            ) From 36ddc6e50614a081922f4f622c817484214b234e Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 14:32:13 -0800 Subject: [PATCH 25/34] Breaking out the imageClickHandler was breaking things so I reverted --- components/WeaponUnit/index.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index bf342704..fc69e77d 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -52,14 +52,10 @@ const WeaponUnit = (props: Props) => { props.updateUncap(props.gridWeapon.id, uncap) } - function imageClickHandler() { - if (props.editable) props.onClick - } - return (
            -
            +
            {} }> {weapon?.name.en} { (props.editable) ? : '' }
            From 44966fe8fe480b761d2fc11994b6da7817c312fd Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Tue, 1 Feb 2022 15:50:06 -0800 Subject: [PATCH 26/34] Add interactive uncap indicators for summons --- components/ExtraSummons/index.tsx | 8 ++-- components/Party/index.tsx | 20 +++++----- components/SummonGrid/index.tsx | 65 +++++++++++++++++++++---------- components/SummonUnit/index.tsx | 27 ++++++++----- pages/p/[party].tsx | 14 +++---- types/GridSummon.d.ts | 1 + 6 files changed, 85 insertions(+), 50 deletions(-) diff --git a/components/ExtraSummons/index.tsx b/components/ExtraSummons/index.tsx index c3b4868e..e32b8e4a 100644 --- a/components/ExtraSummons/index.tsx +++ b/components/ExtraSummons/index.tsx @@ -12,12 +12,13 @@ export enum GridType { // Props interface Props { - grid: GridArray + grid: GridArray editable: boolean exists: boolean found?: boolean offset: number onClick: (position: number) => void + updateUncap: (id: string, uncap: number) => void } const ExtraSummons = (props: Props) => { @@ -32,11 +33,12 @@ const ExtraSummons = (props: Props) => { return (
          • { props.onClick(props.offset + i) }} editable={props.editable} position={props.offset + i} unitType={1} - summon={props.grid[props.offset + i]} + gridSummon={props.grid[props.offset + i]} + onClick={() => { props.onClick(props.offset + i) }} + updateUncap={props.updateUncap} />
          • ) diff --git a/components/Party/index.tsx b/components/Party/index.tsx index 71c89bc9..22677894 100644 --- a/components/Party/index.tsx +++ b/components/Party/index.tsx @@ -24,11 +24,11 @@ import './index.scss' interface Props { partyId?: string mainWeapon?: GridWeapon - mainSummon?: Summon - friendSummon?: Summon + mainSummon?: GridSummon + friendSummon?: GridSummon characters?: GridArray weapons?: GridArray - summons?: GridArray + summons?: GridArray extra: boolean editable: boolean exists: boolean @@ -47,11 +47,11 @@ const Party = (props: Props) => { // Grid data const [characters, setCharacters] = useState>({}) const [weapons, setWeapons] = useState>({}) - const [summons, setSummons] = useState>({}) + const [summons, setSummons] = useState>({}) const [mainWeapon, setMainWeapon] = useState() - const [mainSummon, setMainSummon] = useState() - const [friendSummon, setFriendSummon] = useState() + const [mainSummon, setMainSummon] = useState() + const [friendSummon, setFriendSummon] = useState() const [extra, setExtra] = useState(false) @@ -185,8 +185,8 @@ const Party = (props: Props) => { case GridType.Summon: const summon = item as Summon saveSummon(summon, position, partyId) - .then(() => { - storeSummon(summon, position) + .then((response) => { + storeSummon(response.data.grid_summon, position) }) break } @@ -224,7 +224,7 @@ const Party = (props: Props) => { } // Summons - function storeSummon(summon: Summon, position: number) { + function storeSummon(summon: GridSummon, position: number) { if (position == -1) { setMainSummon(summon) } else if (position == 6) { @@ -238,7 +238,7 @@ const Party = (props: Props) => { } async function saveSummon(summon: Summon, position: number, party: string) { - await api.endpoints.summons.create({ + return await api.endpoints.summons.create({ 'summon': { 'party_id': party, 'summon_id': summon.id, diff --git a/components/SummonGrid/index.tsx b/components/SummonGrid/index.tsx index 97cbf927..64ea5fcc 100644 --- a/components/SummonGrid/index.tsx +++ b/components/SummonGrid/index.tsx @@ -1,10 +1,13 @@ -import React, { useState } from 'react' +import React, { useCallback, useState } from 'react' import { useModal as useModal } from '~utils/useModal' -import SearchModal from '~components/SearchModal' -import ExtraSummons from '~components/ExtraSummons' -import SummonUnit from '~components/SummonUnit' +import debounce from 'lodash.debounce' +import SearchModal from '~components/SearchModal' +import SummonUnit from '~components/SummonUnit' +import ExtraSummons from '~components/ExtraSummons' + +import api from '~utils/api' import './index.scss' // GridType @@ -19,9 +22,9 @@ export enum GridType { interface Props { userId?: string partyId?: string - main?: Summon | undefined - friend?: Summon | undefined - grid: GridArray + main?: GridSummon | undefined + friend?: GridSummon | undefined + grid: GridArray editable: boolean exists: boolean found?: boolean @@ -33,11 +36,7 @@ const SummonGrid = (props: Props) => { const [searchPosition, setSearchPosition] = useState(0) const numSummons: number = 4 - - function openSearchModal(position: number) { - setSearchPosition(position) - openModal() - } + const searchGrid: GridArray = Object.values(props.grid).map((o) => o.summon) function receiveSummon(summon: Summon, position: number) { props.onSelect(GridType.Summon, summon, position) @@ -54,30 +53,54 @@ const SummonGrid = (props: Props) => { return (object as Summon).granblue_id !== undefined } + function openSearchModal(position: number) { + setSearchPosition(position) + openModal() + } + + async function updateUncap(id: string, level: number) { + await api.updateUncap('summon', id, level) + .catch(error => { + console.error(error) + }) + } + + const initiateUncapUpdate = (id: string, uncapLevel: number) => { + debouncedAction(id, uncapLevel) + } + + const debouncedAction = useCallback( + () => debounce((id, number) => { + updateUncap(id, number) + }, 1000), [] + )() + return (
            Main Summon
            { openSearchModal(0) }} editable={props.editable} key="grid_main_summon" position={-1} unitType={0} - summon={props.main} + gridSummon={props.main} + onClick={() => { openSearchModal(-1) }} + updateUncap={initiateUncapUpdate} />
            Friend Summon
            { openSearchModal(6) }} editable={props.editable} key="grid_friend_summon" position={6} unitType={2} - summon={props.friend} + gridSummon={props.friend} + onClick={() => { openSearchModal(6) }} + updateUncap={initiateUncapUpdate} />
            @@ -89,11 +112,12 @@ const SummonGrid = (props: Props) => { return (
          • { openSearchModal(i) }} editable={props.editable} position={i} unitType={1} - summon={props.grid[i]} + gridSummon={props.grid[i]} + onClick={() => { openSearchModal(i) }} + updateUncap={initiateUncapUpdate} />
          • ) @@ -104,16 +128,17 @@ const SummonGrid = (props: Props) => {
            {open ? ( void - summon: Summon | undefined + updateUncap: (id: string, uncap: number) => void + gridSummon: GridSummon | undefined position: number editable: boolean unitType: 0 | 1 | 2 @@ -25,10 +24,11 @@ const SummonUnit = (props: Props) => { 'grid': props.unitType == 1, 'friend': props.unitType == 2, 'editable': props.editable, - 'filled': (props.summon !== undefined) + 'filled': (props.gridSummon !== undefined) }) - const summon = props.summon + const gridSummon = props.gridSummon + const summon = gridSummon?.summon useEffect(() => { generateImageUrl() @@ -36,8 +36,8 @@ const SummonUnit = (props: Props) => { function generateImageUrl() { let imgSrc = "" - if (props.summon) { - const summon = props.summon! + if (props.gridSummon) { + const summon = props.gridSummon.summon! // Generate the correct source for the summon if (props.unitType == 0 || props.unitType == 2) @@ -49,6 +49,11 @@ const SummonUnit = (props: Props) => { setImageUrl(imgSrc) } + function passUncapData(uncap: number) { + if (props.gridSummon) + props.updateUncap(props.gridSummon.id, uncap) + } + return (
            @@ -56,12 +61,14 @@ const SummonUnit = (props: Props) => { {summon?.name.en} { (props.editable) ? : '' }
            + { (gridSummon) ? + uncapLevel={gridSummon?.uncap_level} + updateUncap={passUncapData} + /> : '' }

            {summon?.name.en}

            diff --git a/pages/p/[party].tsx b/pages/p/[party].tsx index 6d002c8a..310e66f4 100644 --- a/pages/p/[party].tsx +++ b/pages/p/[party].tsx @@ -24,11 +24,11 @@ const PartyRoute: React.FC = () => { const [characters, setCharacters] = useState>({}) const [weapons, setWeapons] = useState>({}) - const [summons, setSummons] = useState>({}) + const [summons, setSummons] = useState>({}) const [mainWeapon, setMainWeapon] = useState() - const [mainSummon, setMainSummon] = useState() - const [friendSummon, setFriendSummon] = useState() + const [mainSummon, setMainSummon] = useState() + const [friendSummon, setFriendSummon] = useState() const [partyId, setPartyId] = useState('') const [extra, setExtra] = useState(false) @@ -97,15 +97,15 @@ const PartyRoute: React.FC = () => { } function populateSummons(list: [GridSummon]) { - let summons: GridArray = {} + let summons: GridArray = {} list.forEach((object: GridSummon) => { if (object.main) - setMainSummon(object.summon) + setMainSummon(object) else if (object.friend) - setFriendSummon(object.summon) + setFriendSummon(object) else if (!object.main && !object.friend && object.position != null) - summons[object.position] = object.summon + summons[object.position] = object }) return summons diff --git a/types/GridSummon.d.ts b/types/GridSummon.d.ts index 2f366574..6cbb3fe6 100644 --- a/types/GridSummon.d.ts +++ b/types/GridSummon.d.ts @@ -4,4 +4,5 @@ interface GridSummon { friend: boolean position: number | null summon: Summon + uncap_level: number } \ No newline at end of file From 827473ee5a41dd138ad1c5f2db53b5a5c23b29dd Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 2 Feb 2022 16:54:14 -0800 Subject: [PATCH 27/34] Refactor object grids to handle business logic instead of Party --- components/CharacterGrid/index.tsx | 209 +++++++++++++++---- components/CharacterUnit/index.tsx | 38 ++-- components/ExtraSummons/index.tsx | 2 +- components/ExtraWeapons/index.tsx | 3 +- components/Party/index.tsx | 299 +++++++-------------------- components/SummonGrid/index.tsx | 300 +++++++++++++++++++--------- components/SummonUnit/index.tsx | 5 +- components/UncapIndicator/index.tsx | 50 +++-- components/WeaponGrid/index.tsx | 253 ++++++++++++++++------- components/WeaponUnit/index.tsx | 12 +- package-lock.json | 18 ++ package.json | 1 + pages/p/[party].tsx | 6 +- types/Character.d.ts | 2 + types/GridCharacter.d.ts | 3 +- types/GridSummon.d.ts | 2 +- 16 files changed, 726 insertions(+), 477 deletions(-) diff --git a/components/CharacterGrid/index.tsx b/components/CharacterGrid/index.tsx index dc7b043f..ba05648b 100644 --- a/components/CharacterGrid/index.tsx +++ b/components/CharacterGrid/index.tsx @@ -1,11 +1,18 @@ -import React, { useState } from 'react' +/* eslint-disable react-hooks/exhaustive-deps */ +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { useCookies } from 'react-cookie' import { useModal as useModal } from '~utils/useModal' +import { AxiosResponse } from 'axios' +import debounce from 'lodash.debounce' + import CharacterUnit from '~components/CharacterUnit' import SearchModal from '~components/SearchModal' +import api from '~utils/api' import './index.scss' +// GridType export enum GridType { Class, Character, @@ -13,67 +20,185 @@ export enum GridType { Summon } +// Props interface Props { - userId?: string - grid: GridArray + partyId?: string + characters: GridArray editable: boolean - exists: boolean - onSelect: (type: GridType, character: Character, position: number) => void + createParty: () => Promise> + pushHistory?: (path: string) => void } const CharacterGrid = (props: Props) => { - const { open, openModal, closeModal } = useModal() - const [searchPosition, setSearchPosition] = useState(0) - + // Constants const numCharacters: number = 5 - function isCharacter(object: Character | Weapon | Summon): object is Character { - // There aren't really any unique fields here - return (object as Character).gender !== undefined - } + // Cookies + const [cookies, _] = useCookies(['user']) + const headers = (cookies.user != null) ? { + headers: { + 'Authorization': `Bearer ${cookies.user.access_token}` + } + } : {} + // Set up states for Grid data + const [characters, setCharacters] = useState>({}) + + // Set up states for Search + const { open, openModal, closeModal } = useModal() + const [itemPositionForSearch, setItemPositionForSearch] = useState(0) + + // Create a temporary state to store previous character uncap values + const [previousUncapValues, setPreviousUncapValues] = useState<{[key: number]: number}>({}) + + // Create a state dictionary to store pure objects for Search + const [searchGrid, setSearchGrid] = useState>({}) + + // Set states from props + useEffect(() => { + setCharacters(props.characters || {}) + }, [props]) + + // Update search grid whenever characters are updated + useEffect(() => { + let newSearchGrid = Object.values(characters).map((o) => o.character) + setSearchGrid(newSearchGrid) + }, [characters]) + + // Methods: Adding an object from search function openSearchModal(position: number) { - setSearchPosition(position) + setItemPositionForSearch(position) openModal() } - function receiveCharacter(character: Character, position: number) { - props.onSelect(GridType.Character, character, position) - } + function receiveCharacterFromSearch(object: Character | Weapon | Summon, position: number) { + const character = object as Character - function sendData(object: Character | Weapon | Summon, position: number) { - if (isCharacter(object)) { - receiveCharacter(object, position) + if (!props.partyId) { + props.createParty() + .then(response => { + const party = response.data.party + if (props.pushHistory) props.pushHistory(`/p/${party.shortcode}`) + saveCharacter(party.id, character, position) + .then(response => storeGridCharacter(response.data.grid_character)) + }) + } else { + saveCharacter(props.partyId, character, position) + .then(response => storeGridCharacter(response.data.grid_character)) } } + async function saveCharacter(partyId: string, character: Character, position: number) { + return await api.endpoints.characters.create({ + 'character': { + 'party_id': partyId, + 'character_id': character.id, + 'position': position, + 'mainhand': (position == -1), + 'uncap_level': characterUncapLevel(character) + } + }, headers) + } + + function storeGridCharacter(gridCharacter: GridCharacter) { + // Store the grid unit at the correct position + let newCharacters = Object.assign({}, characters) + newCharacters[gridCharacter.position] = gridCharacter + setCharacters(newCharacters) + } + + // Methods: Helpers + function characterUncapLevel(character: Character) { + let uncapLevel + + if (character.special) { + uncapLevel = 3 + if (character.uncap.ulb) uncapLevel = 5 + else if (character.uncap.flb) uncapLevel = 4 + } else { + uncapLevel = 4 + if (character.uncap.ulb) uncapLevel = 6 + else if (character.uncap.flb) uncapLevel = 5 + } + + return uncapLevel + } + + // Methods: Updating uncap level + // Note: Saves, but debouncing is not working properly + async function saveUncap(id: string, position: number, uncapLevel: number) { + try { + await api.updateUncap('weapon', id, uncapLevel) + .then(response => { + storeGridCharacter(response.data.grid_character) + }) + } catch (error) { + console.error(error) + + // Revert optimistic UI + updateUncapLevel(position, previousUncapValues[position]) + + // Remove optimistic key + let newPreviousValues = {...previousUncapValues} + delete newPreviousValues[position] + setPreviousUncapValues(newPreviousValues) + } + } + + const initiateUncapUpdate = useCallback( + (id: string, position: number, uncapLevel: number) => { + debouncedAction(id, position, uncapLevel) + + // Save the current value in case of an unexpected result + let newPreviousValues = {...previousUncapValues} + newPreviousValues[position] = characters[position].uncap_level + setPreviousUncapValues(newPreviousValues) + + // Optimistically update UI + updateUncapLevel(position, uncapLevel) + }, [previousUncapValues, characters] + ) + + const debouncedAction = useMemo(() => + debounce((id, position, number) => { + saveUncap(id, position, number) + }, 1000), [saveUncap] + ) + + const updateUncapLevel = (position: number, uncapLevel: number) => { + let newCharacters = Object.assign({}, characters) + newCharacters[position].uncap_level = uncapLevel + setCharacters(newCharacters) + } + + // Render: JSX components return (
              - { - Array.from(Array(numCharacters)).map((x, i) => { - return ( -
            • - { openSearchModal(i) }} - editable={props.editable} - position={i} - character={props.grid[i]} - /> -
            • - ) - }) - } + {Array.from(Array(numCharacters)).map((x, i) => { + return ( +
            • + { openSearchModal(i) }} + updateUncap={initiateUncapUpdate} + /> +
            • + ) + })} + {open ? ( - - ) : null} + + ) : null}
            ) diff --git a/components/CharacterUnit/index.tsx b/components/CharacterUnit/index.tsx index 309b3789..f92bd67a 100644 --- a/components/CharacterUnit/index.tsx +++ b/components/CharacterUnit/index.tsx @@ -2,45 +2,53 @@ import React, { useEffect, useState } from 'react' import classnames from 'classnames' import UncapIndicator from '~components/UncapIndicator' - import PlusIcon from '~public/icons/plus.svg' import './index.scss' interface Props { - onClick: () => void - character: Character | undefined + gridCharacter: GridCharacter | undefined position: number editable: boolean + onClick: () => void + updateUncap: (id: string, position: number, uncap: number) => void } const CharacterUnit = (props: Props) => { + console.log(props.gridCharacter?.character.name.en, props.gridCharacter?.uncap_level) + const [imageUrl, setImageUrl] = useState('') const classes = classnames({ CharacterUnit: true, 'editable': props.editable, - 'filled': (props.character !== undefined) + 'filled': (props.gridCharacter !== undefined) }) - const character = props.character + const gridCharacter = props.gridCharacter + const character = gridCharacter?.character useEffect(() => { generateImageUrl() }) - function generateImageUrl() { let imgSrc = "" - if (props.character) { - const character = props.character! + if (props.gridCharacter) { + const character = props.gridCharacter.character! imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/chara-main/${character.granblue_id}_01.jpg` } setImageUrl(imgSrc) } + function passUncapData(uncap: number) { + console.log(`passuncapdata ${uncap}`) + if (props.gridCharacter) + props.updateUncap(props.gridCharacter.id, props.position, uncap) + } + return (
            @@ -48,11 +56,15 @@ const CharacterUnit = (props: Props) => { {character?.name.en} { (props.editable) ? : '' }
            - + { (gridCharacter && character) ? + : '' }

            {character?.name.en}

            diff --git a/components/ExtraSummons/index.tsx b/components/ExtraSummons/index.tsx index e32b8e4a..80d21a4b 100644 --- a/components/ExtraSummons/index.tsx +++ b/components/ExtraSummons/index.tsx @@ -18,7 +18,7 @@ interface Props { found?: boolean offset: number onClick: (position: number) => void - updateUncap: (id: string, uncap: number) => void + updateUncap: (id: string, position: number, uncap: number) => void } const ExtraSummons = (props: Props) => { diff --git a/components/ExtraWeapons/index.tsx b/components/ExtraWeapons/index.tsx index 752a94be..efa1dfa5 100644 --- a/components/ExtraWeapons/index.tsx +++ b/components/ExtraWeapons/index.tsx @@ -15,11 +15,10 @@ export enum GridType { interface Props { grid: GridArray editable: boolean - exists: boolean found?: boolean offset: number onClick: (position: number) => void - updateUncap: (id: string, uncap: number) => void + updateUncap: (id: string, position: number, uncap: number) => void } const ExtraWeapons = (props: Props) => { diff --git a/components/Party/index.tsx b/components/Party/index.tsx index 22677894..51d7eb4e 100644 --- a/components/Party/index.tsx +++ b/components/Party/index.tsx @@ -1,15 +1,14 @@ -import React, { ChangeEvent, useEffect, useState } from 'react' +import React, { useEffect, useState } from 'react' import { useCookies } from 'react-cookie' -import api from '~utils/api' -// UI Elements import PartySegmentedControl from '~components/PartySegmentedControl' - -// Grids import WeaponGrid from '~components/WeaponGrid' import SummonGrid from '~components/SummonGrid' import CharacterGrid from '~components/CharacterGrid' +import api from '~utils/api' +import './index.scss' + // GridType enum GridType { Class, @@ -17,96 +16,58 @@ enum GridType { Weapon, Summon } -export { GridType } - -import './index.scss' +// Props interface Props { partyId?: string mainWeapon?: GridWeapon mainSummon?: GridSummon friendSummon?: GridSummon - characters?: GridArray + characters?: GridArray weapons?: GridArray summons?: GridArray extra: boolean editable: boolean - exists: boolean pushHistory?: (path: string) => void } const Party = (props: Props) => { + // Cookies const [cookies, _] = useCookies(['user']) - const headers = (cookies.user != null) ? { headers: { 'Authorization': `Bearer ${cookies.user.access_token}` } } : {} - // Grid data - const [characters, setCharacters] = useState>({}) - const [weapons, setWeapons] = useState>({}) - const [summons, setSummons] = useState>({}) - - const [mainWeapon, setMainWeapon] = useState() - const [mainSummon, setMainSummon] = useState() - const [friendSummon, setFriendSummon] = useState() - + // Set up states const [extra, setExtra] = useState(false) - - useEffect(() => { - setPartyId(props.partyId || '') - setMainWeapon(props.mainWeapon) - setMainSummon(props.mainSummon) - setFriendSummon(props.friendSummon) - setCharacters(props.characters || {}) - setWeapons(props.weapons || {}) - setSummons(props.summons || {}) - setExtra(props.extra || false) - }, [props.partyId, props.mainWeapon, props.mainSummon, props.friendSummon, props.characters, props.weapons, props.summons, props.extra]) - - const weaponGrid = ( - - ) - - const summonGrid = ( - - ) - - const characterGrid = ( - - ) - const [currentTab, setCurrentTab] = useState(GridType.Weapon) - const [partyId, setPartyId] = useState('') + // Set states from props + useEffect(() => { + setExtra(props.extra || false) + }, [props]) + + // Methods: Creating a new party + async function createParty() { + let body = { + party: { + ...(cookies.user) && { user_id: cookies.user.user_id }, + is_extra: extra + } + } + + return await api.endpoints.parties.create(body, headers) + } + + // Methods: Updating the party's extra flag + // Note: This doesn't save to the server yet. function checkboxChanged(event: React.ChangeEvent) { setExtra(event.target.checked) } + // Methods: Navigating with segmented control function segmentClicked(event: React.ChangeEvent) { switch(event.target.value) { case 'class': @@ -126,174 +87,66 @@ const Party = (props: Props) => { } } - function itemSelected(type: GridType, item: Character | Weapon | Summon, position: number) { - if (!partyId) { - createParty() - .then(response => { - return response.data.party - }) - .then(party => { - if (props.pushHistory) { - props.pushHistory(`/p/${party.shortcode}`) - } + // Render: JSX components + const navigation = ( + + ) - return party.id - }) - .then(partyId => { - setPartyId(partyId) - saveItem(partyId, type, item, position) - }) - } else { - saveItem(partyId, type, item, position) - } - } + const weaponGrid = ( + + ) - async function createParty() { - const body = (!cookies.user) ? { - party: { - is_extra: extra - } - } : { - party: { - user_id: cookies.user.userId, - is_extra: extra - } - } + const summonGrid = ( + + ) - return await api.endpoints.parties.create(body, headers) - } + const characterGrid = ( + + ) - function saveItem(partyId: string, type: GridType, item: Character | Weapon | Summon, position: number) { - switch(type) { - case GridType.Class: - saveClass() - break + const currentGrid = () => { + switch(currentTab) { case GridType.Character: - const character = item as Character - saveCharacter(character, position, partyId) - .then(() => { - storeCharacter(character, position) - }) - break + return characterGrid case GridType.Weapon: - const weapon = item as Weapon - saveWeapon(weapon, position, partyId) - .then((response) => { - storeWeapon(response.data.grid_weapon) - }) - break + return weaponGrid case GridType.Summon: - const summon = item as Summon - saveSummon(summon, position, partyId) - .then((response) => { - storeSummon(response.data.grid_summon, position) - }) - break + return summonGrid } } - - // Weapons - function storeWeapon(weapon: GridWeapon) { - if (weapon.position == -1) { - setMainWeapon(weapon) - } else { - // Store the grid unit weapon at the correct position - let newWeapons = Object.assign({}, weapons) - newWeapons[weapon.position!] = weapon - setWeapons(newWeapons) - } - } - - async function saveWeapon(weapon: Weapon, position: number, party: string) { - let uncapLevel = 3 - - if (weapon.uncap.ulb) - uncapLevel = 5 - else if (weapon.uncap.flb) - uncapLevel = 4 - - return await api.endpoints.weapons.create({ - 'weapon': { - 'party_id': party, - 'weapon_id': weapon.id, - 'position': position, - 'mainhand': (position == -1), - 'uncap_level': uncapLevel - } - }, headers) - } - - // Summons - function storeSummon(summon: GridSummon, position: number) { - if (position == -1) { - setMainSummon(summon) - } else if (position == 6) { - setFriendSummon(summon) - } else { - // Store the grid unit summon at the correct position - let newSummons = Object.assign({}, summons) - newSummons[position] = summon - setSummons(newSummons) - } - } - - async function saveSummon(summon: Summon, position: number, party: string) { - return await api.endpoints.summons.create({ - 'summon': { - 'party_id': party, - 'summon_id': summon.id, - 'position': position, - 'main': (position == -1), - 'friend': (position == 6) - } - }, headers) - } - - // Character - function storeCharacter(character: Character, position: number) { - // Store the grid unit character at the correct position - let newCharacters = Object.assign({}, characters) - newCharacters[position] = character - setCharacters(newCharacters) - } - - async function saveCharacter(character: Character, position: number, party: string) { - await api.endpoints.characters.create({ - 'character': { - 'party_id': party, - 'character_id': character.id, - 'position': position - } - }, headers) - } - - // Class - function saveClass() { - // TODO: Implement this - } return (
            - - - { - (() => { - switch(currentTab) { - case GridType.Character: - return characterGrid - case GridType.Weapon: - return weaponGrid - case GridType.Summon: - return summonGrid - } - })() - } + { navigation } + { currentGrid() }
            ) } diff --git a/components/SummonGrid/index.tsx b/components/SummonGrid/index.tsx index 64ea5fcc..bce5de33 100644 --- a/components/SummonGrid/index.tsx +++ b/components/SummonGrid/index.tsx @@ -1,6 +1,9 @@ -import React, { useCallback, useState } from 'react' +/* eslint-disable react-hooks/exhaustive-deps */ +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { useCookies } from 'react-cookie' import { useModal as useModal } from '~utils/useModal' +import { AxiosResponse } from 'axios' import debounce from 'lodash.debounce' import SearchModal from '~components/SearchModal' @@ -20,128 +23,237 @@ export enum GridType { // Props interface Props { - userId?: string partyId?: string - main?: GridSummon | undefined - friend?: GridSummon | undefined - grid: GridArray + mainSummon: GridSummon | undefined + friendSummon: GridSummon | undefined + summons: GridArray editable: boolean - exists: boolean - found?: boolean - onSelect: (type: GridType, summon: Summon, position: number) => void + createParty: () => Promise> + pushHistory?: (path: string) => void } const SummonGrid = (props: Props) => { - const { open, openModal, closeModal } = useModal() - const [searchPosition, setSearchPosition] = useState(0) - + // Constants const numSummons: number = 4 - const searchGrid: GridArray = Object.values(props.grid).map((o) => o.summon) - function receiveSummon(summon: Summon, position: number) { - props.onSelect(GridType.Summon, summon, position) - } - - function sendData(object: Character | Weapon | Summon, position: number) { - if (isSummon(object)) { - receiveSummon(object, position) + // Cookies + const [cookies, _] = useCookies(['user']) + const headers = (cookies.user != null) ? { + headers: { + 'Authorization': `Bearer ${cookies.user.access_token}` } - } + } : {} - function isSummon(object: Character | Weapon | Summon): object is Summon { - // There aren't really any unique fields here - return (object as Summon).granblue_id !== undefined - } + // Set up states for Grid data + const [summons, setSummons] = useState>({}) + const [mainSummon, setMainSummon] = useState() + const [friendSummon, setFriendSummon] = useState() + // Set up states for Search + const { open, openModal, closeModal } = useModal() + const [itemPositionForSearch, setItemPositionForSearch] = useState(0) + + // Create a temporary state to store previous weapon uncap value + const [previousUncapValues, setPreviousUncapValues] = useState<{[key: number]: number}>({}) + + // Create a state dictionary to store pure objects for Search + const [searchGrid, setSearchGrid] = useState>({}) + + // Set states from props + useEffect(() => { + setSummons(props.summons || {}) + setMainSummon(props.mainSummon) + setFriendSummon(props.friendSummon) + }, [props]) + + // Update search grid whenever any summon is updated + useEffect(() => { + let newSearchGrid = Object.values(summons).map((o) => o.summon) + + if (mainSummon) + newSearchGrid.unshift(mainSummon.summon) + + if (friendSummon) + newSearchGrid.unshift(friendSummon.summon) + + setSearchGrid(newSearchGrid) + }, [summons, mainSummon, friendSummon]) + + // Methods: Adding an object from search function openSearchModal(position: number) { - setSearchPosition(position) + setItemPositionForSearch(position) openModal() } - async function updateUncap(id: string, level: number) { - await api.updateUncap('summon', id, level) - .catch(error => { - console.error(error) - }) + function receiveSummonFromSearch(object: Character | Weapon | Summon, position: number) { + const summon = object as Summon + + if (!props.partyId) { + props.createParty() + .then(response => { + const party = response.data.party + if (props.pushHistory) props.pushHistory(`/p/${party.shortcode}`) + saveSummon(party.id, summon, position) + .then(response => storeGridSummon(response.data.grid_summon)) + }) + } else { + saveSummon(props.partyId, summon, position) + .then(response => storeGridSummon(response.data.grid_summon)) + } } - const initiateUncapUpdate = (id: string, uncapLevel: number) => { - debouncedAction(id, uncapLevel) + async function saveSummon(partyId: string, summon: Summon, position: number) { + let uncapLevel = 3 + if (summon.uncap.ulb) uncapLevel = 5 + else if (summon.uncap.flb) uncapLevel = 4 + + return await api.endpoints.summons.create({ + 'summon': { + 'party_id': partyId, + 'summon_id': summon.id, + 'position': position, + 'main': (position == -1), + 'friend': (position == 6), + 'uncap_level': uncapLevel + } + }, headers) } - const debouncedAction = useCallback( - () => debounce((id, number) => { - updateUncap(id, number) - }, 1000), [] - )() + function storeGridSummon(gridSummon: GridSummon) { + if (gridSummon.position == -1) { + setMainSummon(gridSummon) + } else if (gridSummon.position == 6) { + setFriendSummon(gridSummon) + } else { + // Store the grid unit at the correct position + let newSummons = Object.assign({}, summons) + newSummons[gridSummon.position] = gridSummon + setSummons(newSummons) + } + } + // Methods: Updating uncap level + // Note: Saves, but debouncing is not working properly + async function saveUncap(id: string, position: number, uncapLevel: number) { + try { + await api.updateUncap('summon', id, uncapLevel) + .then(response => { + storeGridSummon(response.data.grid_summon) + }) + } catch (error) { + console.error(error) + + // Revert optimistic UI + updateUncapLevel(position, previousUncapValues[position]) + + // Remove optimistic key + let newPreviousValues = {...previousUncapValues} + delete newPreviousValues[position] + setPreviousUncapValues(newPreviousValues) + } + } + + const initiateUncapUpdate = useCallback( + (id: string, position: number, uncapLevel: number) => { + debouncedAction(id, position, uncapLevel) + + // Save the current value in case of an unexpected result + let newPreviousValues = {...previousUncapValues} + newPreviousValues[position] = summons[position].uncap_level + setPreviousUncapValues(newPreviousValues) + + // Optimistically update UI + updateUncapLevel(position, uncapLevel) + }, [previousUncapValues, summons] + ) + + const debouncedAction = useMemo(() => + debounce((id, position, number) => { + saveUncap(id, position, number) + }, 1000), [saveUncap] + ) + + const updateUncapLevel = (position: number, uncapLevel: number) => { + let newSummons = Object.assign({}, summons) + newSummons[position].uncap_level = uncapLevel + setSummons(newSummons) + } + + // Render: JSX components + const mainSummonElement = ( +
            +
            Main Summon
            + { openSearchModal(-1) }} + updateUncap={initiateUncapUpdate} + /> +
            + ) + + const friendSummonElement = ( +
            +
            Friend Summon
            + { openSearchModal(6) }} + updateUncap={initiateUncapUpdate} + /> +
            + ) + const summonGridElement = ( +
            +
            Summons
            +
              + {Array.from(Array(numSummons)).map((x, i) => { + return (
            • + { openSearchModal(i) }} + updateUncap={initiateUncapUpdate} + /> +
            • ) + })} +
            +
            + ) + const subAuraSummonElement = ( + + ) return (
            -
            -
            Main Summon
            - { openSearchModal(-1) }} - updateUncap={initiateUncapUpdate} - /> -
            - -
            -
            Friend Summon
            - { openSearchModal(6) }} - updateUncap={initiateUncapUpdate} - /> -
            - -
            -
            Summons
            -
              - { - Array.from(Array(numSummons)).map((x, i) => { - return ( -
            • - { openSearchModal(i) }} - updateUncap={initiateUncapUpdate} - /> -
            • - ) - }) - } -
            -
            + { mainSummonElement } + { friendSummonElement } + { summonGridElement }
            - + { subAuraSummonElement } {open ? ( diff --git a/components/SummonUnit/index.tsx b/components/SummonUnit/index.tsx index 85b19145..c76a9e92 100644 --- a/components/SummonUnit/index.tsx +++ b/components/SummonUnit/index.tsx @@ -8,7 +8,7 @@ import './index.scss' interface Props { onClick: () => void - updateUncap: (id: string, uncap: number) => void + updateUncap: (id: string, position: number, uncap: number) => void gridSummon: GridSummon | undefined position: number editable: boolean @@ -67,7 +67,8 @@ const SummonUnit = (props: Props) => { ulb={summon?.uncap.ulb || false} flb={summon?.uncap.flb || false} uncapLevel={gridSummon?.uncap_level} - updateUncap={passUncapData} + updateUncap={passUncapData} + special={false} /> : '' }

            {summon?.name.en}

            diff --git a/components/UncapIndicator/index.tsx b/components/UncapIndicator/index.tsx index 6073e583..5eb58724 100644 --- a/components/UncapIndicator/index.tsx +++ b/components/UncapIndicator/index.tsx @@ -8,27 +8,36 @@ interface Props { rarity?: number uncapLevel: number flb: boolean - ulb?: boolean + ulb: boolean + special: boolean updateUncap: (uncap: number) => void } const UncapIndicator = (props: Props) => { const [uncap, setUncap] = useState(props.uncapLevel) - useEffect(() => { - props.updateUncap(uncap) - }, [uncap]) - const numStars = setNumStars() function setNumStars() { let numStars if (props.type === 'character') { - if (props.flb) { - numStars = 5 + if (props.special) { + if (props.ulb) { + numStars = 5 + } else if (props.flb) { + numStars = 4 + } else { + numStars = 3 + } } else { - numStars = 4 - } + if (props.ulb) { + numStars = 6 + } else if (props.flb) { + numStars = 5 + } else { + numStars = 4 + } + } } else { if (props.ulb) { numStars = 5 @@ -43,31 +52,38 @@ const UncapIndicator = (props: Props) => { } function toggleStar(index: number, empty: boolean) { - if (empty) setUncap(index + 1) - else setUncap(index) + if (empty) props.updateUncap(index + 1) + else props.updateUncap(index) } const transcendence = (i: number) => { - return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> + return = props.uncapLevel} key={`star_${i}`} index={i} onClick={toggleStar} /> + } + + const ulb = (i: number) => { + return = props.uncapLevel} key={`star_${i}`} index={i} onClick={toggleStar} /> } const flb = (i: number) => { - return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> + return = props.uncapLevel} key={`star_${i}`} index={i} onClick={toggleStar} /> } const mlb = (i: number) => { - return = uncap} key={`star_${i}`} index={i} onClick={toggleStar} /> + // console.log("MLB; Number of stars:", props.uncapLevel) + return = props.uncapLevel} key={`star_${i}`} index={i} onClick={toggleStar} /> } - - return (
              { Array.from(Array(numStars)).map((x, i) => { if (props.type === 'character' && i > 4) { - return transcendence(i) + if (props.special) + return ulb(i) + else + return transcendence(i) } else if ( + props.special && props.type === 'character' && i == 3 || props.type === 'character' && i == 4 || props.type !== 'character' && i > 2) { return flb(i) diff --git a/components/WeaponGrid/index.tsx b/components/WeaponGrid/index.tsx index c3e80c6c..a476701f 100644 --- a/components/WeaponGrid/index.tsx +++ b/components/WeaponGrid/index.tsx @@ -1,6 +1,9 @@ -import React, { useCallback, useState } from 'react' +/* eslint-disable react-hooks/exhaustive-deps */ +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { useCookies } from 'react-cookie' import { useModal as useModal } from '~utils/useModal' +import { AxiosResponse } from 'axios' import debounce from 'lodash.debounce' import SearchModal from '~components/SearchModal' @@ -20,65 +23,199 @@ export enum GridType { // Props interface Props { - userId?: string partyId?: string - mainhand?: GridWeapon | undefined - grid: GridArray + mainhand: GridWeapon | undefined + weapons: GridArray extra: boolean editable: boolean - exists: boolean - found?: boolean - onSelect: (type: GridType, weapon: Weapon, position: number) => void + createParty: () => Promise> + pushHistory?: (path: string) => void } const WeaponGrid = (props: Props) => { - const { open, openModal, closeModal } = useModal() - const [searchPosition, setSearchPosition] = useState(0) - + // Constants const numWeapons: number = 9 - const searchGrid: GridArray = Object.values(props.grid).map((o) => o.weapon) - function receiveWeapon(weapon: Weapon, position: number) { - props.onSelect(GridType.Weapon, weapon, position) - } - - function sendData(object: Character | Weapon | Summon, position: number) { - if (isWeapon(object)) { - receiveWeapon(object, position) + // Cookies + const [cookies, _] = useCookies(['user']) + const headers = (cookies.user != null) ? { + headers: { + 'Authorization': `Bearer ${cookies.user.access_token}` } - } + } : {} - function isWeapon(object: Character | Weapon | Summon): object is Weapon { - return (object as Weapon).proficiency !== undefined - } + // Set up states for Grid data + const [weapons, setWeapons] = useState>({}) + const [mainWeapon, setMainWeapon] = useState() + // Set up states for Search + const { open, openModal, closeModal } = useModal() + const [itemPositionForSearch, setItemPositionForSearch] = useState(0) + + // Create a temporary state to store previous weapon uncap values + const [previousUncapValues, setPreviousUncapValues] = useState<{[key: number]: number}>({}) + + // Create a state dictionary to store pure objects for Search + const [searchGrid, setSearchGrid] = useState>({}) + + // Set states from props + useEffect(() => { + setWeapons(props.weapons || {}) + setMainWeapon(props.mainhand) + }, [props]) + + // Update search grid whenever weapons or the mainhand are updated + useEffect(() => { + let newSearchGrid = Object.values(weapons).map((o) => o.weapon) + + if (mainWeapon) + newSearchGrid.unshift(mainWeapon.weapon) + + setSearchGrid(newSearchGrid) + }, [weapons, mainWeapon]) + + // Methods: Adding an object from search function openSearchModal(position: number) { - setSearchPosition(position) + setItemPositionForSearch(position) openModal() } - async function updateUncap(id: string, level: number) { - await api.updateUncap('weapon', id, level) - .catch(error => { - console.error(error) - }) + function receiveWeaponFromSearch(object: Character | Weapon | Summon, position: number) { + const weapon = object as Weapon + + if (!props.partyId) { + props.createParty() + .then(response => { + const party = response.data.party + if (props.pushHistory) props.pushHistory(`/p/${party.shortcode}`) + saveWeapon(party.id, weapon, position) + .then(response => storeGridWeapon(response.data.grid_weapon)) + }) + } else { + saveWeapon(props.partyId, weapon, position) + .then(response => storeGridWeapon(response.data.grid_weapon)) + } } - const initiateUncapUpdate = (id: string, uncapLevel: number) => { - debouncedAction(id, uncapLevel) + async function saveWeapon(partyId: string, weapon: Weapon, position: number) { + let uncapLevel = 3 + if (weapon.uncap.ulb) uncapLevel = 5 + else if (weapon.uncap.flb) uncapLevel = 4 + + return await api.endpoints.weapons.create({ + 'weapon': { + 'party_id': partyId, + 'weapon_id': weapon.id, + 'position': position, + 'mainhand': (position == -1), + 'uncap_level': uncapLevel + } + }, headers) } - const debouncedAction = useCallback( - () => debounce((id, number) => { - updateUncap(id, number) - }, 1000), [] - )() + function storeGridWeapon(gridWeapon: GridWeapon) { + if (gridWeapon.position == -1) { + setMainWeapon(gridWeapon) + } else { + // Store the grid unit at the correct position + let newWeapons = Object.assign({}, props.weapons) + newWeapons[gridWeapon.position] = gridWeapon + setWeapons(newWeapons) + } + } - const extraGrid = ( + // Methods: Updating uncap level + // Note: Saves, but debouncing is not working properly + async function saveUncap(id: string, position: number, uncapLevel: number) { + // TODO: Don't make an API call if the new uncapLevel is the same as the current uncapLevel + try { + await api.updateUncap('weapon', id, uncapLevel) + .then(response => { + storeGridWeapon(response.data.grid_weapon) + }) + } catch (error) { + console.error(error) + + // Revert optimistic UI + updateUncapLevel(position, previousUncapValues[position]) + + // Remove optimistic key + let newPreviousValues = {...previousUncapValues} + delete newPreviousValues[position] + setPreviousUncapValues(newPreviousValues) + } + } + + const memoizeAction = useCallback( + (id: string, position: number, uncapLevel: number) => { + debouncedAction(id, position, uncapLevel) + }, [] + ) + + function initiateUncapUpdate(id: string, position: number, uncapLevel: number) { + memoizeAction(id, position, uncapLevel) + + // Save the current value in case of an unexpected result + let newPreviousValues = {...previousUncapValues} + newPreviousValues[position] = (mainWeapon && position == -1) ? mainWeapon.uncap_level : weapons[position].uncap_level + setPreviousUncapValues(newPreviousValues) + + // Optimistically update UI + updateUncapLevel(position, uncapLevel) + + } + + const debouncedAction = useMemo(() => + debounce((id, position, number) => { + saveUncap(id, position, number) + }, 1000), [saveUncap] + ) + + const updateUncapLevel = (position: number, uncapLevel: number) => { + if (mainWeapon && position == -1) { + mainWeapon.uncap_level = uncapLevel + setMainWeapon(mainWeapon) + } else { + let newWeapons = Object.assign({}, weapons) + newWeapons[position].uncap_level = uncapLevel + setWeapons(newWeapons) + } + } + + // Render: JSX components + const mainhandElement = ( + { openSearchModal(-1) }} + updateUncap={initiateUncapUpdate} + /> + ) + + const weaponGridElement = ( + Array.from(Array(numWeapons)).map((x, i) => { + return ( +
            • + { openSearchModal(i) }} + updateUncap={initiateUncapUpdate} + /> +
            • + ) + }) + ) + + const extraGridElement = ( { return (
              - { openSearchModal(-1) }} - updateUncap={initiateUncapUpdate} - /> - -
                - { - Array.from(Array(numWeapons)).map((x, i) => { - return ( -
              • - { openSearchModal(i) }} - updateUncap={initiateUncapUpdate} - /> -
              • - ) - }) - } -
              + { mainhandElement } +
                { weaponGridElement }
              - { (() => { - if(props.extra) { - return extraGrid - } - })() } + { (() => { return (props.extra) ? extraGridElement : '' })() } {open ? ( diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index fc69e77d..b50e541e 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -7,12 +7,12 @@ import PlusIcon from '~public/icons/plus.svg' import './index.scss' interface Props { - onClick: () => void - updateUncap: (id: string, uncap: number) => void gridWeapon: GridWeapon | undefined + unitType: 0 | 1 position: number editable: boolean - unitType: 0 | 1 + onClick: () => void + updateUncap: (id: string, position: number, uncap: number) => void } const WeaponUnit = (props: Props) => { @@ -48,8 +48,9 @@ const WeaponUnit = (props: Props) => { } function passUncapData(uncap: number) { + console.log("Passing uncap data to updateUncap callback...") if (props.gridWeapon) - props.updateUncap(props.gridWeapon.id, uncap) + props.updateUncap(props.gridWeapon.id, props.position, uncap) } return ( @@ -66,7 +67,8 @@ const WeaponUnit = (props: Props) => { ulb={gridWeapon.weapon.uncap.ulb || false} flb={gridWeapon.weapon.uncap.flb || false} uncapLevel={gridWeapon.uncap_level} - updateUncap={passUncapData} + updateUncap={passUncapData} + special={false} /> : '' }
              diff --git a/package-lock.json b/package-lock.json index efd90a14..5d16aaeb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@radix-ui/react-label": "^0.1.4", "@radix-ui/react-switch": "^0.1.4", "@svgr/webpack": "^6.2.0", + "@types/axios": "^0.14.0", "axios": "^0.25.0", "classnames": "^2.3.1", "lodash.debounce": "^4.0.8", @@ -2982,6 +2983,15 @@ "node": ">=10.13.0" } }, + "node_modules/@types/axios": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", + "integrity": "sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=", + "deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!", + "dependencies": { + "axios": "*" + } + }, "node_modules/@types/cookie": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", @@ -8754,6 +8764,14 @@ "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" }, + "@types/axios": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", + "integrity": "sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=", + "requires": { + "axios": "*" + } + }, "@types/cookie": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz", diff --git a/package.json b/package.json index f7d84b90..898e39c7 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@radix-ui/react-label": "^0.1.4", "@radix-ui/react-switch": "^0.1.4", "@svgr/webpack": "^6.2.0", + "@types/axios": "^0.14.0", "axios": "^0.25.0", "classnames": "^2.3.1", "lodash.debounce": "^4.0.8", diff --git a/pages/p/[party].tsx b/pages/p/[party].tsx index 310e66f4..968eed90 100644 --- a/pages/p/[party].tsx +++ b/pages/p/[party].tsx @@ -22,7 +22,7 @@ const PartyRoute: React.FC = () => { const [loading, setLoading] = useState(true) const [editable, setEditable] = useState(false) - const [characters, setCharacters] = useState>({}) + const [characters, setCharacters] = useState>({}) const [weapons, setWeapons] = useState>({}) const [summons, setSummons] = useState>({}) @@ -73,11 +73,11 @@ const PartyRoute: React.FC = () => { } function populateCharacters(list: [GridCharacter]) { - let characters: GridArray = {} + let characters: GridArray = {} list.forEach((object: GridCharacter) => { if (object.position != null) - characters[object.position] = object.character + characters[object.position] = object }) return characters diff --git a/types/Character.d.ts b/types/Character.d.ts index dc7a1ffd..e004581e 100644 --- a/types/Character.d.ts +++ b/types/Character.d.ts @@ -21,6 +21,7 @@ interface Character { } uncap: { flb: boolean + ulb: boolean } race: { race1: number @@ -31,4 +32,5 @@ interface Character { proficiency2: number } position?: number + special: boolean } \ No newline at end of file diff --git a/types/GridCharacter.d.ts b/types/GridCharacter.d.ts index 0f3dd5f3..47784b17 100644 --- a/types/GridCharacter.d.ts +++ b/types/GridCharacter.d.ts @@ -1,5 +1,6 @@ interface GridCharacter { id: string - position: number | null + position: number character: Character + uncap_level: number } \ No newline at end of file diff --git a/types/GridSummon.d.ts b/types/GridSummon.d.ts index 6cbb3fe6..0ce8c2fc 100644 --- a/types/GridSummon.d.ts +++ b/types/GridSummon.d.ts @@ -2,7 +2,7 @@ interface GridSummon { id: string main: boolean friend: boolean - position: number | null + position: number summon: Summon uncap_level: number } \ No newline at end of file From f482b344296ba15404efcf825936dce3fdfc4003 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 2 Feb 2022 18:41:44 -0800 Subject: [PATCH 28/34] Remove extra prop --- pages/p/[party].tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/p/[party].tsx b/pages/p/[party].tsx index 968eed90..7150c885 100644 --- a/pages/p/[party].tsx +++ b/pages/p/[party].tsx @@ -127,7 +127,6 @@ const PartyRoute: React.FC = () => { weapons={weapons} summons={summons} editable={editable} - exists={found} extra={extra} />
            From 065c198e672c62367b1b1a8f8d28189f35dd5729 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 2 Feb 2022 18:43:55 -0800 Subject: [PATCH 29/34] Fix uncap indicator optimistic ui update bug --- components/WeaponGrid/index.tsx | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/components/WeaponGrid/index.tsx b/components/WeaponGrid/index.tsx index a476701f..1af8b717 100644 --- a/components/WeaponGrid/index.tsx +++ b/components/WeaponGrid/index.tsx @@ -146,29 +146,28 @@ const WeaponGrid = (props: Props) => { } } + function initiateUncapUpdate(id: string, position: number, uncapLevel: number) { + memoizeAction(id, position, uncapLevel) + + // Save the current value in case of an unexpected result + let newPreviousValues = {...previousUncapValues} + newPreviousValues[position] = (mainWeapon && position == -1) ? mainWeapon.uncap_level : weapons[position].uncap_level + setPreviousUncapValues(newPreviousValues) + + // Optimistically update UI + updateUncapLevel(position, uncapLevel) + } + const memoizeAction = useCallback( (id: string, position: number, uncapLevel: number) => { debouncedAction(id, position, uncapLevel) - }, [] + }, [props] ) - function initiateUncapUpdate(id: string, position: number, uncapLevel: number) { - memoizeAction(id, position, uncapLevel) - - // Save the current value in case of an unexpected result - let newPreviousValues = {...previousUncapValues} - newPreviousValues[position] = (mainWeapon && position == -1) ? mainWeapon.uncap_level : weapons[position].uncap_level - setPreviousUncapValues(newPreviousValues) - - // Optimistically update UI - updateUncapLevel(position, uncapLevel) - - } - const debouncedAction = useMemo(() => - debounce((id, position, number) => { + debounce((id, position, number) => { saveUncap(id, position, number) - }, 1000), [saveUncap] + }, 500), [props, saveUncap] ) const updateUncapLevel = (position: number, uncapLevel: number) => { @@ -176,7 +175,7 @@ const WeaponGrid = (props: Props) => { mainWeapon.uncap_level = uncapLevel setMainWeapon(mainWeapon) } else { - let newWeapons = Object.assign({}, weapons) + let newWeapons = Object.assign({}, props.weapons) newWeapons[position].uncap_level = uncapLevel setWeapons(newWeapons) } From ecfc62900d0eb951e4a0a6efe096983ff7d27191 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 2 Feb 2022 19:07:10 -0800 Subject: [PATCH 30/34] Trading working uncap indicators for working party creation We start storing the party ID here so that we know (and can come to know) when we are working with an existing party. Updating the weapon grid based on `weapons` the state vs `props.weapons` makes saving items to a party work properly. Unfortunately, it sends us back to square one with debouncing the uncap indicators. --- components/CharacterGrid/index.tsx | 22 ++++++++++++++++------ components/SummonGrid/index.tsx | 19 ++++++++++++++----- components/WeaponGrid/index.tsx | 14 ++++++++++---- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/components/CharacterGrid/index.tsx b/components/CharacterGrid/index.tsx index ba05648b..84ed5adb 100644 --- a/components/CharacterGrid/index.tsx +++ b/components/CharacterGrid/index.tsx @@ -41,6 +41,9 @@ const CharacterGrid = (props: Props) => { } } : {} + // Set up state for party + const [partyId, setPartyId] = useState('') + // Set up states for Grid data const [characters, setCharacters] = useState>({}) @@ -56,6 +59,7 @@ const CharacterGrid = (props: Props) => { // Set states from props useEffect(() => { + setPartyId(props.partyId || '') setCharacters(props.characters || {}) }, [props]) @@ -74,7 +78,7 @@ const CharacterGrid = (props: Props) => { function receiveCharacterFromSearch(object: Character | Weapon | Summon, position: number) { const character = object as Character - if (!props.partyId) { + if (!partyId) { props.createParty() .then(response => { const party = response.data.party @@ -83,7 +87,7 @@ const CharacterGrid = (props: Props) => { .then(response => storeGridCharacter(response.data.grid_character)) }) } else { - saveCharacter(props.partyId, character, position) + saveCharacter(partyId, character, position) .then(response => storeGridCharacter(response.data.grid_character)) } } @@ -147,7 +151,7 @@ const CharacterGrid = (props: Props) => { const initiateUncapUpdate = useCallback( (id: string, position: number, uncapLevel: number) => { - debouncedAction(id, position, uncapLevel) + memoizeAction(id, position, uncapLevel) // Save the current value in case of an unexpected result let newPreviousValues = {...previousUncapValues} @@ -159,14 +163,20 @@ const CharacterGrid = (props: Props) => { }, [previousUncapValues, characters] ) + const memoizeAction = useCallback( + (id: string, position: number, uncapLevel: number) => { + debouncedAction(id, position, uncapLevel) + }, [props] + ) + const debouncedAction = useMemo(() => - debounce((id, position, number) => { + debounce((id, position, number) => { saveUncap(id, position, number) - }, 1000), [saveUncap] + }, 500), [props, saveUncap] ) const updateUncapLevel = (position: number, uncapLevel: number) => { - let newCharacters = Object.assign({}, characters) + let newCharacters = {...characters} newCharacters[position].uncap_level = uncapLevel setCharacters(newCharacters) } diff --git a/components/SummonGrid/index.tsx b/components/SummonGrid/index.tsx index bce5de33..3533bed1 100644 --- a/components/SummonGrid/index.tsx +++ b/components/SummonGrid/index.tsx @@ -44,6 +44,9 @@ const SummonGrid = (props: Props) => { } } : {} + // Set up state for party + const [partyId, setPartyId] = useState('') + // Set up states for Grid data const [summons, setSummons] = useState>({}) const [mainSummon, setMainSummon] = useState() @@ -88,7 +91,7 @@ const SummonGrid = (props: Props) => { function receiveSummonFromSearch(object: Character | Weapon | Summon, position: number) { const summon = object as Summon - if (!props.partyId) { + if (!partyId) { props.createParty() .then(response => { const party = response.data.party @@ -97,7 +100,7 @@ const SummonGrid = (props: Props) => { .then(response => storeGridSummon(response.data.grid_summon)) }) } else { - saveSummon(props.partyId, summon, position) + saveSummon(partyId, summon, position) .then(response => storeGridSummon(response.data.grid_summon)) } } @@ -155,7 +158,7 @@ const SummonGrid = (props: Props) => { const initiateUncapUpdate = useCallback( (id: string, position: number, uncapLevel: number) => { - debouncedAction(id, position, uncapLevel) + memoizeAction(id, position, uncapLevel) // Save the current value in case of an unexpected result let newPreviousValues = {...previousUncapValues} @@ -167,10 +170,16 @@ const SummonGrid = (props: Props) => { }, [previousUncapValues, summons] ) + const memoizeAction = useCallback( + (id: string, position: number, uncapLevel: number) => { + debouncedAction(id, position, uncapLevel) + }, [props] + ) + const debouncedAction = useMemo(() => - debounce((id, position, number) => { + debounce((id, position, number) => { saveUncap(id, position, number) - }, 1000), [saveUncap] + }, 500), [props, saveUncap] ) const updateUncapLevel = (position: number, uncapLevel: number) => { diff --git a/components/WeaponGrid/index.tsx b/components/WeaponGrid/index.tsx index 1af8b717..ba9fec97 100644 --- a/components/WeaponGrid/index.tsx +++ b/components/WeaponGrid/index.tsx @@ -44,6 +44,9 @@ const WeaponGrid = (props: Props) => { } } : {} + // Set up state for party + const [partyId, setPartyId] = useState('') + // Set up states for Grid data const [weapons, setWeapons] = useState>({}) const [mainWeapon, setMainWeapon] = useState() @@ -60,6 +63,7 @@ const WeaponGrid = (props: Props) => { // Set states from props useEffect(() => { + setPartyId(props.partyId || '') setWeapons(props.weapons || {}) setMainWeapon(props.mainhand) }, [props]) @@ -83,16 +87,18 @@ const WeaponGrid = (props: Props) => { function receiveWeaponFromSearch(object: Character | Weapon | Summon, position: number) { const weapon = object as Weapon - if (!props.partyId) { + if (!partyId) { props.createParty() .then(response => { const party = response.data.party + setPartyId(party.id) + if (props.pushHistory) props.pushHistory(`/p/${party.shortcode}`) saveWeapon(party.id, weapon, position) .then(response => storeGridWeapon(response.data.grid_weapon)) }) } else { - saveWeapon(props.partyId, weapon, position) + saveWeapon(partyId, weapon, position) .then(response => storeGridWeapon(response.data.grid_weapon)) } } @@ -118,7 +124,7 @@ const WeaponGrid = (props: Props) => { setMainWeapon(gridWeapon) } else { // Store the grid unit at the correct position - let newWeapons = Object.assign({}, props.weapons) + let newWeapons = Object.assign({}, weapons) newWeapons[gridWeapon.position] = gridWeapon setWeapons(newWeapons) } @@ -175,7 +181,7 @@ const WeaponGrid = (props: Props) => { mainWeapon.uncap_level = uncapLevel setMainWeapon(mainWeapon) } else { - let newWeapons = Object.assign({}, props.weapons) + let newWeapons = Object.assign({}, weapons) newWeapons[position].uncap_level = uncapLevel setWeapons(newWeapons) } From 8192f1d0ced4676ce063d21e04c6ade530b165bc Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 2 Feb 2022 19:08:48 -0800 Subject: [PATCH 31/34] Update index.tsx --- components/CharacterUnit/index.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/CharacterUnit/index.tsx b/components/CharacterUnit/index.tsx index f92bd67a..dc0600ae 100644 --- a/components/CharacterUnit/index.tsx +++ b/components/CharacterUnit/index.tsx @@ -15,8 +15,6 @@ interface Props { } const CharacterUnit = (props: Props) => { - console.log(props.gridCharacter?.character.name.en, props.gridCharacter?.uncap_level) - const [imageUrl, setImageUrl] = useState('') const classes = classnames({ @@ -44,7 +42,6 @@ const CharacterUnit = (props: Props) => { } function passUncapData(uncap: number) { - console.log(`passuncapdata ${uncap}`) if (props.gridCharacter) props.updateUncap(props.gridCharacter.id, props.position, uncap) } From 11e1a81ada484f21ffa3f3b1622c535a76faab7f Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 2 Feb 2022 19:28:47 -0800 Subject: [PATCH 32/34] Fix extra switch --- components/Party/index.tsx | 4 ++-- components/ToggleSwitch/index.tsx | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/components/Party/index.tsx b/components/Party/index.tsx index 51d7eb4e..99a5ab17 100644 --- a/components/Party/index.tsx +++ b/components/Party/index.tsx @@ -90,7 +90,7 @@ const Party = (props: Props) => { // Render: JSX components const navigation = ( { partyId={props.partyId} mainhand={props.mainWeapon} weapons={props.weapons || {}} - extra={props.extra} + extra={extra} editable={props.editable} createParty={createParty} pushHistory={props.pushHistory} diff --git a/components/ToggleSwitch/index.tsx b/components/ToggleSwitch/index.tsx index 379a3c8a..ddcd0e54 100644 --- a/components/ToggleSwitch/index.tsx +++ b/components/ToggleSwitch/index.tsx @@ -12,20 +12,20 @@ interface Props { const ToggleSwitch: React.FC = (props: Props) => { return (
            - - + +
            - ); + ) } export default ToggleSwitch \ No newline at end of file From 8f77794262a1017a2052e93e075cc087ca5bbacd Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 2 Feb 2022 19:37:28 -0800 Subject: [PATCH 33/34] Update index.tsx --- components/WeaponUnit/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx index b50e541e..6f2ef0c3 100644 --- a/components/WeaponUnit/index.tsx +++ b/components/WeaponUnit/index.tsx @@ -48,7 +48,6 @@ const WeaponUnit = (props: Props) => { } function passUncapData(uncap: number) { - console.log("Passing uncap data to updateUncap callback...") if (props.gridWeapon) props.updateUncap(props.gridWeapon.id, props.position, uncap) } From 4fb2fd16b805755b99afe525bc5765d2355f7448 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 2 Feb 2022 20:36:22 -0800 Subject: [PATCH 34/34] Fix optimistic UI and prevent saving identical uncap values --- components/CharacterGrid/index.tsx | 29 +++++++++++++++++-------- components/SummonGrid/index.tsx | 34 ++++++++++++++++++++++-------- components/WeaponGrid/index.tsx | 32 ++++++++++++++++++---------- 3 files changed, 66 insertions(+), 29 deletions(-) diff --git a/components/CharacterGrid/index.tsx b/components/CharacterGrid/index.tsx index 84ed5adb..af78ed7e 100644 --- a/components/CharacterGrid/index.tsx +++ b/components/CharacterGrid/index.tsx @@ -63,6 +63,13 @@ const CharacterGrid = (props: Props) => { setCharacters(props.characters || {}) }, [props]) + // Initialize an array of current uncap values for each characters + useEffect(() => { + let initialPreviousUncapValues: {[key: number]: number} = {} + Object.values(props.characters).map(o => initialPreviousUncapValues[o.position] = o.uncap_level) + setPreviousUncapValues(initialPreviousUncapValues) + }, [props]) + // Update search grid whenever characters are updated useEffect(() => { let newSearchGrid = Object.values(characters).map((o) => o.character) @@ -131,11 +138,12 @@ const CharacterGrid = (props: Props) => { // Methods: Updating uncap level // Note: Saves, but debouncing is not working properly async function saveUncap(id: string, position: number, uncapLevel: number) { + storePreviousUncapValue(position) + try { - await api.updateUncap('weapon', id, uncapLevel) - .then(response => { - storeGridCharacter(response.data.grid_character) - }) + if (uncapLevel != previousUncapValues[position]) + await api.updateUncap('weapon', id, uncapLevel) + .then(response => { storeGridCharacter(response.data.grid_character) }) } catch (error) { console.error(error) @@ -153,11 +161,6 @@ const CharacterGrid = (props: Props) => { (id: string, position: number, uncapLevel: number) => { memoizeAction(id, position, uncapLevel) - // Save the current value in case of an unexpected result - let newPreviousValues = {...previousUncapValues} - newPreviousValues[position] = characters[position].uncap_level - setPreviousUncapValues(newPreviousValues) - // Optimistically update UI updateUncapLevel(position, uncapLevel) }, [previousUncapValues, characters] @@ -181,6 +184,14 @@ const CharacterGrid = (props: Props) => { setCharacters(newCharacters) } + function storePreviousUncapValue(position: number) { + // Save the current value in case of an unexpected result + let newPreviousValues = {...previousUncapValues} + newPreviousValues[position] = characters[position].uncap_level + + setPreviousUncapValues(newPreviousValues) + } + // Render: JSX components return (
            diff --git a/components/SummonGrid/index.tsx b/components/SummonGrid/index.tsx index 3533bed1..476a6292 100644 --- a/components/SummonGrid/index.tsx +++ b/components/SummonGrid/index.tsx @@ -62,6 +62,15 @@ const SummonGrid = (props: Props) => { // Create a state dictionary to store pure objects for Search const [searchGrid, setSearchGrid] = useState>({}) + // Initialize an array of current uncap values for each summon + useEffect(() => { + let initialPreviousUncapValues: {[key: number]: number} = {} + if (props.mainSummon) initialPreviousUncapValues[-1] = props.mainSummon.uncap_level + if (props.friendSummon) initialPreviousUncapValues[6] = props.friendSummon.uncap_level + Object.values(props.summons).map(o => initialPreviousUncapValues[o.position] = o.uncap_level) + setPreviousUncapValues(initialPreviousUncapValues) + }, [props]) + // Set states from props useEffect(() => { setSummons(props.summons || {}) @@ -138,11 +147,12 @@ const SummonGrid = (props: Props) => { // Methods: Updating uncap level // Note: Saves, but debouncing is not working properly async function saveUncap(id: string, position: number, uncapLevel: number) { + storePreviousUncapValue(position) + try { - await api.updateUncap('summon', id, uncapLevel) - .then(response => { - storeGridSummon(response.data.grid_summon) - }) + if (uncapLevel != previousUncapValues[position]) + await api.updateUncap('summon', id, uncapLevel) + .then(response => { storeGridSummon(response.data.grid_summon) }) } catch (error) { console.error(error) @@ -160,11 +170,6 @@ const SummonGrid = (props: Props) => { (id: string, position: number, uncapLevel: number) => { memoizeAction(id, position, uncapLevel) - // Save the current value in case of an unexpected result - let newPreviousValues = {...previousUncapValues} - newPreviousValues[position] = summons[position].uncap_level - setPreviousUncapValues(newPreviousValues) - // Optimistically update UI updateUncapLevel(position, uncapLevel) }, [previousUncapValues, summons] @@ -188,6 +193,17 @@ const SummonGrid = (props: Props) => { setSummons(newSummons) } + function storePreviousUncapValue(position: number) { + // Save the current value in case of an unexpected result + let newPreviousValues = {...previousUncapValues} + + if (mainSummon && position == -1) newPreviousValues[position] = mainSummon.uncap_level + else if (friendSummon && position == 6) newPreviousValues[position] = friendSummon.uncap_level + else newPreviousValues[position] = summons[position].uncap_level + + setPreviousUncapValues(newPreviousValues) + } + // Render: JSX components const mainSummonElement = (
            diff --git a/components/WeaponGrid/index.tsx b/components/WeaponGrid/index.tsx index ba9fec97..a684299a 100644 --- a/components/WeaponGrid/index.tsx +++ b/components/WeaponGrid/index.tsx @@ -68,6 +68,14 @@ const WeaponGrid = (props: Props) => { setMainWeapon(props.mainhand) }, [props]) + // Initialize an array of current uncap values for each weapon + useEffect(() => { + let initialPreviousUncapValues: {[key: number]: number} = {} + if (props.mainhand) initialPreviousUncapValues[-1] = props.mainhand.uncap_level + Object.values(props.weapons).map(o => initialPreviousUncapValues[o.position] = o.uncap_level) + setPreviousUncapValues(initialPreviousUncapValues) + }, [props]) + // Update search grid whenever weapons or the mainhand are updated useEffect(() => { let newSearchGrid = Object.values(weapons).map((o) => o.weapon) @@ -133,12 +141,12 @@ const WeaponGrid = (props: Props) => { // Methods: Updating uncap level // Note: Saves, but debouncing is not working properly async function saveUncap(id: string, position: number, uncapLevel: number) { - // TODO: Don't make an API call if the new uncapLevel is the same as the current uncapLevel + storePreviousUncapValue(position) + try { - await api.updateUncap('weapon', id, uncapLevel) - .then(response => { - storeGridWeapon(response.data.grid_weapon) - }) + if (uncapLevel != previousUncapValues[position]) + await api.updateUncap('weapon', id, uncapLevel) + .then(response => { storeGridWeapon(response.data.grid_weapon) }) } catch (error) { console.error(error) @@ -155,11 +163,6 @@ const WeaponGrid = (props: Props) => { function initiateUncapUpdate(id: string, position: number, uncapLevel: number) { memoizeAction(id, position, uncapLevel) - // Save the current value in case of an unexpected result - let newPreviousValues = {...previousUncapValues} - newPreviousValues[position] = (mainWeapon && position == -1) ? mainWeapon.uncap_level : weapons[position].uncap_level - setPreviousUncapValues(newPreviousValues) - // Optimistically update UI updateUncapLevel(position, uncapLevel) } @@ -167,7 +170,7 @@ const WeaponGrid = (props: Props) => { const memoizeAction = useCallback( (id: string, position: number, uncapLevel: number) => { debouncedAction(id, position, uncapLevel) - }, [props] + }, [props, previousUncapValues] ) const debouncedAction = useMemo(() => @@ -187,6 +190,13 @@ const WeaponGrid = (props: Props) => { } } + function storePreviousUncapValue(position: number) { + // Save the current value in case of an unexpected result + let newPreviousValues = {...previousUncapValues} + newPreviousValues[position] = (mainWeapon && position == -1) ? mainWeapon.uncap_level : weapons[position].uncap_level + setPreviousUncapValues(newPreviousValues) + } + // Render: JSX components const mainhandElement = (