Skip to content

refactor: Replace date-fns with native Intl APIs and update phone uti…#668

Merged
ashwin31 merged 1 commit intomasterfrom
sf_import
Mar 3, 2026
Merged

refactor: Replace date-fns with native Intl APIs and update phone uti…#668
ashwin31 merged 1 commit intomasterfrom
sf_import

Conversation

@ashwin31
Copy link
Copy Markdown
Member

@ashwin31 ashwin31 commented Mar 3, 2026

…lities to be asynchronous.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved phone number validation and formatting accuracy across the application
    • Enhanced phone number display on user profile to consistently show properly formatted values
    • Optimized redirect behavior during organization switch operations
  • Refactor

    • Modernized date formatting implementation for improved performance and code maintainability

Copilot AI review requested due to automatic review settings March 3, 2026 10:28
* @returns {string} Formatted date string or '-' if no date
*/
export function formatDate(date, formatStr = 'MMM d, yyyy') {
export function formatDate(date) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').


const relativeFormatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

const RELATIVE_UNITS = /** @type {const} */ ([
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

year: 'numeric'
});

const relativeFormatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

*/

import { format, formatDistanceToNow } from 'date-fns';
const dateFormatter = new Intl.DateTimeFormat('en-US', {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

* @returns {string} Formatted date string or '-' if no date
*/
export function formatDate(date, formatStr = 'MMM d, yyyy') {
export function formatDate(date) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').


const relativeFormatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

const RELATIVE_UNITS = /** @type {const} */ ([
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

year: 'numeric'
});

const relativeFormatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

*/

import { format, formatDistanceToNow } from 'date-fns';
const dateFormatter = new Intl.DateTimeFormat('en-US', {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

const trimmed = phoneNumber.trim();

try {
const { isValidPhoneNumber, parsePhoneNumber, isPossiblePhoneNumber } = await getLib();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
'destructuring binding' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
Missing semicolon.

* @returns {Promise<{ isValid: boolean, formatted?: string, error?: string }>}
*/
export function validatePhoneNumber(phoneNumber, defaultCountry) {
export async function validatePhoneNumber(phoneNumber, defaultCountry) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').
Expected an assignment or function call and instead saw an expression.
Missing semicolon.
Unexpected 'async'.

@@ -1,19 +1,27 @@
import { isValidPhoneNumber, parsePhoneNumber, isPossiblePhoneNumber } from 'libphonenumber-js';
/** @type {Promise<typeof import('libphonenumber-js')> | null} */
let _lib = null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

errors.phone = phoneValidation.error || 'Please enter a valid phone number';
} else {
formattedPhone = formatPhoneForStorage(phone.trim());
formattedPhone = await formatPhoneForStorage(phone.trim());
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing semicolon.

let formattedPhone = null;
if (phone && phone.trim().length > 0) {
const phoneValidation = validatePhoneNumber(phone.trim());
const phoneValidation = await validatePhoneNumber(phone.trim());
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
Missing semicolon.

@ashwin31 ashwin31 merged commit 6fa9fb9 into master Mar 3, 2026
6 of 7 checks passed
@ashwin31 ashwin31 deleted the sf_import branch March 3, 2026 10:28
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 3, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0f2af3 and c046137.

⛔ Files ignored due to path filters (1)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • frontend/package.json
  • frontend/src/hooks.server.js
  • frontend/src/lib/utils/formatting.js
  • frontend/src/lib/utils/phone.js
  • frontend/src/routes/(app)/profile/+page.server.js
  • frontend/src/routes/(app)/profile/+page.svelte

📝 Walkthrough

Walkthrough

Removed the date-fns dependency and migrated date formatting logic to use the native Intl API. Converted phone utility functions to async with dynamic imports of libphonenumber-js. Updated profile page components to await async phone validation and formatting operations. Changed HTTP redirect status code from 307 to 303 on org-switch failure.

Changes

Cohort / File(s) Summary
Dependency Removal
frontend/package.json
Removed date-fns version ^4.1.0 dependency.
Date Formatting Refactor
frontend/src/lib/utils/formatting.js
Replaced date-fns-based formatters with native Intl API. Introduced dateFormatter and relativeFormatter with custom RELATIVE_UNITS mapping. Updated formatDate() to remove format string parameter; updated formatRelativeDate() to compute numeric diff and use Intl relative time formatting.
Phone Utilities Async Migration
frontend/src/lib/utils/phone.js
Converted synchronous phone functions to async with dynamic imports. validatePhoneNumber(), formatPhoneNumber(), and formatPhoneForStorage() now return Promises. Added internal getLib() helper for lazy loading libphonenumber-js.
Profile Page Server Updates
frontend/src/routes/(app)/profile/+page.server.js
Updated phone validation and formatting calls to await async results from validatePhoneNumber() and formatPhoneForStorage().
Profile Page Component Updates
frontend/src/routes/(app)/profile/+page.svelte
Added formattedDisplayPhone state variable. Introduced async effect to compute and cache formatted phone display. Updated phone validation function to await validatePhoneNumber(). Updated phone number UI display to use formatted value with fallbacks.
Server Hook Modification
frontend/src/hooks.server.js
Changed HTTP redirect status code from 307 to 303 on org-switch failure.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Date-fns is gone, Intl takes the stage,
Phone numbers now dance in async ballet,
Dynamic imports load what's needed today,
The profile page flows with promises to obey,
A hop towards performance and modern display! ✨

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sf_import

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors frontend formatting utilities by removing date-fns in favor of native Intl APIs, and updates phone utilities to lazy-load libphonenumber-js via async helpers (propagating async usage into the profile page and server action).

Changes:

  • Replace date-fns date/relative formatting with Intl.DateTimeFormat and Intl.RelativeTimeFormat.
  • Refactor phone utilities to async functions with dynamic import caching for libphonenumber-js.
  • Update profile UI/server action usage to await phone validation/formatting and adjust redirects.

Reviewed changes

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

Show a summary per file
File Description
frontend/src/routes/(app)/profile/+page.svelte Adapts profile UI to async phone formatting/validation and displays resolved formatted phone.
frontend/src/routes/(app)/profile/+page.server.js Awaits async phone validation/formatting before sending updates to the API.
frontend/src/lib/utils/phone.js Converts phone helpers to async and lazy-loads libphonenumber-js.
frontend/src/lib/utils/formatting.js Replaces date-fns with Intl formatters for absolute + relative dates.
frontend/src/hooks.server.js Adjusts org-switch-failure redirect status code.
frontend/package.json Removes date-fns dependency.
frontend/pnpm-lock.yaml Removes date-fns lock entries.
Files not reviewed (1)
  • frontend/pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)

frontend/src/routes/(app)/profile/+page.svelte:61

  • validatePhone is now async and is invoked on every oninput. Multiple in-flight validations can resolve out of order and set phoneError based on a previous input value. Consider debouncing validation and/or tracking the latest validated formData.phone value (or a counter) so only the most recent validation result updates phoneError.
  async function validatePhone() {
    if (!formData.phone.trim()) {
      phoneError = '';
      return;
    }

    const validation = await validatePhoneNumber(formData.phone);
    if (!validation.isValid) {
      phoneError = validation.error || 'Invalid phone number';
    } else {
      phoneError = '';
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +40 to +47
// Format phone for display (async, resolved into state)
$effect(() => {
if (data.user.phone) {
formatPhoneNumber(data.user.phone).then((f) => (formattedDisplayPhone = f));
} else {
formattedDisplayPhone = '';
}
});
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The async $effect that formats data.user.phone can race if data.user.phone changes before the previous formatPhoneNumber() promise resolves (stale promise may overwrite formattedDisplayPhone). Consider guarding with a monotonic request id / captured value check (only assign if the phone value is still current), or using an abortable pattern in the effect cleanup.

Copilot uses AI. Check for mistakes.
year: 'numeric'
});

const relativeFormatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

dateFormatter is configured with locale en-US, but relativeFormatter uses en. If the intent is consistent formatting across the app, consider using the same locale (or deriving both from a single locale setting) to avoid mismatched language/region output.

Suggested change
const relativeFormatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
const relativeFormatter = new Intl.RelativeTimeFormat('en-US', { numeric: 'auto' });

Copilot uses AI. Check for mistakes.
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.

2 participants