You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
6.0 KiB
121 lines
6.0 KiB
import React, { useEffect, useMemo, useState } from 'react'; |
|
import { TabBar } from './components.jsx'; |
|
import { HomeCardsScreen, HomeListScreen, HomeFeedScreen, HomeTimelineXScreen, HomeSplashScreen } from './screens/screens-home.jsx'; |
|
import { |
|
BookingSpecsScreen, BookingDoctorScreen, BookingTimeScreen, |
|
BookingConfirmScreen, BookingSuccessScreen, |
|
DoctorsTabScreen, DoctorDetailScreen, |
|
} from './screens/screens-booking.jsx'; |
|
import { |
|
ApptsTabScreen, ApptDetailScreen, |
|
ResultsScreen, ResultAudioScreen, ResultEndoscopyScreen, |
|
RecoveryScreen, AudioTestScreen, |
|
ProfileTabScreen, QRScreen, |
|
TelemedScreen, MedcardScreen, NotificationsScreen, |
|
} from './screens/screens-misc.jsx'; |
|
import { ChatsListScreen, ChatConversationScreen } from './screens/screens-chats.jsx'; |
|
import { ArticlesScreen, ArticleDetailScreen } from './screens/screens-articles.jsx'; |
|
import { HomeV2Screen, SearchScreen, ContactsScreen, PricesScreen } from './screens/screens-v2.jsx'; |
|
import { DevColorsScreen, DevExamplesScreen } from './screens/screens-dev.jsx'; |
|
import { DocsScreen } from './screens/screens-docs.jsx'; |
|
import { ProfilePlateScreen, ApptsPlateScreen, ApptDetailPlateScreen, MedcardPlateScreen } from './screens/screens-plate.jsx'; |
|
|
|
function renderScreen(screenId, nav, ctx) { |
|
const parts = screenId.split(':'); |
|
const id = parts[0]; |
|
const plate = ctx.design === 'plate'; |
|
// В plate-режиме главная всегда «Светлая плитка», независимо от homeVariant |
|
const homeVariant = plate ? 'splash' : ctx.homeVariant; |
|
const HOME = { cards: HomeCardsScreen, list: HomeListScreen, feed: HomeFeedScreen, timelineX: HomeTimelineXScreen, splash: HomeSplashScreen }[homeVariant] || HomeCardsScreen; |
|
|
|
// Plate-подмены (fallback на Клод если plate-версии нет) |
|
if (plate) { |
|
switch (id) { |
|
case 'profile': return <ProfilePlateScreen nav={nav} ctx={ctx} />; |
|
case 'appts': return <ApptsPlateScreen nav={nav} />; |
|
case 'appt': return <ApptDetailPlateScreen nav={nav} apptId={parts[1]} />; |
|
case 'medcard': return <MedcardPlateScreen nav={nav} />; |
|
} |
|
} |
|
|
|
switch (id) { |
|
case 'home': return <HOME nav={nav} ctx={ctx} />; |
|
case 'home-v2': return <HomeV2Screen nav={nav} ctx={ctx} />; |
|
case 'doctors': return <DoctorsTabScreen nav={nav} ctx={ctx} />; |
|
case 'doctor': return <DoctorDetailScreen nav={nav} doctorId={parts[1]} />; |
|
case 'booking-specs': return <BookingSpecsScreen nav={nav} />; |
|
case 'booking-doctor': return <BookingDoctorScreen nav={nav} specId={parts[1]} />; |
|
case 'booking-time': return <BookingTimeScreen nav={nav} doctorId={parts[1]} />; |
|
case 'booking-confirm': return <BookingConfirmScreen nav={nav} doctorId={parts[1]} dateIdx={+parts[2]} time={parts[3]} />; |
|
case 'booking-success': return <BookingSuccessScreen nav={nav} />; |
|
case 'appts': return <ApptsTabScreen nav={nav} />; |
|
case 'appt': return <ApptDetailScreen nav={nav} apptId={parts[1]} />; |
|
case 'results': return <ResultsScreen nav={nav} />; |
|
case 'result-audio': return <ResultAudioScreen nav={nav} />; |
|
case 'result': return <ResultEndoscopyScreen nav={nav} resultId={parts[1]} />; |
|
case 'recovery': return <RecoveryScreen nav={nav} />; |
|
case 'audiotest': return <AudioTestScreen nav={nav} />; |
|
case 'chat': return parts[1] |
|
? <ChatConversationScreen nav={nav} chatId={parts[1]} /> |
|
: <ChatsListScreen nav={nav} />; |
|
case 'profile': return <ProfileTabScreen nav={nav} ctx={ctx} />; |
|
case 'qr': return <QRScreen nav={nav} />; |
|
case 'telemed': return <TelemedScreen nav={nav} />; |
|
case 'medcard': return <MedcardScreen nav={nav} />; |
|
case 'notifications': return <NotificationsScreen nav={nav} />; |
|
case 'articles': return <ArticlesScreen nav={nav} />; |
|
case 'article': return <ArticleDetailScreen nav={nav} articleId={parts[1]} />; |
|
case 'search': return <SearchScreen nav={nav} />; |
|
case 'contacts': return <ContactsScreen nav={nav} />; |
|
case 'prices': return <PricesScreen nav={nav} />; |
|
case 'dev-colors': return <DevColorsScreen nav={nav} ctx={ctx} />; |
|
case 'dev-examples': return <DevExamplesScreen nav={nav} ctx={ctx} />; |
|
case 'docs': return <DocsScreen nav={nav} />; |
|
default: return <div style={{padding: 40, textAlign: 'center'}}>Экран не найден: {screenId}</div>; |
|
} |
|
} |
|
|
|
const TAB_IDS = ['home', 'appts', 'doctors', 'chat', 'profile']; |
|
|
|
export function PhoneApp({ initialScreen, ctx, onCurrentChange }) { |
|
const [stack, setStack] = useState([initialScreen]); |
|
|
|
useEffect(() => { setStack([initialScreen]); }, [initialScreen]); |
|
|
|
const current = stack[stack.length - 1]; |
|
|
|
useEffect(() => { |
|
if (onCurrentChange) onCurrentChange(current); |
|
}, [current, onCurrentChange]); |
|
|
|
const nav = useMemo(() => ({ |
|
push: (id) => setStack(s => [...s, id]), |
|
pop: () => setStack(s => s.length > 1 ? s.slice(0, -1) : s), |
|
set: (id) => setStack([id]), |
|
reset:() => setStack(['home']), |
|
}), []); |
|
|
|
const rootId = current.split(':')[0]; |
|
const hasSubId = current.includes(':'); |
|
const tabId = hasSubId ? null : (rootId === 'home-v2' ? 'home' : (TAB_IDS.includes(rootId) ? rootId : null)); |
|
const showTabBar = tabId !== null; |
|
|
|
const modalScreens = ['qr', 'telemed', 'booking-success', 'audiotest']; |
|
const isModal = modalScreens.includes(current.split(':')[0]); |
|
|
|
return ( |
|
<div style={{ |
|
position: 'absolute', inset: 0, |
|
background: 'var(--c-bg)', |
|
overflow: 'hidden', |
|
fontFamily: 'var(--font-base)', |
|
}}> |
|
<div style={{ position: 'absolute', inset: 0, overflowY: 'auto', overflowX: 'hidden', paddingTop: 58, paddingBottom: showTabBar ? 80 : 0 }}> |
|
{renderScreen(current, nav, ctx)} |
|
</div> |
|
{showTabBar && !isModal && ( |
|
<TabBar active={tabId} onChange={(t) => nav.set(t)} /> |
|
)} |
|
</div> |
|
); |
|
}
|
|
|