fix(booking): preserve selected doctor when changing calendar date

This commit is contained in:
Dana Medical Developer 2026-10-23 08:18:22 +00:00
parent c49407047b
commit 1d8f166e88
2 changed files with 37 additions and 14 deletions

View File

@ -128,15 +128,33 @@ try {
await chooseDoctor(2); await chooseDoctor(2);
await reply(pending.at(-1), [free('09:00'), { ...free('14:15'), start: '2070-10-24T14:15:00+03:00' }]); await reply(pending.at(-1), [free('09:00'), { ...free('14:15'), start: '2070-10-24T14:15:00+03:00' }]);
assert.deepEqual(times(), ['14:15'], 'Selected date restricts the actual time list too'); assert.deepEqual(times(), ['14:15'], 'Selected date restricts the actual time list too');
await click(container.querySelector('.slot-chip--time'));
assert.ok(container.querySelector('input[type="tel"]'));
await act(async () => Simulate.change(container.querySelector('input[type="date"]'), { target: { value: '2070-10-25' } })); await act(async () => Simulate.change(container.querySelector('input[type="date"]'), { target: { value: '2070-10-25' } }));
assert.deepEqual(times(), []); assert.deepEqual(times(), []);
assert.equal(container.querySelector('.doctor-picker__trigger .doctor-picker__name').textContent, 'Выберите врача', 'Changing date clears the selected doctor and window'); assert.equal(container.querySelector('input[type="tel"]'), null, 'Changing date clears the chosen time and contacts step');
assert.deepEqual(await availableDoctorIDs(), []); assert.match(container.querySelector('.doctor-picker__trigger .doctor-picker__name').textContent, /Второй врач/, 'Changing date preserves the doctor even when no windows are available');
assert.match(text(), /На эту дату свободных окон нет/); assert.deepEqual(await availableDoctorIDs(), ['2']);
assert.equal(container.querySelector('.lead-modal__availability--warning'), null, 'An empty selected date keeps its informational style'); assert.match(text(), /У выбранного врача на эту дату свободных окон нет/);
assert.ok(container.querySelector('.lead-modal__availability--warning'));
await act(async () => Simulate.change(container.querySelector('input[type="date"]'), { target: { value: '2070-10-23' } }));
assert.match(container.querySelector('.doctor-picker__trigger .doctor-picker__name').textContent, /Второй врач/);
assert.equal(pending.at(-1).slug, 'second');
await reply(pending.at(-1), [free('11:45')]);
assert.deepEqual(times(), ['11:45'], 'Available date opens the preserved doctor schedule without a second selection');
await act(async () => Simulate.change(container.querySelector('input[type="date"]'), { target: { value: '' } })); await act(async () => Simulate.change(container.querySelector('input[type="date"]'), { target: { value: '' } }));
await reply(pending.at(-1), [free('12:45')]);
assert.deepEqual(times(), ['12:45'], 'Clearing date keeps the doctor and restores all their dates');
assert.deepEqual(await availableDoctorIDs(), ['1','2','3'], 'Clearing date restores the doctor-first flow'); assert.deepEqual(await availableDoctorIDs(), ['1','2','3'], 'Clearing date restores the doctor-first flow');
await act(async () => root.render(null));
await render({ doctor: doctors[0] });
await reply(pending.at(-1), [free('10:30')]);
await act(async () => Simulate.input(container.querySelector('input[type="date"]'), { target: { value: '2070-10-23' } }));
await reply(pending.at(-1), [free('13:30')]);
assert.match(container.querySelector('.doctor-picker__trigger .doctor-picker__name').textContent, /Первый врач/);
assert.deepEqual(times(), ['13:30'], 'Doctor preselected from a card also survives calendar selection');
const originalDoctorLoader = api.doctors; const originalDoctorLoader = api.doctors;
for (const fail of [false, true]) { for (const fail of [false, true]) {
await act(async () => root.render(null)); await act(async () => root.render(null));

View File

@ -63,9 +63,7 @@ export default function LeadModal({ form = 'appointment', doctor, slot, service,
const [status, setStatus] = useState({ state: 'idle', message: '' }); const [status, setStatus] = useState({ state: 'idle', message: '' });
const chosenDoctor = doctors.find((d) => String(d.id) === values.doctorId) const chosenDoctor = doctors.find((d) => String(d.id) === values.doctorId)
|| (doctor && String(doctor.id) === values.doctorId ? doctor : null); || (doctor && String(doctor.id) === values.doctorId ? doctor : null);
const selectedDoctor = form === 'appointment' && date const selectedDoctor = chosenDoctor;
&& (availability.loading || !availability.days.find((day) => day.date === date)?.doctor_ids.includes(chosenDoctor?.id))
? null : chosenDoctor;
const native = form === 'appointment' && selectedDoctor?.booking?.provider === 'native' const native = form === 'appointment' && selectedDoctor?.booking?.provider === 'native'
&& unavailableDoctorId !== selectedDoctor.id; && unavailableDoctorId !== selectedDoctor.id;
const onNativeUnavailable = useCallback( const onNativeUnavailable = useCallback(
@ -90,7 +88,6 @@ export default function LeadModal({ form = 'appointment', doctor, slot, service,
setDate(e.target.value); setDate(e.target.value);
setRequestedSlot(undefined); setRequestedSlot(undefined);
setUnavailableDoctorId(null); setUnavailableDoctorId(null);
setValues((previous) => ({ ...previous, doctorId: '' }));
setStatus({ state: 'idle', message: '' }); setStatus({ state: 'idle', message: '' });
}; };
@ -180,6 +177,14 @@ export default function LeadModal({ form = 'appointment', doctor, slot, service,
: doctorsLoaded && doctorOptions.length === 0 : doctorsLoaded && doctorOptions.length === 0
? 'Список врачей сейчас недоступен. Позвоните в клинику, чтобы уточнить запись.' ? 'Список врачей сейчас недоступен. Позвоните в клинику, чтобы уточнить запись.'
: date ? 'Выберите врача из списка — покажем его свободные часы на выбранную дату.' : ''; : date ? 'Выберите врача из списка — покажем его свободные часы на выбранную дату.' : '';
// Дата фильтрует окна, но не отменяет сделанный посетителем выбор врача.
const selectedDateMessage = selectedDoctor && date
? availability.loading ? 'Проверяем свободные окна выбранного врача…'
: availability.error ? 'Не удалось проверить расписание. Попробуйте выбрать дату ещё раз.'
: !availability.days.find((day) => day.date === date)?.doctor_ids.includes(selectedDoctor.id)
? 'У выбранного врача на эту дату свободных окон нет. Выберите другую дату или другого специалиста.' : ''
: '';
const appointmentMessage = selectedDoctor ? selectedDateMessage : availabilityMessage;
const submit = async (e) => { const submit = async (e) => {
e.preventDefault(); e.preventDefault();
@ -271,13 +276,13 @@ export default function LeadModal({ form = 'appointment', doctor, slot, service,
onInput={changeDate} onInput={changeDate}
onChange={changeDate} onChange={changeDate}
/> />
<span className="lead-modal__subtitle">Можно выбрать дату и увидеть только свободных в этот день врачей.</span> <span className="lead-modal__subtitle">{selectedDoctor ? 'Выберите дату — покажем свободные окна выбранного врача.' : 'Можно выбрать дату и увидеть только свободных в этот день врачей.'}</span>
</label> </label>
)} )}
{form === 'appointment' && status.state !== 'done' && ( {form === 'appointment' && status.state !== 'done' && (
<DoctorPicker <DoctorPicker
doctors={doctor && !date && !doctorOptions.some((d) => d.id === doctor.id) ? [doctor, ...doctorOptions] : doctorOptions} doctors={selectedDoctor && !doctorOptions.some((d) => d.id === selectedDoctor.id) ? [selectedDoctor, ...doctorOptions] : doctorOptions}
value={values.doctorId} value={values.doctorId}
onChange={set('doctorId')} onChange={set('doctorId')}
date={date} date={date}
@ -286,10 +291,10 @@ export default function LeadModal({ form = 'appointment', doctor, slot, service,
/> />
)} )}
{form === 'appointment' && !selectedDoctor ? ( {form === 'appointment' && (!selectedDoctor || selectedDateMessage) ? (
availabilityMessage ? ( appointmentMessage ? (
<p className={`lead-modal__availability${doctorsLoaded && !date && doctorOptions.length === 0 ? ' lead-modal__availability--warning' : ''}`} role="status"> <p className={`lead-modal__availability${(selectedDoctor && date && !availability.loading) || (doctorsLoaded && !date && doctorOptions.length === 0) ? ' lead-modal__availability--warning' : ''}`} role="status">
{availabilityMessage} {appointmentMessage}
</p> </p>
) : null ) : null
) : native ? ( ) : native ? (