Skip to content

Replace moment with date-fns v3#86

Open
cerredz wants to merge 2 commits into
BAWES-Universe:masterfrom
cerredz:fix/31-replace-moment-date-fns-v3
Open

Replace moment with date-fns v3#86
cerredz wants to merge 2 commits into
BAWES-Universe:masterfrom
cerredz:fix/31-replace-moment-date-fns-v3

Conversation

@cerredz
Copy link
Copy Markdown

@cerredz cerredz commented May 15, 2026

Closes #31.

Summary

  • upgraded date-fns from v2 to v3 and removed direct moment
  • removed ion2-calendar, which depended on moment, and replaced it with a local Ionic/date-fns calendar modal for the existing single-date and range-date flows
  • routed existing date-fns call sites through a small compatibility wrapper so Angular 15 / TypeScript 4.8 can consume the v3 runtime without parsing unsupported v3 declaration syntax

Verification

  • npm run build passes
  • rg -n moment|ion2-calendar src package.json package-lock.json returns no matches
  • git diff --check passes

Note: npm run lint currently fails on 713 pre-existing template equality violations across the app, unrelated to this change.

Summary by CodeRabbit

Release Notes

  • New Features

    • Redesigned calendar modal component for improved date selection functionality.
  • Chores

    • Updated date utilities library to version 3.6.0.
    • Removed legacy calendar and moment dependencies; internal code reorganization to support new calendar implementation.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Warning

Rate limit exceeded

@cerredz has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 24 minutes and 37 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3e474f71-945e-4afd-9a18-6825858f412d

📥 Commits

Reviewing files that changed from the base of the PR and between 6311fad and c66bcb4.

📒 Files selected for processing (1)
  • src/app/components/calendar-modal/calendar-modal.component.ts
📝 Walkthrough

Walkthrough

This PR migrates the app from moment.js and ion2-calendar to date-fns v3 with a custom Ionic calendar modal. The wrapper module centralizes date-fns utility imports, the new CalendarModal component replaces the removed ion2-calendar package, and imports across 25+ files are redirected to use the local wrapper.

Changes

Date-fns v3 migration with custom calendar modal

