// Main App — frames, theme, tabs, sheets, simulated state.

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "platform": "ios",
  "dark": true,
  "accent": "ton",
  "live": true
}/*EDITMODE-END*/;

// Model/Backdrop/Symbol are per-collection attributes → only valid when exactly
// one collection is selected. Otherwise strip them so a stale attr-filter never
// applies across multiple/zero collections.
function normalizeAdvFilters(f) {
  return (f.collection && f.collection.length === 1)
    ? f
    : { ...f, model: [], backdrop: [], symbol: [] };
}

// Floating cart button — pops up when the first item is added, drops away
// when the cart empties, and the count badge springs + rolls on every change.
function CartFab({ count, onClick }) {
  const [render, setRender] = React.useState(count > 0);
  const [cls, setCls] = React.useState('');
  React.useEffect(() => {
    if (count > 0) {
      setRender(true);
      setCls('is-in');
      const t = setTimeout(() => setCls(''), 470); // drop anim so :active press works
      return () => clearTimeout(t);
    }
    if (render) {
      setCls('is-out');
      const t = setTimeout(() => { setRender(false); setCls(''); }, 300);
      return () => clearTimeout(t);
    }
  }, [count > 0]);

  if (!render) return null;
  return (
    <button onClick={onClick} aria-label="Корзина" className={'card-press cart-fab ' + cls} style={{
      position: 'absolute', top: 10, right: 16, zIndex: 8,
      width: 56, height: 56, borderRadius: 18, border: 0, cursor: 'pointer',
      background: 'linear-gradient(135deg, var(--accent), var(--accent-2))',
      color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center',
      boxShadow: '0 12px 28px var(--accent-glow), 0 4px 10px rgba(0,0,0,0.28), inset 0 1px 0 rgba(255,255,255,0.32)',
    }}>
      <Icons.cart size={25}/>
      <span className="cart-fab-badge" key={count} style={{
        position: 'absolute', top: -6, right: -6,
        minWidth: 24, height: 24, padding: '0 6px', borderRadius: 999,
        background: '#fff', color: 'var(--accent)',
        fontSize: 13, fontWeight: 800,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        boxShadow: '0 3px 9px rgba(0,0,0,0.32)',
      }}>
        <span className="d">{count}</span>
      </span>
    </button>
  );
}

