refactor: extract shared player, session, and chat packages #5

Merged
ryan merged 14 commits from refactor/shared-player-session-chat into main 2026-03-03 08:50:13 +00:00
2 changed files with 31 additions and 30 deletions
Showing only changes of commit 0808c4d972 - Show all commits

View File

@@ -15,7 +15,6 @@ import (
chatcomponents "github.com/ryanhamamura/games/chat/components" chatcomponents "github.com/ryanhamamura/games/chat/components"
"github.com/ryanhamamura/games/connect4" "github.com/ryanhamamura/games/connect4"
"github.com/ryanhamamura/games/db/repository" "github.com/ryanhamamura/games/db/repository"
"github.com/ryanhamamura/games/features/c4game/components"
"github.com/ryanhamamura/games/features/c4game/pages" "github.com/ryanhamamura/games/features/c4game/pages"
"github.com/ryanhamamura/games/sessions" "github.com/ryanhamamura/games/sessions"
) )
@@ -113,8 +112,16 @@ func HandleGameEvents(store *connect4.Store, nc *nats.Conn, sm *scs.SessionManag
chatCfg := c4ChatConfig(gameID) chatCfg := c4ChatConfig(gameID)
room := chat.NewPersistentRoom(nc, connect4.ChatSubject(gameID), queries, gameID) room := chat.NewPersistentRoom(nc, connect4.ChatSubject(gameID), queries, gameID)
patchAll := func() error {
myColor = gi.GetPlayerColor(playerID)
g := gi.GetGame()
return sse.PatchElementTempl(pages.GameContent(g, myColor, room.Messages(), chatCfg))
}
// Send initial render // Send initial render
sendGameComponents(sse, gi, myColor, room, chatCfg) if err := patchAll(); err != nil {
return
}
// Subscribe to game state updates // Subscribe to game state updates
gameCh := make(chan *nats.Msg, 64) gameCh := make(chan *nats.Msg, 64)
@@ -137,14 +144,12 @@ func HandleGameEvents(store *connect4.Store, nc *nats.Conn, sm *scs.SessionManag
case <-ctx.Done(): case <-ctx.Done():
return return
case <-gameCh: case <-gameCh:
myColor = gi.GetPlayerColor(playerID) if err := patchAll(); err != nil {
sendGameComponents(sse, gi, myColor, room, chatCfg) return
case msg := <-chatCh:
_, snapshot := room.Receive(msg.Data)
if snapshot == nil {
continue
} }
if err := sse.PatchElementTempl(chatcomponents.Chat(snapshot, chatCfg)); err != nil { case msg := <-chatCh:
room.Receive(msg.Data)
if err := patchAll(); err != nil {
return return
} }
} }
@@ -300,13 +305,3 @@ func HandleRematch(store *connect4.Store, sm *scs.SessionManager) http.HandlerFu
} }
} }
} }
// sendGameComponents patches all game-related SSE components.
func sendGameComponents(sse *datastar.ServerSentEventGenerator, gi *connect4.Instance, myColor int, room *chat.Room, chatCfg chatcomponents.Config) {
g := gi.GetGame()
sse.PatchElementTempl(components.Board(g, myColor)) //nolint:errcheck
sse.PatchElementTempl(components.StatusBanner(g, myColor)) //nolint:errcheck
sse.PatchElementTempl(components.PlayerInfo(g, myColor)) //nolint:errcheck
sse.PatchElementTempl(chatcomponents.Chat(room.Messages(), chatCfg)) //nolint:errcheck
}

View File

@@ -17,21 +17,27 @@ templ GamePage(g *connect4.Game, myColor int, messages []chat.Message, chatCfg c
data-signals="{chatMsg: ''}" data-signals="{chatMsg: ''}"
data-init={ datastar.GetSSE("/games/%s/events", g.ID) } data-init={ datastar.GetSSE("/games/%s/events", g.ID) }
> >
@sharedcomponents.BackToLobby() @GameContent(g, myColor, messages, chatCfg)
@sharedcomponents.StealthTitle("text-3xl font-bold")
@components.PlayerInfo(g, myColor)
@components.StatusBanner(g, myColor)
<div class="c4-game-area">
@components.Board(g, myColor)
@chatcomponents.Chat(messages, chatCfg)
</div>
if g.Status == connect4.StatusWaitingForPlayer {
@components.InviteLink(g.ID)
}
</main> </main>
} }
} }
templ GameContent(g *connect4.Game, myColor int, messages []chat.Message, chatCfg chatcomponents.Config) {
<div id="game-content">
@sharedcomponents.BackToLobby()
@sharedcomponents.StealthTitle("text-3xl font-bold")
@components.PlayerInfo(g, myColor)
@components.StatusBanner(g, myColor)
<div class="c4-game-area">
@components.Board(g, myColor)
@chatcomponents.Chat(messages, chatCfg)
</div>
if g.Status == connect4.StatusWaitingForPlayer {
@components.InviteLink(g.ID)
}
</div>
}
templ JoinPage(gameID string) { templ JoinPage(gameID string) {
@layouts.Base("Connect 4 - Join") { @layouts.Base("Connect 4 - Join") {
@sharedcomponents.GameJoinPrompt( @sharedcomponents.GameJoinPrompt(