Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "signal-range",
"version": "1.0.0",
"version": "1.0.1",
"description": "Signal Range: Space Electronic Warfare Lab",
"main": "dist/index.js",
"scripts": {
Expand Down
49 changes: 1 addition & 48 deletions src/pages/base-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,23 @@ import { BaseElement } from "@app/components/base-element";
import { EventBus } from "@app/events/event-bus";
import { DualTransmissionViolationData, Events, ObjectiveFailedData, ScenarioTimeExpiredData } from "@app/events/events";
import { Logger } from "@app/logging/logger";
import { Character } from "@app/modal/character-enum";
import { DialogHistoryManager } from "@app/modal/dialog-history-manager";
import { DialogManager } from "@app/modal/dialog-manager";
import { LevelCompleteModal } from "@app/modal/level-complete-modal";
import { ObjectiveFailedModal } from "@app/modal/objective-failed-modal";
import { QuizModal } from "@app/modal/quiz-modal";
import { TimePenaltyToast } from "@app/modal/time-penalty-toast";
import { ObjectivesManager } from "@app/objectives/objectives-manager";
import { NavigationOptions, Router } from "@app/router";
import { ScenarioManager } from "@app/scenario-manager";
import { ScenarioDialogManager } from "@app/scenarios/scenario-dialog-manager";
import { ScenarioCompletionHandler } from "@app/scoring/scenario-completion-handler";
import { ScoreCalculator } from "@app/scoring/score-calculator";
import { TimePenaltyToast } from "@app/modal/time-penalty-toast";
import { SimulationManager } from "@app/simulation/simulation-manager";
import { AppState } from "@app/sync/storage";
import { Auth } from "@app/user-account/auth";
import { ProgressSaveManager } from "@app/user-account/progress-save-manager";
import { ScenarioProgressEntry } from "@app/user-account/types";
import { getUserDataService } from "@app/user-account/user-data-service";
import { getAssetUrl } from "@app/utils/asset-url";

export abstract class BasePage extends BaseElement {
abstract id: string;
Expand Down Expand Up @@ -120,9 +117,6 @@ export abstract class BasePage extends BaseElement {
'Introduction',
introClip.emotion
);

// Schedule login prompt dialog to show 5 seconds after intro dialog is closed
this.scheduleLoginPrompt_();
}
}

Expand Down Expand Up @@ -195,47 +189,6 @@ export abstract class BasePage extends BaseElement {
}
}

/**
* Schedule login prompt dialog to show 5 seconds after the intro dialog is closed
*/
protected scheduleLoginPrompt_(): void {
// Check periodically if the intro dialog has been closed
const checkDialogClosed = setInterval(() => {
const dialogManager = DialogManager.getInstance();

if (!dialogManager.isShowing()) {
// Dialog is closed, clear the interval and schedule the login prompt
clearInterval(checkDialogClosed);

// Wait 5 seconds, then check if user is logged in
setTimeout(async () => {
const isLoggedIn = await Auth.isLoggedIn();

if (!isLoggedIn) {
// User is not logged in, show the login prompt dialog
dialogManager.show(
`
<p>
Hey, normally you make an account on the computer and log what you are doing.
</p>
<p>
If you want to keep your notes on your desk, that's up to you, but just know none of us will have any idea what you did today if you ask us tomorrow!
</p>

<p>
(You can make an account in the top right corner of the screen in order to save your progress automatically. It's free and only takes a minute!)
</p>
`,
Character.CHARLIE_BROOKS,
getAssetUrl('/assets/campaigns/login-first.mp3'),
'Login Reminder'
);
}
}, 5000);
}
}, 100); // Check every 100ms
}

/**
* Clean up progress save manager and completion handler.
* Call this in subclass destroy() methods.
Expand Down
31 changes: 31 additions & 0 deletions src/pages/campaign-selection.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,37 @@
text-transform: uppercase;
}

.login-warning {
display: flex;
align-items: center;
justify-content: center;
gap: 0.75rem;
margin-top: 1.25rem;
padding: 0.75rem 1.25rem;
background: linear-gradient(135deg, rgba(255, 152, 0, 0.15) 0%, rgba(255, 152, 0, 0.1) 100%);
border: 1px solid rgba(255, 152, 0, 0.4);
border-radius: 6px;
max-width: 700px;
}

.login-warning-icon {
font-size: 1.25rem;
color: #ff9800;
flex-shrink: 0;
}

.login-warning-text {
font-size: 0.875rem;
color: #ddd;
line-height: 1.5;
text-transform: none;
letter-spacing: normal;
}

.login-warning-text strong {
color: #ff9800;
}

.campaign-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
Expand Down
24 changes: 24 additions & 0 deletions src/pages/campaign-selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { qs } from "@app/engine/utils/query-selector";
import { Logger } from "@app/logging/logger";
import { Router } from "@app/router";
import { sandboxData } from "@app/scenarios/sandbox";
import { Auth } from "@app/user-account/auth";
import { getUserDataService } from "@app/user-account/user-data-service";
import { getAssetUrl } from "@app/utils/asset-url";
import { html } from "../engine/utils/development/formatter";
Expand Down Expand Up @@ -59,6 +60,10 @@ export class CampaignSelectionPage extends BasePage {
const { App } = await import('../app');
await App.authReady;

// Check if user is logged in and update the warning visibility
const isLoggedIn = await Auth.isLoggedIn();
this.updateLoginWarning_(!isLoggedIn);

const userDataService = getUserDataService();
const progressResponse = await userDataService.getAllScenariosProgress().catch(() => null);

Expand All @@ -72,6 +77,18 @@ export class CampaignSelectionPage extends BasePage {
} catch (error) {
Logger.error('Failed to load user progress:', error);
// Continue without progress info - user may not be authenticated
// Show the login warning if we couldn't load user data
this.updateLoginWarning_(true);
}
}

/**
* Show or hide the login warning message
*/
private updateLoginWarning_(show: boolean): void {
const warning = this.dom_.querySelector('.login-warning') as HTMLElement;
if (warning) {
warning.style.display = show ? 'flex' : 'none';
}
}

Expand Down Expand Up @@ -111,6 +128,13 @@ export class CampaignSelectionPage extends BasePage {
<div class="campaign-selection-header">
<h1>Signal Range Training</h1>
<div class="subtitle">Select a campaign to begin your training</div>
<div class="login-warning" style="display: none;">
<span class="login-warning-icon">&#9888;</span>
<span class="login-warning-text">
You can play <strong>Scenario 1</strong> of the North Atlantic Teleport Services campaign without an account, but you'll need to
<strong>create a free account</strong> (top right) to track your progress and unlock additional scenarios.
</span>
</div>
</div>

<div class="campaign-grid">
Expand Down
10 changes: 10 additions & 0 deletions src/scenario-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ import { Character, Emotion } from './modal/character-enum';
import { ScenarioData } from './ScenarioData';
import { sandboxData } from './scenarios/sandbox';

declare global {
interface Window {
DEVELOPER_MODE?: boolean;
}
}

export interface DialogClip {
text: string;
character: Character;
Expand Down Expand Up @@ -148,6 +154,10 @@ export function isScenarioLocked(scenario: ScenarioData, completedScenarioIds: s
return false;
}

if (window.DEVELOPER_MODE) {
return false;
}

return !scenario.prerequisiteScenarioIds.every(prereqId =>
completedScenarioIds.includes(prereqId)
);
Expand Down
Loading