Skip to content

Move platform-neutral hooks and utils out of frontend - #74

Merged
aichannode merged 6 commits into
mainfrom
refactor/shared-platform-neutral-hooks
Aug 10, 2026
Merged

Move platform-neutral hooks and utils out of frontend#74
aichannode merged 6 commits into
mainfrom
refactor/shared-platform-neutral-hooks

Conversation

@heyradcode

Copy link
Copy Markdown
Collaborator

Description

Moves code that has no web coupling out of frontend and into @shared/core, so
mobile can consume it instead of reimplementing it. From a review that flagged four
items; a sweep for completeness found two more.

Moved

From To
frontend/src/hooks/usePetCooldowns.ts shared/src/hooks/pets/usePetCooldowns.ts
frontend/src/hooks/battle/useLiveBattleAnimation.ts shared/src/hooks/battle/useLiveBattleAnimation.ts
frontend/src/hooks/battle/useBattleOutcome.ts shared/src/hooks/battle/useBattleOutcome.ts
frontend/src/utils/address.ts shared/src/utils/common/address.ts
.../battle/battle-matchmaking.ts shared/src/utils/battleMatchmaking.ts
toDialoguePet, BattlePersonas from .../battle/battle-utils.ts shared/src/utils/battleDialoguePet.ts

Bodies are unchanged. Only the imports moved to relative paths, and StrikeLogEntry
now comes from @cryptopets/protocol directly, matching the sibling hooks in that
folder. Every test moved with its code: frontend 394 to 370, shared 543 to 567.

Three decisions worth reviewing:

  • sameAccount moved with shortAddress. Same file, same test file, same
    platform-neutrality test. It is a two-line wrapper over the protocol's
    normalizeAccount, and mobile needs it for the same "is this me" checks the chat
    and leaderboard do. Leaving it would split one module across two packages.
  • BattleOutcome moved to shared/src/types/battle.ts, since it is the hook's
    return type. MechanicalLogLine stayed in the frontend: isFighter is a rendering
    concern.
  • battle-utils.ts kept its three message strings. Those are frontend copy;
    mobile will want its own wording. What moved is the two functions that are
    contracts with the backend: toDialoguePet builds the dialogue endpoint's payload,
    and opponentKey encodes the owner::id shape that exists because Solana pet ids
    are not globally unique.

battle-matchmaking.ts is the one worth a second look. pickRandomOpponent and
sortOpponentsByMatch decide which opponents a player sees and in what order, so a
reimplementation on mobile would rank the same roster differently, and nobody would
notice until two screens were compared side by side.

Also in here

  • mobile/src/components/ConnectButton.tsx had its own inline copy of the address
    truncation, with an ASCII ... and no length guard. It now calls shortAddress,
    so both clients render addresses the same way. That is the first place the move
    pays for itself.
  • A no-restricted-imports boundary on shared: nothing in @shared/core may
    import through a frontend path alias (@components/*, @hooks/*, and the rest) or
    a platform-only module (react-router-dom, react-native, next/*). Verified it
    fires by probing each group, not just that the package still passes. This is how
    the six modules ended up misplaced to begin with.
  • bash.exe.stackdump, committed at the repo root, is untracked now.
  • CLAUDE.md pointed at useBattleOutcome beside useBattlePanel. That line exists
    to stop someone splitting the panel, so a wrong pointer in it does real damage.
    AGENTS.md claimed no module-boundary lint existed; it now says one does, and what
    it does not cover.

Test factories

Three frontend suites replace @shared/core with a mock factory and were relying on
the real implementations reaching them by a separate module path. They now import
those modules directly and spread them, so the assertions still run against real
code rather than stubs:

  • useBattlePanel.test.ts asserts on the animation's 700ms timing (the result card
    must stay hidden until the last strike plays).
  • useResultDialogue.test.ts asserts on the persona toDialoguePet builds.
  • chat.test.tsx and leaderboard.test.tsx assert on the EVM-folds/base58-does-not
    rule, and their hand-written normalizeAccount stubs are now dead, since nothing
    in the frontend imports it any more.

Verification

frontend 370 tests / 48 files, shared 567 / 80, mobile jest 1/1. Lint clean on
frontend (including lint:css), shared, and mobile. tsc -b --force and
vite build on frontend, pnpm --filter backend build for the third @shared/core
consumer (it only imports @shared/core/node, which is untouched).

@vercel

vercel Bot commented Aug 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
do-not-stop-frontend Ready Ready Preview Aug 10, 2026 2:41pm
do-not-stop-website Ready Ready Preview Aug 10, 2026 2:41pm

@github-actions

Copy link
Copy Markdown

🧪 Coverage

Package Statements Branches Functions Lines Overall
backend 84.82% (2438/2874) 78.51% (1246/1587) 82.62% (466/564) 85.38% (2313/2709) 83.57% (6463/7734)
frontend 70.39% (1650/2344) 71.79% (1418/1975) 69.15% (435/629) 71.21% (1504/2112) 70.92% (5007/7060)
shared 60.12% (1672/2781) 60.87% (1069/1756) 59.86% (352/588) 61.74% (1514/2452) 60.80% (4607/7577)

@heyradcode
heyradcode requested a review from aichannode August 10, 2026 14:47
@heyradcode heyradcode self-assigned this Aug 10, 2026

@aichannode aichannode left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks clean, thanks @heyradcode 👍

@aichannode
aichannode merged commit 523f4f5 into main Aug 10, 2026
9 checks passed
@aichannode
aichannode deleted the refactor/shared-platform-neutral-hooks branch August 10, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants