Pular para o conteúdo principal

Intervalos de tempo

Um atributo timeInterval é uma regra de recorrência, e não uma lista de horários: uma data de referência, faixas de horário diárias e sinalizadores de repetição. Para transformá-lo em pares concretos [start, end] para a janela que você exibe, use os helpers de nível superior expandAttributeTimeIntervals e expandTimeIntervals e o type guard 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'], …]

Os três helpers são puros: eles não alteram a entrada e não fazem requisições.

Onde ficam as agendas​

A API retorna as agendas em dois formatos, e os helpers aceitam ambos:

FormatoOnde encontrarContém
Entidade (ITimeIntervalEntitySchedule)attributeValues[marker].value[].values[] em páginas, produtos, blocos e conjuntos de atributosuma faixa dates com pares times
Formulário (ITimeIntervalSchedule)attributes[].localizeInfos.intervals[] em formuláriosum range com intervals que trazem um period de horário em minutos

expandAttributeTimeIntervals(attr, window)​

Expande um atributo de entidade em uma única chamada: percorre os grupos e as agendas do atributo, expande cada um e mescla os resultados. A mesclagem importa, porque a remoção de duplicatas e a ordenação só valem dentro de uma única agenda; combinar os grupos manualmente pode gerar horários duplicados ou fora de ordem.

Para qualquer coisa que não seja um atributo timeInterval, retorna um array vazio, então você pode chamá-lo sem verificar type antes.

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',
});

expandTimeIntervals(schedule, window)​

Expande uma única agenda. Use-o quando você já tem uma, normalmente em formulários, cujas agendas já estão tipadas em localizeInfos.intervals:

import { expandTimeIntervals } from 'oneentry';

const form = await Forms.getFormByMarker('booking_form');
if ('statusCode' in form) throw new Error(form.message);
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 é tipado como unknown, porque o seu formato depende de type. Este type guard restringe um atributo a ITimeIntervalAttributeValue, para que você possa acessar as agendas sem conversão de tipo:

import { isTimeIntervalAttribute } from 'oneentry';

const attr = page.attributeValues.interval;

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

A janela​

const window = { from: '2025-04-01', to: '2025-04-30' };
  • from e to aceitam um Date, uma string ISO ou milissegundos desde a época Unix.
  • Os dois limites são inclusivos e comparados pelo dia em UTC; o horário em from/to é ignorado.
  • A janela é obrigatória: uma agenda é uma regra de recorrência sem fim definido, e só você sabe até onde expandi-la.

Semântica da recorrência​

  • dates[0] / range[0] é ao mesmo tempo a fase da recorrência e o primeiro dia válido. Nada anterior é retornado, por mais ampla que seja a janela.
  • dates[1] / range[1] encerra a validade. Se não for posterior ao início, a agenda fica ancorada nesse único dia; com um sinalizador de recorrência definido, a recorrência passa a não ter fim e apenas a janela limita o resultado.
  • inEveryWeek repete a cada 7 dias a partir da data de referência.
  • inEveryMonth repete no mesmo dia do mês, pulando os meses curtos demais.
  • Com as duas flags definidas, aplica-se a regra semanal.
  • Sem nenhum sinalizador, a agenda é uma faixa de datas simples: todos os dias nela geram horários.
  • O resultado é sem duplicatas e ordenado pelo início e depois pelo fim.
  • Todos os cálculos são feitos em UTC, então o resultado não depende do fuso horário da máquina.

Migrando do campo timeIntervals​

As versões anteriores do SDK adicionavam um array calculado timeIntervals a todos os valores de atributo timeInterval. Esse campo não existe mais. Ele continha um ano inteiro de horários, independentemente do que quem chamava precisava: um único atributo com horários de hora em hora se expandia para cerca de 2.000 linhas de JSON, e períodos de horário menores chegavam a megabytes, o suficiente para ultrapassar os limites de cache de dados dos frameworks. Ele também nunca foi declarado em nenhuma interface ou esquema, então o código TypeScript só conseguia acessá-lo por meio de uma conversão de tipo.

Antes, você lia o campo pré-calculado:

const slots = page.attributeValues.interval.value[0].values[0].timeIntervals;

Agora, expanda a janela que você de fato renderiza:

import { expandAttributeTimeIntervals } from 'oneentry';

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

Os dados de origem (dates/range, times/intervals, inEveryWeek, inEveryMonth) não mudaram e continuam presentes em todas as agendas. Nada se perde: os horários são calculados sob demanda em vez de antecipadamente, e o que vai para o cache é a regra compacta.

Os métodos _addTimeIntervalsToSchedules e _addTimeIntervalsToFormSchedules também foram removidos de todos os módulos (apesar do prefixo _, eles podiam ser chamados, por exemplo Pages._addTimeIntervalsToSchedules). Use expandTimeIntervals no lugar deles.

Tipos​

Todos eles são exportados da raiz do pacote e de oneentry/types (veja Importação de tipos):

TipoDescreve
ITimeIntervalAttributeValueUm IAttributeValue restrito a type: 'timeInterval', cujo value é um array de grupos
ITimeIntervalGroupUma entrada do value do atributo: agendas que compartilham um intervalId
ITimeIntervalEntityScheduleUma agenda de entidade: dates, times, inEveryWeek, inEveryMonth
ITimeIntervalScheduleUma agenda de formulário: range, intervals, inEveryWeek, inEveryMonth
ITimeIntervalRangeUma faixa diária com start, end e um period de horário em minutos (null quando não é fatiada)
ITimeIntervalPointUm ponto no dia: { hours, minutes }
ITimeIntervalWindowA janela de expansão: { from, to }
TimeIntervalPairUm horário resolvido: [start, end], ambos strings ISO 8601 em UTC

Exemplo: exibindo um mês de horários​

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;
}, {} as Record<string, Array<[string, string]>>);

Relacionados​