Layer / File(s) Summary
Date-fns wrapper and dependency upgrade
package.json, src/app/util/date-fns.ts
Created a CommonJS wrapper at src/app/util/date-fns.ts that re-exports 12 date-fns v3 utilities (format, parseISO, startOfMonth, etc.) as typed constants. Upgraded date-fns from ^2.29.3 to ^3.6.0 and removed ion2-calendar and moment dependencies.
Custom calendar modal component
src/app/components/calendar-modal/calendar-modal.component.ts, calendar-modal.component.html, calendar-modal.component.scss, calendar-modal.module.ts
Introduces CalendarModal component with CalendarDay, CalendarResult, and CalendarModalOptions interfaces. Supports single-date and date-range selection modes via Ionic datetime controls, with title, minDate, and scroll-to-date options. Includes conditional UI branches, date normalization helpers, and modal dismiss/confirm actions.
Calendar modal module registration
src/app/app.module.ts
Registered CalendarModalModule in AppModule imports, replacing the prior ion2-calendar CalendarModule. No other bootstrap or provider changes.
Update calendar modal imports across components
src/app/components/date-range-refinement-list/..., src/app/pages/logged-in/candidate/candidate-view/..., leave-request.page.ts, leave-request-form.page.ts, transfer-form.page.ts
Replaced ion2-calendar imports of CalendarModal, CalendarModalOptions, and CalendarResult with imports from the local calendar-modal.component. Updated transfer-form.page.ts type comment from 'moment' to 'js-date'.
Redirect date-fns imports to wrapper module
src/app/components/appeal-filter/..., date-dropdown/..., date-picker/..., date-popup/..., request-filter/..., story-filter/..., time-picker/..., src/app/pages/logged-in/candidate/..., company/..., email-campaign/..., fulltimer/..., reports/valocity/..., story/job-form/..., transfer/...
Updated ~25 components and pages to import format, parseISO, and other date utilities from src/app/util/date-fns instead of the external date-fns package, enabling centralized wrapper control.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop into v3, the modern way,
Moment's gone, date-fns here to stay,
A custom modal, shiny and new,
Wrapper exports, all tried and true,
Bundle shrinks, the app feels light!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Replace moment with date-fns v3' accurately and concisely summarizes the main objective of this PR—removing moment.js and upgrading to date-fns v3.
Linked Issues check ✅ Passed The PR successfully meets all coding requirements from issue #31: moment removed from package.json and src/, date-fns upgraded to v3, ion2-calendar replaced with local CalendarModal component, new date-fns wrapper created, all date utility imports migrated, and ng build passes.
Out of Scope Changes check ✅ Passed All changes directly support the migration objectives: dependency updates, calendar component replacement, utility wrapper creation, and import refactoring across components. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/components/calendar-modal/calendar-modal.component.ts`:
- Around line 83-93: The confirm() handler in calendar-modal.component currently
dismisses the modal with from/to as-is, which can produce an inverted range when
fromValue > toValue; fix by converting both values using toCalendarDay (use the
resulting comparable timestamp or date) then normalize so the earlier day is
assigned to "from" and the later to "to" (swap if necessary) before calling
this.modalCtrl.dismiss({ ...from, from, to }); reference: confirm(),
isRangeMode, fromValue, toValue, toCalendarDay, modalCtrl.dismiss.

In `@src/app/util/date-fns.ts`:
- Around line 1-3: The file currently uses a CommonJS require assigned to the
dateFns variable (declare const require; const dateFns = require('date-fns');),
which prevents tree-shaking; replace that with ESM named imports for only the
utilities used (e.g., eachDayOfInterval, endOfMonth, format, getDate, getMonth,
getYear, isSameDay, isSameMonth, isSameYear, isToday, parseISO, startOfMonth) or
import those functions from their submodule paths (like 'date-fns/format') and
remove the declare/require and dateFns variable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c69cba4b-622b-441c-b6d5-8aa1218a5185

📥 Commits

Reviewing files that changed from the base of the PR and between 39a33ff and 6311fad.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (33)
  • package.json
  • src/app/app.module.ts
  • src/app/components/appeal-filter/appeal-filter.component.ts
  • src/app/components/calendar-modal/calendar-modal.component.html
  • src/app/components/calendar-modal/calendar-modal.component.scss
  • src/app/components/calendar-modal/calendar-modal.component.ts
  • src/app/components/calendar-modal/calendar-modal.module.ts
  • src/app/components/date-dropdown/date-dropdown.component.ts
  • src/app/components/date-picker/date-picker.component.ts
  • src/app/components/date-popup/date-popup.component.ts
  • src/app/components/date-range-refinement-list/date-range-refinement-list.component.ts
  • src/app/components/request-filter/request-filter.component.ts
  • src/app/components/story-filter/story-filter.component.ts
  • src/app/components/time-picker/time-picker.component.ts
  • src/app/pages/logged-in/candidate-assign-form/candidate-assign-form.page.ts
  • src/app/pages/logged-in/candidate/candidate-assigned-history/candidate-assigned-history.page.ts
  • src/app/pages/logged-in/candidate/candidate-certificate-form/candidate-certificate-form.page.ts
  • src/app/pages/logged-in/candidate/candidate-form/candidate-form.page.ts
  • src/app/pages/logged-in/candidate/candidate-view/candidate-view.page.ts
  • src/app/pages/logged-in/candidate/candidate-work-log/log-time-manually/log-time-manually.page.ts
  • src/app/pages/logged-in/company/company-contract/company-contract-form/company-contract-form.page.ts
  • src/app/pages/logged-in/company/company-request-list/company-request-list.page.ts
  • src/app/pages/logged-in/company/request-interview-filter/request-interview-filter.page.ts
  • src/app/pages/logged-in/email-campaign/email-campaign-form/email-campaign-form.page.ts
  • src/app/pages/logged-in/fulltimer/fulltimer-form/fulltimer-form.page.ts
  • src/app/pages/logged-in/leave-request/leave-request.page.ts
  • src/app/pages/logged-in/leave/leave-request-form/leave-request-form.page.ts
  • src/app/pages/logged-in/reports/valocity/valocity.page.ts
  • src/app/pages/logged-in/story/job-form/job-form.page.ts
  • src/app/pages/logged-in/transfer/transfer-candidate-list/transfer-candidate-list.page.ts
  • src/app/pages/logged-in/transfer/transfer-form/transfer-form.page.ts
  • src/app/pages/logged-in/transfer/transfer-list-all/transfer-list-all.page.ts
  • src/app/util/date-fns.ts

Comment thread src/app/components/calendar-modal/calendar-modal.component.ts
Comment thread src/app/util/date-fns.ts
Comment on lines +1 to +3
declare const require: any;

const dateFns = require('date-fns');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🌐 Web query:

For date-fns v3, do CommonJS require('date-fns') imports preserve tree-shaking in webpack/Angular builds, or are ESM named imports required for optimal bundle size?

💡 Result:

For date-fns v3, using CommonJS require imports does not preserve tree-shaking in webpack or Angular builds [1][2]. To achieve optimal bundle size, you must use ESM named imports [3][4]. In date-fns v3, the library is a dual-package that supports both CommonJS and ESM [1][2]. However, tree-shaking—the process by which bundlers like webpack remove unused code—relies on the static structure of ES modules [5][6]. When you use CommonJS require statements, the bundler cannot statically analyze the dependency graph to safely eliminate unused functions, often resulting in the entire library (or large portions of it) being included in your final bundle [7][6][3]. To ensure optimal bundle size: 1. Use ESM named imports: Import functions directly from their specific submodules [3][4]. For example, use import { format } from 'date-fns/format'; instead of import { format } from 'date-fns'; [1][2]. 2. Avoid wildcard imports: Never use import * as dateFns from 'date-fns';, as this forces the bundler to include the entire library [3]. 3. Build Configuration: Ensure your build environment (webpack, Angular CLI) is configured for production mode (e.g., mode: 'production' in webpack or ng build --configuration production in Angular), which enables the optimizations necessary for tree-shaking to take effect [8][9]. While date-fns v3 improved its internal structure to be more compatible with modern bundlers, using ESM imports remains the standard requirement for effective tree-shaking [3][2]. If you are migrating from v2, note that v3 requires named imports even when importing from submodules (e.g., import { addDays } from 'date-fns/addDays';) [1][2].

Citations:


🏁 Script executed:

# Check the actual file to confirm the problematic pattern
cat -n src/app/util/date-fns.ts

Repository: BAWES-Universe/studenthub-staff

Length of output: 1364


Switch to ESM named imports to preserve tree-shaking and achieve bundle-size goals.

Line 3 uses CommonJS require('date-fns'), which prevents webpack/Angular from tree-shaking unused code. This pulls the entire library into the bundle, directly undermining this PR's bundle-reduction objective. Replace with ESM named imports:

import { eachDayOfInterval, endOfMonth, format, getDate, getMonth, getYear, isSameDay, isSameMonth, isSameYear, isToday, parseISO, startOfMonth } from 'date-fns';

For even better tree-shaking, import from submodules (e.g., import { format } from 'date-fns/format';).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/util/date-fns.ts` around lines 1 - 3, The file currently uses a
CommonJS require assigned to the dateFns variable (declare const require; const
dateFns = require('date-fns');), which prevents tree-shaking; replace that with
ESM named imports for only the utilities used (e.g., eachDayOfInterval,
endOfMonth, format, getDate, getMonth, getYear, isSameDay, isSameMonth,
isSameYear, isToday, parseISO, startOfMonth) or import those functions from
their submodule paths (like 'date-fns/format') and remove the declare/require
and dateFns variable.

@cerredz
Copy link
Copy Markdown
Author

cerredz commented May 15, 2026

Addressed the range-order review item in commit c66bcb4: the calendar modal now converts both selected dates to CalendarDay and swaps them when needed so from is always the earlier date and to is always the later date.

Validation:

  • npm ci fails on the existing Capacitor peer dependency conflict, so I used npm ci --legacy-peer-deps for this fresh checkout.
  • npm run build passes after the range fix.
  • git diff --check passes.

I also tested the suggested date-fns ESM wrapper change, but it is not safe with this project stack. A named import from date-fns fails ng build because this Angular/TypeScript version cannot parse date-fns v3 export type * declarations in node_modules/date-fns/*. Submodule ESM imports hit the same declaration path, and .js submodule specifiers are not exported by date-fns. I left the compatibility wrapper unchanged to keep the build green.

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.

[UPGRADE] Replace moment.js with date-fns v3

1 participant