Saltar al contenido principal

Intervalos de Tiempo

Un atributo timeInterval es una regla de recurrencia, no una lista de espacios: una fecha de anclaje, rangos de tiempo diarios y banderas de repetición. Resuélvelo en pares concretos [inicio, fin] para la ventana que realmente renderizas con los ayudantes de nivel superior expandAttributeTimeIntervals, expandTimeIntervals y el guardia de tipo isTimeIntervalAttribute.

import { expandAttributeTimeIntervals } from 'oneentry';

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});
// [['2025-04-14T09:00:00.000Z', '2025-04-14T10:00:00.000Z'], …]

Los tres ayudantes son puros: no mutan su entrada y no realizan solicitudes.

Dónde viven los horarios

La API devuelve horarios en dos formas, y ambas son aceptadas por los ayudantes:

FormaDónde encontrarloContiene
Entidad (ITimeIntervalEntitySchedule)attributeValues[marker].value[].values[] en páginas, productos, bloques y conjuntos de atributosun rango de fechas con pares de tiempos
Formulario (ITimeIntervalSchedule)attributes[].localizeInfos.intervals[] en formulariosun rango con intervalos que llevan un periodo de espacio en minutos

expandAttributeTimeIntervals(attr, window)

El camino de una sola llamada para atributos de entidad: recorre los grupos y horarios del atributo, expande cada uno de ellos y fusiona los resultados. La fusión es importante: la deduplicación y el orden solo se mantienen dentro de un solo horario, por lo que combinar grupos manualmente puede resultar en espacios duplicados o desordenados.

Cualquier cosa que no sea un atributo timeInterval produce un array vacío, por lo que es seguro llamarlo sin verificar type primero.

import { expandAttributeTimeIntervals } from 'oneentry';

const page = await Pages.getPageByUrl('booking');

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});

expandTimeIntervals(schedule, window)

Resuelve un único horario. Utilízalo cuando ya tengas uno: notablemente en formularios, cuyos horarios ya están tipados en localizeInfos.intervals:

import { expandTimeIntervals } from 'oneentry';

const form = await Forms.getFormByMarker('booking_form');
const field = form.attributes.find((a) => a.marker === 'schedule');

const slots = (field?.localizeInfos.intervals ?? []).flatMap((schedule) =>
expandTimeIntervals(schedule, { from: '2025-05-01', to: '2025-05-31' }),
);

isTimeIntervalAttribute(attr)

IAttributeValue.value está tipado como unknown, porque su forma depende de type. Este guardia de tipo reduce un atributo a ITimeIntervalAttributeValue, que es lo que te permite acceder a los horarios sin un cast:

import { isTimeIntervalAttribute } from 'oneentry';

const attr = page.attributeValues.interval;

if (isTimeIntervalAttribute(attr)) {
attr.value[0].values[0].dates; // fully typed
}

La ventana

const window = { from: '2025-04-01', to: '2025-04-30' };
  • from y to aceptan una Date, una cadena ISO o milisegundos de época.
  • Ambos límites son inclusivos y se comparan a una granularidad de día UTC: la parte de hora del día de from/to se ignora.
  • La ventana es requerida: un horario es una regla de recurrencia abierta, y solo tú sabes hasta dónde debe resolverse.

Semántica de recurrencia

  • dates[0] / range[0] es tanto la fase de recurrencia como el primer día válido: nada anterior se emite, por amplio que sea la ventana.
  • dates[1] / range[1] termina la validez. Cuando no se extiende más allá del inicio, el horario está anclado a ese único día; con una bandera de recurrencia establecida, la recurrencia es entonces abierta y solo la ventana limita el resultado.
  • inEveryWeek se repite cada 7 días desde el ancla.
  • inEveryMonth se repite en el mismo día del mes, omitiendo meses que son demasiado cortos.
  • Con ambas banderas establecidas, se aplica la regla semanal, que es lo que siempre ha significado en la práctica.
  • Con ninguna bandera, el horario es un rango de fechas simple: cada día de él produce espacios.
  • El resultado se deduplica y se ordena por inicio, luego por fin.
  • Toda la aritmética es UTC, por lo que el resultado no depende de la zona horaria de la máquina.

Migrando del campo timeIntervals

Las versiones anteriores del SDK inyectaban un array timeIntervals computado en cada valor de atributo timeInterval. Ese campo ya no existe. Materializaba un año completo de espacios independientemente de lo que necesitara el llamador: un solo atributo con espacios horarios se expandía a aproximadamente 2,000 líneas de JSON, y períodos de espacio más finos alcanzaban megabytes, suficiente para superar los límites de caché de datos del marco. Nunca se declaró en ninguna interfaz o esquema, por lo que los consumidores de TypeScript solo podían acceder a él a través de un cast.

// before — read the pre-computed field
const slots = page.attributeValues.interval.value[0].values[0].timeIntervals;

// now — expand the window you actually render
import { expandAttributeTimeIntervals } from 'oneentry';

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});

Los datos fuente que se están expandiendo (dates/range, times/intervals, inEveryWeek, inEveryMonth) no han cambiado y siguen presentes en cada horario: nada se pierde, simplemente se resuelve bajo demanda en lugar de de manera anticipada, y la regla compacta es lo que se almacena en caché.

Los métodos _addTimeIntervalsToSchedules y _addTimeIntervalsToFormSchedules fueron eliminados de cada módulo también (a pesar del prefijo _, eran invocables, por ejemplo, Pages._addTimeIntervalsToSchedules). Usa expandTimeIntervals en su lugar.

Tipos

Todos estos se exportan desde la raíz del paquete y desde oneentry/types (ver Importando Tipos):

TipoDescribe
ITimeIntervalAttributeValueUn IAttributeValue reducido a type: 'timeInterval', cuyo value es un array de grupos
ITimeIntervalGroupUna entrada del value del atributo: horarios que comparten un intervalId
ITimeIntervalEntityScheduleUn horario de entidad: dates, times, inEveryWeek, inEveryMonth
ITimeIntervalScheduleUn horario de formulario: range, intervals, inEveryWeek, inEveryMonth
ITimeIntervalRangeUn rango diario con start, end y un periodo de espacio en minutos (null cuando no está segmentado)
ITimeIntervalPointUn punto en un día - { horas, minutos }
ITimeIntervalWindowLa ventana de expansión - { from, to }
TimeIntervalPairUn espacio resuelto - [start, end], ambas cadenas ISO 8601 UTC

Ejemplo: renderizando un mes de espacios

import { expandAttributeTimeIntervals } from 'oneentry';

const page = await Pages.getPageByUrl('booking');

if ('statusCode' in page) {
throw new Error(page.message);
}

const slots = expandAttributeTimeIntervals(page.attributeValues.interval, {
from: '2025-04-01',
to: '2025-04-30',
});

// Group the slots by day for a calendar view
const byDay = slots.reduce((acc, [start, end]) => {
const day = start.slice(0, 10);
(acc[day] ??= []).push([start, end]);
return acc;
}, {});

🔗 Documentación Relacionada