valtech-components 4.0.490 → 4.0.492

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.
@@ -2,5 +2,5 @@
2
2
  * Current version of valtech-components.
3
3
  * This is automatically updated during the publish process.
4
4
  */
5
- export const VERSION = '4.0.490';
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDdXJyZW50IHZlcnNpb24gb2YgdmFsdGVjaC1jb21wb25lbnRzLlxuICogVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQgZHVyaW5nIHRoZSBwdWJsaXNoIHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gJzQuMC40OTAnO1xuIl19
5
+ export const VERSION = '4.0.492';
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDdXJyZW50IHZlcnNpb24gb2YgdmFsdGVjaC1jb21wb25lbnRzLlxuICogVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQgZHVyaW5nIHRoZSBwdWJsaXNoIHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gJzQuMC40OTInO1xuIl19
@@ -59,7 +59,7 @@ import fixWebmDuration from 'fix-webm-duration';
59
59
  * Current version of valtech-components.
60
60
  * This is automatically updated during the publish process.
61
61
  */
62
- const VERSION = '4.0.490';
62
+ const VERSION = '4.0.492';
63
63
 
64
64
  // Control de estado de refresco (singleton a nivel de módulo)
65
65
  let isRefreshing = false;
@@ -62551,30 +62551,33 @@ class ChessimalsChallengeProgressService {
62551
62551
  const uid = this.currentUid;
62552
62552
  if (!uid)
62553
62553
  return of(this.readLocalActiveRun());
62554
- const activeQuery = query$1(collection(this.firestore, this.runsPath(uid)), where('status', '==', 'active'), limit(1));
62554
+ const activeQuery = query$1(collection(this.firestore, this.runsPath(uid)), where('status', '==', 'active'));
62555
62555
  return new Observable((subscriber) => {
62556
62556
  subscriber.next(this.readLocalActiveRun());
62557
62557
  const unsubscribe = onSnapshot(activeQuery, (snapshot) => {
62558
- const run = snapshot.docs[0]?.data();
62559
- this.writeLocalActiveRun(run);
62560
- subscriber.next(run);
62558
+ const remoteRun = snapshot.docs
62559
+ .map((item) => item.data())
62560
+ .reduce((best, run) => this.newestActiveRun(best, run), undefined);
62561
+ const next = this.newestActiveRun(this.readLocalActiveRun(uid), remoteRun);
62562
+ this.writeLocalActiveRun(next);
62563
+ subscriber.next(next);
62561
62564
  }, () => subscriber.next(this.readLocalActiveRun()));
62562
62565
  return unsubscribe;
62563
62566
  });
62564
62567
  }
62565
62568
  async saveRun(run) {
62566
- this.writeLocalActiveRun(run.status === 'active' ? run : undefined);
62567
62569
  const uid = await this.ensureUser();
62570
+ const ownedRun = { ...run, userId: uid };
62571
+ this.writeLocalActiveRun(ownedRun.status === 'active' ? ownedRun : undefined, uid);
62568
62572
  await setDoc(this.runRef(uid, run.id), this.withoutUndefined({
62569
- ...run,
62570
- userId: uid,
62573
+ ...ownedRun,
62571
62574
  updatedAt: new Date().toISOString(),
62572
62575
  updatedAtServer: serverTimestamp(),
62573
62576
  }), { merge: true });
62574
62577
  }
