valtech-components 4.0.395 → 4.0.397
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/components/organisms/mini-games/chessimals-game.component.mjs +51 -18
- package/esm2022/lib/components/organisms/mini-games/chessimals-online.service.mjs +145 -22
- package/esm2022/lib/components/organisms/mini-games/types.mjs +1 -1
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +194 -39
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/mini-games/chessimals-game.component.d.ts +4 -0
- package/lib/components/organisms/mini-games/chessimals-online.service.d.ts +14 -1
- package/lib/components/organisms/mini-games/types.d.ts +7 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -58,7 +58,7 @@ import fixWebmDuration from 'fix-webm-duration';
|
|
|
58
58
|
* Current version of valtech-components.
|
|
59
59
|
* This is automatically updated during the publish process.
|
|
60
60
|
*/
|
|
61
|
-
const VERSION = '4.0.
|
|
61
|
+
const VERSION = '4.0.397';
|
|
62
62
|
|
|
63
63
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
64
64
|
let isRefreshing = false;
|
|
@@ -61587,13 +61587,14 @@ const COLLECTION_PATH = 'miniGames/chessimals/games';
|
|
|
61587
61587
|
const GAME_TTL_MS = 24 * 60 * 60 * 1000;
|
|
61588
61588
|
class ChessimalsOnlineService {
|
|
61589
61589
|
constructor() {
|
|
61590
|
-
this.
|
|
61590
|
+
this.firebaseAuth = inject(Auth);
|
|
61591
|
+
this.auth = inject(AuthService);
|
|
61591
61592
|
this.firestore = inject(Firestore);
|
|
61592
61593
|
this.firebase = inject(FirebaseService);
|
|
61593
61594
|
this.profiles = inject(MiniGamePlayerProfileService);
|
|
61594
61595
|
}
|
|
61595
61596
|
get currentUid() {
|
|
61596
|
-
return this.
|
|
61597
|
+
return this.firebaseAuth.currentUser?.uid;
|
|
61597
61598
|
}
|
|
61598
61599
|
normalizeGameId(value) {
|
|
61599
61600
|
const raw = (value ?? '').trim().toUpperCase();
|
|
@@ -61663,11 +61664,11 @@ class ChessimalsOnlineService {
|
|
|
61663
61664
|
this.assertNotExpired(state);
|
|
61664
61665
|
if (this.isParticipant(state, uid))
|
|
61665
61666
|
return;
|
|
61666
|
-
if (
|
|
61667
|
+
if (this.isHostWaiting(state, uid))
|
|
61667
61668
|
return;
|
|
61668
61669
|
if (state.status !== 'waiting' || !state.online?.lobby)
|
|
61669
61670
|
return;
|
|
61670
|
-
if (state
|
|
61671
|
+
if (this.isPendingGuest(state, uid))
|
|
61671
61672
|
return;
|
|
61672
61673
|
const now = new Date();
|
|
61673
61674
|
const guest = this.createParticipant(uid, now.toISOString());
|
|
@@ -61692,7 +61693,7 @@ class ChessimalsOnlineService {
|
|
|
61692
61693
|
throw new Error('CHESSIMALS_GAME_NOT_FOUND');
|
|
61693
61694
|
const state = snapshot.data();
|
|
61694
61695
|
this.assertNotExpired(state);
|
|
61695
|
-
if (
|
|
61696
|
+
if (!this.isHostWaiting(state, uid) || !state.online.pendingGuest)
|
|
61696
61697
|
return;
|
|
61697
61698
|
const now = new Date();
|
|
61698
61699
|
const [hostSide, guestSide] = Math.random() > 0.5 ? ['white', 'black'] : ['black', 'white'];
|
|
@@ -61728,7 +61729,7 @@ class ChessimalsOnlineService {
|
|
|
61728
61729
|
throw new Error('CHESSIMALS_GAME_NOT_FOUND');
|
|
61729
61730
|
const state = snapshot.data();
|
|
61730
61731
|
this.assertNotExpired(state);
|
|
61731
|
-
if (
|
|
61732
|
+
if (!this.isHostWaiting(state, uid) || !state.online.pendingGuest)
|
|
61732
61733
|
return;
|
|
61733
61734
|
const now = new Date();
|
|
61734
61735
|
const online = { ...state.online, updatedAt: now.toISOString() };
|
|
@@ -61830,8 +61831,12 @@ class ChessimalsOnlineService {
|
|
|
61830
61831
|
const participants = state.online?.participants;
|
|
61831
61832
|
if (!participants?.white || !participants.black || !state.online)
|
|
61832
61833
|
return;
|
|
61833
|
-
const
|
|
61834
|
-
const
|
|
61834
|
+
const currentParticipant = this.participantForSide(state, this.participantSide(state, uid));
|
|
61835
|
+
const requestKey = this.participantKey(currentParticipant);
|
|
61836
|
+
if (!requestKey)
|
|
61837
|
+
return;
|
|
61838
|
+
const requests = Array.from(new Set([...(state.online.rematchRequests ?? []), requestKey]));
|
|
61839
|
+
const bothReady = [participants.white, participants.black].every((item) => this.participantRequestKeys(item).some((key) => requests.includes(key)));
|
|
61835
61840
|
const now = new Date();
|
|
61836
61841
|
if (!bothReady) {
|
|
61837
61842
|
transaction.set(ref, {
|
|
@@ -61862,20 +61867,62 @@ class ChessimalsOnlineService {
|
|
|
61862
61867
|
});
|
|
61863
61868
|
}
|
|
61864
61869
|
participantSide(state, uid = this.currentUid) {
|
|
61865
|
-
|
|
61866
|
-
|
|
61867
|
-
|
|
61868
|
-
|
|
61869
|
-
|
|
61870
|
-
|
|
61871
|
-
|
|
61870
|
+
const entries = this.participantEntries(state);
|
|
61871
|
+
const currentSeatKey = this.currentSeatKey(uid);
|
|
61872
|
+
if (currentSeatKey) {
|
|
61873
|
+
const seatMatch = entries.find(([, participant]) => this.participantKey(participant) === currentSeatKey);
|
|
61874
|
+
if (seatMatch)
|
|
61875
|
+
return seatMatch[0];
|
|
61876
|
+
}
|
|
61877
|
+
if (uid) {
|
|
61878
|
+
const currentProfile = this.profiles.activeProfile();
|
|
61879
|
+
if (currentProfile) {
|
|
61880
|
+
const legacyProfileMatch = entries.find(([, participant]) => participant.uid === uid
|
|
61881
|
+
&& participant.avatar === currentProfile.avatar
|
|
61882
|
+
&& this.normalizeColor(participant.color) === this.normalizeColor(currentProfile.color));
|
|
61883
|
+
if (legacyProfileMatch)
|
|
61884
|
+
return legacyProfileMatch[0];
|
|
61885
|
+
}
|
|
61886
|
+
const uidMatches = entries.filter(([, participant]) => participant.uid === uid);
|
|
61887
|
+
if (uidMatches.length === 1)
|
|
61888
|
+
return uidMatches[0][0];
|
|
61889
|
+
}
|
|
61890
|
+
const accountUserId = this.auth.user()?.userId;
|
|
61891
|
+
if (accountUserId) {
|
|
61892
|
+
const accountMatches = entries.filter(([, participant]) => participant.accountUserId === accountUserId);
|
|
61893
|
+
if (accountMatches.length === 1)
|
|
61894
|
+
return accountMatches[0][0];
|
|
61895
|
+
}
|
|
61872
61896
|
return undefined;
|
|
61873
61897
|
}
|
|
61874
61898
|
isParticipant(state, uid = this.currentUid) {
|
|
61875
61899
|
return !!this.participantSide(state, uid);
|
|
61876
61900
|
}
|
|
61877
61901
|
isHostWaiting(state, uid = this.currentUid) {
|
|
61878
|
-
return
|
|
61902
|
+
return state.status === 'waiting' && this.matchesCurrentParticipant(state.online?.lobby, uid);
|
|
61903
|
+
}
|
|
61904
|
+
isPendingGuest(state, uid = this.currentUid) {
|
|
61905
|
+
return state.status === 'waiting' && this.matchesCurrentParticipant(state.online?.pendingGuest, uid);
|
|
61906
|
+
}
|
|
61907
|
+
hasCurrentRematchRequest(state, uid = this.currentUid) {
|
|
61908
|
+
const side = this.participantSide(state, uid);
|
|
61909
|
+
const participant = this.participantForSide(state, side);
|
|
61910
|
+
return this.participantRequestKeys(participant).some((key) => (state.online?.rematchRequests ?? []).includes(key));
|
|
61911
|
+
}
|
|
61912
|
+
hasOpponentRematchRequest(state, uid = this.currentUid) {
|
|
61913
|
+
const side = this.participantSide(state, uid);
|
|
61914
|
+
if (!side)
|
|
61915
|
+
return false;
|
|
61916
|
+
const opponent = this.participantForSide(state, side === 'white' ? 'black' : 'white');
|
|
61917
|
+
return this.participantRequestKeys(opponent).some((key) => (state.online?.rematchRequests ?? []).includes(key));
|
|
61918
|
+
}
|
|
61919
|
+
participantKey(participant) {
|
|
61920
|
+
return participant?.seatKey
|
|
61921
|
+
|| this.buildSeatKey(participant?.uid, participant?.profileId)
|
|
61922
|
+
|| participant?.profileId
|
|
61923
|
+
|| participant?.accountUserId
|
|
61924
|
+
|| participant?.uid
|
|
61925
|
+
|| '';
|
|
61879
61926
|
}
|
|
61880
61927
|
shareUrl(gameId, baseRoute = '/mini-games') {
|
|
61881
61928
|
const origin = typeof window === 'undefined' ? '' : window.location.origin;
|
|
@@ -61905,7 +61952,7 @@ class ChessimalsOnlineService {
|
|
|
61905
61952
|
}
|
|
61906
61953
|
async ensureUser() {
|
|
61907
61954
|
await this.firebase.whenFirebaseAuthReady();
|
|
61908
|
-
const user = this.
|
|
61955
|
+
const user = this.firebaseAuth.currentUser;
|
|
61909
61956
|
if (user?.uid) {
|
|
61910
61957
|
await user.getIdToken();
|
|
61911
61958
|
return user.uid;
|
|
@@ -61921,16 +61968,88 @@ class ChessimalsOnlineService {
|
|
|
61921
61968
|
}
|
|
61922
61969
|
}
|
|
61923
61970
|
createParticipant(uid, joinedAt) {
|
|
61971
|
+
const user = this.auth.user();
|
|
61972
|
+
const firebaseUser = this.firebaseAuth.currentUser;
|
|
61924
61973
|
const profile = this.profiles.activeProfile();
|
|
61974
|
+
const handle = this.normalizeHandle(user?.handle);
|
|
61975
|
+
const avatarUrl = user?.avatarUrl?.trim() || firebaseUser?.photoURL?.trim() || undefined;
|
|
61976
|
+
const email = user?.email?.trim() || firebaseUser?.email?.trim() || undefined;
|
|
61977
|
+
const profileId = profile?.id ?? user?.userId ?? uid;
|
|
61925
61978
|
return {
|
|
61926
61979
|
uid,
|
|
61927
|
-
|
|
61928
|
-
|
|
61980
|
+
accountUserId: user?.userId,
|
|
61981
|
+
profileId,
|
|
61982
|
+
seatKey: this.buildSeatKey(uid, profileId),
|
|
61983
|
+
name: user?.name?.trim()
|
|
61984
|
+
|| firebaseUser?.displayName?.trim()
|
|
61985
|
+
|| email
|
|
61986
|
+
|| this.profiles.displayName(profile, 'Jugador'),
|
|
61987
|
+
handle,
|
|
61988
|
+
email,
|
|
61929
61989
|
avatar: profile?.avatar ?? '♟️',
|
|
61990
|
+
avatarUrl,
|
|
61930
61991
|
color: profile?.color ?? '#ff00b2',
|
|
61931
61992
|
joinedAt,
|
|
61932
61993
|
};
|
|
61933
61994
|
}
|
|
61995
|
+
normalizeHandle(handle) {
|
|
61996
|
+
const trimmed = handle?.trim();
|
|
61997
|
+
if (!trimmed)
|
|
61998
|
+
return undefined;
|
|
61999
|
+
return trimmed.startsWith('@') ? trimmed : `@${trimmed}`;
|
|
62000
|
+
}
|
|
62001
|
+
buildSeatKey(uid, profileId) {
|
|
62002
|
+
const normalizedUid = uid?.trim();
|
|
62003
|
+
const normalizedProfileId = profileId?.trim();
|
|
62004
|
+
if (!normalizedUid || !normalizedProfileId)
|
|
62005
|
+
return undefined;
|
|
62006
|
+
return `${normalizedUid}:${normalizedProfileId}`;
|
|
62007
|
+
}
|
|
62008
|
+
currentSeatKey(uid = this.currentUid) {
|
|
62009
|
+
return this.buildSeatKey(uid, this.profiles.activeProfile()?.id);
|
|
62010
|
+
}
|
|
62011
|
+
participantForSide(state, side) {
|
|
62012
|
+
if (!side)
|
|
62013
|
+
return undefined;
|
|
62014
|
+
return state.online?.participants?.[side];
|
|
62015
|
+
}
|
|
62016
|
+
participantEntries(state) {
|
|
62017
|
+
const participants = state.online?.participants;
|
|
62018
|
+
return ['white', 'black']
|
|
62019
|
+
.map((side) => [side, participants?.[side]])
|
|
62020
|
+
.filter((entry) => !!entry[1]);
|
|
62021
|
+
}
|
|
62022
|
+
participantRequestKeys(participant) {
|
|
62023
|
+
if (!participant)
|
|
62024
|
+
return [];
|
|
62025
|
+
const keys = [
|
|
62026
|
+
this.participantKey(participant),
|
|
62027
|
+
participant.uid,
|
|
62028
|
+
participant.accountUserId,
|
|
62029
|
+
participant.profileId,
|
|
62030
|
+
];
|
|
62031
|
+
return Array.from(new Set(keys.filter((key) => !!key)));
|
|
62032
|
+
}
|
|
62033
|
+
matchesCurrentParticipant(participant, uid = this.currentUid) {
|
|
62034
|
+
if (!participant)
|
|
62035
|
+
return false;
|
|
62036
|
+
const seatKey = this.currentSeatKey(uid);
|
|
62037
|
+
if (seatKey && this.participantKey(participant) === seatKey)
|
|
62038
|
+
return true;
|
|
62039
|
+
const profile = this.profiles.activeProfile();
|
|
62040
|
+
if (uid && profile) {
|
|
62041
|
+
return participant.uid === uid
|
|
62042
|
+
&& participant.avatar === profile.avatar
|
|
62043
|
+
&& this.normalizeColor(participant.color) === this.normalizeColor(profile.color);
|
|
62044
|
+
}
|
|
62045
|
+
if (uid && participant.uid === uid)
|
|
62046
|
+
return true;
|
|
62047
|
+
const accountUserId = this.auth.user()?.userId;
|
|
62048
|
+
return !!accountUserId && participant.accountUserId === accountUserId;
|
|
62049
|
+
}
|
|
62050
|
+
normalizeColor(color) {
|
|
62051
|
+
return (color ?? '').trim().toLowerCase();
|
|
62052
|
+
}
|
|
61934
62053
|
withUpdatedAt(state, date = new Date()) {
|
|
61935
62054
|
if (!state.online)
|
|
61936
62055
|
return state;
|
|
@@ -61949,10 +62068,13 @@ class ChessimalsOnlineService {
|
|
|
61949
62068
|
};
|
|
61950
62069
|
}
|
|
61951
62070
|
createMoveLogEntry(args) {
|
|
62071
|
+
const participant = this.participantForSide(args.state, args.side);
|
|
61952
62072
|
return this.withoutUndefined({
|
|
61953
62073
|
id: args.id,
|
|
61954
62074
|
at: new Date().toISOString(),
|
|
61955
62075
|
uid: args.uid,
|
|
62076
|
+
profileId: participant?.profileId,
|
|
62077
|
+
seatKey: this.participantKey(participant) || undefined,
|
|
61956
62078
|
side: args.side,
|
|
61957
62079
|
status: args.status,
|
|
61958
62080
|
code: args.code,
|
|
@@ -61977,8 +62099,8 @@ class ChessimalsOnlineService {
|
|
|
61977
62099
|
if (!state.online)
|
|
61978
62100
|
return undefined;
|
|
61979
62101
|
const side = this.participantSide(state, uid);
|
|
61980
|
-
const isLobbyHost = state
|
|
61981
|
-
const isPendingGuest = state
|
|
62102
|
+
const isLobbyHost = this.isHostWaiting(state, uid);
|
|
62103
|
+
const isPendingGuest = this.isPendingGuest(state, uid);
|
|
61982
62104
|
if (!side && !isLobbyHost && !isPendingGuest)
|
|
61983
62105
|
return undefined;
|
|
61984
62106
|
const opponent = side
|
|
@@ -63172,7 +63294,7 @@ class ChessimalsGameComponent {
|
|
|
63172
63294
|
return 'spectator';
|
|
63173
63295
|
if (this.online.isHostWaiting(game, uid))
|
|
63174
63296
|
return 'waiting';
|
|
63175
|
-
if (
|
|
63297
|
+
if (this.online.isPendingGuest(game, uid))
|
|
63176
63298
|
return 'pending';
|
|
63177
63299
|
return this.online.participantSide(game, uid) ?? 'spectator';
|
|
63178
63300
|
});
|
|
@@ -63194,9 +63316,8 @@ class ChessimalsGameComponent {
|
|
|
63194
63316
|
const uid = this.onlineUid();
|
|
63195
63317
|
if (!uid || this.onlineRole() === 'spectator')
|
|
63196
63318
|
return 'none';
|
|
63197
|
-
const
|
|
63198
|
-
const
|
|
63199
|
-
const hasOther = requests.some((item) => item !== uid);
|
|
63319
|
+
const hasMine = this.online.hasCurrentRematchRequest(game, uid);
|
|
63320
|
+
const hasOther = this.online.hasOpponentRematchRequest(game, uid);
|
|
63200
63321
|
if (hasOther && !hasMine)
|
|
63201
63322
|
return 'incoming';
|
|
63202
63323
|
if (hasMine)
|
|
@@ -63918,13 +64039,33 @@ class ChessimalsGameComponent {
|
|
|
63918
64039
|
const uid = this.onlineUid();
|
|
63919
64040
|
return !!uid
|
|
63920
64041
|
&& game.mode === 'online'
|
|
63921
|
-
&& game
|
|
63922
|
-
&& game.online?.lobby?.uid === uid
|
|
64042
|
+
&& this.online.isHostWaiting(game, uid)
|
|
63923
64043
|
&& !!game.online.pendingGuest;
|
|
63924
64044
|
}
|
|
63925
64045
|
pendingGuestName() {
|
|
63926
64046
|
return this.game().online?.pendingGuest?.name ?? this.t('defaultPlayerName');
|
|
63927
64047
|
}
|
|
64048
|
+
pendingGuestHandle() {
|
|
64049
|
+
return this.game().online?.pendingGuest?.handle ?? '';
|
|
64050
|
+
}
|
|
64051
|
+
pendingGuestAvatar() {
|
|
64052
|
+
return this.game().online?.pendingGuest?.avatar ?? '♟️';
|
|
64053
|
+
}
|
|
64054
|
+
pendingGuestAvatarUrl() {
|
|
64055
|
+
return this.game().online?.pendingGuest?.avatarUrl ?? '';
|
|
64056
|
+
}
|
|
64057
|
+
pendingGuestAvatarProps() {
|
|
64058
|
+
const guest = this.game().online?.pendingGuest;
|
|
64059
|
+
return {
|
|
64060
|
+
user: {
|
|
64061
|
+
name: guest?.name,
|
|
64062
|
+
handle: guest?.handle,
|
|
64063
|
+
avatarUrl: guest?.avatarUrl,
|
|
64064
|
+
},
|
|
64065
|
+
size: 'small',
|
|
64066
|
+
bordered: true,
|
|
64067
|
+
};
|
|
64068
|
+
}
|
|
63928
64069
|
waitingTitle() {
|
|
63929
64070
|
if (this.canReviewPendingGuest())
|
|
63930
64071
|
return this.t('chessimalsJoinRequestTitle');
|
|
@@ -64079,12 +64220,12 @@ class ChessimalsGameComponent {
|
|
|
64079
64220
|
this.game.set(state);
|
|
64080
64221
|
this.selectedBoardSize.set(state.boardSize);
|
|
64081
64222
|
this.resumeSplashVisible.set(false);
|
|
64082
|
-
const
|
|
64083
|
-
const
|
|
64223
|
+
const previousPendingKey = previous.id === state.id ? this.online.participantKey(previous.online?.pendingGuest) : '';
|
|
64224
|
+
const nextPendingKey = this.online.participantKey(state.online?.pendingGuest);
|
|
64084
64225
|
if (state.status === 'waiting' &&
|
|
64085
|
-
|
|
64086
|
-
!!
|
|
64087
|
-
|
|
64226
|
+
this.online.isHostWaiting(state, this.online.currentUid) &&
|
|
64227
|
+
!!nextPendingKey &&
|
|
64228
|
+
nextPendingKey !== previousPendingKey) {
|
|
64088
64229
|
this.audio.chessimalsJoinRequest();
|
|
64089
64230
|
void this.haptics.success();
|
|
64090
64231
|
}
|
|
@@ -64312,12 +64453,19 @@ class ChessimalsGameComponent {
|
|
|
64312
64453
|
</div>
|
|
64313
64454
|
@if (canReviewPendingGuest()) {
|
|
64314
64455
|
<div class="chessimals-pending-player">
|
|
64315
|
-
|
|
64316
|
-
|
|
64317
|
-
|
|
64456
|
+
@if (pendingGuestAvatarUrl()) {
|
|
64457
|
+
<val-user-avatar [props]="pendingGuestAvatarProps()" />
|
|
64458
|
+
} @else {
|
|
64459
|
+
<span class="chessimals-player-strip__avatar" aria-hidden="true">
|
|
64460
|
+
{{ pendingGuestAvatar() }}
|
|
64461
|
+
</span>
|
|
64462
|
+
}
|
|
64318
64463
|
<div>
|
|
64319
64464
|
<small>{{ t('chessimalsJoinRequestPlayer') }}</small>
|
|
64320
64465
|
<strong>{{ pendingGuestName() }}</strong>
|
|
64466
|
+
@if (pendingGuestHandle()) {
|
|
64467
|
+
<small>{{ pendingGuestHandle() }}</small>
|
|
64468
|
+
}
|
|
64321
64469
|
</div>
|
|
64322
64470
|
</div>
|
|
64323
64471
|
}
|
|
@@ -64876,12 +65024,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
64876
65024
|
</div>
|
|
64877
65025
|
@if (canReviewPendingGuest()) {
|
|
64878
65026
|
<div class="chessimals-pending-player">
|
|
64879
|
-
|
|
64880
|
-
|
|
64881
|
-
|
|
65027
|
+
@if (pendingGuestAvatarUrl()) {
|
|
65028
|
+
<val-user-avatar [props]="pendingGuestAvatarProps()" />
|
|
65029
|
+
} @else {
|
|
65030
|
+
<span class="chessimals-player-strip__avatar" aria-hidden="true">
|
|
65031
|
+
{{ pendingGuestAvatar() }}
|
|
65032
|
+
</span>
|
|
65033
|
+
}
|
|
64882
65034
|
<div>
|
|
64883
65035
|
<small>{{ t('chessimalsJoinRequestPlayer') }}</small>
|
|
64884
65036
|
<strong>{{ pendingGuestName() }}</strong>
|
|
65037
|
+
@if (pendingGuestHandle()) {
|
|
65038
|
+
<small>{{ pendingGuestHandle() }}</small>
|
|
65039
|
+
}
|
|
64885
65040
|
</div>
|
|
64886
65041
|
</div>
|
|
64887
65042
|
}
|