mirror of
https://github.com/tiennm99/noitu.git
synced 2026-10-14 06:17:56 +00:00
feat(online): seat the chat beside the game and score the series
A room screen wide enough for it is two columns now: the game or the lobby on one side and the room's conversation on the other, so neither has to be scrolled past to reach the other. A phone keeps one column, the game first, with the chat folded behind an unread count while a game is on. One chat panel spans both phases by staying in the same place in the markup — a remounted panel reopened having read nothing, and handed the reader the lobby's conversation back as unread mail. The room also keeps the score of the series. PlayerSlot carries the games a seat has won since the room opened, credited before the lobby is broadcast so the players see it the moment a game ends, and shown in the lobby and beside each player's score on the board. It belongs to the seat rather than to the room, because vacating one is exactly when the name on it stops meaning the same person. The conversation reads as a log — one line per message, "name: text", each seat in its own colour — rather than as a stack of bubbles, which stops being legible once four people are talking. ChatMessage carries the seat that spoke, so a line is coloured by what the server said rather than by matching display names, and a line whose seat has been vacated is in nobody's colour. The board's word button gets a test id of its own: it and the chat's send button both read "Gửi", and the two are now on screen together.
This commit is contained in:
1 parent
4e2e9e1433
commit
e19b083dc0
24 files changed
+521
-104
No files matched your search
@@ -317,6 +317,7 @@ function seat(fields = {}) {
|
||||
isOwner: false,
|
||||
ready: false,
|
||||
connected: true,
|
||||
wins: 0,
|
||||
...fields
|
||||
};
|
||||
}
|
||||
@@ -372,6 +373,37 @@ describe('room messages', () => {
|
||||
store.apply(pair());
|
||||
expect(store.freeSeats).toBe(2);
|
||||
});
|
||||
|
||||
it('reads the series score off the room, not off the game', () => {
|
||||
const store = createGameStore();
|
||||
store.apply(
|
||||
pair({
|
||||
players: [
|
||||
seat({ playerId: 'p1', name: 'Chủ', isOwner: true, wins: 2 }),
|
||||
seat({ playerId: 'p2', name: 'Lan', isMe: true, wins: 1 })
|
||||
]
|
||||
})
|
||||
);
|
||||
|
||||
expect(store.winsOf('p1')).toBe(2);
|
||||
expect(store.winsOf('p2')).toBe(1);
|
||||
// A game starting clears the board and keeps the room, tally included.
|
||||
store.apply(started());
|
||||
expect(store.winsOf('p1')).toBe(2);
|
||||
// Nobody the room does not seat has a tally.
|
||||
expect(store.winsOf('bot')).toBe(0);
|
||||
});
|
||||
|
||||
it('numbers the seats, which is what a chat line is coloured by', () => {
|
||||
const store = createGameStore();
|
||||
store.apply(pair());
|
||||
|
||||
expect(store.seatIndexOf('p1')).toBe(1);
|
||||
expect(store.seatIndexOf('p2')).toBe(2);
|
||||
// A line whose seat the server cleared belongs to nobody.
|
||||
expect(store.seatIndexOf('')).toBe(0);
|
||||
expect(store.seatIndexOf('p9')).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('pong', () => {
|
||||
@@ -389,6 +421,7 @@ describe('chat', () => {
|
||||
function line(fields) {
|
||||
return msg('chatMessage', {
|
||||
fromMe: false,
|
||||
playerId: 'p2',
|
||||
author: 'Lan',
|
||||
text: 'chào',
|
||||
sentUnixMs: 1756998000123n,
|
||||
@@ -406,6 +439,15 @@ describe('chat', () => {
|
||||
expect(store.state.chat[0].atMs).toBe(1756998000123);
|
||||
});
|
||||
|
||||
it('keeps the seat a line came from, which is what colours it', () => {
|
||||
const store = createGameStore();
|
||||
store.apply(line({ text: 'của tôi', fromMe: true, playerId: 'p1' }));
|
||||
// An author the server cleared: the seat goes with the name.
|
||||
store.apply(line({ text: 'của ai', playerId: '', author: '' }));
|
||||
|
||||
expect(store.state.chat.map((/** @type {any} */ m) => m.playerId)).toEqual(['p1', '']);
|
||||
});
|
||||
|
||||
it('stops at the window the server keeps, so the two cannot disagree', () => {
|
||||
const store = createGameStore();
|
||||
for (let i = 0; i < CHAT_WINDOW + 5; i++) {
|
||||
|
||||
Reference in new issue
Block a user