67 lines
2.8 KiB
TypeScript
67 lines
2.8 KiB
TypeScript
// Предзаполнение формы заявки из CTA в любой секции.
|
|
// Маленький store вместо контекста: секции остаются серверными компонентами,
|
|
// кнопки — клиентскими островками, форма подписывается на store сама.
|
|
import type { Interest } from '@kvarta/shared/lead';
|
|
|
|
export const LEAD_SECTION_ID = 'lead';
|
|
export const LEAD_NAME_INPUT_ID = 'lead-name';
|
|
|
|
export type LeadPrefillInput = {
|
|
interest: Interest;
|
|
comment?: string;
|
|
/** id секции, откуда пришла CTA, — пойдёт в submitPage последнего касания */
|
|
source?: string;
|
|
};
|
|
|
|
export type LeadPrefill = LeadPrefillInput & { seq: number };
|
|
|
|
type Listener = (prefill: LeadPrefill) => void;
|
|
|
|
let current: LeadPrefill | null = null;
|
|
const listeners = new Set<Listener>();
|
|
|
|
export function getLeadPrefill(): LeadPrefill | null {
|
|
return current;
|
|
}
|
|
|
|
export function subscribeLeadPrefill(listener: Listener): () => void {
|
|
listeners.add(listener);
|
|
return () => {
|
|
listeners.delete(listener);
|
|
};
|
|
}
|
|
|
|
/** Выставить значения формы, плавно доскроллить до #lead и поставить фокус в поле имени. */
|
|
export function prefillLead(input: LeadPrefillInput): void {
|
|
current = { ...input, seq: (current?.seq ?? 0) + 1 };
|
|
for (const listener of listeners) listener(current);
|
|
if (typeof document === 'undefined') return;
|
|
|
|
const reduceMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;
|
|
document
|
|
.getElementById(LEAD_SECTION_ID)
|
|
?.scrollIntoView({ behavior: reduceMotion ? 'auto' : 'smooth', block: 'start' });
|
|
// preventScroll — чтобы фокус не оборвал плавный скролл рывком к полю
|
|
document.getElementById(LEAD_NAME_INPUT_ID)?.focus({ preventScroll: true });
|
|
}
|
|
|
|
/**
|
|
* Применить предзаполнение к текущим значениям формы.
|
|
* Комментарий, который посетитель напечатал сам, не трогаем; свой прошлый предзаполненный — заменяем.
|
|
*/
|
|
export function applyPrefill<T extends { interest: Interest | ''; comment: string }>(
|
|
values: T,
|
|
prefill: LeadPrefillInput,
|
|
lastPrefilledComment: string | null,
|
|
): { values: T; prefilledComment: string | null } {
|
|
const typedByVisitor = values.comment.trim() !== '' && values.comment !== lastPrefilledComment;
|
|
if (typedByVisitor) {
|
|
return { values: { ...values, interest: prefill.interest }, prefilledComment: lastPrefilledComment };
|
|
}
|
|
const comment = prefill.comment ?? '';
|
|
return {
|
|
values: { ...values, interest: prefill.interest, comment },
|
|
prefilledComment: comment === '' ? null : comment,
|
|
};
|
|
}
|