62575
62578
  async recordChallengeStarted(run) {
62576
- this.writeLocalActiveRun(run);
62577
62579
  const uid = await this.ensureUser();
62580
+ this.writeLocalActiveRun({ ...run, userId: uid }, uid);
62578
62581
  const current = await this.readStats(uid);
62579
62582
  await setDoc(this.statsRef(uid), {
62580
62583
  ...current,
@@ -62720,30 +62723,57 @@ class ChessimalsChallengeProgressService {
62720
62723
  runsPath(uid) {
62721
62724
  return `users/${uid}/miniGames/chessimals/challengeRuns`;
62722
62725
  }
62723
- readLocalActiveRun() {
62726
+ readLocalActiveRun(uid = this.currentUid) {
62727
+ if (!uid)
62728
+ return undefined;
62724
62729
  try {
62725
- const raw = localStorage.getItem(LOCAL_ACTIVE_RUN_KEY);
62730
+ const raw = localStorage.getItem(this.localActiveRunKey(uid));
62726
62731
  if (!raw)
62727
62732
  return undefined;
62728
62733
  const run = JSON.parse(raw);
62729
- return run.status === 'active' ? run : undefined;
62734
+ return run.status === 'active' && (!run.userId || run.userId === uid) ? run : undefined;
62730
62735
  }
62731
62736
  catch {
62732
62737
  return undefined;
62733
62738
  }
62734
62739
  }
62735
- writeLocalActiveRun(run) {
62740
+ writeLocalActiveRun(run, uid = this.currentUid) {
62741
+ if (!uid)
62742
+ return;
62736
62743
  try {
62737
62744
  if (run?.status === 'active') {
62738
- localStorage.setItem(LOCAL_ACTIVE_RUN_KEY, JSON.stringify(run));
62745
+ localStorage.setItem(this.localActiveRunKey(uid), JSON.stringify({ ...run, userId: uid }));
62739
62746
  return;
62740
62747
  }
62741
- localStorage.removeItem(LOCAL_ACTIVE_RUN_KEY);
62748
+ localStorage.removeItem(this.localActiveRunKey(uid));
62742
62749
  }
62743
62750
  catch {
62744
62751
  // Local persistence is only a refresh fallback.
62745
62752
  }
62746
62753
  }
62754
+ localActiveRunKey(uid) {
62755
+ return `${LOCAL_ACTIVE_RUN_KEY}.${uid}`;
62756
+ }
62757
+ newestActiveRun(local, remote) {
62758
+ if (local?.status !== 'active')
62759
+ return remote?.status === 'active' ? remote : undefined;
62760
+ if (remote?.status !== 'active')
62761
+ return local;
62762
+ if (local.id !== remote.id)
62763
+ return this.runTime(local) >= this.runTime(remote) ? local : remote;
62764
+ if (this.runProgressScore(local) > this.runProgressScore(remote))
62765
+ return local;
62766
+ if (this.runProgressScore(remote) > this.runProgressScore(local))
62767
+ return remote;
62768
+ return this.runTime(local) >= this.runTime(remote) ? local : remote;
62769
+ }
62770
+ runProgressScore(run) {
62771
+ return run.currentRound * 100 + run.wins * 10 - run.losses;
62772
+ }
62773
+ runTime(run) {
62774
+ const value = Date.parse(run.updatedAt);
62775
+ return Number.isFinite(value) ? value : 0;
62776
+ }
62747
62777
  withoutUndefined(value) {
62748
62778
  return Object.entries(value).reduce((acc, [key, entry]) => {
62749
62779
  if (entry !== undefined)
@@ -63261,6 +63291,38 @@ const MINI_GAMES_I18N = {
63261
63291
  chessimalsChallengeVoiceWonBody: '{bot} ajusta su plan. El siguiente rival no va a regalar diagonales.',
63262
63292
  chessimalsChallengeVoiceLostTitle: 'Te ganó el pulso',
63263
63293
  chessimalsChallengeVoiceLostBody: '{bot} se queda enfrente. La revancha pide una captura más limpia.',
63294
+ chessimalsChallengeVoiceWonSproutTitle: 'Encontraste el sendero',
63295
+ chessimalsChallengeVoiceWonSproutBody: '{bot} sonríe bajito. Ya no te va a dejar tanto aire por los bordes.',
63296
+ chessimalsChallengeVoiceLostSproutTitle: 'Te dejó respirar de más',
63297
+ chessimalsChallengeVoiceLostSproutBody: '{bot} probó una ruta simple y bastó. La revancha empieza cerrando el centro.',
63298
+ chessimalsChallengeVoiceWonSentinelTitle: 'Rompiste el muro',
63299
+ chessimalsChallengeVoiceWonSentinelBody: '{bot} aprieta el escudo. El próximo bloqueo va a llegar antes.',
63300
+ chessimalsChallengeVoiceLostSentinelTitle: 'El muro aguantó',
63301
+ chessimalsChallengeVoiceLostSentinelBody: '{bot} te frenó sin prisa. Necesitas cambiar el ritmo antes de chocar.',
63302
+ chessimalsChallengeVoiceWonHunterTitle: 'Le negaste la presa',
63303
+ chessimalsChallengeVoiceWonHunterBody: '{bot} guarda el blanco. La próxima diagonal tendrá trampa.',
63304
+ chessimalsChallengeVoiceLostHunterTitle: 'Cayó la trampa',
63305
+ chessimalsChallengeVoiceLostHunterBody: '{bot} encontró captura limpia. Mira dos diagonales antes de avanzar.',
63306
+ chessimalsChallengeVoiceWonJumperTitle: 'Le cortaste el salto',
63307
+ chessimalsChallengeVoiceWonJumperBody: '{bot} cambia de pata. Sus poderes van a buscar huecos raros.',
63308
+ chessimalsChallengeVoiceLostJumperTitle: 'Saltó donde dolía',
63309
+ chessimalsChallengeVoiceLostJumperBody: '{bot} abrió una ruta torcida. La revancha pide cubrir las casillas largas.',
63310
+ chessimalsChallengeVoiceWonPredatorTitle: 'Domaste el rugido',
63311
+ chessimalsChallengeVoiceWonPredatorBody: '{bot} retrocede un paso. Ahora va a forzar capturas con menos aviso.',
63312
+ chessimalsChallengeVoiceLostPredatorTitle: 'Te cazó el avance',
63313
+ chessimalsChallengeVoiceLostPredatorBody: '{bot} olió el peón suelto. No le regales piezas aisladas.',
63314
+ chessimalsChallengeVoiceWonOracleTitle: 'Le rompiste el cálculo',
63315
+ chessimalsChallengeVoiceWonOracleBody: '{bot} recalcula en silencio. La siguiente línea va a pelear el centro.',
63316
+ chessimalsChallengeVoiceLostOracleTitle: 'Vio la línea antes',
63317
+ chessimalsChallengeVoiceLostOracleBody: '{bot} leyó tu plan. Varía el primer avance y no repitas diagonales.',
63318
+ chessimalsChallengeVoiceWonSprinterTitle: 'Le ganaste la carrera',
63319
+ chessimalsChallengeVoiceWonSprinterBody: '{bot} mira la fila final. Desde ahora cada tempo cuenta doble.',
63320
+ chessimalsChallengeVoiceLostSprinterTitle: 'Llegó medio paso antes',
63321
+ chessimalsChallengeVoiceLostSprinterBody: '{bot} aceleró sin mirar atrás. Bloquea sus peones antes de perseguir.',
63322
+ chessimalsChallengeVoiceWonChampionTitle: 'El trono crujió',
63323
+ chessimalsChallengeVoiceWonChampionBody: '{bot} inclina la corona. Nadie cruza la última fila por accidente.',
63324
+ chessimalsChallengeVoiceLostChampionTitle: 'La corona pesó',
63325
+ chessimalsChallengeVoiceLostChampionBody: '{bot} cerró la mesa. Para tumbarlo necesitas paciencia y una captura decisiva.',
63264
63326
  chessimalsChallengeVoiceCompletedTitle: 'Ruta domada',
63265
63327
  chessimalsChallengeVoiceCompletedBody: '{bot} cae y la mesa queda tuya. Desafío completo.',
63266
63328
  chessimalsChallengeVoiceFailedTitle: 'La ruta se cerró',
@@ -63919,6 +63981,38 @@ const MINI_GAMES_I18N = {
63919
63981
  chessimalsChallengeVoiceWonBody: '{bot} adjusts their plan. The next rival will not give away diagonals.',
63920
63982
  chessimalsChallengeVoiceLostTitle: 'They won the pulse',
63921
63983
  chessimalsChallengeVoiceLostBody: '{bot} stays across the board. The rematch asks for a cleaner capture.',
63984
+ chessimalsChallengeVoiceWonSproutTitle: 'You found the path',
63985
+ chessimalsChallengeVoiceWonSproutBody: '{bot} gives a small grin. The edges will not stay that open.',
63986
+ chessimalsChallengeVoiceLostSproutTitle: 'They let you breathe too long',
63987
+ chessimalsChallengeVoiceLostSproutBody: '{bot} tried a simple route and it was enough. Start the rematch by closing the center.',
63988
+ chessimalsChallengeVoiceWonSentinelTitle: 'You broke the wall',
63989
+ chessimalsChallengeVoiceWonSentinelBody: '{bot} tightens the shield. The next block will arrive sooner.',
63990
+ chessimalsChallengeVoiceLostSentinelTitle: 'The wall held',
63991
+ chessimalsChallengeVoiceLostSentinelBody: '{bot} stopped you without rushing. Change the rhythm before you crash again.',
63992
+ chessimalsChallengeVoiceWonHunterTitle: 'You denied the prey',
63993
+ chessimalsChallengeVoiceWonHunterBody: '{bot} keeps the target in mind. The next diagonal will be baited.',
63994
+ chessimalsChallengeVoiceLostHunterTitle: 'The trap landed',
63995
+ chessimalsChallengeVoiceLostHunterBody: '{bot} found a clean capture. Read two diagonals before stepping forward.',
63996
+ chessimalsChallengeVoiceWonJumperTitle: 'You cut the leap',
63997
+ chessimalsChallengeVoiceWonJumperBody: '{bot} changes footing. Their powers will hunt for strange gaps.',
63998
+ chessimalsChallengeVoiceLostJumperTitle: 'They jumped where it hurt',
63999
+ chessimalsChallengeVoiceLostJumperBody: '{bot} opened a crooked route. Cover the long squares in the rematch.',
64000
+ chessimalsChallengeVoiceWonPredatorTitle: 'You tamed the roar',
64001
+ chessimalsChallengeVoiceWonPredatorBody: '{bot} steps back. Now the captures will come with less warning.',
64002
+ chessimalsChallengeVoiceLostPredatorTitle: 'They hunted your advance',
64003
+ chessimalsChallengeVoiceLostPredatorBody: '{bot} smelled the loose pawn. Do not leave isolated pieces behind.',
64004
+ chessimalsChallengeVoiceWonOracleTitle: 'You broke the calculation',
64005
+ chessimalsChallengeVoiceWonOracleBody: '{bot} recalculates in silence. The next line will fight for the center.',
64006
+ chessimalsChallengeVoiceLostOracleTitle: 'They saw the line first',
64007
+ chessimalsChallengeVoiceLostOracleBody: '{bot} read your plan. Vary the first step and do not repeat diagonals.',
64008
+ chessimalsChallengeVoiceWonSprinterTitle: 'You won the race',
64009
+ chessimalsChallengeVoiceWonSprinterBody: '{bot} looks at the back row. Every tempo counts double now.',
64010
+ chessimalsChallengeVoiceLostSprinterTitle: 'They arrived half a step early',
64011
+ chessimalsChallengeVoiceLostSprinterBody: '{bot} accelerated without looking back. Block their pawns before chasing.',
64012
+ chessimalsChallengeVoiceWonChampionTitle: 'The throne cracked',
64013
+ chessimalsChallengeVoiceWonChampionBody: '{bot} tips the crown. Nobody crosses the back row by accident.',
64014
+ chessimalsChallengeVoiceLostChampionTitle: 'The crown was heavy',
64015
+ chessimalsChallengeVoiceLostChampionBody: '{bot} closed the table. To topple them, you need patience and one decisive capture.',
63922
64016
  chessimalsChallengeVoiceCompletedTitle: 'Route cleared',
63923
64017
  chessimalsChallengeVoiceCompletedBody: '{bot} falls and the table is yours. Challenge complete.',
63924
64018
  chessimalsChallengeVoiceFailedTitle: 'The route closed',
@@ -65891,6 +65985,7 @@ class ChessimalsGameComponent {
65891
65985
  updatedAt: now,
65892
65986
  };
65893
65987
  this.challengeRun.set(run);
65988
+ this.activeStoredChallengeRun.set(run);
65894
65989
  this.challengeLastWon.set(undefined);
65895
65990
  this.challengeLastBot.set(undefined);
65896
65991
  this.challengeLastRoundStats.set(undefined);
@@ -66064,6 +66159,7 @@ class ChessimalsGameComponent {
66064
66159
  updatedAt: now,
66065
66160
  finishedAt: now,
66066
66161
  };
66162
+ this.activeStoredChallengeRun.set(undefined);
66067
66163
  void this.challengeProgress.saveRun(nextRun).catch((error) => {
66068
66164
  console.warn('[Chessimals] challenge abandon save failed', error);
66069
66165
  });
@@ -67590,6 +67686,11 @@ class ChessimalsGameComponent {
67590
67686
  return this.t('chessimalsChallengeVoiceCompletedTitle');
67591
67687
  if (phase === 'failed')
67592
67688
  return this.t('chessimalsChallengeVoiceFailedTitle');
67689
+ const bot = this.challengeLastBot() ?? this.activeChallengeBot();
67690
+ const result = this.challengeLastWon() ? 'Won' : 'Lost';
67691
+ const botTitle = this.challengeVoiceText(bot, result, 'Title');
67692
+ if (botTitle)
67693
+ return botTitle;
67593
67694
  return this.challengeLastWon()
67594
67695
  ? this.t('chessimalsChallengeVoiceWonTitle')
67595
67696
  : this.t('chessimalsChallengeVoiceLostTitle');
@@ -67597,6 +67698,10 @@ class ChessimalsGameComponent {
67597
67698
  challengeRivalVoiceBody() {
67598
67699
  const bot = this.challengeLastBot() ?? this.activeChallengeBot();
67599
67700
  const botName = bot ? this.challengeBotName(bot) : this.t('chessimalsBotName');
67701
+ const result = this.challengeLastWon() ? 'Won' : 'Lost';
67702
+ const botBody = this.challengeVoiceText(bot, result, 'Body');
67703
+ if (botBody)
67704
+ return botBody.replace('{bot}', botName);
67600
67705
  const key = this.challengePhase() === 'completed'
67601
67706
  ? 'chessimalsChallengeVoiceCompletedBody'
67602
67707
  : this.challengePhase() === 'failed'
@@ -67606,6 +67711,13 @@ class ChessimalsGameComponent {
67606
67711
  : 'chessimalsChallengeVoiceLostBody';
67607
67712
  return this.t(key).replace('{bot}', botName);
67608
67713
  }
67714
+ challengeVoiceText(bot, result, part) {
67715
+ if (!bot)
67716
+ return undefined;
67717
+ const key = `chessimalsChallengeVoice${result}${this.capitalize(bot.id)}${part}`;
67718
+ const text = this.t(key);
67719
+ return text === key ? undefined : text;
67720
+ }
67609
67721
  challengeNextRivalLabel() {
67610
67722
  return this.challengeLastWon()
67611
67723
  ? this.t('chessimalsChallengeNextRivalLabel')