Repository: hashicorp/vault
File: ui/app/components/clients/date-range.ts (TypeScript)

Code before:
  @tracked startDate = ''; // format yyyy-MM
  @tracked endDate = ''; // format yyyy-MM
  @tracked selectedStart = this.args.billingStartTime;
  currentMonth = format(timestamp.now(), 'yyyy-MM');

  constructor(owner: unknown, args: Args) {
    super(owner, args);
    this.setTrackedFromArgs();
  }

  setTrackedFromArgs() {
    if (this.args.startTime) {
      this.startDate = parseAPITimestamp(this.args.startTime, 'yyyy-MM') as string;
      this.selectedStart = this.formattedDate(this.args.startTime) as string;
    }
    if (this.args.endTime) {
      this.endDate = parseAPITimestamp(this.args.endTime, 'yyyy-MM') as string;
    }
  }

  formattedDate = (isoTimestamp: string) => {
    return parseAPITimestamp(isoTimestamp, 'MMMM yyyy');
  };

  get historicalBillingPeriods() {
    const count = this.args.retentionMonths / 12;
    const periods: string[] = [];

    for (let i = 1; i <= count; i++) {
      const startDate = new Date(this.args.billingStartTime);
      const utcMonth = startDate.getUTCMonth();
      const utcYear = startDate.getUTCFullYear() - i;

      startDate.setUTCFullYear(utcYear);
      startDate.setUTCMonth(utcMonth);

      periods.push(startDate.toISOString());
    }

    return periods;
  }

  get useDefaultDates() {
    return !this.startDate && !this.endDate;
  }

  get validationError() {
    if (this.useDefaultDates && this.version.isEnterprise) {
      // this means we want to reset, which is fine for ent only
      return null;
    }

Review comment (suggestion):
We should probably account for this not being divisible evenly by 12. Since we only want users to query full billing periods, we should probably wrap this calculation in `Math.floor()` (instead of `Math.ceil()`). But might be worth conferring with the backend. 


Code after:
  @tracked startDate = ''; // format yyyy-MM
  @tracked endDate = ''; // format yyyy-MM
  @tracked selectedStart = this.args.billingStartTime;
  currentMonth = format(timestamp.now(), 'yyyy-MM');

  constructor(owner: unknown, args: Args) {
    super(owner, args);
    this.setTrackedFromArgs();
  }

  setTrackedFromArgs() {
    if (this.args.startTime) {
      this.startDate = parseAPITimestamp(this.args.startTime, 'yyyy-MM') as string;
      this.selectedStart = this.formattedDate(this.args.startTime) as string;
    }
    if (this.args.endTime) {
      this.endDate = parseAPITimestamp(this.args.endTime, 'yyyy-MM') as string;
    }
  }

  formattedDate = (isoTimestamp: string) => {
    return parseAPITimestamp(isoTimestamp, 'MMMM yyyy');
  };

  get historicalBillingPeriods() {
    // we want whole billing periods
    const count = Math.floor(this.args.retentionMonths / 12);
    const periods: string[] = [];

    for (let i = 1; i <= count; i++) {
      const startDate = new Date(this.args.billingStartTime);
      const utcMonth = startDate.getUTCMonth();
      const utcYear = startDate.getUTCFullYear() - i;

      startDate.setUTCFullYear(utcYear);
      startDate.setUTCMonth(utcMonth);

      periods.push(startDate.toISOString());
    }

    return periods;
  }

  get useDefaultDates() {
    return !this.startDate && !this.endDate;
  }

  get validationError() {
    if (this.useDefaultDates && this.version.isEnterprise) {
      // this means we want to reset, which is fine for ent only
      return null;