Skip to content

refactor(sign-in): migrate sign-in page to the design system#73605

Open
levadadenys wants to merge 7 commits into
stagingfrom
denys/re/signin-flow-rebrand
Open

refactor(sign-in): migrate sign-in page to the design system#73605
levadadenys wants to merge 7 commits into
stagingfrom
denys/re/signin-flow-rebrand

Conversation

@levadadenys

@levadadenys levadadenys commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Migrates the sign-in page (/users/sign_in) from server-rendered HAML to
React + DSCO/MUI with semantic color tokens, matching the sign-up flow. The
sign-in form, the section-code entry, and the page title are now React; their
styles move out of application.scss into a component module.scss.

Before:
image

After:
image
image

In scope: SignInForm (login/password fields, forgot-password link, sign-in

  • sign-up buttons), SectionCodeEntry, the page title (Typography), and
    retiring their legacy CSS.

Out of scope, unchanged: OAuth/social login buttons, the course blocks
("Try it out without signing in"), the global flash banner, and the LTI
account-linking variant.

What's here

  • New SignInForm + SectionCodeEntry (apps/src/signIn/) using DSCO
    TextField / Link + MUI Button / Typography.
  • Page title rendered as MUI Typography (was a HAML <h2>).
  • Even two-column layout restored (the sign-in and OAuth columns split the row);
    the section-code label now matches the sign-in field labels (same DSCO label).
  • Section-code entry migrated; the OAuth buttons stay HAML (own initiative). The
    dev-only OAuth notice got a little vertical spacing.
  • Legacy #signin / .section-sign-in CSS retired from application.scss;
    kept .flex-container, .vertical-or, #change-password, and .blue-button
    (shared with the out-of-scope LTI variant / other pages).

