-
Notifications
You must be signed in to change notification settings - Fork 24
Replace moment.js with date-fns v3 #87
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| import { CommonModule } from '@angular/common'; | ||
| import { Component, Input, NgModule } from '@angular/core'; | ||
| import { IonicModule, ModalController } from '@ionic/angular'; | ||
| import { format } from 'date-fns'; | ||
|
|
||
| export interface CalendarResult { | ||
| string: string; | ||
| unix: number; | ||
| date: Date; | ||
| } | ||
|
|
||
| export interface CalendarModalOptions { | ||
| canBackwardsSelected?: boolean; | ||
| defaultDate?: Date | string; | ||
| defaultDateRange?: { | ||
| from?: Date | string; | ||
| to?: Date | string; | ||
| }; | ||
| defaultScrollTo?: Date | string; | ||
| pickMode?: 'single' | 'range'; | ||
| title?: string; | ||
| } | ||
|
|
||
| export interface CalendarComponentOptions extends CalendarModalOptions {} | ||
|
|
||
| @Component({ | ||
| selector: 'ion-calendar-modal', | ||
| template: ` | ||
| <ion-header> | ||
| <ion-toolbar> | ||
| <ion-title>{{ options?.title || 'Select Date' }}</ion-title> | ||
| <ion-buttons slot="end"> | ||
| <ion-button (click)="close()">Cancel</ion-button> | ||
| </ion-buttons> | ||
| </ion-toolbar> | ||
| </ion-header> | ||
|
|
||
| <ion-content class="ion-padding"> | ||
| <ng-container *ngIf="isRange; else singleDate"> | ||
| <ion-item lines="none"> | ||
| <ion-label position="stacked">From</ion-label> | ||
| <ion-datetime | ||
| presentation="date" | ||
| [min]="minDate" | ||
| [value]="fromValue" | ||
| (ionChange)="updateFrom($event)" | ||
| ></ion-datetime> | ||
| </ion-item> | ||
|
|
||
| <ion-item lines="none"> | ||
| <ion-label position="stacked">To</ion-label> | ||
| <ion-datetime | ||
| presentation="date" | ||
| [min]="minDate" | ||
| [value]="toValue" | ||
| (ionChange)="updateTo($event)" | ||
| ></ion-datetime> | ||
| </ion-item> | ||
| </ng-container> | ||
|
|
||
| <ng-template #singleDate> | ||
| <ion-datetime | ||
| presentation="date" | ||
| [min]="minDate" | ||
| [value]="singleValue" | ||
| (ionChange)="updateSingle($event)" | ||
| ></ion-datetime> | ||
| </ng-template> | ||
| </ion-content> | ||
|
|
||
| <ion-footer> | ||
| <ion-toolbar> | ||
| <ion-buttons slot="end"> | ||
| <ion-button color="primary" (click)="confirm()">Done</ion-button> | ||
| </ion-buttons> | ||
| </ion-toolbar> | ||
| </ion-footer> | ||
| `, | ||
| }) | ||
| export class CalendarModal { | ||
| @Input() options: CalendarModalOptions = {}; | ||
|
|
||
| singleValue = this.toInputValue(new Date()); | ||
| fromValue = this.toInputValue(new Date()); | ||
| toValue = this.toInputValue(new Date()); | ||
| minDate: string | null = null; | ||
|
|
||
| constructor(private modalCtrl: ModalController) {} | ||
|
|
||
| ngOnInit() { | ||
| const today = new Date(); | ||
| const range = this.options?.defaultDateRange; | ||
|
|
||
| this.singleValue = this.toInputValue(this.options?.defaultDate || this.options?.defaultScrollTo || today); | ||
| this.fromValue = this.toInputValue(range?.from || this.options?.defaultScrollTo || today); | ||
| this.toValue = this.toInputValue(range?.to || this.options?.defaultScrollTo || today); | ||
|
|
||
| if (this.options?.canBackwardsSelected === false) { | ||
| this.minDate = this.toInputValue(today); | ||
| } | ||
| } | ||
|
|
||
| get isRange() { | ||
| return this.options?.pickMode === 'range'; | ||
| } | ||
|
|
||
| normalizeValue(value: string | string[] | null | undefined) { | ||
| if (Array.isArray(value)) { | ||
| return value[0] || this.toInputValue(new Date()); | ||
| } | ||
|
|
||
| return value || this.toInputValue(new Date()); | ||
| } | ||
|
|
||
| updateFrom(event: Event) { | ||
| this.fromValue = this.normalizeValue((event as CustomEvent).detail?.value); | ||
| } | ||
|
|
||
| updateTo(event: Event) { | ||
| this.toValue = this.normalizeValue((event as CustomEvent).detail?.value); | ||
| } | ||
|
|
||
| updateSingle(event: Event) { | ||
| this.singleValue = this.normalizeValue((event as CustomEvent).detail?.value); | ||
| } | ||
|
|
||
| close() { | ||
| this.modalCtrl.dismiss(); | ||
| } | ||
|
|
||
| confirm() { | ||
| if (this.isRange) { | ||
| this.modalCtrl.dismiss({ | ||
| from: this.toResult(this.fromValue), | ||
| to: this.toResult(this.toValue), | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| this.modalCtrl.dismiss(this.toResult(this.singleValue)); | ||
| } | ||
|
|
||
| private toInputValue(value: Date | string) { | ||
| return format(this.toDate(value), 'yyyy-MM-dd'); | ||
| } | ||
|
|
||
| private toResult(value: Date | string): CalendarResult { | ||
| const date = this.toDate(value); | ||
|
|
||
| return { | ||
| string: format(date, 'yyyy-MM-dd'), | ||
| unix: Math.floor(date.getTime() / 1000), | ||
| date, | ||
| }; | ||
| } | ||
|
|
||
| private toDate(value: Date | string) { | ||
| return value instanceof Date ? value : new Date(value); | ||
| } | ||
| } | ||
|
|
||
| @NgModule({ | ||
| declarations: [CalendarModal], | ||
| imports: [CommonModule, IonicModule], | ||
| exports: [CalendarModal], | ||
| }) | ||
| export class CalendarModule {} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; | ||
|
|
||
| export function parseISO(value: string): Date { | ||
| return new Date(value); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. |
||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| export function format(value: Date | string | number, pattern: string): string { | ||
| const date = value instanceof Date ? value : new Date(value); | ||
| const hours12 = date.getHours() % 12 || 12; | ||
| const replacements: Record<string, string> = { | ||
| yyyy: String(date.getFullYear()), | ||
| MM: pad(date.getMonth() + 1), | ||
| MMM: MONTHS[date.getMonth()], | ||
| dd: pad(date.getDate()), | ||
| d: String(date.getDate()), | ||
| HH: pad(date.getHours()), | ||
| hh: pad(hours12), | ||
| mm: pad(date.getMinutes()), | ||
| ss: pad(date.getSeconds()), | ||
| a: date.getHours() >= 12 ? 'PM' : 'AM', | ||
| }; | ||
|
|
||
| return pattern.replace(/yyyy|MMM|MM|dd|d|HH|hh|mm|ss|a/g, token => replacements[token]); | ||
| } | ||
|
|
||
| export function startOfMonth(value: Date | number): Date { | ||
| const date = toDate(value); | ||
| return new Date(date.getFullYear(), date.getMonth(), 1); | ||
| } | ||
|
|
||
| export function endOfMonth(value: Date | number): Date { | ||
| const date = toDate(value); | ||
| return new Date(date.getFullYear(), date.getMonth() + 1, 0); | ||
| } | ||
|
|
||
| export function eachDayOfInterval(interval: { start: Date; end: Date }): Date[] { | ||
| const days: Date[] = []; | ||
| const current = new Date(interval.start); | ||
|
|
||
| while (current <= interval.end) { | ||
| days.push(new Date(current)); | ||
| current.setDate(current.getDate() + 1); | ||
| } | ||
|
|
||
| return days; | ||
| } | ||
|
|
||
| export function getDate(value: Date | number): number { | ||
| return toDate(value).getDate(); | ||
| } | ||
|
|
||
| export function getMonth(value: Date | number): number { | ||
| return toDate(value).getMonth(); | ||
| } | ||
|
|
||
| export function getYear(value: Date | number): number { | ||
| return toDate(value).getFullYear(); | ||
| } | ||
|
|
||
| export function isSameDay(left: Date | number, right: Date | number): boolean { | ||
| return format(toDate(left), 'yyyy-MM-dd') === format(toDate(right), 'yyyy-MM-dd'); | ||
| } | ||
|
|
||
| export function isSameMonth(left: Date | number, right: Date | number): boolean { | ||
| return toDate(left).getMonth() === toDate(right).getMonth(); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| export function isSameYear(left: Date | number, right: Date | number): boolean { | ||
| return toDate(left).getFullYear() === toDate(right).getFullYear(); | ||
| } | ||
|
|
||
| export function isToday(value: Date | number): boolean { | ||
| return isSameDay(toDate(value), new Date()); | ||
| } | ||
|
|
||
| function toDate(value: Date | number): Date { | ||
| return value instanceof Date ? value : new Date(value); | ||
| } | ||
|
|
||
| function pad(value: number): string { | ||
| return String(value).padStart(2, '0'); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.