Cboard access frontend#2159
Conversation
Add getAccessClients() and getAccessBoard(code) methods to the API class for the Cboard Access feature (issue cboard-org#2138). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add playTileAudio, vocalizeTile, findNextBoard, processTileClick, and scrollBoardToTop for use by Board.container.js and AccessViewer (issue cboard-org#2139). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace inline playAudio method and say() function with vocalizeTile, findNextBoard, and scrollBoardToTop from Board.utils. Remove now-unused ogv and IS_BROWSING_FROM_* imports (issue cboard-org#2139). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add AccessViewer with local board navigation state, single-request board loading, and O(1) board lookup. Includes AccessViewerNavbar (Back, Home, Settings, Lock), AccessViewerHeader (client branding), and AccessViewerError (invalid/expired/error states). Reuses vocalizeTile and scrollBoardToTop from Board.utils (issue cboard-org#2140). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hide Navbar and EditToolbar, disable drag & drop when viewerMode is true. A single prop covers all viewer restrictions (issue cboard-org#2141). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
viewerMode alone now controls navbar visibility in Board.component, so hideNavbar is no longer needed (issue cboard-org#2141). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hide remove buttons, action buttons (Share, Backspace, Clear, Live mode) and disable onWrite handler when viewerMode is true (issue cboard-org#2142). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Register AccessViewer as a public route before authenticated routes. Internal board navigation is handled by AccessViewer state (issue cboard-org#2144). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add initDeepLinking() to cordova-util.js and call it from initCordovaPlugins(). Handles deep link matches by pushing to the AccessViewer route via shared history (issue cboard-org#2146). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Include /access/* and /board/* paths so iOS opens the app directly when users scan a QR or tap an access link (issue cboard-org#2146). Note: replace TEAM_ID with the actual Apple Developer Team ID. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
react-intl v2 has no hooks — use injectIntl HOC instead. Also remove the output state that was set but never rendered (issue cboard-org#2140). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
playTileAudio is called internally by vocalizeTile — no direct usage in Board.container (issue cboard-org#2139). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
history.js imports isCordova from cordova-util, so importing history at the top of cordova-util creates a cycle. Lazy-require history inside initDeepLinking so it resolves after both modules are initialized. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend changed GET /access/:code to GET /access/:slug/:code to validate that code belongs to the given client slug. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Matches the updated backend endpoint that requires both the client slug and access code for validation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pass both slug and code to getAccessBoard to match the updated /access/:slug/:code endpoint. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Board.component.js calls onFocusTile unconditionally on tile focus, causing a crash when not provided. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| "apps": [], | ||
| "details": [ | ||
| { | ||
| "appID": "TEAM_ID.com.unicef.cboard", |
There was a problem hiding this comment.
We should remember to replace with real one
There was a problem hiding this comment.
Yes! I don't know it hehe
…importing history directly as a resolved singleton
…er, BoardContainer, and GridContainer for improved scroll state management
There was a problem hiding this comment.
@magush27 Good Work! I left some comments. We need to remember to update hte apple-app-site-association file and remove the changes on the config.yml
I think that we need to implement some test for this new implementation. What do you think?
| export const initDeepLinking = history => { | ||
| if (!window.IonicDeeplink) { | ||
| console.log('IonicDeeplink plugin not available'); | ||
| return; | ||
| } | ||
|
|
||
| window.IonicDeeplink.route( | ||
| { | ||
| '/access/:slug/:code': { target: 'access' }, | ||
| '/board/:id': { target: 'board' } | ||
| }, | ||
| match => { | ||
| if (match.$route === '/access/:slug/:code') { | ||
| history.push(`/access/${match.$args.slug}/${match.$args.code}`); | ||
| } | ||
| if (match.$route === '/board/:id') { | ||
| history.push(`/board/${match.$args.id}`); | ||
| } | ||
| }, | ||
| nomatch => { | ||
| console.log('Deep link no match:', nomatch.$link); | ||
| } | ||
| ); | ||
| }; |
There was a problem hiding this comment.
We currently do not support the IonicDeeplink plugin in the Cboard repository. The plugin is already installed (ionic-plugin-deeplinks), but it has never actually been used in the Cboard App. Unfortunately, the plugin is now publicly archived, so we should consider removing it and replacing it with the plugin you suggested.
Could you make those changes in the Ccboard repository?
There was a problem hiding this comment.
I don't remember mentioning a replacing plugin, but I think it's a good idea to handle this natively instead of using a dependency. I'm thinking to handle it this way:
- On iOS: implement
handleOpenURL(built into Cordova for custom URL schemes) +apple-app-site-associationfor Universal Links - On Android: handle the intent via
window.handleOpenURLor theresumeevent
What do you think?
There was a problem hiding this comment.
Not sure if this can be implemented without a Cordova plugin. If that’s an option, go with it.
| import { Stream } from 'stream'; | ||
| import 'fake-indexeddb/auto'; | ||
|
|
||
| if (typeof MessageChannel === 'undefined') { |
There was a problem hiding this comment.
Do you get to the root cause of why the test failed and we needed to add this changes?
There was a problem hiding this comment.
Yes, the MessageChannel mock was added because the ogv library (version ^1.8.9, a WebAssembly audio/video decoder) uses MessageChannel internally. Jest runs in a Node.js/jsdom environment which doesn't implement MessageChannel, so any test that indirectly imports ogv would crash with MessageChannel is not defined. This prevents the crash without actually implementing the full API
There was a problem hiding this comment.
I find it a bit strange that the tests didn’t fail when the OGV import was still inside Board.container.
There was a problem hiding this comment.
I found a more accurate root cause:
The tests dind't fail before becase Board.container.test.js has jest.mock('ogv', ...) at line 4 and it mocks the OGV module so the real one (which uses MessageChannel) never loads. That's why those tests were always fine.
They started failing now because OGV was moved from Board.container.js into Board.utils.js in commit 5a8535e ("Import pure utility functionalities"). Board.utils.js is now imported by more things across the codebase. Any test that transitively imports Board.utils.js without the ogv mock will load the real OGV library, which hits MessageChannel and crashes in jsdom.
So the setupTests.js polyfill it's a global solution that covers all current and future test files that pull in Board.utils.js. The alternative would be adding jest.mock('ogv', ...) to every test file that imports Board.utils.js, which is much more fragile.
|
@RodriSanchez1 yes! I think it's a good idea to add tests regarding this implementation, I'll do that after solving the other comments you left |
…nto cboard-access-frontend
Closes #2137