Notable decisions

  • show_flashes stays server-rendered — it consumes the flash and the view
    renders before the layout, so it's what surfaces failed-login errors.
  • UI-test DOM hooks preserved (#signin, #user_login, #user_password,
    #signin-button, #section_code); one stale Cucumber selector updated to
    #section_code_submit.
  • hashed_email is server-set and threaded through unchanged (no client-side
    hashing on sign-in).

Links

  • Jira:

Testing story

Automated (green locally): apps/test/unit/signIn/SignInFormTest.tsx +
SectionCodeEntryTest.tsx (13 tests), yarn run typecheck, ESLint, Stylelint,
scss-lint (application.scss), haml-lint (both views).

Manual, in-browser on staging + local (iterated on QA feedback): page renders,
two-column layout balance, title, label alignment, and ?brand=codeai-next
semantic tokens. Reviewer/QA should still confirm the functional flows end to
end: a real login, a failed login (flash error), a section-code submit to
/users/new, and the forgot-password link.

Follow-ups (not in this PR)

  • Course blocks ("Try it out without signing in") — spec'd separately for a
    later PR; drags in shared pegasus CSS + per-card server data, and there's no
    DSCO Card primitive yet.
  • OAuth / social login buttons — separate initiative.

Privacy and security

No auth or Devise controller/session changes. The form still POSTs
user[login], user[password], user[hashed_email] to /users/sign_in with a
CSRF token via RailsAuthenticityToken; hashed_email is server-set and passed
through unchanged.

🤖 Generated with Claude Code

Replace the server-rendered sign-in form and section-code entry with React
components using DSCO TextField, MUI Button/Typography, and semantic color
tokens, matching the sign-up flow. OAuth buttons, course blocks, and the LTI
account-linking variant are unchanged.

- New SignInForm + SectionCodeEntry (apps/src/signIn/) with a layout-only
  module.scss (semantic tokens, no hex/legacy vars)
- Mount both from devise/sessions/_login.js; retire the old jQuery handlers
  (userReturnTo write moves into SignInForm's effect)
- Retire #signin / .section-sign-in CSS from application.scss; keep
  .flex-container, .vertical-or, #change-password and .blue-button (shared with
  the out-of-scope LTI variant / other pages)
- Preserve the UI-test DOM hooks (#signin, #user_login, #user_password,
  #signin-button, #section_code); update one stale cucumber selector
- Keep show_flashes server-rendered so failed-login errors still surface

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

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.

Pull request overview

Migrates the /users/sign_in page from server-rendered HAML form markup to React components built with DSCO/MUI primitives, keeping the underlying Devise/Rails session POST and flash-error rendering server-side.

Changes:

  • Replaced the legacy HAML #signin form with a React-mounted SignInForm that posts to /users/sign_in and preserves existing UI-test DOM hooks.
  • Replaced the legacy section-code HAML form with a React-mounted SectionCodeEntry, and updated the Cucumber selector accordingly.
  • Retired legacy sign-in/section-code CSS from application.scss in favor of a colocated CSS module, and added unit tests for both new components.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
dashboard/test/ui/features/platform/signing_in.feature Updates UI test click target to the new #section_code_submit button id.
dashboard/app/views/devise/shared/_oauth_links.haml Replaces the section-code HAML form with a React mount point and data attributes.
dashboard/app/views/devise/sessions/_login.html.haml Replaces the sign-in HAML form with a React mount point and passes required props via data-*.
dashboard/app/assets/stylesheets/application.scss Removes legacy sign-in/section-code styling and leaves #change-password styling intact.
apps/test/unit/signIn/SignInFormTest.tsx Adds unit coverage for form fields, submit wiring, analytics event, and userReturnTo storage behavior.
apps/test/unit/signIn/SectionCodeEntryTest.tsx Adds unit coverage for section-code heading/input/button and GET submit behavior.
apps/src/sites/studio/pages/devise/sessions/_login.js Mounts SignInForm and SectionCodeEntry React roots using server-provided data-*.
apps/src/signIn/signInStyles.module.scss Adds layout-only CSS module styles for the new sign-in React components.
apps/src/signIn/SignInForm.tsx Introduces the DSCO/MUI-based sign-in form that preserves Devise POST field names and key DOM hooks.
apps/src/signIn/SectionCodeEntry.tsx Introduces the DSCO/MUI-based section-code entry form with preserved input/button ids.

levadadenys and others added 4 commits July 2, 2026 18:28
The sign-in column was capped at max-width 28rem while the OAuth column keeps
flex-grow: 2 uncapped, so the OAuth column grew to fill the row and dwarfed the
form. Restore the even split by matching the legacy #signin sizing
(flex-grow: 2, min-width: 450px) and constrain the form content to a readable
width via a .formArea wrapper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the "Sign in" page title out of the server-rendered HAML <h2> into a
React MUI Typography (variant h2) mounted at #sign-in-title, so it follows the
design system's type scale like the rest of the migrated page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render the section-code label via the TextField's own label prop instead of a
separate Typography h6, so both columns use the identical DSCO field label
(same size, weight, padding, and top alignment). Also give the dev-only OAuth
notice a little vertical breathing room (display:block + margin-block) between
the section-code field and the OAuth buttons.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@levadadenys levadadenys marked this pull request as ready for review July 2, 2026 16:31
@levadadenys levadadenys requested a review from Copilot July 2, 2026 16:31

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread dashboard/app/assets/stylesheets/application.scss Outdated
Comment thread apps/src/signIn/SignInForm.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3149c743b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/src/signIn/SignInForm.tsx Outdated
Comment thread dashboard/app/assets/stylesheets/application.scss
@levadadenys levadadenys requested review from a team and ebeastlake July 2, 2026 17:13
…y #signin styles

Addresses the drone failures and PR review feedback:

- GlobalEditionTest / fa sign_in_page: the form action was hard-coded to
  /users/sign_in, dropping the region/locale prefix (e.g. /fa/users/sign_in).
  Pass session_path(resource_name) from the server via the mount's
  data-sign-in-path and use it as the form action; restore id="new_user".
  Update global_edition_test to assert the region-versioned URL on the mount
  (the form is React-rendered now).
- #signin regression: several server-rendered pages (existing_account, PD/Foorm
  logged-out) still use id="signin" and relied on the shared block. Move that
  styling to a .signin-legacy class those pages opt into, so the React sign-in
  page (which reuses #signin as a test hook) doesn't inherit legacy form/button
  rules and the other pages keep their styling.
- Guard the forgot-password link on both path and label to avoid an empty link.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@levadadenys levadadenys requested a review from a team July 3, 2026 07:38
…legacy hash-on-submit)

devise/sessions/new.js attaches a submit handler to form#new_user that calls
window.dashboard.hashEmail against #user_hashed_email. The React sign-in form
has no such element, so once the form carried id="new_user" that handler broke
the native POST and login never reached /home (platform/signing_in and
login_redirect UI tests failed). The id was only added to satisfy an old
assertion in global_edition_test, which now checks the mount's
data-sign-in-path instead, so the id is unnecessary. Remove it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@artem-vavilov artem-vavilov left a comment

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.

Tested this locally, and it looks great to me. Nice work! 🙌🏻

I am wondering if we could also use this opportunity to improve the forms’ accessibility a bit by marking the relevant fields as required.

It would also be helpful to have someone from the @code-dot-org/platform team take a look at these changes.

@artem-vavilov artem-vavilov requested a review from a team July 3, 2026 13:59
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.

3 participants