import {EgPermService} from '@eg/core/perm.service';
import {EgPcrudService} from '@eg/core/pcrud.service';
import {EgOrgService} from '@eg/core/org.service';
+import {EgAudioService} from '@eg/share/audio.service';
@NgModule({
declarations: [
EgAuthService,
EgPermService,
EgPcrudService,
- EgOrgService
+ EgOrgService,
+ EgAudioService
]
};
}
// Resolves if login workstation matches a workstation known to this
- // browser instance.
+ // browser instance. No attempt is made to see if the workstation
+ // is present on the server. That happens at login time.
verifyWorkstation(): Promise<void> {
if (!this.user()) {
--- /dev/null
+/**
+ * Plays audio files (alerts, generally) by key name. Each sound uses a
+ * dot-path to indicate the sound.
+ *
+ * For example:
+ *
+ * this.audio.play('warning.checkout.no_item');
+ *
+ * URLs are tested in the following order until an audio file is found
+ * or no other paths are left to check.
+ *
+ * /audio/notifications/warning/checkout/not_found.wav
+ * /audio/notifications/warning/checkout.wav
+ * /audio/notifications/warning.wav
+ *
+ * Files are only played when sounds are configured to play via
+ * workstation settings.
+ */
+import {Injectable, EventEmitter} from '@angular/core';
+import {EgStoreService} from '@eg/core/store.service';
+const AUDIO_BASE_URL = '/audio/notifications/';
+
+@Injectable()
+export class EgAudioService {
+
+ // map of requested audio path to resolved path
+ private urlCache: {[path:string] : string} = {};
+
+ constructor(private store: EgStoreService) {}
+
+ play(path: string): void {
+ if (path) {
+ this.playUrl(path, path);
+ }
+ }
+
+ playUrl(path: string, origPath: string): void {
+ //console.debug(`audio: playUrl(${path}, ${origPath})`);
+
+ this.store.getItem('eg.audio.disable').then(audioDisabled => {
+ if (audioDisabled) return;
+
+ let url = this.urlCache[path] ||
+ AUDIO_BASE_URL + path.replace(/\./g, '/') + '.wav';
+
+ let player = new Audio(url);
+
+ player.onloadeddata = () => {
+ this.urlCache[origPath] = url;
+ player.play();
+ console.debug(`audio: ${url}`);
+ };
+
+ if (this.urlCache[path]) {
+ // when serving from the cache, avoid secondary URL lookups.
+ return;
+ }
+
+ player.onerror = () => {
+ // Unable to play path at the requested URL.
+
+ if (!path.match(/\./)) {
+ // all fall-through options have been exhausted.
+ // No path to play.
+ console.warn(
+ "No suitable URL found for path '" + origPath + "'");
+ return;
+ }
+
+ // Fall through to the next (more generic) option
+ path = path.replace(/\.[^\.]+$/, '');
+ this.playUrl(path, origPath);
+ }
+ });
+ }
+}
+
+
this.workstations.push(ws);
this.store.setItem('eg.workstation.all', this.workstations)
- .then(ok => this.newName = '');
+ .then(ok => {
+ this.newName = '';
+ // when registering our first workstation, mark it as the
+ // default and show it as selected in the ws selector.
+ if (this.workstations.length == 1) {
+ this.selectedName = ws.name;
+ this.setDefault();
+ }
+ });
}
}
ActivatedRoute, ActivatedRouteSnapshot} from '@angular/router';
import {EgStoreService} from '@eg/core/store.service';
import {EgNetService} from '@eg/core/net.service';
-import {EgAuthService} from '@eg/core/auth.service';
+import {EgAuthService, EgAuthWsState} from '@eg/core/auth.service';
+
+const LOGIN_PATH = '/staff/login';
+const WS_MANAGE_PATH = '/staff/admin/workstation/workstations/manage';
/**
* Load data used by all staff modules.
@Injectable()
export class EgStaffResolver implements Resolve<Observable<any>> {
- readonly loginPath = '/staff/login';
- readonly wsRemPath = '/staff/admin/workstation/workstations/remove/';
-
// Tracks the primary resolve observable.
observer: Observer<any>;
handleInvalidToken(state: RouterStateSnapshot): void {
console.debug('EgStaffResolver: authtoken is not valid');
this.auth.redirectUrl = state.url;
- this.router.navigate([this.loginPath]);
+ this.router.navigate([LOGIN_PATH]);
this.observer.error('invalid or no auth token');
}
- // For the purposes of route resolving, an invalid workstation is
- // not an error condition when we're on the workstation admin page.
- // However, it does mean that not all of the usual data will be
- // loaded and available on the workstation admin page. Once a valid
- // workstation is applied and the user re-logs in, the page must be
- // reloaded to fetch all of the needed staff data.
handleInvalidWorkstation(path: string): void {
- if (path.indexOf(this.wsRemPath) < 0) {
- this.router.navigate([
- this.wsRemPath + this.auth.workstation()]);
- this.observer.error('invalid workstation, redirecting');
- } else {
+
+ if (path.startsWith(WS_MANAGE_PATH)) {
+ // user is navigating to the WS admin page.
this.observer.complete();
+ } else {
+ this.router.navigate([WS_MANAGE_PATH]);
+ this.observer.error(`Auth session linked to no
+ workstation or a workstation unknown to this browser`);
}
}
import {EgAuthService, EgAuthWsState} from '@eg/core/auth.service';
import {EgNetService} from '@eg/core/net.service';
+const LOGIN_PATH = '/staff/login';
+const WS_BASE_PATH = '/staff/admin/workstation/workstations/';
+const WS_MANAGE_PATH = '/staff/admin/workstation/workstations/manage';
+
@Component({
templateUrl: 'staff.component.html',
styleUrls: ['staff.component.css']
export class EgStaffComponent implements OnInit {
- readonly loginPath = '/staff/login';
- readonly wsAdminBasePath = '/staff/admin/workstation/workstations/';
constructor(
private router: Router,
// with the page. Fix it by wrapping it in zone.run().
// This is the only navigate() where I have seen this happen.
this.zone.run(() => {
- this.router.navigate([this.loginPath]);
+ this.router.navigate([LOGIN_PATH]);
});
});
}
/**
- * Verifying the auth token on every route is overkill, since
- * an expired token will make itself known with the first API
- * call or when the auth session poll discovers it, but we do
- * want to prevent navigation from the login or workstation admin
- * page, since these can be accessed without a valid authtoken or
- * workstation, respectively, once the initial route resolvers have
- * done their jobs.
+ * Prevent the user from leaving the login page when they don't have
+ * a valid authoken.
+ *
+ * Prevent the user from leaving the workstation admin page when
+ * they don't have a valid workstation.
+ *
+ * This does not verify auth tokens with the server on every route,
+ * because that would be overkill. This is only here to keep
+ * people boxed in.
*/
basicAuthChecks(url: string): void {
- // Access to login page is always granted
- if (url == this.loginPath) return;
+ // No auth checks needed for login page.
+ if (url.startsWith(LOGIN_PATH)) return;
+ // We lost our authtoken, go back to the login page.
if (!this.auth.token())
- this.router.navigate([this.loginPath]);
+ this.router.navigate([LOGIN_PATH]);
- // Access to workstation admin page is granted regardless
- // of workstation validity.
- if (url.indexOf(this.wsAdminBasePath) >= 0) return;
+ // No workstation checks needed for workstation admin page.
+ if (url.startsWith(WS_BASE_PATH)) return;
if (this.auth.workstationState != EgAuthWsState.VALID)
- this.router.navigate([this.wsAdminBasePath]);
+ this.router.navigate([WS_MANAGE_PATH]);
}
}