Skip to content

Cboard access frontend#2159

Open
RodriSanchez1 wants to merge 59 commits into
cboard-org:masterfrom
magush27:cboard-access-frontend
Open

Cboard access frontend#2159
RodriSanchez1 wants to merge 59 commits into
cboard-org:masterfrom
magush27:cboard-access-frontend

Conversation

@RodriSanchez1

@RodriSanchez1 RodriSanchez1 commented Apr 21, 2026

Copy link
Copy Markdown
Collaborator

Closes #2137

magush27 and others added 27 commits April 20, 2026 14:32
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>
Comment thread src/components/Board/Board.component.js Outdated

@tomivm tomivm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks Good!!

Comment thread src/cordova-util.js Outdated
"apps": [],
"details": [
{
"appID": "TEAM_ID.com.unicef.cboard",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remember to replace with real one

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! I don't know it hehe

Comment thread src/cordova-util.js Outdated
Comment thread src/components/Board/Board.utils.js
Comment thread src/components/Board/Board.component.js Outdated

@tomivm tomivm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job @magush27 !!!

@magush27 magush27 requested a review from tomivm May 8, 2026 19:03
@RodriSanchez1 RodriSanchez1 marked this pull request as ready for review May 13, 2026 17:25
…er, BoardContainer, and GridContainer for improved scroll state management

@RodriSanchez1 RodriSanchez1 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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?

Comment thread src/components/AccessViewer/AccessViewer.js Outdated
Comment thread src/components/AccessViewer/AccessViewerError.js
Comment thread src/components/AccessViewer/AccessViewerNavbar.js Outdated
Comment thread src/components/AccessViewer/AccessViewer.css Outdated
Comment thread src/components/Board/Output/SymbolOutput/SymbolOutput.js Outdated
Comment thread src/components/AccessViewer/AccessViewerNavbar.js Outdated
Comment thread src/cordova-util.js
Comment on lines +38 to +61
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);
}
);
};

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-association for Universal Links
  • On Android: handle the intent via window.handleOpenURL or the resume event

What do you think?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this can be implemented without a Cordova plugin. If that’s an option, go with it.

Comment thread src/setupTests.js
Comment on lines 3 to +6
import { Stream } from 'stream';
import 'fake-indexeddb/auto';

if (typeof MessageChannel === 'undefined') {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you get to the root cause of why the test failed and we needed to add this changes?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@RodriSanchez1 RodriSanchez1 May 14, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it a bit strange that the tests didn’t fail when the OGV import was still inside Board.container.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

…equest 2159" and "Add QA image build and

  deployment steps to CircleCI configuration"

  Reverts the CircleCI config changes from a55fb12 and 7b846a7, restoring .circleci/config.yml to its state at
  8a99537.
@magush27

Copy link
Copy Markdown
Collaborator

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cboard Access - Frontend Implementation

3 participants