]> git.localhorst.tv Git - alttp.git/commitdiff
include hth signup links with episode crew
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 2 Feb 2026 13:21:57 +0000 (14:21 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 2 Feb 2026 13:21:57 +0000 (14:21 +0100)
resources/js/components/episodes/Crew.jsx
resources/js/components/episodes/Item.jsx
resources/js/helpers/Episode.js
resources/js/i18n/de.js
resources/js/i18n/en.js

index c20021a8fd6d77e482e84ef159f347a827df40a8..a0164c68d435d74f4fbe02a20d16525e00fb2319 100644 (file)
@@ -7,8 +7,10 @@ import CrewList from './CrewList';
 import Icon from '../common/Icon';
 import { compareCrew } from '../../helpers/Crew';
 import {
+       getHTHSignupLink,
        getSGLanguages,
        getSGSignupLink,
+       hasHTHRestream,
        hasPassed,
        hasSGRestream,
 } from '../../helpers/Episode';
@@ -38,6 +40,7 @@ const Crew = ({ episode }) => {
        const showCommentators = React.useMemo(() =>
                commentators.length || (!hasPassed(episode) && (
                        canApplyForEpisode(user, episode, 'commentary') ||
+                       hasHTHRestream(episode) ||
                        hasSGRestream(episode)
                ))
        , [commentators, episode, user]);
@@ -45,10 +48,15 @@ const Crew = ({ episode }) => {
        const showTracker = React.useMemo(() =>
                trackers.length || (!hasPassed(episode) && (
                        canApplyForEpisode(user, episode, 'tracking') ||
+                       hasHTHRestream(episode) ||
                        hasSGRestream(episode)
                ))
        , [episode, trackers, user]);
 
+       const showHthSignup = React.useMemo(() =>
+               !hasPassed(episode) && hasHTHRestream(episode)
+       , [episode]);
+
        const showSgSignup = React.useMemo(() =>
                !hasPassed(episode) && hasSGRestream(episode)
        , [episode]);
@@ -71,6 +79,17 @@ const Crew = ({ episode }) => {
                                                </Button>
                                        </div>
                                : null}
+                               {showHthSignup ?
+                                       <div className="button-bar m-2">
+                                               <Button
+                                                       href={getHTHSignupLink(episode, 'de', 'commentator')}
+                                                       target="_blank"
+                                                       variant="outline-secondary"
+                                               >
+                                                       {t('episodes.hthSignUp')}
+                                               </Button>
+                                       </div>
+                               : null}
                                {showSgSignup ?
                                        <div className="button-bar m-2">
                                                {sgLanguages.map(lang =>
@@ -104,6 +123,17 @@ const Crew = ({ episode }) => {
                                                </Button>
                                        </div>
                                : null}
+                               {showHthSignup ?
+                                       <div className="button-bar m-2">
+                                               <Button
+                                                       href={getHTHSignupLink(episode, 'de', 'tracker')}
+                                                       target="_blank"
+                                                       variant="outline-secondary"
+                                               >
+                                                       {t('episodes.hthSignUp')}
+                                               </Button>
+                                       </div>
+                               : null}
                                {showSgSignup ?
                                        <div className="button-bar m-2">
                                                {sgLanguages.map(lang =>
index 941faf183b2c90becb148eea1975bde8a21804e2..465c4c3552cbb63e3c0db1866b7eaef1e23b3d53 100644 (file)
@@ -10,7 +10,7 @@ import Crew from './Crew';
 import MultiLink from './MultiLink';
 import Players from './Players';
 import Icon from '../common/Icon';
-import { hasPassed, hasSGRestream, isActive } from '../../helpers/Episode';
+import { hasHTHRestream, hasPassed, hasSGRestream, isActive } from '../../helpers/Episode';
 import { getLink } from '../../helpers/Event';
 import {
        canApplyForEpisode,
@@ -154,6 +154,7 @@ const Item = ({ episode }) => {
                        : null}
                        {(episode.crew && episode.crew.length) || (!hasPassed(episode) && (
                                        hasSGRestream(episode)
+                                       || hasHTHRestream(episode)
                                        || canApplyForEpisode(user, episode, 'commentary')
                                        || canApplyForEpisode(user, episode, 'tracking')
                        )) ?
index 009865ceb96f03af452e9a8b40a13d3ccf05278c..ef34cea020a3cf975ab3617457de0d7c55fae3f3 100644 (file)
@@ -16,6 +16,9 @@ export const acceptsCrew = episode => {
                c.pivot && (c.pivot.accept_comms || c.pivot.accept_tracker));
 };
 
+export const getHTHSignupLink = episode =>
+       `https://hth.zeldaspeedruns.com/event/${episode.ext_info.handle}/races/${episode.ext_id.substr(4)}/signups`;
+
 export const getSGLanguages = episode => {
        if (!episode || !episode.channels) return [];
        const sgChannels = episode.channels.filter(
@@ -36,6 +39,11 @@ export const getSGLanguages = episode => {
 export const getSGSignupLink = (episode, lang, role) =>
        `https://speedgaming.org/${lang}/${role}/signup/${episode.ext_id.substr(3)}/`;
 
+export const hasHTHRestream = episode => {
+       if (!episode?.ext_id || !episode.ext_id.startsWith('hth:') || !episode.ext_info?.handle || episode.do_not_restream) return false;
+       return true;
+};
+
 export const hasPassed = episode => {
        if (!episode || !episode.start) return false;
        const now = moment();
index 34f18c3d6ec38f13273982c1acaba4f51603095b..53f12f484e6e563affde708c72b2a9028d644382 100644 (file)
@@ -251,6 +251,7 @@ export default {
                        estimatePreview: '{{ estimate }} Std.',
                        estimatePreviewWithEnd: '{{ estimate }} Std. (endet {{ end, LL LT }} Uhr)',
                        extSyncWarning: 'Achtung: Diese Episopde wird mit einer externen Datenquelle synchronisiert und Änderungen können überschrieben werden!',
+                       hthSignUp: 'HTH Anmeldung',
                        missingStreams: 'Fehlende Runner-Streams',
                        players: {
                                name_override: 'Abweichender Name',
index a4b681c673a7a1c34727020b2ffe776fe7f3c987..0741973b764617058ee51abfbe6fc4ef6eaa4530 100644 (file)
@@ -251,6 +251,7 @@ export default {
                        estimatePreview: '{{ estimate }}h',
                        estimatePreviewWithEnd: '{{ estimate }}h (ends {{ end, LL LT }})',
                        extSyncWarning: 'Warning: This episode is synchronized to an external data source. Changes may be overwritten!',
+                       hthSignUp: 'HTH Signup',
                        missingStreams: 'Missing runner streams',
                        players: {
                                name_override: 'Name override',