Add step date picker and show full renewal dates.

Replace native date inputs with year→month→day glass picker and display exact next renewal dates in the businesses list.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-26 10:58:47 +03:30
co-authored by Cursor
parent 58408fed07
commit b50e4fd812
4 changed files with 539 additions and 12 deletions
+16 -11
View File
@@ -14,6 +14,8 @@ import {
} from 'lucide-react'
import { ConfirmDeleteModal } from '../components/ConfirmDeleteModal'
import { BusinessActionsOverflowMenu } from '../components/BusinessActionsOverflowMenu'
import { MultiSelectDropdown } from '../components/MultiSelectDropdown'
import { StepDatePicker } from '../components/StepDatePicker'
import { ToggleSwitch } from '../components/ToggleSwitch'
import { formatCellForDisplay, toE164CellNumber } from '../lib/cellNumber'
import type {
@@ -45,7 +47,6 @@ import {
import { listBusinessCategories } from '../services/categoryService'
import { listUserTitles, type UserTitleOption } from '../services/userTitleService'
import { Modal } from '../components/Modal'
import { MultiSelectDropdown } from '../components/MultiSelectDropdown'
import { PrimaryColorSwatchControl } from '../components/PrimaryColorSwatchControl'
import { useToast } from '../context/ToastContext'
import {
@@ -148,11 +149,11 @@ function formatRenewalCell(
) {
const contractAt = annualRenewalAt || createdAt || null
if (!contractAt) {
return { yearLabel: '—', daysLabel: null as string | null, tone: null as 'ok' | 'warn' | 'danger' | null }
return { dateLabel: '—', daysLabel: null as string | null, tone: null as 'ok' | 'warn' | 'danger' | null }
}
const next = nextAnnualRenewal(contractAt)
if (!next) {
return { yearLabel: '—', daysLabel: null, tone: null }
return { dateLabel: '—', daysLabel: null, tone: null }
}
const daysLabel =
next.daysRemaining === 0
@@ -161,7 +162,11 @@ function formatRenewalCell(
? '1 day left'
: `${next.daysRemaining} days left`
return {
yearLabel: String(next.year),
dateLabel: next.next.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
}),
daysLabel,
tone: renewalTone(next.daysRemaining),
}
@@ -1294,7 +1299,7 @@ export function BusinessesPage() {
<td className={styles.td}>{b.name}</td>
<td className={styles.td}>
<div className={styles.renewalCell}>
<span className={styles.renewalYear}>{renewal.yearLabel}</span>
<span className={styles.renewalDate}>{renewal.dateLabel}</span>
{renewal.daysLabel ? (
<span
className={`${styles.renewalDays} ${
@@ -1532,12 +1537,12 @@ export function BusinessesPage() {
</div>
<div className={styles.field}>
<label htmlFor="edit-annual-renewal">Annual renewal</label>
<input
<StepDatePicker
id="edit-annual-renewal"
type="date"
value={editAnnualRenewalAt}
onChange={(e) => setEditAnnualRenewalAt(e.target.value)}
onChange={setEditAnnualRenewalAt}
disabled={editSubmitting}
placeholder="Select renewal date"
/>
</div>
<div className={styles.field}>
@@ -2077,12 +2082,12 @@ export function BusinessesPage() {
<div className={`${styles.field} ${styles.formCol4}`}>
<label htmlFor="create-annual-renewal">Annual renewal</label>
<input
<StepDatePicker
id="create-annual-renewal"
type="date"
value={createAnnualRenewalAt}
onChange={(e) => setCreateAnnualRenewalAt(e.target.value)}
onChange={setCreateAnnualRenewalAt}
disabled={createSubmitting}
placeholder="Select renewal date"
/>
</div>