Skip to content

Implement PicturePasswordGrid component#14546

Open
AlexVelezLl wants to merge 3 commits intolearningequality:developfrom
AlexVelezLl:picture-password-option
Open

Implement PicturePasswordGrid component#14546
AlexVelezLl wants to merge 3 commits intolearningequality:developfrom
AlexVelezLl:picture-password-option

Conversation

@AlexVelezLl
Copy link
Copy Markdown
Member

@AlexVelezLl AlexVelezLl commented Apr 7, 2026

Summary

  • Implements PicturePasswordOption and PicturePasswordGrid components.
  • Creates picturePasswordStrings.js file.
  • Adds unit tests for PicturePasswordOption and PicturePasswordGrid.
Grabacion.de.pantalla.2026-04-07.a.la.s.3.44.07.p.m.mov

For now, hadn't actually implemented anything specific for specific screen breakpoints, given that it will depend on the parent's available space, but I have implemented the grid so that icons are responsive to the available width, and if we ever consider changing the grid layout for smaller screens, we can do it easily:

Grabacion.de.pantalla.2026-04-07.a.la.s.3.45.37.p.m.mov

References

Closes #14409.
Closes #14410.

Reviewer guidance

  • Import and use the components in any place you want to use as playground.

AI usage

Asked Claude to know what the most accessible DOM node layout was for this, and asked him to write the unit tests, which I then tweaked to use the most recent test guidelines.

@github-actions github-actions bot added APP: User Re: User app (sign-in, sign-up, user profile, etc.) DEV: frontend SIZE: medium labels Apr 7, 2026
@AlexVelezLl AlexVelezLl requested a review from rtibblesbot April 7, 2026 13:58
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

Two acceptance criteria from #14409 aren't met. CI passing. Visual inspection: reviewed 4 frames from the PR video — selected, default, disabled, and hover states all render correctly against the spec. Badge in upper-left, grayscale+opacity for disabled, blue border+tint for selected.

  • blocking: select event emits no payload — see inline
  • blocking: no separate event for disabled activation — see inline
  • nitpick: badge SCSS comment says "top-right" but code/spec places it top-left — see inline
  • praise: native checkbox + aria-disabled accessibility design — see inline

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Reviewed the pull request diff checking for:

  • Correctness: bugs, edge cases, undocumented behavior, resource leaks, hardcoded values
  • Design: unnecessary complexity, naming, readability, comment accuracy, redundant state
  • Architecture: duplicated concerns, minimal interfaces, composition over inheritance
  • Testing: behavior-based assertions, mocks only at hard boundaries, accurate coverage
  • Completeness: missing dependencies, unupdated usages, i18n, accessibility, security
  • Principles: DRY (same reason to change), SRP, Rule of Three (no premature abstraction)
  • Checked CI status and linked issue acceptance criteria
  • For UI changes: inspected screenshots for layout, visual completeness, and consistency


