Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localize expiration timestamps for device assurance grace period #3703

Merged
merged 7 commits into from
Sep 4, 2024

Conversation

trevoring-okta
Copy link
Contributor

@trevoring-okta trevoring-okta commented Aug 29, 2024

Description:

  • Uses Date.toLocaleString() (has extensive browser coverage, including IE11) to render an ISO8601 formatted string in a format that is essentially Okta's short-with-timezone format (e.g. 11/29/2021, 4:15 PM EDT)
  • Uses the languageCode widget prop/setting to pass the client's locale to the function

PR Checklist

Issue:

Reviewers:

Screenshot/Video:

Screenshot 2024-09-03 at 5 52 15 PM

Screenshot 2024-09-03 at 5 53 16 PM

Downstream Monolith Build:

let localizedExpiry;
switch (key.split(GRACE_PERIOD_TITLE_KEY)[1]) {
case GRACE_PERIOD_DUE_BY_DATE_SUFFIX:
localizedExpiry = TimeUtil.formatUnixEpochToDeviceAssuranceGracePeriodDueDate(
Copy link
Contributor

Choose a reason for hiding this comment

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

Proposal for Gen3: after merging PR to use i18next we can utilize DateTime localization

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh nice, I didn't know this was inflight. Looks like it would work well, I'll make a follow up ticket and include it as a comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Internal Ref: OKTA-798446

@@ -437,7 +437,7 @@ export const transformOktaVerifyEnrollPoll: IdxStepTransformer = ({

const stepper: StepperLayout = {
type: UISchemaLayoutType.STEPPER,
key: 'stepper_' + channelType,
key: `stepper_${channelType}`,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was pulled in as an automatic lint fix. I'll leave it here but it's unrelated to my actual code changes

Comment on lines -1659 to -1660
# {0} is the number of days until the grace period expires
idx.device_assurance.grace_period.warning.title.due_by_days = Your device doesn't meet the security requirements. Fix the issue within {0} days to prevent lockout.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We are consolidating to a single string for the expiration message. This can get deleted in the next translation run

"message": "Your device doesn't meet the security requirements. Fix the issue within 7 days to prevent lockout.",
"message": "Your device doesn't meet the security requirements. Fix the issue by 09/05/2024, 12:00 AM UTC to prevent lockout.",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Update: we will send a localized string that specifies UTC as the timezone for this message field to still provide a semantically correct expiry string from the server. This will cover cases where we might have a L10N error and client-side loc() fails.

E.g. For this specific mock, the server will send an ISO8601 format string of "2024-09-05T00:00:00.000Z" as the param and the message field will be that same string localized to UTC rather than the client's timezone -> "09/05/2024, 12:00 AM UTC"

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good thought to have the fallback, although does the code currently handle if a call to loc returns L10N_ERROR well?

Copy link
Contributor Author

@trevoring-okta trevoring-okta Sep 4, 2024

Choose a reason for hiding this comment

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

You're right, I just checked and it will still render L10N_ERROR as the string. The main case I'm looking to add coverage for is something going wrong in the TimeUtil function when creating the localized expiry param. I'll add a check to use the fallback message if the param comes back falsy because of an invalid Date object.

Digging into this more, I don't think this fallback message with the server-side localized string will ever actually get rendered to the SIW because the generic transformer that localizes all IDX transaction messages will always run before my grace period code is hit, so the actual fallback string users might see is "Your device doesn't meet the security requirements. Fix the issue by 2024-09-05T00:00:00.000Z to prevent lockout." with the ISO8601 string as the parameter before it's processed into the ideal format via TimeUtil. Regardless, I think having this be the server-side message in the IDX payload is better than what I originally had, which was a Unix timestamp

@@ -95,13 +61,14 @@ test.requestHooks(dueByDaysMock)('should render correct messaging and navigate t

test.requestHooks(oneOptionMock)('should render correct messaging for grace period with one option', async t => {
const deviceAssuranceGracePeriodPage = await setup(t);
const expiryLocaleString = TimeUtil.formatDateToDeviceAssuranceGracePeriodExpiryLocaleString(new Date('2024-09-05T00:00:00.000Z'));
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any way to avoid using the TimeUtil here in the test as well? I assume you are doing this so the string is always formatted for the TZ of the machine running the test rather than using a static string. Not ideal, but could be acceptable if we're unit testing formatDateToDeviceAssuranceGracePeriodExpiryLocaleString well

Copy link
Contributor

Choose a reason for hiding this comment

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

There might be ways to override the timezone in testcafe, although forcing a timezone in a unit test is a lot easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah looks like TestCafe doesn't have a built-in way to enforce a specific timezone. During my first pass at this PR I was struggling to set a hard-coded timezone for Jest, but I just found a solution that works. Will add some unit tests

* @param {LanguageCode} languageCode The user's language code / locale
* @return {String} The formatted `short-with-timezone` local string
*/
formatDateToDeviceAssuranceGracePeriodExpiryLocaleString: (date, languageCode) => date.toLocaleString(languageCode, {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to do any input validation or checks for null/undefined?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will move the check for an invalid Date object in here 👍 I just checked and toLocaleString() handles null/undefined values for the locale param so we shouldn't need to validate languageCode

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually looks like toLocaleString() only handles undefined. Will add some validation for other cases

* @param {LanguageCode} languageCode The user's language code / locale
* @return {String} The formatted `short-with-timezone` local string
*/
formatDateToDeviceAssuranceGracePeriodExpiryLocaleString: (date, languageCode) => date.toLocaleString(languageCode, {
Copy link
Contributor

@shawyu-okta shawyu-okta Sep 3, 2024

Choose a reason for hiding this comment

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

Related but separate: We might want to add a few simple unit tests here to show our expected output.

Unit tests aren't super interesting besides defining behavior since this is just wrapping toLocaleString but you might consider moving some more of the fallback and business logic into this utility, which would make the unit tests more useful and also would test the fallback behavior you're expecting.

lesterchoi-okta
lesterchoi-okta previously approved these changes Sep 4, 2024
month: '2-digit',
day: '2-digit',
hour: 'numeric',
minute: 'numeric',
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought you were truncating the minute -- or maybe you meant you'd round down? I thought minute: 'numeric' would show a single digit for values <10m after the hour, but it seems to be overridden by one of the other values

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, yeah we're rounding down, though I actually forgot to enforce that. I looked up why numeric doesn't show a single digit value and apparently that happens for specific combinations of these options, but to be safe I'll use '2-digit' for hour and minute

@oktapp-aperture-okta oktapp-aperture-okta bot merged commit e3e2ad9 into master Sep 4, 2024
3 checks passed
@oktapp-aperture-okta oktapp-aperture-okta bot deleted the ti-OKTA-798277-localize-gp-expiry branch September 4, 2024 20:03
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.

4 participants