From d2c71fa84c9475a48cd024d22dfb54a45bbce3f8 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Fri, 25 Feb 2022 00:57:35 -0500 Subject: [PATCH] progress? --- .../tts_configs/TtsConfigsEditRulePage.tsx | 33 +++-- .../CheerState.ts | 23 ++- .../EventMatchPredicateBuilderComponent.tsx | 133 +++++++++++------- .../BitsCheermotePrefixSpendThresholdForm.tsx | 3 - 4 files changed, 123 insertions(+), 69 deletions(-) diff --git a/packages/storyteller/src/pages/tts_configs/TtsConfigsEditRulePage.tsx b/packages/storyteller/src/pages/tts_configs/TtsConfigsEditRulePage.tsx index fc7d7f3d39..7c90f8742b 100644 --- a/packages/storyteller/src/pages/tts_configs/TtsConfigsEditRulePage.tsx +++ b/packages/storyteller/src/pages/tts_configs/TtsConfigsEditRulePage.tsx @@ -33,12 +33,13 @@ function TtsConfigsEditRulePage(props: Props) { const [twitchEventRule, setTwitchEventRule] = useState(undefined); - // ========== Values passed to subcomponents for editing ========== + // Sent to sub-components to initialize UI + const [serverEventMatchPredicate, setServerEventMatchPredicate] = useState({}); + const [serverEventResponse, setServerEventResponse] = useState({}); - const [newEventMatchPredicate, setNewEventMatchPredicate] = useState({}); - const [newEventResponse, setNewEventResponse] = useState({}); + // ========== In-Progress Model Edits ========== - const [cheerState, setCheerState] = useState({}); + const [modifiedEventMatchPredicate, setModifiedEventMatchPredicate] = useState({}); // ========== ??? ========== @@ -60,15 +61,19 @@ function TtsConfigsEditRulePage(props: Props) { const response = await GetTwitchEventRule(token); if (GetTwitchEventRuleIsOk(response)) { + // Source of truth setTwitchEventRule(response.twitch_event_rule); + setServerEventMatchPredicate(response.twitch_event_rule.event_match_predicate); + setServerEventResponse(response.twitch_event_rule.event_response); + + // In-progress modifications + setModifiedEventMatchPredicate(response.twitch_event_rule.event_match_predicate); + + // TODO REMOVE setEventMatchPredicate(response.twitch_event_rule.event_match_predicate); setEventResponse(response.twitch_event_rule.event_response); setRuleIsDisabled(response.twitch_event_rule.rule_is_disabled); - // TODO - setNewEventMatchPredicate(response.twitch_event_rule.event_match_predicate); - setNewEventResponse(response.twitch_event_rule.event_response); - let serverBitsRuleType = BitsRuleType.BitsCheermoteNameExactMatch; switch (response.twitch_event_rule.event_category) { @@ -123,14 +128,12 @@ function TtsConfigsEditRulePage(props: Props) { break; } - console.log(token); - setTtsModelToken(token); setEventResponse(response); } - const updateEventMatchPredicate = (predicate: EventMatchPredicate) => { - setNewEventMatchPredicate(predicate); + const updateModifiedEventMatchPredicate = (predicate: EventMatchPredicate) => { + setModifiedEventMatchPredicate(predicate); } const handleFormSubmit = async (ev: React.FormEvent) : Promise => { @@ -172,7 +175,7 @@ function TtsConfigsEditRulePage(props: Props) { updated_at: twitchEventRule.updated_at, // Updated in UI - event_match_predicate: eventMatchPredicate, + event_match_predicate: modifiedEventMatchPredicate, event_response: eventResponse, rule_is_disabled: ruleIsDisabled, }; @@ -190,8 +193,8 @@ function TtsConfigsEditRulePage(props: Props) { 1) { + newBits = cheerState.bits; + } predicate.bits_spend_threshold = { - minimum_bits_spent: 1, + minimum_bits_spent: newBits, } break; } diff --git a/packages/storyteller/src/pages/tts_configs/event_match_predicate_builder/EventMatchPredicateBuilderComponent.tsx b/packages/storyteller/src/pages/tts_configs/event_match_predicate_builder/EventMatchPredicateBuilderComponent.tsx index 9790eccc9b..95dd790580 100644 --- a/packages/storyteller/src/pages/tts_configs/event_match_predicate_builder/EventMatchPredicateBuilderComponent.tsx +++ b/packages/storyteller/src/pages/tts_configs/event_match_predicate_builder/EventMatchPredicateBuilderComponent.tsx @@ -9,18 +9,18 @@ import { BitsSpendThresholdForm } from './subforms/BitsSpendThresholdForm'; import { ChannelPointsRewardNameExactMatchForm } from './subforms/ChannelPointsRewardNameExactMatchForm'; import { ChannelPointsRuleType } from './types/ChannelPointsRuleType'; import { CheerUtil } from '../../../twitch/CheerUtil'; -import { CheerState, predicateToCheerState } from './CheerState'; - -// TODO: Don't duplicate -const CHEER_REGEX = /^([A-Za-z]+)(\d+)?$/; +import { CheerState, CheerStateIsCustom, CheerStateIsOfficial, cheerStateToPredicate, predicateToCheerState } from './CheerState'; interface EventMatchPredicateBuilderComponentProps { // CANNOT BE CHANGED AFTER CREATION twitchEventCategory: TwitchEventCategory, + // Original event match predicate from the server + // (also immutable for sanity and because we lose information on UI changes) + serverEventMatchPredicate: EventMatchPredicate, + // Updates sent back up the tree - eventMatchPredicate: EventMatchPredicate, - updateEventMatchPredicate: (predicate: EventMatchPredicate) => void, + updateModifiedEventMatchPredicate: (predicate: EventMatchPredicate) => void, // FakeYou voices allTtsModels: TtsModelListItem[], @@ -35,8 +35,6 @@ function EventMatchPredicateBuilderComponent(props: EventMatchPredicateBuilderCo // ========== Cached Values for Editing ========== - - // New, and remove everything else: const [cheerState, setCheerState] = useState({}); @@ -79,28 +77,28 @@ function EventMatchPredicateBuilderComponent(props: EventMatchPredicateBuilderCo let bitsV = undefined; let cheerPrefixV = undefined; - let newCheerState = predicateToCheerState(props.eventMatchPredicate); + let newCheerState = predicateToCheerState(props.serverEventMatchPredicate); switch (props.twitchEventCategory) { case TwitchEventCategory.Bits: - if (!!props.eventMatchPredicate.bits_cheermote_name_exact_match) { + if (!!props.serverEventMatchPredicate.bits_cheermote_name_exact_match) { newBitsRuleType = BitsRuleType.BitsCheermoteNameExactMatch; - cheerAndBitsV = props.eventMatchPredicate.bits_cheermote_name_exact_match.cheermote_name; + cheerAndBitsV = props.serverEventMatchPredicate.bits_cheermote_name_exact_match.cheermote_name; - } else if (!!props.eventMatchPredicate.bits_cheermote_prefix_spend_threshold) { + } else if (!!props.serverEventMatchPredicate.bits_cheermote_prefix_spend_threshold) { newBitsRuleType = BitsRuleType.BitsCheermotePrefixSpendThreshold; - cheerPrefixV = props.eventMatchPredicate.bits_cheermote_prefix_spend_threshold.cheermote_prefix; - bitsV = props.eventMatchPredicate.bits_cheermote_prefix_spend_threshold.minimum_bits_spent; + cheerPrefixV = props.serverEventMatchPredicate.bits_cheermote_prefix_spend_threshold.cheermote_prefix; + bitsV = props.serverEventMatchPredicate.bits_cheermote_prefix_spend_threshold.minimum_bits_spent; - } else if (!!props.eventMatchPredicate.bits_spend_threshold) { + } else if (!!props.serverEventMatchPredicate.bits_spend_threshold) { newBitsRuleType = BitsRuleType.BitsSpendThreshold; - bitsV = props.eventMatchPredicate.bits_spend_threshold.minimum_bits_spent; + bitsV = props.serverEventMatchPredicate.bits_spend_threshold.minimum_bits_spent; } break; case TwitchEventCategory.ChannelPoints: // NB: Only one rule type - if (!!props.eventMatchPredicate.channel_points_reward_name_exact_match) { - setRewardName(props.eventMatchPredicate.channel_points_reward_name_exact_match.reward_name); + if (!!props.serverEventMatchPredicate.channel_points_reward_name_exact_match) { + setRewardName(props.serverEventMatchPredicate.channel_points_reward_name_exact_match.reward_name); newChannelPointsRuleType = ChannelPointsRuleType.ChannelPointsRewardNameExactMatch; } break; @@ -111,15 +109,16 @@ function EventMatchPredicateBuilderComponent(props: EventMatchPredicateBuilderCo setCheerState(newCheerState); - console.table(props.eventMatchPredicate) + console.log('\n\n======== useEffect() ======='); + console.table(props.serverEventMatchPredicate) console.log('cheerState', newCheerState); + console.log('\n\n'); if (!!cheerAndBitsV) { let { cheerPrefix, bitValue } = CheerUtil.parseCheerString(cheerAndBitsV); setCheerPrefix(cheerPrefix || ''); setBitsValue(bitValue || 1); setCheerNameOrPrefix(cheerAndBitsV); // TODO: DIE - console.log('parsed', cheerPrefix, bitValue); } if (!!bitsV) { setBitsValue(bitsV || 1); @@ -131,7 +130,7 @@ function EventMatchPredicateBuilderComponent(props: EventMatchPredicateBuilderCo setBitsRuleType(newBitsRuleType); setChannelPointsRuleType(newChannelPointsRuleType); - }, [props.twitchEventCategory, props.eventMatchPredicate]); + }, [props.twitchEventCategory, props.serverEventMatchPredicate]); // TODO: We need to recalculate the model. const handleChangedBitsRuleType = (ev: React.FormEvent) : boolean => { @@ -159,7 +158,7 @@ function EventMatchPredicateBuilderComponent(props: EventMatchPredicateBuilderCo break; } - props.updateEventMatchPredicate(predicate); + props.updateModifiedEventMatchPredicate(predicate); setBitsRuleType(newRuleType); return true; @@ -181,15 +180,15 @@ function EventMatchPredicateBuilderComponent(props: EventMatchPredicateBuilderCo // // switch (bitsRuleType) { // case BitsRuleType.BitsCheermoteNameExactMatch: -// currentNameOrPrefix = props.eventMatchPredicate.bits_cheermote_name_exact_match?.cheermote_name || ''; +// currentNameOrPrefix = props.serverEventMatchPredicate.bits_cheermote_name_exact_match?.cheermote_name || ''; // break; // case BitsRuleType.BitsCheermotePrefixSpendThreshold: -// currentNameOrPrefix = props.eventMatchPredicate.bits_cheermote_prefix_spend_threshold?.cheermote_prefix || ''; -// currentMinimumBitsSpent = props.eventMatchPredicate.bits_cheermote_prefix_spend_threshold?.minimum_bits_spent || 1; +// currentNameOrPrefix = props.serverEventMatchPredicate.bits_cheermote_prefix_spend_threshold?.cheermote_prefix || ''; +// currentMinimumBitsSpent = props.serverEventMatchPredicate.bits_cheermote_prefix_spend_threshold?.minimum_bits_spent || 1; // break; // case BitsRuleType.BitsSpendThreshold: // // No name -// currentMinimumBitsSpent = props.eventMatchPredicate.bits_cheermote_prefix_spend_threshold?.minimum_bits_spent || 1; +// currentMinimumBitsSpent = props.serverEventMatchPredicate.bits_cheermote_prefix_spend_threshold?.minimum_bits_spent || 1; // break; // } @@ -217,7 +216,7 @@ function EventMatchPredicateBuilderComponent(props: EventMatchPredicateBuilderCo break; } - props.updateEventMatchPredicate(predicate); + props.updateModifiedEventMatchPredicate(predicate); } const handleChangedCheerName = (name: string) => { @@ -243,33 +242,69 @@ function EventMatchPredicateBuilderComponent(props: EventMatchPredicateBuilderCo break; } - props.updateEventMatchPredicate(predicate); + props.updateModifiedEventMatchPredicate(predicate); } const handleChangedMinimumBitsSpent = (minimumSpent: number) => { - let predicate : EventMatchPredicate = {}; - switch (bitsRuleType) { - case BitsRuleType.BitsCheermoteNameExactMatch: - let joined = CheerUtil.joinCheerAndPrefix(cheerPrefix, minimumSpent); - predicate.bits_cheermote_name_exact_match = { - cheermote_name: joined, // Combined value - } - break; - case BitsRuleType.BitsCheermotePrefixSpendThreshold: - predicate.bits_cheermote_prefix_spend_threshold = { - cheermote_prefix: cheerPrefix, // Untouched existing value - minimum_bits_spent: minimumSpent, // New value - } - break; - case BitsRuleType.BitsSpendThreshold: - predicate.bits_spend_threshold = { - minimum_bits_spent: minimumSpent, // New value - } - break; + // 1) Update Cheer State + // 2) Update NewEventMatchPredicate + let newCheerState = {}; + + if (CheerStateIsOfficial(cheerState)) { + newCheerState = { + cheerPrefix: cheerState.cheerPrefix, // Unchanged + bits: minimumSpent, + } + } else if (CheerStateIsCustom(cheerState)) { + // Test if the cheer name includes numbers, eg. 'Sus12', or '1984', that differ from bit spend + let { cheerPrefix, bitValue } = CheerUtil.parseCheerString(cheerState.cheerFull || ''); + let cheerFull = cheerState.cheerFull; + + if (!!cheerPrefix && !!bitValue && bitValue === cheerState.bits) { + // Let's replace the cheer. + cheerFull = CheerUtil.joinCheerAndPrefix(cheerPrefix, minimumSpent); + } + + newCheerState = { + cheerFull: cheerFull, + bits: minimumSpent, + } + + } else { + newCheerState = { + bits: minimumSpent, + } } - props.updateEventMatchPredicate(predicate); + setCheerState(newCheerState); + + + let predicate = cheerStateToPredicate(newCheerState, bitsRuleType); + + + + //switch (bitsRuleType) { + // case BitsRuleType.BitsCheermoteNameExactMatch: + // let joined = CheerUtil.joinCheerAndPrefix(cheerPrefix, minimumSpent); + // predicate.bits_cheermote_name_exact_match = { + // cheermote_name: joined, // Combined value + // } + // break; + // case BitsRuleType.BitsCheermotePrefixSpendThreshold: + // predicate.bits_cheermote_prefix_spend_threshold = { + // cheermote_prefix: cheerPrefix, // Untouched existing value + // minimum_bits_spent: minimumSpent, // New value + // } + // break; + // case BitsRuleType.BitsSpendThreshold: + // predicate.bits_spend_threshold = { + // minimum_bits_spent: minimumSpent, // New value + // } + // break; + //} + + props.updateModifiedEventMatchPredicate(predicate); } // TODO @@ -284,7 +319,7 @@ function EventMatchPredicateBuilderComponent(props: EventMatchPredicateBuilderCo break; } - props.updateEventMatchPredicate(predicate); + props.updateModifiedEventMatchPredicate(predicate); } let ruleTypeSelect = <> diff --git a/packages/storyteller/src/pages/tts_configs/event_match_predicate_builder/subforms/BitsCheermotePrefixSpendThresholdForm.tsx b/packages/storyteller/src/pages/tts_configs/event_match_predicate_builder/subforms/BitsCheermotePrefixSpendThresholdForm.tsx index ea9f8174b9..502f912539 100644 --- a/packages/storyteller/src/pages/tts_configs/event_match_predicate_builder/subforms/BitsCheermotePrefixSpendThresholdForm.tsx +++ b/packages/storyteller/src/pages/tts_configs/event_match_predicate_builder/subforms/BitsCheermotePrefixSpendThresholdForm.tsx @@ -4,9 +4,6 @@ import { faGem } from '@fortawesome/free-solid-svg-icons'; import { CHEER_BIT_LEVELS, CHEER_PREFIXES, CHEER_PREFIX_TO_STRING_MAP } from '../../../../twitch/Cheers'; import { CheerState, CheerStateIsCustom, CheerStateIsOfficial } from '../CheerState'; -// TODO: Don't duplicate -const CHEER_REGEX = /^([A-Za-z]+)(\d+)?$/; - interface BitsCheermotePrefixSpendThresholdProps { cheerState: CheerState,