Wire admin studio SSR and search infrastructure

This commit is contained in:
2026-05-01 11:46:06 +02:00
parent 257b0dbef6
commit 18cea8b0f0
329 changed files with 197465 additions and 2741 deletions

View File

@@ -1,4 +1,5 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import DateTimePicker from '../ui/DateTimePicker'
/**
* SchedulePublishPicker
@@ -82,14 +83,18 @@ export default function SchedulePublishPicker({
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
)
const [dateStr, setDateStr] = useState(initial.date || '')
const [timeStr, setTimeStr] = useState(initial.time || '')
const [localDateTime, setLocalDateTime] = useState(initial.date && initial.time ? `${initial.date}T${initial.time}` : '')
const [error, setError] = useState('')
const minScheduleLocalDateTime = (() => {
const next = toLocalDateTimeString(new Date(Date.now() + MIN_FUTURE_MS).toISOString(), timezone)
return next.date && next.time ? `${next.date}T${next.time}` : ''
})()
const validate = useCallback(
(d, t) => {
if (!d || !t) return 'Date and time are required.'
const iso = localToUtcIso(d, t, timezone)
(value) => {
const [datePart = '', timePart = ''] = String(value || '').split('T')
if (!datePart || !timePart) return 'Date and time are required.'
const iso = localToUtcIso(datePart, timePart.slice(0, 5), timezone)
if (!iso) return 'Invalid date or time.'
const target = new Date(iso)
if (Number.isNaN(target.getTime())) return 'Invalid date or time.'
@@ -101,31 +106,38 @@ export default function SchedulePublishPicker({
[timezone]
)
useEffect(() => {
const next = toLocalDateTimeString(scheduledAt, timezone)
setLocalDateTime(next.date && next.time ? `${next.date}T${next.time}` : '')
}, [scheduledAt, timezone])
useEffect(() => {
if (mode !== 'schedule') {
setError('')
return
}
if (!dateStr && !timeStr) {
if (!localDateTime) {
setError('')
onScheduleAt?.(null)
return
}
const err = validate(dateStr, timeStr)
const err = validate(localDateTime)
setError(err)
if (!err) {
onScheduleAt?.(localToUtcIso(dateStr, timeStr, timezone))
const [datePart = '', timePart = ''] = localDateTime.split('T')
onScheduleAt?.(localToUtcIso(datePart, timePart.slice(0, 5), timezone))
} else {
onScheduleAt?.(null)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dateStr, timeStr, mode])
}, [localDateTime, mode, timezone])
const previewLabel = useMemo(() => {
if (mode !== 'schedule' || error) return null
const iso = localToUtcIso(dateStr, timeStr, timezone)
const [datePart = '', timePart = ''] = localDateTime.split('T')
const iso = localToUtcIso(datePart, timePart.slice(0, 5), timezone)
return formatPreviewLabel(iso, timezone)
}, [mode, error, dateStr, timeStr, timezone])
}, [mode, error, localDateTime, timezone])
return (
<div className="space-y-3">
@@ -167,45 +179,18 @@ export default function SchedulePublishPicker({
{mode === 'schedule' && (
<div className="space-y-2 rounded-xl border border-white/10 bg-white/[0.03] p-3">
<div className="flex flex-col gap-2 sm:flex-row">
<div className="flex-1">
<label className="block text-[10px] uppercase tracking-wide text-white/40 mb-1" htmlFor="schedule-date">
Date
</label>
<input
id="schedule-date"
type="date"
disabled={disabled}
value={dateStr}
onChange={(e) => setDateStr(e.target.value)}
min={new Date().toISOString().slice(0, 10)}
className="w-full rounded-lg border border-white/15 bg-white/8 px-3 py-1.5 text-sm text-white placeholder-white/30 focus:outline-none focus:ring-1 focus:ring-sky-400/60 disabled:opacity-50"
/>
</div>
<div className="w-28 shrink-0">
<label className="block text-[10px] uppercase tracking-wide text-white/40 mb-1" htmlFor="schedule-time">
Time
</label>
<input
id="schedule-time"
type="time"
disabled={disabled}
value={timeStr}
onChange={(e) => setTimeStr(e.target.value)}
className="w-full rounded-lg border border-white/15 bg-white/8 px-3 py-1.5 text-sm text-white placeholder-white/30 focus:outline-none focus:ring-1 focus:ring-sky-400/60 disabled:opacity-50"
/>
</div>
</div>
<p className="text-[10px] text-white/35">
Timezone: <span className="text-white/55">{timezone}</span>
</p>
{error && (
<p className="text-xs text-red-400" role="alert">
{error}
</p>
)}
<DateTimePicker
id="schedule-datetime"
label="Release date and time"
value={localDateTime}
onChange={setLocalDateTime}
placeholder="Pick a release slot"
disabled={disabled}
minDateTime={minScheduleLocalDateTime}
clearable
hint={`Timezone: ${timezone}`}
error={error}
/>
{previewLabel && (
<p className="text-xs text-emerald-300/80">