// AppView renders the device chrome + the active screen. The brief tab-switch
// loading state (skeleton) is driven from App via `shownTab` / `tabLoading`.
function AppView({ tab, setTab, shownTab, tabLoading, platform, bare, balance, onGiftClick, onDeposit, onCartOpen, onAddToCart, onRemoveFromCart, onStartSend, cart, live, cartCount, advFilters, openFilters, hiddenIds, myGifts, onGiftsChanged }) {
  const t = useT();
  const titles = {
    market:   { t: t('title_market'),  s: t('sub_market') },
    wallet:   { t: t('title_wallet'),  s: t('sub_wallet') },
    mine:     { t: t('title_mine'),    s: '' },
    profile:  { t: t('title_profile'), s: '' },
  };
  const tt = titles[tab];

  // Cart is a prominent floating button at the top-right of the gift area.
  // <CartFab> owns its own enter/exit + count-change animation (see below).
  const cartFab = (tab === 'market' && !tabLoading)
    ? <CartFab count={cartCount} onClick={onCartOpen}/>
    : null;

  return (
    <div className="app-view">
      <div className="app-bg" style={{ position: 'absolute', inset: 0, zIndex: 0 }}/>
      {/* Симулятор iOS: спейсер под фейковый статус-бар. Реальный Telegram (bare):
          вместо него отступ на системную safe-area (чёлка/динамик), а не пустые 56px. */}
      {bare
        ? <div style={{ height: 'env(safe-area-inset-top, 0px)', flexShrink: 0, zIndex: 1, position: 'relative' }}/>
        : (platform === 'ios' && <div style={{ height: 56, flexShrink: 0, zIndex: 1, position: 'relative' }}/>)}
      <MiniAppHeader title={tt.t} subtitle={tt.s} onClose={() => {}}/>
      <div style={{ position: 'relative', flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
        <div className="screen-scroll">
          {/* Маркет ВСЕГДА смонтирован (скрыт на др. вкладках/при загрузке) — лента, страница
              и фильтры НЕ сбрасываются при переходе между вкладками. */}
          <div style={{ display: (shownTab === 'market' && !tabLoading) ? 'block' : 'none' }}>
            <MarketScreen onGift={onGiftClick} onAddToCart={onAddToCart} onRemoveFromCart={onRemoveFromCart} cart={cart}
                          advFilters={advFilters} openFilters={openFilters} hiddenIds={hiddenIds}/>
          </div>
          {tabLoading ? (
            <ScreenSkeleton tab={tab}/>
          ) : shownTab === 'wallet' ? (
            <WalletScreen balance={balance} onDeposit={onDeposit}/>
          ) : shownTab === 'mine' ? (
            <MyGiftsScreen onStartSend={onStartSend} onGiftClick={onGiftClick}
                           gifts={myGifts} onChanged={onGiftsChanged}/>
          ) : shownTab === 'profile' ? (
            <ProfileScreen/>
          ) : null}
        </div>
        {cartFab}
      </div>
      <BottomNav active={tab} onChange={setTab} platform={platform}/>
    </div>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [tab, setTabState] = React.useState('market');
  // Tab-switch loading: `tab` highlights instantly in the nav, while the
  // content shown lags behind a short skeleton "loading" beat. State lives
  // here in App (not AppView) because AppView re-mounts on tab change, which
  // would otherwise reset the loading state.
  const [shownTab, setShownTab] = React.useState('market');
  const [tabLoading, setTabLoading] = React.useState(false);
  const shownRef = React.useRef('market');
  const tabTimer = React.useRef(0);
  const setTab = React.useCallback((next) => {
    setTabState(next);
    if (window.SFX) window.SFX.tap();
    if (next === shownRef.current) {
      setTabLoading(false);
      clearTimeout(tabTimer.current);
      return;
    }
    setTabLoading(true);
    document.querySelectorAll('.screen-scroll').forEach(el => { el.scrollTop = 0; });
    clearTimeout(tabTimer.current);
    tabTimer.current = setTimeout(() => {
      shownRef.current = next;
      setShownTab(next);
      setTabLoading(false);
    }, 440);
  }, []);
  React.useEffect(() => () => clearTimeout(tabTimer.current), []);
  // РЕАЛЬНЫЙ ₽-баланс с бэка (таблица balances). Рефетч по bump'у balanceReload.
  const [balanceReload, setBalanceReload] = React.useState(0);
  const bumpBalance = React.useCallback(() => setBalanceReload(x => x + 1), []);
  const _bal = (window.DataSource && window.DataSource.useBalance)
    ? window.DataSource.useBalance(balanceReload)
    : { balance_rub: 0 };
  const balance = _bal.balance_rub || 0;
  const [viewing, setViewing] = React.useState(null);
  const [buying, setBuying] = React.useState(null);
  const [depositOpen, setDepositOpen] = React.useState(false);
  const [cart, setCart] = React.useState([]);
  const [cartOpen, setCartOpen] = React.useState(false);
  // Listings the user has bought — used to hide them from the market grid
  // so a sold-out gift doesn't linger after checkout.
  const [purchasedIds, setPurchasedIds] = React.useState(() => new Set());
  const [filtersOpen, setFiltersOpen] = React.useState(false);
  const [filterTab, setFilterTab]     = React.useState('collection');
  const [advFilters, setAdvFilters]   = React.useState({ collection: [], model: [], backdrop: [], symbol: [] });
  const [sendStage, setSendStage] = React.useState(null);
  const [sendIds, setSendIds] = React.useState([]);
  const [sentInfo, setSentInfo] = React.useState(null);
  const [lang, setLang] = React.useState('ru');

  // Реальные купленные (held) подарки юзера с бэка; refetch по bump'у giftsReload.
  const [giftsReload, setGiftsReload] = React.useState(0);

  // Scroll-lock фона авторитетно из состояния App: пока открыта ЛЮБАЯ модалка —
  // body.sheet-open (CSS душит `.screen-scroll{overflow:hidden}`), иначе снят.
  // Единый владелец класса (SheetShell больше его не трогает) — нет гонки, из-за
  // которой скролл ленты залипал после закрытия карточки/оплаты.
  const anySheet = !!(viewing || buying || depositOpen || cartOpen || filtersOpen || sendStage);
  React.useEffect(() => {
    document.body.classList.toggle('sheet-open', anySheet);
    return () => document.body.classList.remove('sheet-open');
  }, [anySheet]);

  // ── Telegram WebApp: bare-режим (на весь вьюпорт, без фейкового телефона) когда
  // запущены ВНУТРИ Telegram. В браузере — прежний дизайн-симулятор с рамкой.
  // ?bare=1 форсит bare, ?frame=1 форсит симулятор (для отладки).
  const bare = React.useMemo(() => {
    try {
      const p = new URLSearchParams(window.location.search);
      if (p.get('frame') === '1') return false;
      if (p.get('bare') === '1') return true;
      const tg = window.Telegram && window.Telegram.WebApp;
      return !!(tg && tg.initData);
    } catch (_) { return false; }
  }, []);

  React.useEffect(() => {
    const tg = window.Telegram && window.Telegram.WebApp;
    if (!tg) return;
    try {
      tg.ready();
      if (tg.expand) tg.expand();
      // Свайп-вниз Telegram не закрывает мини-апп и не конфликтует со скроллом ленты.
      if (tg.disableVerticalSwipes) tg.disableVerticalSwipes();
      if (tg.setHeaderColor) tg.setHeaderColor('#140f22');
      if (tg.setBackgroundColor) tg.setBackgroundColor('#140f22');
    } catch (_) {}
  }, []);
  const _mg = (window.DataSource && window.DataSource.useMyGifts)
    ? window.DataSource.useMyGifts(giftsReload)
    : { data: null };
  const myGifts = (_mg.data && _mg.data.items) || [];
  const onGiftsChanged = React.useCallback(() => setGiftsReload(x => x + 1), []);

  React.useEffect(() => {
    document.body.setAttribute('data-theme', t.dark ? 'dark' : 'light');
    document.body.setAttribute('data-accent', t.accent);
  }, [t.dark, t.accent]);

  // Warm the real collection floors into cache on launch, so the collection
  // filter opens with real prices instantly (no mock-price flash, no spinner).
  React.useEffect(() => { if (window.loadCollectionFloors) window.loadCollectionFloors(); }, []);

  // When exactly one collection is selected, warm its model/symbol/backdrop
  // attribute lists + icon images so those filters open instantly and crisp.
  const singleCollection = advFilters.collection.length === 1 ? advFilters.collection[0] : null;
  React.useEffect(() => {
    if (singleCollection && window.prefetchGiftAttrs) window.prefetchGiftAttrs(singleCollection);
  }, [singleCollection]);

  // Runtime i18n: walks the DOM after each render and swaps RU phrases for
  // EN equivalents while `lang === 'en'`. Restores originals on switch back.
  React.useEffect(() => {
    if (typeof window.__i18nSetLang === 'function') window.__i18nSetLang(lang);
  }, [lang, tab, viewing, buying, depositOpen, cartOpen, sendStage]);

  const handleStartBuy = (gift) => {
    setViewing(null);
    setTimeout(() => setBuying(gift), 200);
  };
  // Commit a purchase: deduct balance, hide bought listings from the market,
  // and (for cart checkout) empty the cart. Called from the *flow* the
  // instant the success stage is entered, so dragging the sheet shut after
  // confetti still leaves consistent state.
  // Баланс уже списан на бэке (pay_with_balance) — тут только прячем купленные
  // лоты с маркета, чистим корзину и рефетчим реальный баланс + «Мои».
  const commitPurchase = React.useCallback((items) => {
    const list = Array.isArray(items) ? items : [items];
    if (list.length === 0) return;
    setPurchasedIds(prev => {
      const next = new Set(prev);
      list.forEach(i => next.add(i.id));
      return next;
    });
    setCart(prev => prev.filter(i => !list.some(b => b.id === i.id)));
    bumpBalance();
    onGiftsChanged();
  }, [bumpBalance, onGiftsChanged]);

  // Single-gift purchase: PurchaseFlow now reports success via onSuccess as
  // soon as confetti starts. onComplete only handles the closing nav action.
  const handleBuyComplete = (_gift, action) => {
    setBuying(null);
    if (action === 'goto') setTab('mine');
  };
  // Реальное пополнение: /me/deposit → invoice; mock-провайдер подтверждаем
  // webhook'ом (как покупку). Возвращаем промис — DepositSheet ждёт и закрывается.
  const handleDepositConfirm = async (amount, method) => {
    const DS = window.DataSource;
    try {
      if (DS && DS.deposit) {
        // method = выбранная платёжка ('cryptobot'/'platega'). Бэк: настроена →
        // реальный invoice; не настроена в dev → mock-fallback.
        const inv = await DS.deposit(amount, method);   // {payment_id, order_id, amount_rub, invoice_url, provider}
        const isMock = inv.provider === 'mock'
          || !inv.invoice_url || inv.invoice_url.includes('/mock-pay/') || inv.invoice_url === 'about:blank';
        if (isMock && DS.mockPay) {
          await DS.mockPay(inv);                  // dev: зачисляем сразу через локальный webhook
        } else if (inv.invoice_url) {
          // Реальная платёжка: открываем оплату; баланс зачислит webhook после оплаты.
          const tg = window.Telegram && window.Telegram.WebApp;
          const url = inv.invoice_url;
          try {
            if (url.startsWith('https://t.me/') && tg && tg.openTelegramLink) tg.openTelegramLink(url);
            else if (tg && tg.openLink) tg.openLink(url);
            else window.open(url, '_blank', 'noopener,noreferrer');
          } catch (_) { try { window.open(url, '_blank'); } catch (__) {} }
        }
        bumpBalance();                            // рефетч (mock — сразу; реальная — после оплаты)
        if (window.SFX) window.SFX.success();
      }
    } catch (e) {
      console.warn('[deposit]', e);              // тихо: баланс просто не изменится
    } finally {
      setDepositOpen(false);
    }
  };

  const addToCart = (listing) => {
    setCart(prev => prev.find(i => i.id === listing.id) ? prev : [...prev, listing]);
    setViewing(null);
    if (window.SFX) window.SFX.click();
  };
  const removeFromCart = (id) => { setCart(prev => prev.filter(i => i.id !== id)); if (window.SFX) window.SFX.pop(); };

  // Cart checkout: balance/cart already committed when the sheet entered
  // 'success' — this only handles where to send the user next.
  const handleCartCheckout = (action) => {
    setCartOpen(false);
    if (action === 'goto') setTab('mine');
  };

  const handleStartSend = (giftIds) => {
    const ids = Array.isArray(giftIds) ? giftIds : [giftIds];
    setSendIds(ids);
    // If invoked with a specific gift (the common "Send" button on a single
    // gift card), jump straight to the recipient step — the user already
    // chose what to send. The "+" button there lets them add more.
    // Without a preselection, start with the multi-select picker.
    setSendStage(ids.length > 0 ? 'recipient' : 'select');
  };
  const handleSendComplete = (info) => {
    // Снапшот отправленных ДО рефетча: после onGiftsChanged они исчезнут из myGifts,
    // а success-шиту ещё нужно их показать.
    const sent = myGifts.filter(g => sendIds.includes(g.id));
    setSentInfo({ ...info, gifts: sent });
    setSendStage('sent');
    onGiftsChanged();                 // отправленные ушли из held — рефетч «Моих»
    if (window.SFX) window.SFX.success();
  };

  const tgPlatform = (window.Telegram && window.Telegram.WebApp && window.Telegram.WebApp.platform) || '';
  const platform = bare ? (tgPlatform === 'android' ? 'android' : 'ios') : t.platform;
  const shared = {
    tab, setTab, shownTab, tabLoading, platform, bare, balance, live: t.live,
    onGiftClick: setViewing,
    onDeposit: () => setDepositOpen(true),
    onCartOpen: () => setCartOpen(true),
    onAddToCart: addToCart,
    onRemoveFromCart: removeFromCart,
    onStartSend: handleStartSend,
    cart,
    cartCount: cart.length,
    advFilters,
    hiddenIds: purchasedIds,
    myGifts,
    onGiftsChanged,
    openFilters: (which) => {
      if (which === '__reset') {
        setAdvFilters({ collection: [], model: [], backdrop: [], symbol: [] });
        return;
      }
      setFilterTab(which);
      setFiltersOpen(true);
    },
  };

  const modalProps = {
    viewing, buying, depositOpen, cartOpen, filtersOpen, cart, balance,
    filterTab, advFilters, setAdvFilters,
    sendStage, sendIds, setSendStage, setSendIds, handleSendComplete, sentInfo, setSentInfo,
    setViewing, setBuying, setDepositOpen, setCartOpen, setFiltersOpen,
    handleStartBuy, handleBuyComplete, handleDepositConfirm,
    addToCart, removeFromCart, handleCartCheckout, setTab,
    commitPurchase, myGifts, onGiftsChanged,
  };

  // Реальный Telegram: рендерим на весь вьюпорт без симулятора и tweaks-панели.
  if (bare) {
    return (
      <LangContext.Provider value={{ lang, setLang }}>
        <div className="tg-bare">
          <AppView {...shared}/>
          <ModalLayer bare device={platform} {...modalProps}/>
        </div>
      </LangContext.Provider>
    );
  }

  return (
    <LangContext.Provider value={{ lang, setLang }}>
    <div style={{
      minHeight: '100vh',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 20, gap: 28,
    }}>
      {platform === 'ios' && (
        <div style={{ position: 'relative', transformOrigin: 'center' }}>
          <IOSDevice dark={t.dark} width={380} height={780}>
            <AppView {...shared}/>
          </IOSDevice>
          <ModalLayer device="ios" {...modalProps}/>
        </div>
      )}
      {platform === 'android' && (
        <div style={{ position: 'relative' }}>
          <AndroidDevice dark={t.dark} width={390} height={780}>
            <AppView {...shared}/>
          </AndroidDevice>
          <ModalLayer device="android" {...modalProps}/>
        </div>
      )}
      {platform === 'both' && (
        <>
          <div style={{ position: 'relative' }}>
            <IOSDevice dark={t.dark} width={380} height={780}>
              <AppView {...shared}/>
            </IOSDevice>
            <ModalLayer device="ios" {...modalProps}/>
          </div>
          <div style={{ position: 'relative' }}>
            <AndroidDevice dark={t.dark} width={390} height={780}>
              <AppView {...shared}/>
            </AndroidDevice>
          </div>
        </>
      )}

      <TweaksPanel>
        <TweakSection label="Устройство"/>
        <TweakRadio label="Платформа" value={t.platform}
                    options={[
                      { value: 'ios', label: 'iOS' },
                      { value: 'android', label: 'Android' },
                    ]}
                    onChange={(v) => setTweak('platform', v)}/>
        <TweakToggle label="Тёмная тема" value={t.dark} onChange={(v) => setTweak('dark', v)}/>

        <TweakSection label="Акцент"/>
        <TweakColor label="Цвет"
                    value={t.accent === 'ton' ? '#0098EA' : t.accent === 'purple' ? '#a855f7' : '#10b981'}
                    options={['#0098EA', '#a855f7', '#10b981']}
                    onChange={(v) => {
                      const map = { '#0098EA': 'ton', '#a855f7': 'purple', '#10b981': 'mint' };
                      setTweak('accent', map[v] || 'ton');
                    }}/>

        <TweakSection label="Поведение"/>
        <TweakToggle label="Живая лента" value={t.live} onChange={(v) => setTweak('live', v)}/>

        <TweakSection label="Навигация"/>
        <TweakRadio label="Экран" value={tab}
                    options={TABS.map(x => ({ value: x.id, label: x.label }))}
                    onChange={setTab}/>

        <TweakSection label="Демо"/>
        <TweakButton label="Открыть карточку подарка" onClick={() => setViewing(MARKET_LISTINGS[0])}/>
        <TweakButton label="Открыть пополнение" onClick={() => setDepositOpen(true)}/>
      </TweaksPanel>
    </div>
    </LangContext.Provider>
  );
}

// Modal layer absolutely positions inside the device wrapper.
function ModalLayer({ device, bare = false, viewing, buying, depositOpen, cartOpen, filtersOpen, cart, balance,
                     filterTab, advFilters, setAdvFilters,
                     sendStage, sendIds, setSendStage, setSendIds, handleSendComplete, sentInfo, setSentInfo,
                     setViewing, setBuying, setDepositOpen, setCartOpen, setFiltersOpen,
                     handleStartBuy, handleBuyComplete, handleDepositConfirm,
                     addToCart, removeFromCart, handleCartCheckout, setTab, commitPurchase,
                     myGifts, onGiftsChanged }) {
  const hasModal = viewing || buying || depositOpen || cartOpen || filtersOpen || sendStage;
  if (!hasModal) return null;
  const width  = device === 'ios' ? 380 : 390;
  const height = 780;
  const radius = device === 'ios' ? 48 : 18;
  // bare (реальный Telegram): sheets на весь вьюпорт (фиксировано, по центру на десктопе).
  // Симулятор: абсолютно внутри фейкового телефона.
  const wrapStyle = bare
    ? { position: 'fixed', inset: 0, maxWidth: 520, margin: '0 auto', overflow: 'hidden', zIndex: 80 }
    : { position: 'absolute', top: 0, left: 0, width, height, borderRadius: radius, overflow: 'hidden' };
  return (
    <div style={wrapStyle}>
      {viewing && (
        <GiftDetailSheet listing={viewing}
                         balance={balance}
                         inCart={cart.some(i => i.id === viewing.id)}
                         onClose={() => setViewing(null)}
                         onBuy={handleStartBuy}
                         onAddToCart={addToCart}/>
      )}
      {buying && (
        <PurchaseFlow gift={buying}
                      balance={balance}
                      onClose={() => setBuying(null)}
                      onSuccess={() => { commitPurchase(buying); onGiftsChanged(); }}
                      onComplete={handleBuyComplete}/>
      )}
      {depositOpen && (
        <DepositSheet open={depositOpen}
                      onClose={() => setDepositOpen(false)}
                      onConfirm={handleDepositConfirm}/>
      )}
      {cartOpen && (
        <CartSheet cart={cart}
                   balance={balance}
                   onClose={() => setCartOpen(false)}
                   onRemove={removeFromCart}
                   onSuccess={(items) => { commitPurchase(items); onGiftsChanged(); }}
                   onCheckout={handleCartCheckout}
                   onBrowseMore={() => setTab('market')}/>
      )}
      {sendStage === 'select' && (
        <SheetShell onClose={() => setSendStage(sendIds.length ? 'recipient' : null)}>
          <SendSelectSheet initialIds={sendIds} gifts={myGifts}
                           onCancel={() => setSendStage(sendIds.length ? 'recipient' : null)}
                           onNext={(ids) => { setSendIds(ids); setSendStage('recipient'); }}/>
        </SheetShell>
      )}
      {sendStage === 'recipient' && (
        <SheetShell onClose={() => setSendStage(null)}>
          <SendRecipientSheet gifts={myGifts.filter(g => sendIds.includes(g.id))}
                              onBack={(ids) => { if (ids) setSendIds(ids); setSendStage('select'); }}
                              onAddMore={(ids) => { if (ids) setSendIds(ids); setSendStage('select'); }}
                              onSend={(r) => handleSendComplete(r)}/>
        </SheetShell>
      )}
      {sendStage === 'sent' && (
        <SheetShell onClose={() => { setSendStage(null); setSentInfo(null); }} dismissable={false} hideGrip>
          <SendSuccessSheet gifts={(sentInfo && sentInfo.gifts) || []}
                            recipient={sentInfo}/>
        </SheetShell>
      )}
      {filtersOpen && (
        <FilterSheet filters={advFilters}
                     tab={filterTab}
                     collection={advFilters.collection.length === 1 ? advFilters.collection[0] : null}
                     onClose={() => setFiltersOpen(false)}
                     onApply={(f) => setAdvFilters(prev => {
                       // Смена ЕДИНСТВЕННОЙ коллекции A→B обязана сбрасывать model/backdrop/symbol —
                       // атрибуты чужой коллекции дают гарантированно пустую выдачу.
                       const next = normalizeAdvFilters(f);
                       return (prev.collection[0] !== next.collection[0])
                         ? { ...next, model: [], backdrop: [], symbol: [] }
                         : next;
                     })}/>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
