Implement academy analytics, billing, and web stories updates
This commit is contained in:
@@ -11,6 +11,9 @@ const MONTH_NAMES = [
|
||||
'July', 'August', 'September', 'October', 'November', 'December',
|
||||
]
|
||||
|
||||
const YEAR_MIN = 1900
|
||||
const YEAR_MAX = 2105
|
||||
|
||||
const DAY_ABBR = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']
|
||||
|
||||
function pad(value) {
|
||||
@@ -40,16 +43,35 @@ function parseDatePart(value) {
|
||||
return new Date(year, month - 1, day)
|
||||
}
|
||||
|
||||
function splitDateTime(value) {
|
||||
if (!value) {
|
||||
return { date: '', time: '' }
|
||||
function normalizeDateTimeInput(value) {
|
||||
const raw = String(value || '').trim()
|
||||
if (!raw) return { date: '', time: '' }
|
||||
|
||||
const match = raw.match(/^(\d{4}-\d{2}-\d{2})(?:[ T](\d{2}:\d{2})(?::\d{2})?)?(?:Z|[+-]\d{2}:?\d{2})?$/)
|
||||
if (match) {
|
||||
return {
|
||||
date: match[1],
|
||||
time: match[2] || '',
|
||||
}
|
||||
}
|
||||
|
||||
const [date = '', time = ''] = String(value).split('T')
|
||||
const parsed = new Date(raw)
|
||||
if (Number.isNaN(parsed.getTime())) {
|
||||
return { date: raw, time: '' }
|
||||
}
|
||||
|
||||
return {
|
||||
date,
|
||||
time: time.slice(0, 5),
|
||||
date: toISODate(parsed),
|
||||
time: `${pad(parsed.getHours())}:${pad(parsed.getMinutes())}`,
|
||||
}
|
||||
}
|
||||
|
||||
function splitDateTime(value) {
|
||||
const normalized = normalizeDateTimeInput(value)
|
||||
|
||||
return {
|
||||
date: normalized.date,
|
||||
time: normalized.time.slice(0, 5),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,7 +438,7 @@ export default function DateTimePicker({
|
||||
className="fixed z-[500] overflow-hidden rounded-2xl border border-white/12 bg-nova-900 shadow-2xl shadow-black/50"
|
||||
style={{ top: dropPos.top, left: dropPos.left, width: dropPos.width }}
|
||||
>
|
||||
<div className="flex items-center justify-between px-3 pt-3">
|
||||
<div className="flex items-center justify-between gap-2 px-3 pt-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={prevMonth}
|
||||
@@ -428,7 +450,32 @@ export default function DateTimePicker({
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<span className="text-sm font-semibold text-white">{MONTH_NAMES[viewMonth]} {viewYear}</span>
|
||||
<div className="flex min-w-0 flex-1 items-center justify-center gap-2">
|
||||
<span className="whitespace-nowrap text-sm font-semibold text-white">{MONTH_NAMES[viewMonth]}</span>
|
||||
<div className="flex items-center gap-1 rounded-xl border border-white/10 bg-white/[0.04] px-1 py-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setViewYear((current) => Math.max(YEAR_MIN, current - 1))}
|
||||
disabled={viewYear <= YEAR_MIN}
|
||||
className="flex h-8 w-8 items-center justify-center rounded-lg text-slate-400 transition-all hover:bg-white/8 hover:text-white disabled:cursor-not-allowed disabled:opacity-30"
|
||||
aria-label="Previous year"
|
||||
>
|
||||
<i className="fa-solid fa-minus text-[11px]" aria-hidden="true" />
|
||||
</button>
|
||||
|
||||
<span className="min-w-[72px] px-2 text-center text-sm font-semibold text-white">{viewYear}</span>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setViewYear((current) => Math.min(YEAR_MAX, current + 1))}
|
||||
disabled={viewYear >= YEAR_MAX}
|
||||
className="flex h-8 w-8 items-center justify-center rounded-lg text-slate-400 transition-all hover:bg-white/8 hover:text-white disabled:cursor-not-allowed disabled:opacity-30"
|
||||
aria-label="Next year"
|
||||
>
|
||||
<i className="fa-solid fa-plus text-[11px]" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user