const onSelect = () => {
if (!props.disabled) {
emit('select');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocking: The select event emits no payload, but #14409's acceptance criteria state "An event is emitted with the icon token when clicked/activated and not disabled." The parent grid needs the token to record which icon was chosen.

Change to:

emit('select', props.icon);


await userEvent.click(screen.getByRole('checkbox', { name: picturePasswordStrings.bird$() }));

expect(emitted()['select']).toBeTruthy();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocking: This test only checks that the event was emitted, not its payload. Once the payload is added, add an assertion like:

expect(emitted()['select'][0]).toEqual(['birdColorful']);

if (!props.disabled) {
emit('select');
}
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocking: #14409 requires "A separate event fires when a disabled option receives a click or Space/Enter keypress (this will be needed by the parent grid for the screen reader live region announcement in the following issue)." Currently onSelect() silently returns when disabled — no event is emitted.

Add an else branch:

const onSelect = () => {
  if (props.disabled) {
    emit('disabledSelect');
  } else {
    emit('select', props.icon);
  }
};

And add a corresponding unit test verifying that clicking a disabled option emits disabledSelect.


.badge {
position: absolute;
// Position the badge centered on the top-right corner of the option, just outside the border.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nitpick: Comment says "top-right corner" but left: negative positions the badge at the top-left corner (which matches the spec and the screenshots). Should be "top-left corner".

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Top-right corner for RTL languages? hahaa okay, no. Fixed.

We do not set the `disabled` HTML attribute so the input keeps focus.
`aria-disabled` communicates the disabled state to assistive technology.
-->
<input
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

praise: Using a native <input type="checkbox"> with aria-disabled instead of the HTML disabled attribute is the right call — it keeps the element in the tab order and focusable by keyboard users, while still communicating the disabled state to assistive technology. The comment explaining the rationale is helpful.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

@LianaHarris360 LianaHarris360 self-assigned this Apr 7, 2026
@AlexVelezLl AlexVelezLl force-pushed the picture-password-option branch from bdddeea to af8e151 Compare April 7, 2026 16:51
@AlexVelezLl AlexVelezLl requested a review from rtibblesbot April 7, 2026 16:53
@AlexVelezLl AlexVelezLl force-pushed the picture-password-option branch from af8e151 to f89363e Compare April 7, 2026 16:56
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

All three blocking issues from the prior review are resolved.

Prior findings

Resolved:

  • select event emitted with no payload (blocking) — now emits props.icon at line 121
  • Test didn't assert payload (blocking) — toEqual(['birdColorful']) assertion added at line 25
  • No disabledSelect event when disabled (blocking) — event emitted in else branch; test added
  • Comment said "top-right corner" but badge is top-left (nitpick) — comment corrected

4/4 prior findings resolved. 0 re-raised.

CI passing (build assets job still in progress at review time, all other checks green). Visual: 4 video frames reviewed — selected, hover, disabled, and default states all render correctly.

praise: The test suite now covers the full contract — select payload, disabled suppression, disabledSelect emission, badge visibility, and both aria-disabled branches. That's thorough for a single-component PR.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

@LianaHarris360 LianaHarris360 requested a review from akolson April 7, 2026 20:06
@AlexVelezLl AlexVelezLl changed the title Implement PicturePasswordOption component Implement PicturePasswordGrid component Apr 7, 2026
@AlexVelezLl AlexVelezLl requested a review from rtibblesbot April 7, 2026 20:49
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

Good implementation of the Grid component — all acceptance criteria from #14410 are met. CI passing. Visual inspection: reviewed 7 frames from the PR video — selected/disabled/complete states all render correctly, badge positioning and progress bar fill correctly, submit button enables at 3 selections.

Prior findings

Resolved:

  • select event emitted with no payload (blocking) — now emits props.icon at line 127
  • Test didn't assert payload (blocking) — toEqual(['birdColorful']) assertion added at line 25
  • No disabledSelect event when disabled (blocking) — else branch added; test added
  • Comment said "top-right corner" but badge is top-left (nitpick) — comment corrected

4/4 prior findings resolved. 0 re-raised.


New findings below.

  • suggestion: Live region re-triggering approach — see inline
  • suggestion: Submit button is missing type="button" — see inline
  • nitpick: ICON_ENTRIES defined inside setup() — see inline
  • praise: Deselect logic using slice — see inline
  • praise: useKLiveRegion delegation — see inline

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

sendPoliteMessage(ORDINAL_STRING_MAP[position]({ icon: iconLabelFor(id) }));
};

const handleDisabledSelect = () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: The issue spec required a nextTick clear-before-set pattern to guarantee re-announcement when the same disabled-icon message is sent repeatedly: clear the live region, await a tick, then set the new content. useKLiveRegion.sendPoliteMessage does the opposite — it sets immediately and clears after 350ms. If a user taps the same disabled icon twice within that 350ms window, the DOM text hasn't changed between calls, and some screen readers won't re-announce.

The test mocks sendPoliteMessage so it only verifies the function was called twice — it doesn't verify the DOM actually re-triggers. This is worth checking against NVDA/VoiceOver: does rapid repeated tapping of the same disabled icon re-announce? If screen reader testing confirms it works, a comment explaining the delegation to KDS is sufficient.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I imagine this may be the desired behavior, given that useKLiveRegion is implemented this way.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Fair point — if useKLiveRegion handles the timing internally, delegating to it is the right call. Withdrawing this suggestion.


<!-- Submit button: shows only a forward-arrow icon; the aria-label
cycles through four instructional states as the sequence is built. -->
<button
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Missing type="button". Without it, the button defaults to type="submit" inside any ancestor <form> element. The sign-in page likely has a form wrapping the username/password fields; if this grid is placed inside that form, clicking the arrow would both emit submit and trigger a native form submission. Add type="button" to be safe.

signInWithSequence$,
} = picturePasswordStrings;

const ICON_ENTRIES = Object.entries(PICTURE_PASSWORD_SET).map(([idStr, data]) => ({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nitpick: ICON_ENTRIES is derived entirely from the static JSON import PICTURE_PASSWORD_SET — it doesn't depend on props, reactive state, or anything that changes at runtime. Defined inside setup(), it's recomputed on every component mount. Move it to module scope (above export default) to compute it once.

const existingIndex = sequence.value.indexOf(id);
if (existingIndex >= 0) {
// Deselect: drop this icon and everything after it.
sequence.value = sequence.value.slice(0, existingIndex);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

praise: sequence.value.slice(0, existingIndex) is exactly the right tool here — one expression drops the tapped icon and everything after it, enabling mid-sequence correction without a loop or splice. Clean.

setup(props, { emit }) {
const $themeTokens = themeTokens();
const $themePalette = themePalette();
const { sendPoliteMessage } = useKLiveRegion();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

praise: Using useKLiveRegion from KDS rather than wiring a raw aria-live element directly into the component's markup is the right architectural call — it keeps the live-region DOM singleton in one place and lets KDS manage its lifetime. Consistent with how other components in the codebase handle screen-reader announcements.

@AlexVelezLl AlexVelezLl force-pushed the picture-password-option branch from cdb6696 to 6e9d2d4 Compare April 8, 2026 13:34
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

Both suggestions from the prior round are addressed.

Prior findings

2 prior findings unchanged (1 resolved previously).

Newly resolved:

  • Submit button missing type="button" (suggestion) ← was UNADDRESSED — type="button" added at line 43
  • ICON_ENTRIES defined inside setup() (nitpick) ← was UNADDRESSED — moved to module scope at lines 83–86 with an explanatory comment

Acknowledged (not re-raised):

  • Live region re-triggering via useKLiveRegion (suggestion) — author replied: delegating to KDS is intentional

3/3 prior findings resolved or acknowledged. 0 re-raised.


CI: one check still in progress at review time (Build Assets). Visual inspection: reviewed 7 frames from the PR video — colorful and standard icon modes, badge sequence, disabled state, progress bar fill, and submit button all render correctly. No new findings.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

@AlexVelezLl AlexVelezLl force-pushed the picture-password-option branch 2 times, most recently from f370217 to e442c90 Compare April 8, 2026 17:00
Copy link
Copy Markdown
Member

@LianaHarris360 LianaHarris360 left a comment

Choose a reason for hiding this comment

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

I reviewed and tested the changes locally, the updates look good. I only had one visual and one accessibility concern to note. So that Radina can more thoroughly test the updates related to the keyboard and screen reader, can you temporarily keep PicturePasswordGrid in the SignInPage?

@AlexVelezLl
Copy link
Copy Markdown
Member Author

Thanks @LianaHarris360, I have invoked the grid on the signing page, I have used the actual facility settings values so that we can test all combinations, and have hardcoded that the "correct" sequence is: bee, star, moon for testing purposes.

Grabacion.de.pantalla.2026-04-09.a.la.s.10.18.54.a.m.mov

@AlexVelezLl AlexVelezLl force-pushed the picture-password-option branch from e57b32d to ea6b851 Compare April 9, 2026 15:21
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

Prior findings

All 7 prior findings remain resolved or acknowledged — no changes since last review.


CI build-assets job is queued (no test failures). One new blocking finding on the index.vue QA commit.

  • blocking: index.vue QA scaffolding should be removed before merging — see inline

Correct! Signed in successfully.
</p>
<!-- eslint-enable vue/no-bare-strings-in-template -->
<PicturePasswordGrid
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocking: This entire block (lines 48–69 + the handlePicturePasswordSubmit method) is QA-only scaffolding that shouldn't land on develop as-is:

  1. Unconditional renderingPicturePasswordGrid is shown to every user on the sign-in page, with no v-if guard checking whether picture password is enabled for the facility. Every learner will see a 12-icon grid they can't use.
  2. Bare strings with eslint-disable — "Incorrect sequence. Try again." and "Correct! Signed in successfully." are hard-coded English, bypassing i18n enforcement.
  3. Inline stylesstyle="color: red" / style="margin: 16px 0" can't be auto-flipped by RTLCSS; directional styles must live in <style> blocks.
  4. Hardcoded stub authhandlePicturePasswordSubmit treats '1.2.3' as a successful login; the TODO comment confirms this is not real.

The component implementations (PicturePasswordGrid.vue, PicturePasswordOption.vue) are complete and ready. Please remove this scaffolding before merging — the SignInPage integration belongs in a separate PR once the backend authentication endpoint is wired up.

@radinamatic
Copy link
Copy Markdown
Member

radinamatic commented Apr 10, 2026

Points for improvement after testing with the screen reader:

  1. The biggest issue is that after selecting an icon, the visual selection is in place, screen reader announces the selection correctly, but the checkbox is not actually checked, so when the user navigates away AND returns the focus to it, NVDA announces the state as not checked 😕

    Win10 (start)  Running  - Oracle VirtualBox_014
  2. On page load the focus is inside the Username input field, which is default position as the first interactive element. I'm thinking that we should set the Sign into [facility] to be the main heading H1 instead of the Kolibri (this is about semantics, styling can remain the same if preferred), and set the focus on it on page load.

  3. When the user selects an incorrect set of icons and tries to submit, the error message Incorrect sequence. Try again. must be passed to the aria-live region, and focus returned to the that same location or the main heading H1 above it.

    Win10 (start)  Running  - Oracle VirtualBox_012
  4. Color of the font for that same error message Incorrect sequence. Try again. gives an insufficient contrast with the background, we need a darker red.

    Win10 (start)  Running  - Oracle VirtualBox_013
  5. After selecting the 3 icons, when user traverses the disabled checkbox, requirement for interacting with a disabled icon trigger is not implemented, and the 3 already selected announcement is not passed to the aria-live region.

    3 already selected not announced

@AlexVelezLl
Copy link
Copy Markdown
Member Author

Thanks @radinamatic! Will be checking each point and let you know any questions 👐.

.picture-password-option {
display: inline-flex;
min-width: 44px;
min-height: 44px;
Copy link
Copy Markdown
Member

@LianaHarris360 LianaHarris360 Apr 10, 2026

Choose a reason for hiding this comment

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

Just wanted to flag that the Figma displays the selections with a fixed width and height of 84px, even when the label is shown, which I believe was an intentional design. The issue did specify that the minimum 44x44 touch target should be met, so this is definitely correct, although it would meet those touch targets at 84x84 as well.

Image

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

But if we set a fixed size, this won't be responsive, then?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That's true, and the size is 84x84 when the label isn't shown. I’m wondering if it's possible to keep the selection container the same size even when the label is added, while keeping it responsive? Even if the icons are a little smaller when the label is there.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hmm, I'd say we can play with the padding a bit to make it look more square, but I wouldn't feel that making it always perfectly square would be an option, because what happens if there is a language with a long word? We would want the icon to be smaller or prefer to break the word in a new line, even if that means the height will be larger.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That's a good point. I agree, it's not worth adjusting the container to always be square in this case, ignore this suggestion!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Playing with paddings, I got an 84px x 83.3px with label.

image

It can still grow vertically in the rare case that a translated word, or an accessibility modified font-size doesn't fit on a single line:

image

While keeping the 84px x 84px when the label is hidden.

image

Let me know your thoughts!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this solution is the best combination for allowing the container to be square when the label is included and allowing it to adjust vertically for future cases, thank you for taking the time to look into this!

@AlexVelezLl AlexVelezLl force-pushed the picture-password-option branch from ea6b851 to d52fb55 Compare April 10, 2026 14:50
@AlexVelezLl
Copy link
Copy Markdown
Member Author

Hi @radinamatic! I have fixed points number 1 and 5. 2, 3, and 4 are not in the scope of this PR, since we are just temporarily presenting the grid on the sign-in page as a playground for you to be able to test it, but this will be removed before merging the PR.

Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

Prior findings

7 prior findings unchanged (all resolved or acknowledged).

Still unaddressed (re-raised below):

  • index.vue QA scaffolding (blocking) — no reply, no code change since last review

7/8 prior findings resolved or acknowledged. 1 re-raised below.


CI mostly passing; Morango integration tests and platform builds still pending (same state as prior round, unrelated to frontend changes). Visual inspection unchanged — no new commits since last review.

kolibri/plugins/user_auth/frontend/views/SignInPage/index.vue:48–69 — blocking: QA scaffolding still present. Three issues remain:

  1. PicturePasswordGrid is rendered unconditionally for all users — no v-if guard on the facility's picture-password feature flag. Every learner sees a 12-icon grid regardless of their facility settings.
  2. Error/success messages ("Incorrect sequence. Try again." / "Correct! Signed in successfully.") are bare English strings suppressed by eslint-disable. They bypass i18n enforcement entirely.
  3. Inline styles (style="color: red; text-align: center", style="margin: 16px 0").

This entire block and the corresponding handlePicturePasswordSubmit method in the script section need to be removed before merging to develop. The grid will be properly integrated with a facility guard in a follow-up issue.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

@AlexVelezLl AlexVelezLl force-pushed the picture-password-option branch from d52fb55 to 3a5d840 Compare April 10, 2026 19:41
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

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

Prior findings

7 prior findings unchanged (all resolved or acknowledged).

Still unaddressed (re-raised below):

  • index.vue QA scaffolding (blocking) — no reply, no code change since last review

7/8 prior findings resolved or acknowledged. 1 re-raised below.


CI passing. Visual inspection: reviewed 2 frames from the PR video — selection and progress-bar states still render correctly.

  • blocking: index.vue QA scaffolding re-raised (see inline)

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

Correct! Signed in successfully.
</p>
<!-- eslint-enable vue/no-bare-strings-in-template -->
<PicturePasswordGrid
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

blocking: (re-raised, 3rd round) This entire block (lines 48–69 + handlePicturePasswordSubmit at line 371) is QA-only scaffolding that must be removed before this lands on develop:

  1. Unconditional renderingPicturePasswordGrid is shown to every user with no v-if checking whether picture password is enabled for the facility.
  2. Bare strings with eslint-disable — "Incorrect sequence. Try again." and "Correct! Signed in successfully." bypass i18n.
  3. Inline stylesstyle="color: red" / style="color: green" bypass theme tokens.
  4. Hardcoded sequence checkhandlePicturePasswordSubmit accepts only '1.2.3' as correct; it's not real authentication.

The picturePasswordIconStyle and picturePasswordShowIconText computed properties and the wrongSequence data field are legitimate and can stay. Remove everything else added to this file and leave a <!-- TODO: integrate PicturePasswordGrid once backend auth is wired --> comment if the integration point needs marking.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is for QA only, it will be removed before merging the PR.

@LianaHarris360 LianaHarris360 dismissed their stale review April 10, 2026 21:03

All requested changes have been addressed on my end, this will be ready to approve & merge after QA passes.

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

Labels

APP: User Re: User app (sign-in, sign-up, user profile, etc.) DEV: frontend SIZE: very large

Projects

None yet

4 participants