Files
Psychotoxical-psysonic/src/hooks/useLuckyMixAvailable.ts
T
Psychotoxical e9e61b9a05 refactor(lucky-mix): review follow-ups from Psychotoxical
- Drop the ~110 lines of dead full-screen overlay CSS that was never
  referenced in JSX (.lucky-mix-overlay*, .lucky-mix-cube*, full-screen
  @keyframes). Keep the .lucky-mix-pip* rules since the inline queue
  variant re-uses them.

- Extract availability gate into hooks/useLuckyMixAvailable.ts (pure
  predicate + hook). Replaces five duplicated inline checks in Sidebar,
  MobileMoreOverlay, RandomLanding, Settings/SidebarCustomizer, and the
  internal re-check in buildAndPlayLuckyMix.

- Add a cancel mechanic:
  * luckyMixStore gets a cancelRequested flag + cancel() method
  * LuckyMixCancelled sentinel is thrown from a bailIfCancelled() helper
    sprinkled between await boundaries in the build loop
  * catch-block swallows the sentinel silently (no toast, no error state)
  * auto-cancel subscription on playerStore detects manual user track
    changes (anything not in queuedIds) and flips cancelRequested so the
    finished mix does not later overwrite the user's choice
  * inline .queue-lucky-loading dice indicator is now a button — click
    triggers explicit cancel, hover fades the dice to signal the action

- Restore the queue snapshot when the build fails before ever starting
  playback, so the user does not land in an empty player after an error.
  If playTrack already ran, leave current state alone (their track plus
  whatever was enqueued is more useful than a stale pre-click queue).

- Rework locale labels to consistently carry the "Mix" suffix so the
  entry reads well next to "Random Mix" / "Random Albums" in the
  sidebar: DE Glücks-Mix, ES Mezcla Suerte, FR Mix Chance, NB Lykkemiks,
  NL Geluksmix, ZH 好运混音. EN stays "Lucky Mix", RU stays
  «Мне повезёт». Toast/settings/randomNavSplit copy aligned to the new
  names. New luckyMix.cancelTooltip key added in all 8 locales.

AudioMuse gating stays — as Cuca confirmed, the feature's quality relies
on a correct similar-track selection, so the requirement is intentional.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 18:41:46 +02:00

41 lines
1.7 KiB
TypeScript

import { useAuthStore } from '../store/authStore';
/**
* Whether "Lucky Mix" should be exposed as a navigable menu/card entry.
*
* Single source of truth for the gate — previously this logic was inlined in
* Sidebar, MobileMoreOverlay, RandomLanding, Settings/SidebarCustomizer, and
* the sidebarNavReorder filter. All call sites share the same three-way
* predicate:
* 1. User hasn't hidden it via the Settings toggle.
* 2. AudioMuse is enabled for the active server (feature depends on
* audiomuse-backed similar-track quality).
* 3. An active server exists at all.
*
* Callers that additionally care about the "split vs hub" navigation mode
* should combine this with `randomNavMode === 'separate'` explicitly — that's
* an orthogonal UI placement concern, not an availability concern.
*/
export function isLuckyMixAvailable(args: {
activeServerId: string | null | undefined;
audiomuseByServer: Record<string, boolean>;
showLuckyMixMenu: boolean;
}): boolean {
const { activeServerId, audiomuseByServer, showLuckyMixMenu } = args;
if (!showLuckyMixMenu) return false;
if (!activeServerId) return false;
return Boolean(audiomuseByServer[activeServerId]);
}
/**
* React hook form — subscribes to the three authStore slices the predicate
* depends on, so any user-facing change (toggle flip, server switch, AudioMuse
* toggle on/off) re-renders the caller automatically.
*/
export function useLuckyMixAvailable(): boolean {
const activeServerId = useAuthStore(s => s.activeServerId);
const audiomuseByServer = useAuthStore(s => s.audiomuseNavidromeByServer);
const showLuckyMixMenu = useAuthStore(s => s.showLuckyMixMenu);
return isLuckyMixAvailable({ activeServerId, audiomuseByServer, showLuckyMixMenu });
}