Skip to content

Commit cc76470

Browse files
committed
fix: address review — canTrial undefined check and deduplicate days calc
- Use `info.canTrial === false` instead of `!info.canTrial` so undefined (API omitted the field) does not incorrectly block plan trial activation - Extract daysRemainingFromDate() shared helper in trials.ts, reuse in both getDaysRemaining() and buildPlanTrialEntry() to eliminate duplicate end-of-day UTC date math
1 parent ab39d10 commit cc76470

File tree

3 files changed

+21
-16
lines changed

3 files changed

+21
-16
lines changed

src/commands/trial/list.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { colorTag } from "../../lib/formatters/markdown.js";
1414
import { type Column, writeTable } from "../../lib/formatters/table.js";
1515
import { resolveOrg } from "../../lib/resolve-target.js";
1616
import {
17+
daysRemainingFromDate,
1718
getDaysRemaining,
1819
getTrialDisplayName,
1920
getTrialFriendlyName,
@@ -117,13 +118,7 @@ function buildPlanTrialEntry(info: CustomerTrialInfo): TrialListEntry | null {
117118
// Currently on a plan trial
118119
const planName = info.planDetails?.name ?? "Business";
119120
const endDate = info.trialEnd ?? null;
120-
let daysRemaining: number | null = null;
121-
if (endDate) {
122-
const end = new Date(endDate);
123-
end.setUTCHours(23, 59, 59, 999);
124-
const diffMs = end.getTime() - Date.now();
125-
daysRemaining = Math.max(0, Math.ceil(diffMs / (1000 * 60 * 60 * 24)));
126-
}
121+
const daysRemaining = endDate ? daysRemainingFromDate(endDate) : null;
127122
return {
128123
name: "plan",
129124
displayName: `${planName} Plan`,

src/commands/trial/start.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,8 @@ async function handlePlanTrial(
250250
);
251251
}
252252

253-
if (!info.canTrial) {
253+
// canTrial is optional in the schema — only reject when explicitly false
254+
if (info.canTrial === false) {
254255
throw new ValidationError(
255256
`No plan trial available for organization '${orgSlug}'.`,
256257
"name"

src/lib/trials.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,22 @@ export function getTrialStatus(trial: ProductTrial): TrialStatus {
193193
return "active";
194194
}
195195

196+
/**
197+
* Calculate days remaining from an end date string.
198+
*
199+
* Treats the end date as end-of-day UTC (23:59:59.999) and returns
200+
* the number of calendar days until expiry, clamped to 0.
201+
*
202+
* @param endDate - ISO date string (e.g., "2026-04-15T00:00:00Z")
203+
* @returns Number of days remaining (0+)
204+
*/
205+
export function daysRemainingFromDate(endDate: string): number {
206+
const end = new Date(endDate);
207+
end.setUTCHours(23, 59, 59, 999);
208+
const diffMs = end.getTime() - Date.now();
209+
return Math.max(0, Math.ceil(diffMs / (1000 * 60 * 60 * 24)));
210+
}
211+
196212
/**
197213
* Calculate days remaining for an active trial.
198214
*
@@ -203,14 +219,7 @@ export function getDaysRemaining(trial: ProductTrial): number | null {
203219
if (!(trial.isStarted && trial.endDate)) {
204220
return null;
205221
}
206-
207-
const end = new Date(trial.endDate);
208-
// Match getTrialStatus: treat endDate as end-of-day UTC
209-
end.setUTCHours(23, 59, 59, 999);
210-
const now = new Date();
211-
const diffMs = end.getTime() - now.getTime();
212-
const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
213-
return Math.max(0, diffDays);
222+
return daysRemainingFromDate(trial.endDate);
214223
}
215224

216225
/**

0 commit comments

Comments
 (0)