feat(landing): заглушка страницы с рабочей формой
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
// Предзаполнение формы заявки из 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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user