Skip to content

Commit 754b7f2

Browse files
committed
173: Added preview screen option through query parameters
1 parent 96dd619 commit 754b7f2

File tree

6 files changed

+122
-80
lines changed

6 files changed

+122
-80
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
- Added support for previews.
6+
57
## [2.0.2] - 2024-04-25
68

79
- [#123](https://github.com/os2display/display-client/pull/123)

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ All endpoint should be configured without a trailing slash. The endpoints `apiEn
3232
left empty if the api is hosted from the root of the same domain as the client. E.g. if the api is at https://example.org and the client is at
3333
https://example.org/client
3434

35+
## Preview
36+
37+
The client can be started in preview mode by setting the following url parameters:
38+
```
39+
preview=<screen|playlist|slide>
40+
preview-id=<id of entity to preview>
41+
preview-token=<token for accessing data>
42+
preview-tenant=<tenant id>
43+
```
44+
45+
The preview will use the token and tenant for acessing the data from the api.
46+
3547
## Docker development setup
3648

3749
Start docker setup

src/app.js

Lines changed: 92 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import jwtDecode from 'jwt-decode';
22
import React, { useEffect, useRef, useState } from 'react';
3+
import PropTypes from 'prop-types';
34
import Screen from './screen';
45
import ContentService from './service/contentService';
56
import ConfigLoader from './config-loader';
@@ -13,10 +14,12 @@ import idFromPath from './id-from-path';
1314
/**
1415
* App component.
1516
*
16-
* @returns {object}
17-
* The component.
17+
* @param {object} props The props.
18+
* @param {string} props.preview Enable preview mode.
19+
* @param {string} props.previewId Id of the item to preview.
20+
* @returns {JSX.Element} The component.
1821
*/
19-
function App() {
22+
function App({ preview, previewId }) {
2023
const fallbackImageUrl = localStorage.getItem(
2124
localStorageKeys.FALLBACK_IMAGE
2225
);
@@ -305,7 +308,7 @@ function App() {
305308
setDisplayFallback(false);
306309
};
307310

308-
// ctrl/cmd i will log screen out and refresh
311+
// ctrl/cmd+i will log screen out and refresh
309312
const handleKeyboard = ({ repeat, metaKey, ctrlKey, code }) => {
310313
if (!repeat && (metaKey || ctrlKey) && code === 'KeyI') {
311314
localStorage.clear();
@@ -314,41 +317,49 @@ function App() {
314317
};
315318

316319
useEffect(() => {
317-
const currentUrl = new URL(window.location.href);
318-
319-
// Make sure have releaseVersion and releaseTimestamp set in url parameters.
320-
if (
321-
!currentUrl.searchParams.has('releaseVersion') ||
322-
!currentUrl.searchParams.has('releaseTimestamp')
323-
) {
324-
ReleaseLoader.loadConfig().then((release) => {
325-
currentUrl.searchParams.set(
326-
'releaseTimestamp',
327-
release.releaseTimestamp
328-
);
329-
currentUrl.searchParams.set('releaseVersion', release.releaseVersion);
320+
if (preview !== null) {
321+
document.addEventListener('screen', screenHandler);
322+
document.addEventListener('contentEmpty', contentEmpty);
323+
document.addEventListener('contentNotEmpty', contentNotEmpty);
330324

331-
window.history.replaceState(null, '', currentUrl);
332-
});
333-
}
325+
startContent(previewId);
326+
} else {
327+
const currentUrl = new URL(window.location.href);
328+
329+
// Make sure have releaseVersion and releaseTimestamp set in url parameters.
330+
if (
331+
!currentUrl.searchParams.has('releaseVersion') ||
332+
!currentUrl.searchParams.has('releaseTimestamp')
333+
) {
334+
ReleaseLoader.loadConfig().then((release) => {
335+
currentUrl.searchParams.set(
336+
'releaseTimestamp',
337+
release.releaseTimestamp
338+
);
339+
currentUrl.searchParams.set('releaseVersion', release.releaseVersion);
340+
341+
window.history.replaceState(null, '', currentUrl);
342+
});
343+
}
334344

335-
document.addEventListener('screen', screenHandler);
336-
document.addEventListener('reauthenticate', reauthenticateHandler);
337-
document.addEventListener('contentEmpty', contentEmpty);
338-
document.addEventListener('contentNotEmpty', contentNotEmpty);
339-
document.addEventListener('keypress', handleKeyboard);
345+
document.addEventListener('screen', screenHandler);
346+
document.addEventListener('reauthenticate', reauthenticateHandler);
347+
document.addEventListener('contentEmpty', contentEmpty);
348+
document.addEventListener('contentNotEmpty', contentNotEmpty);
349+
document.addEventListener('keypress', handleKeyboard);
340350

341-
checkLogin();
351+
checkLogin();
342352

343-
checkForUpdates();
353+
checkForUpdates();
344354

345-
ConfigLoader.loadConfig().then((config) => {
346-
releaseTimestampIntervalRef.current = setInterval(
347-
checkForUpdates,
348-
config.releaseTimestampIntervalTimeout ??
349-
releaseTimestampIntervalTimeoutDefault
350-
);
351-
});
355+
ConfigLoader.loadConfig().then((config) => {
356+
releaseTimestampIntervalRef.current = setInterval(
357+
checkForUpdates,
358+
config.releaseTimestampIntervalTimeout ??
359+
releaseTimestampIntervalTimeoutDefault
360+
);
361+
});
362+
}
352363

353364
return function cleanup() {
354365
Logger.log('info', 'Unmounting App.');
@@ -374,41 +385,45 @@ function App() {
374385
}, []);
375386

376387
useEffect(() => {
377-
// Append screenId to current url for easier debugging. If errors are logged in the API's standard http log this
378-
// makes it easy to see what screen client has made the http call by putting the screen id in the referer http
379-
// header.
380-
if (screen && screen['@id']) {
381-
const url = new URL(window.location.href);
382-
url.searchParams.set('screenId', idFromPath(screen['@id']));
383-
window.history.replaceState(null, '', url);
384-
}
385-
386-
ConfigLoader.loadConfig().then((config) => {
387-
const token = localStorage.getItem(localStorageKeys.API_TOKEN);
388-
const tenantKey = localStorage.getItem(localStorageKeys.TENANT_KEY);
389-
const tenantId = localStorage.getItem(localStorageKeys.TENANT_ID);
390-
391-
if (token && tenantKey && tenantId) {
392-
// Get fallback image.
393-
fetch(`${config.apiEndpoint}/v2/tenants/${tenantId}`, {
394-
headers: {
395-
authorization: `Bearer ${token}`,
396-
'Authorization-Tenant-Key': tenantKey,
397-
},
398-
})
399-
.then((response) => response.json())
400-
.then((tenantData) => {
401-
if (tenantData.fallbackImageUrl) {
402-
localStorage.setItem(
403-
localStorageKeys.FALLBACK_IMAGE,
404-
tenantData.fallbackImageUrl
405-
);
406-
}
407-
});
388+
if (preview === null) {
389+
// Append screenId to current url for easier debugging. If errors are logged in the API's standard http log this
390+
// makes it easy to see what screen client has made the http call by putting the screen id in the referer http
391+
// header.
392+
if (screen && screen['@id']) {
393+
const url = new URL(window.location.href);
394+
url.searchParams.set('screenId', idFromPath(screen['@id']));
395+
window.history.replaceState(null, '', url);
408396
}
409397

410-
setDebug(config?.debug ?? false);
411-
});
398+
ConfigLoader.loadConfig().then((config) => {
399+
const token = localStorage.getItem(localStorageKeys.API_TOKEN);
400+
const tenantKey = localStorage.getItem(localStorageKeys.TENANT_KEY);
401+
const tenantId = localStorage.getItem(localStorageKeys.TENANT_ID);
402+
403+
if (token && tenantKey && tenantId) {
404+
// Get fallback image.
405+
fetch(`${config.apiEndpoint}/v2/tenants/${tenantId}`, {
406+
headers: {
407+
authorization: `Bearer ${token}`,
408+
'Authorization-Tenant-Key': tenantKey,
409+
},
410+
})
411+
.then((response) => response.json())
412+
.then((tenantData) => {
413+
if (tenantData.fallbackImageUrl) {
414+
localStorage.setItem(
415+
localStorageKeys.FALLBACK_IMAGE,
416+
tenantData.fallbackImageUrl
417+
);
418+
}
419+
});
420+
}
421+
422+
setDebug(config?.debug ?? false);
423+
});
424+
} else {
425+
setDebug(false);
426+
}
412427
}, [screen]);
413428

414429
return (
@@ -430,4 +445,14 @@ function App() {
430445
);
431446
}
432447

448+
App.defaultProps = {
449+
preview: null,
450+
previewId: null,
451+
};
452+
453+
App.propTypes = {
454+
preview: PropTypes.string,
455+
previewId: PropTypes.string,
456+
};
457+
433458
export default App;

src/data-sync/api-helper.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,19 @@ class ApiHelper {
2727
let response;
2828

2929
try {
30+
const url = new URL(window.location.href);
31+
const previewToken = url.searchParams.get('preview-token');
32+
const previewTenant = url.searchParams.get('preview-tenant');
33+
3034
Logger.log('info', `Fetching: ${this.endpoint + path}`);
3135

3236
const token = localStorage.getItem(localStorageKeys.API_TOKEN) ?? '';
3337
const tenantKey = localStorage.getItem(localStorageKeys.TENANT_KEY) ?? '';
3438

3539
response = await fetch(this.endpoint + path, {
3640
headers: {
37-
authorization: `Bearer ${token}`,
38-
'Authorization-Tenant-Key': tenantKey,
41+
authorization: `Bearer ${previewToken ?? token}`,
42+
'Authorization-Tenant-Key': previewTenant ?? tenantKey,
3943
},
4044
});
4145

src/index.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import React from 'react';
22
import { createRoot } from 'react-dom/client';
33
import App from './app';
44

5+
const url = new URL(window.location.href);
6+
const preview = url.searchParams.get('preview');
7+
const previewId = url.searchParams.get('preview-id');
8+
59
const container = document.getElementById('root');
610
const root = createRoot(container);
711

8-
root.render(
9-
<React.StrictMode>
10-
<App />
11-
</React.StrictMode>
12-
);
12+
root.render(<App preview={preview} previewId={previewId} />);

src/service/contentService.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,14 @@ class ContentService {
8181

8282
this.stopSyncHandler();
8383

84+
Logger.log(
85+
'info',
86+
`Event received: Start data synchronization from ${data?.screenPath}`
87+
);
8488
if (data?.screenPath) {
85-
Logger.log(
86-
'info',
87-
`Event received: Start data synchronization from ${data.screenPath}`
88-
);
8989
this.startSyncing(data.screenPath);
9090
} else {
91-
Logger.log('info', 'Event received: Start data synchronization');
92-
this.startSyncing();
91+
Logger.log('error', 'Error: screenPath not set.');
9392
}
9493
}
9594

0 commit comments

Comments
 (0)