File size: 3,227 Bytes
709db16
5e0e982
 
 
 
709db16
391340f
5e0e982
 
391340f
 
 
c6253b2
391340f
 
 
 
5e0e982
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391340f
57ed4c2
 
391340f
 
 
 
c6253b2
391340f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e0e982
 
709db16
391340f
 
709db16
5e0e982
 
 
 
 
 
 
 
 
391340f
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/** App entry: auth gate, hash router, toast + pending resolve hosts. */

import { render } from "preact";
import { useCallback, useEffect, useState } from "preact/hooks";
import { getMe } from "./api";
import { PendingResolveProvider } from "./components/PendingResolve";
import { TabBar } from "./components/TabBar";
import { ToastProvider } from "./components/Toast";
import { Home } from "./pages/Home";
import { History } from "./pages/History";
import { EntryDetail } from "./pages/EntryDetail";
import { Daily } from "./pages/Daily";
import { Plan } from "./pages/Plan";
import { Stats } from "./pages/Stats";
import { Remedies } from "./pages/Remedies";
import { Coach } from "./pages/Coach";
import { Settings } from "./pages/Settings";
import { Log } from "./pages/Log";
import { Login } from "./pages/Login";
import { navigate, useRoute } from "./router";
import "./styles/app.css";

function App() {
  const route = useRoute();
  const [ready, setReady] = useState(false);
  const [authenticated, setAuthenticated] = useState(false);
  const [appName, setAppName] = useState("Habit Journal");

  const refreshAuth = useCallback(async () => {
    try {
      const me = await getMe();
      setAuthenticated(me.authenticated);
      setAppName(me.app_name || "Habit Journal");
      return me.authenticated;
    } catch {
      setAuthenticated(false);
      return false;
    } finally {
      setReady(true);
    }
  }, []);

  useEffect(() => {
    void refreshAuth();
  }, [refreshAuth]);

  useEffect(() => {
    if (!ready) return;
    if (!authenticated && route.name !== "login") {
      navigate("/login");
    }
  }, [ready, authenticated, route.name]);

  if (!ready) {
    return <div class="gate-loading">Loading…</div>;
  }

  if (!authenticated || route.name === "login") {
    return (
      <Login
        appName={appName}
        onAuthenticated={() => {
          setAuthenticated(true);
        }}
      />
    );
  }

  let page;
  if (route.name === "log")
    page = <Log initialRemedy={route.remedy} initialHappened={route.happened} />;
  else if (route.name === "home") page = <Home />;
  else if (route.name === "history") page = <History />;
  else if (route.name === "entry") page = <EntryDetail id={route.id} />;
  else if (route.name === "daily") page = <Daily />;
  else if (route.name === "plan") page = <Plan initialDate={route.date} />;
  else if (route.name === "stats") page = <Stats />;
  else if (route.name === "coach") page = <Coach />;
  else if (route.name === "remedies") page = <Remedies />;
  else if (route.name === "settings") page = <Settings />;
  else
    page = (
      <div class="app-shell">
        <main class="page stack">
          <p>Unknown page.</p>
          <button type="button" class="btn btn-primary" onClick={() => navigate("/")}>
            Home
          </button>
        </main>
      </div>
    );

  return (
    <PendingResolveProvider>
      {page}
      <TabBar route={route} />
    </PendingResolveProvider>
  );
}

render(
  <ToastProvider>
    <App />
  </ToastProvider>,
  document.getElementById("app")!,
);

if ("serviceWorker" in navigator) {
  window.addEventListener("load", () => navigator.serviceWorker.register("/sw.js"));
}