(offerId, { onStep } = {})
| 336 | return Boolean(activeWatchPromise); |
| 337 | }, |
| 338 | async watchOffer(offerId, { onStep } = {}) { |
| 339 | if (activeWatchPromise) { |
| 340 | return activeWatchPromise; |
| 341 | } |
| 342 | |
| 343 | const offer = OFFERS.find((item) => item.id === offerId); |
| 344 | if (!offer) { |
| 345 | throw new Error("Reward offer not found."); |
| 346 | } |
| 347 | if (!this.isRewardedSupported()) { |
| 348 | throw new Error(this.getRewardedUnavailableReason()); |
| 349 | } |
| 350 | |
| 351 | await refreshState({ notifyExpiry: false }); |
| 352 | const redemptionStatus = this.canRedeemNow(); |
| 353 | if (!redemptionStatus.ok) { |
| 354 | throw new Error(redemptionStatus.reason); |
| 355 | } |
| 356 | |
| 357 | const sessionId = |
| 358 | typeof crypto?.randomUUID === "function" |
| 359 | ? crypto.randomUUID() |
| 360 | : `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`; |
| 361 | |
| 362 | activeWatchPromise = (async () => { |
| 363 | for (let step = 1; step <= offer.adsRequired; step += 1) { |
| 364 | onStep?.({ |
| 365 | step, |
| 366 | totalSteps: offer.adsRequired, |
| 367 | offer, |
| 368 | }); |
| 369 | await showRewardedStep(offer, step, sessionId); |
| 370 | |
| 371 | if (step < offer.adsRequired) { |
| 372 | toast( |
| 373 | `Reward ${step}/${offer.adsRequired} complete. Loading the next ad...`, |
| 374 | 2500, |
| 375 | ); |
| 376 | } |
| 377 | } |
| 378 | |
| 379 | const redeemedState = normalizeStatus( |
| 380 | await secureAdRewardState.redeem(offer.id), |
| 381 | ); |
| 382 | const grantedDurationMs = |
| 383 | Number(redeemedState.appliedDurationMs) || |
| 384 | Number(redeemedState.grantedDurationMs) || |
| 385 | 0; |
| 386 | |
| 387 | state = redeemedState; |
| 388 | emitChange(); |
| 389 | hideActiveBanner(); |
| 390 | scheduleExpiryCheck(); |
| 391 | |
| 392 | notify( |
| 393 | "Ad-free pass started", |
| 394 | `${formatDuration(grantedDurationMs)} unlocked. Ads will stay hidden until ${new Date(redeemedState.adFreeUntil).toLocaleString()}.`, |
| 395 | "success", |
nothing calls this directly
no test coverage detected