gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: anastasis-webui: first commit


From: gnunet
Subject: [taler-wallet-core] branch master updated: anastasis-webui: first commit
Date: Mon, 11 Oct 2021 10:59:00 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new f23a8ee4 anastasis-webui: first commit
f23a8ee4 is described below

commit f23a8ee4d356645ae3f91862552b256f230c6bcb
Author: Florian Dold <florian@dold.me>
AuthorDate: Mon Oct 11 10:58:55 2021 +0200

    anastasis-webui: first commit
---
 packages/anastasis-webui/.gitignore                |   3 +
 packages/anastasis-webui/README.md                 |  19 +++
 packages/anastasis-webui/package.json              |  50 ++++++
 packages/anastasis-webui/src/.babelrc              |   5 +
 packages/anastasis-webui/src/assets/favicon.ico    | Bin 0 -> 15086 bytes
 .../src/assets/icons/android-chrome-192x192.png    | Bin 0 -> 14058 bytes
 .../src/assets/icons/android-chrome-512x512.png    | Bin 0 -> 51484 bytes
 .../src/assets/icons/apple-touch-icon.png          | Bin 0 -> 12746 bytes
 .../src/assets/icons/favicon-16x16.png             | Bin 0 -> 626 bytes
 .../src/assets/icons/favicon-32x32.png             | Bin 0 -> 1487 bytes
 .../src/assets/icons/mstile-150x150.png            | Bin 0 -> 9050 bytes
 packages/anastasis-webui/src/components/app.tsx    |  23 +++
 .../src/components/header/index.tsx                |  24 +++
 .../src/components/header/style.css                |  48 ++++++
 packages/anastasis-webui/src/declaration.d.ts      |   4 +
 .../src/hooks/use-anastasis-reducer.ts             | 131 +++++++++++++++
 packages/anastasis-webui/src/index.ts              |   4 +
 packages/anastasis-webui/src/manifest.json         |  21 +++
 packages/anastasis-webui/src/routes/home/index.tsx | 187 +++++++++++++++++++++
 packages/anastasis-webui/src/routes/home/style.css |   5 +
 .../anastasis-webui/src/routes/notfound/index.tsx  |  17 ++
 .../anastasis-webui/src/routes/notfound/style.css  |   4 +
 .../anastasis-webui/src/routes/profile/index.tsx   |  44 +++++
 .../anastasis-webui/src/routes/profile/style.css   |   5 +
 packages/anastasis-webui/src/style/index.css       |  20 +++
 packages/anastasis-webui/src/sw.js                 |   4 +
 packages/anastasis-webui/src/template.html         |  15 ++
 .../tests/__mocks__/browserMocks.ts                |  21 +++
 .../anastasis-webui/tests/__mocks__/fileMocks.ts   |   3 +
 .../anastasis-webui/tests/__mocks__/setupTests.ts  |   6 +
 packages/anastasis-webui/tests/declarations.d.ts   |   3 +
 packages/anastasis-webui/tests/header.test.tsx     |  12 ++
 packages/anastasis-webui/tsconfig.json             |  60 +++++++
 33 files changed, 738 insertions(+)

diff --git a/packages/anastasis-webui/.gitignore 
b/packages/anastasis-webui/.gitignore
new file mode 100644
index 00000000..7e0633d5
--- /dev/null
+++ b/packages/anastasis-webui/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+/build
+/*.log
diff --git a/packages/anastasis-webui/README.md 
b/packages/anastasis-webui/README.md
new file mode 100644
index 00000000..9f9b5987
--- /dev/null
+++ b/packages/anastasis-webui/README.md
@@ -0,0 +1,19 @@
+# anastasis-webui
+
+## CLI Commands
+*   `npm install`: Installs dependencies
+
+*   `npm run dev`: Run a development, HMR server
+
+*   `npm run serve`: Run a production-like server
+
+*   `npm run build`: Production-ready build
+
+*   `npm run lint`: Pass TypeScript files using ESLint
+
+*   `npm run test`: Run Jest and Enzyme with
+    
[`enzyme-adapter-preact-pure`](https://github.com/preactjs/enzyme-adapter-preact-pure)
 for
+    your tests
+
+
+For detailed explanation on how things work, checkout the [CLI 
Readme](https://github.com/developit/preact-cli/blob/master/README.md).
diff --git a/packages/anastasis-webui/package.json 
b/packages/anastasis-webui/package.json
new file mode 100644
index 00000000..ddbd9ef2
--- /dev/null
+++ b/packages/anastasis-webui/package.json
@@ -0,0 +1,50 @@
+{
+  "private": true,
+  "name": "anastasis-webui",
+  "version": "0.0.0",
+  "license": "MIT",
+  "scripts": {
+    "build": "preact build",
+    "serve": "sirv build --port 8080 --cors --single",
+    "dev": "preact watch",
+    "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
+    "test": "jest ./tests"
+  },
+  "eslintConfig": {
+    "parser": "@typescript-eslint/parser",
+    "extends": [
+      "preact",
+      "plugin:@typescript-eslint/recommended"
+    ],
+    "ignorePatterns": [
+      "build/"
+    ]
+  },
+  "dependencies": {
+    "preact": "^10.3.1",
+    "preact-render-to-string": "^5.1.4",
+    "preact-router": "^3.2.1"
+  },
+  "devDependencies": {
+    "@types/enzyme": "^3.10.5",
+    "@types/jest": "^26.0.8",
+    "@typescript-eslint/eslint-plugin": "^2.25.0",
+    "@typescript-eslint/parser": "^2.25.0",
+    "enzyme": "^3.11.0",
+    "enzyme-adapter-preact-pure": "^3.1.0",
+    "eslint": "^6.8.0",
+    "eslint-config-preact": "^1.1.1",
+    "jest": "^26.2.2",
+    "jest-preset-preact": "^4.0.2",
+    "preact-cli": "^3.0.0",
+    "sirv-cli": "^1.0.0-next.3",
+    "typescript": "^3.7.5"
+  },
+  "jest": {
+    "preset": "jest-preset-preact",
+    "setupFiles": [
+      "<rootDir>/tests/__mocks__/browserMocks.ts",
+      "<rootDir>/tests/__mocks__/setupTests.ts"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/packages/anastasis-webui/src/.babelrc 
b/packages/anastasis-webui/src/.babelrc
new file mode 100644
index 00000000..12300221
--- /dev/null
+++ b/packages/anastasis-webui/src/.babelrc
@@ -0,0 +1,5 @@
+{
+    "presets": [ 
+        "preact-cli/babel"
+    ]
+}
diff --git a/packages/anastasis-webui/src/assets/favicon.ico 
b/packages/anastasis-webui/src/assets/favicon.ico
new file mode 100644
index 00000000..07419145
Binary files /dev/null and b/packages/anastasis-webui/src/assets/favicon.ico 
differ
diff --git 
a/packages/anastasis-webui/src/assets/icons/android-chrome-192x192.png 
b/packages/anastasis-webui/src/assets/icons/android-chrome-192x192.png
new file mode 100644
index 00000000..93ebe2e2
Binary files /dev/null and 
b/packages/anastasis-webui/src/assets/icons/android-chrome-192x192.png differ
diff --git 
a/packages/anastasis-webui/src/assets/icons/android-chrome-512x512.png 
b/packages/anastasis-webui/src/assets/icons/android-chrome-512x512.png
new file mode 100644
index 00000000..52d1623e
Binary files /dev/null and 
b/packages/anastasis-webui/src/assets/icons/android-chrome-512x512.png differ
diff --git a/packages/anastasis-webui/src/assets/icons/apple-touch-icon.png 
b/packages/anastasis-webui/src/assets/icons/apple-touch-icon.png
new file mode 100644
index 00000000..254e4bb4
Binary files /dev/null and 
b/packages/anastasis-webui/src/assets/icons/apple-touch-icon.png differ
diff --git a/packages/anastasis-webui/src/assets/icons/favicon-16x16.png 
b/packages/anastasis-webui/src/assets/icons/favicon-16x16.png
new file mode 100644
index 00000000..e81177dc
Binary files /dev/null and 
b/packages/anastasis-webui/src/assets/icons/favicon-16x16.png differ
diff --git a/packages/anastasis-webui/src/assets/icons/favicon-32x32.png 
b/packages/anastasis-webui/src/assets/icons/favicon-32x32.png
new file mode 100644
index 00000000..40e9b5b4
Binary files /dev/null and 
b/packages/anastasis-webui/src/assets/icons/favicon-32x32.png differ
diff --git a/packages/anastasis-webui/src/assets/icons/mstile-150x150.png 
b/packages/anastasis-webui/src/assets/icons/mstile-150x150.png
new file mode 100644
index 00000000..9cfb889b
Binary files /dev/null and 
b/packages/anastasis-webui/src/assets/icons/mstile-150x150.png differ
diff --git a/packages/anastasis-webui/src/components/app.tsx 
b/packages/anastasis-webui/src/components/app.tsx
new file mode 100644
index 00000000..5abb12a3
--- /dev/null
+++ b/packages/anastasis-webui/src/components/app.tsx
@@ -0,0 +1,23 @@
+import { FunctionalComponent, h } from 'preact';
+import { Route, Router } from 'preact-router';
+
+import Home from '../routes/home';
+import Profile from '../routes/profile';
+import NotFoundPage from '../routes/notfound';
+import Header from './header';
+
+const App: FunctionalComponent = () => {
+    return (
+        <div id="preact_root">
+            <Header />
+            <Router>
+                <Route path="/" component={Home} />
+                <Route path="/profile/" component={Profile} user="me" />
+                <Route path="/profile/:user" component={Profile} />
+                <NotFoundPage default />
+            </Router>
+        </div>
+    );
+};
+
+export default App;
diff --git a/packages/anastasis-webui/src/components/header/index.tsx 
b/packages/anastasis-webui/src/components/header/index.tsx
new file mode 100644
index 00000000..f2b6fe8a
--- /dev/null
+++ b/packages/anastasis-webui/src/components/header/index.tsx
@@ -0,0 +1,24 @@
+import { FunctionalComponent, h } from 'preact';
+import { Link } from 'preact-router/match';
+import style from './style.css';
+
+const Header: FunctionalComponent = () => {
+    return (
+        <header class={style.header}>
+            <h1>Preact App</h1>
+            <nav>
+                <Link activeClassName={style.active} href="/">
+                    Home
+                </Link>
+                <Link activeClassName={style.active} href="/profile">
+                    Me
+                </Link>
+                <Link activeClassName={style.active} href="/profile/john">
+                    John
+                </Link>
+            </nav>
+        </header>
+    );
+};
+
+export default Header;
diff --git a/packages/anastasis-webui/src/components/header/style.css 
b/packages/anastasis-webui/src/components/header/style.css
new file mode 100644
index 00000000..f08fda70
--- /dev/null
+++ b/packages/anastasis-webui/src/components/header/style.css
@@ -0,0 +1,48 @@
+.header {
+       position: fixed;
+       left: 0;
+       top: 0;
+       width: 100%;
+       height: 56px;
+       padding: 0;
+       background: #673AB7;
+       box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
+       z-index: 50;
+}
+
+.header h1 {
+       float: left;
+       margin: 0;
+       padding: 0 15px;
+       font-size: 24px;
+       line-height: 56px;
+       font-weight: 400;
+       color: #FFF;
+}
+
+.header nav {
+       float: right;
+       font-size: 100%;
+}
+
+.header nav a {
+       display: inline-block;
+       height: 56px;
+       line-height: 56px;
+       padding: 0 15px;
+       min-width: 50px;
+       text-align: center;
+       background: rgba(255,255,255,0);
+       text-decoration: none;
+       color: #FFF;
+       will-change: background-color;
+}
+
+.header nav a:hover,
+.header nav a:active {
+       background: rgba(0,0,0,0.2);
+}
+
+.header nav a.active {
+       background: rgba(0,0,0,0.4);
+}
diff --git a/packages/anastasis-webui/src/declaration.d.ts 
b/packages/anastasis-webui/src/declaration.d.ts
new file mode 100644
index 00000000..bbff36e8
--- /dev/null
+++ b/packages/anastasis-webui/src/declaration.d.ts
@@ -0,0 +1,4 @@
+declare module "*.css" {
+    const mapping: Record<string, string>;
+    export default mapping;
+}
diff --git a/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts 
b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
new file mode 100644
index 00000000..30bab96d
--- /dev/null
+++ b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
@@ -0,0 +1,131 @@
+import { useState } from "preact/hooks";
+
+type ReducerState = any;
+
+interface AnastasisState {
+  reducerState: ReducerState | undefined;
+  currentError: any;
+}
+
+export enum BackupStates {
+  ContinentSelecting = "CONTINENT_SELECTING",
+  CountrySelecting = "COUNTRY_SELECTING",
+}
+
+export enum RecoveryStates {
+  ContinentSelecting = "CONTINENT_SELECTING",
+  CountrySelecting = "COUNTRY_SELECTING",
+}
+
+const reducerBaseUrl = "http://localhost:5000/";;
+
+async function getBackupStartState(): Promise<ReducerState> {
+  const resp = await fetch(new URL("start-backup", reducerBaseUrl).href);
+  return await resp.json();
+}
+
+async function getRecoveryStartState(): Promise<ReducerState> {
+  const resp = await fetch(new URL("start-recovery", reducerBaseUrl).href);
+  return await resp.json();
+}
+
+async function reduceState(
+  state: any,
+  action: string,
+  args: any,
+): Promise<ReducerState> {
+  const resp = await fetch(new URL("action", reducerBaseUrl).href, {
+    method: "POST",
+    headers: {
+      Accept: "application/json",
+      "Content-Type": "application/json",
+    },
+    body: JSON.stringify({
+      state,
+      action,
+      arguments: args,
+    }),
+  });
+  return resp.json();
+}
+
+export interface AnastasisReducerApi {
+  currentReducerState: ReducerState;
+  currentError: any;
+  startBackup: () => void;
+  startRecover: () => void;
+  back: () => void;
+  transition(action: string, args: any): void;
+}
+
+export function useAnastasisReducer(): AnastasisReducerApi {
+  const [anastasisState, setAnastasisState] = useState<AnastasisState>({
+    reducerState: undefined,
+    currentError: undefined,
+  });
+
+  async function doTransition(action: string, args: any) {
+    console.log("reducing with", action, args);
+    const s = await reduceState(anastasisState.reducerState, action, args);
+    console.log("got new state from reducer", s);
+    if (s.code) {
+      setAnastasisState({ ...anastasisState, currentError: s });
+    } else {
+      setAnastasisState({
+        ...anastasisState,
+        currentError: undefined,
+        reducerState: s,
+      });
+    }
+  }
+
+  return {
+    currentReducerState: anastasisState.reducerState,
+    currentError: anastasisState.currentError,
+    async startBackup() {
+      const s = await getBackupStartState();
+      setAnastasisState({
+        ...anastasisState,
+        currentError: undefined,
+        reducerState: s,
+      });
+    },
+    async startRecover() {
+      const s = await getRecoveryStartState();
+      setAnastasisState({
+        ...anastasisState,
+        currentError: undefined,
+        reducerState: s,
+      });
+    },
+    transition(action: string, args: any) {
+      doTransition(action, args);
+    },
+    back() {
+      if (
+        anastasisState.reducerState.backup_state ===
+          BackupStates.ContinentSelecting ||
+        anastasisState.reducerState.recovery_state ===
+          RecoveryStates.ContinentSelecting
+      ) {
+        setAnastasisState({
+          ...anastasisState,
+          currentError: undefined,
+          reducerState: undefined,
+        });
+      } else if (
+        anastasisState.reducerState.backup_state ===
+        BackupStates.CountrySelecting
+      ) {
+        doTransition("unselect_continent", {});
+      } else if (
+        anastasisState.reducerState.recovery_state ===
+        RecoveryStates.CountrySelecting
+      ) {
+        doTransition("unselect_continent", {});
+      } else {
+        doTransition("back", {});
+      }
+    },
+  };
+}
diff --git a/packages/anastasis-webui/src/index.ts 
b/packages/anastasis-webui/src/index.ts
new file mode 100644
index 00000000..3b3f7844
--- /dev/null
+++ b/packages/anastasis-webui/src/index.ts
@@ -0,0 +1,4 @@
+import './style/index.css';
+import App from './components/app';
+
+export default App;
diff --git a/packages/anastasis-webui/src/manifest.json 
b/packages/anastasis-webui/src/manifest.json
new file mode 100644
index 00000000..6b44a2b3
--- /dev/null
+++ b/packages/anastasis-webui/src/manifest.json
@@ -0,0 +1,21 @@
+{
+  "name": "anastasis-webui",
+  "short_name": "anastasis-webui",
+  "start_url": "/",
+  "display": "standalone",
+  "orientation": "portrait",
+  "background_color": "#fff",
+  "theme_color": "#673ab8",
+  "icons": [
+    {
+      "src": "/assets/icons/android-chrome-192x192.png",
+      "type": "image/png",
+      "sizes": "192x192"
+    },
+    {
+      "src": "/assets/icons/android-chrome-512x512.png",
+      "type": "image/png",
+      "sizes": "512x512"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/anastasis-webui/src/routes/home/index.tsx 
b/packages/anastasis-webui/src/routes/home/index.tsx
new file mode 100644
index 00000000..ee339950
--- /dev/null
+++ b/packages/anastasis-webui/src/routes/home/index.tsx
@@ -0,0 +1,187 @@
+import { FunctionalComponent, h } from "preact";
+import { useState } from "preact/hooks";
+import {
+  AnastasisReducerApi,
+  useAnastasisReducer,
+} from "../../hooks/use-anastasis-reducer";
+import style from "./style.css";
+
+const Home: FunctionalComponent = () => {
+  const reducer = useAnastasisReducer();
+  if (!reducer.currentReducerState) {
+    return (
+      <div class={style.home}>
+        <h1>Home</h1>
+        <p>
+          <button onClick={() => reducer.startBackup()}>Backup</button>
+          <button>Recover</button>
+        </p>
+      </div>
+    );
+  }
+  console.log("state", reducer.currentReducerState);
+  if (reducer.currentReducerState.backup_state === "CONTINENT_SELECTING") {
+    return (
+      <div class={style.home}>
+        <h1>Backup: Select Continent</h1>
+        <ErrorBanner reducer={reducer} />
+        <div>
+          {reducer.currentReducerState.continents.map((x: any) => {
+            const sel = (x: string) =>
+              reducer.transition("select_continent", { continent: x });
+            return (
+              <button onClick={() => sel(x.name)} key={x.name}>
+                {x.name}
+              </button>
+            );
+          })}
+        </div>
+        <div>
+          <button onClick={() => reducer.back()}>Back</button>
+        </div>
+      </div>
+    );
+  }
+  if (reducer.currentReducerState.backup_state === "COUNTRY_SELECTING") {
+    return (
+      <div class={style.home}>
+        <h1>Backup: Select Continent</h1>
+        <ErrorBanner reducer={reducer} />
+        <div>
+          {reducer.currentReducerState.countries.map((x: any) => {
+            const sel = (x: any) =>
+              reducer.transition("select_country", {
+                country_code: x.code,
+                currencies: [x.currency],
+              });
+            return (
+              <button onClick={() => sel(x)} key={x.name}>
+                {x.name} ({x.currency})
+              </button>
+            );
+          })}
+        </div>
+        <div>
+          <button onClick={() => reducer.back()}>Back</button>
+        </div>
+      </div>
+    );
+  }
+  if (
+    reducer.currentReducerState.backup_state === "USER_ATTRIBUTES_COLLECTING"
+  ) {
+    return <AttributeEntry reducer={reducer} />;
+  }
+
+  if (reducer.currentReducerState.backup_state === "AUTHENTICATIONS_EDITING") {
+    return <AuthenticationEditor reducer={reducer} />;
+  }
+
+  console.log("unknown state", reducer.currentReducerState);
+  return (
+    <div class={style.home}>
+      <h1>Home</h1>
+      <p>Bug: Unknown state.</p>
+    </div>
+  );
+};
+
+export interface AuthenticationEditorProps {
+  reducer: AnastasisReducerApi;
+}
+
+function AuthenticationEditor(props: AuthenticationEditorProps) {
+  const { reducer } = props;
+  const providers = reducer.currentReducerState.authentication_providers;
+  const authAvailable = new Set<string>();
+  for (const provKey of Object.keys(providers)) {
+    const p = providers[provKey];
+    for (const meth of p.methods) {
+      authAvailable.add(meth.type);
+    }
+  }
+  return (
+    <div class={style.home}>
+      <h1>Backup: Configure Authentication Methods</h1>
+      <p>Auths available: {JSON.stringify(Array.from(authAvailable))}</p>
+      <button>Next</button>
+      <div>
+        <button onClick={() => reducer.back()}>Back</button>
+      </div>
+    </div>
+  );
+}
+
+export interface AttributeEntryProps {
+  reducer: AnastasisReducerApi;
+}
+
+function AttributeEntry(props: AttributeEntryProps) {
+  const reducer = props.reducer;
+  const [attrs, setAttrs] = useState<Record<string, string>>({});
+  return (
+    <div class={style.home}>
+      <h1>Backup: Enter Basic User Attributes</h1>
+      <ErrorBanner reducer={reducer} />
+      <div>
+        {reducer.currentReducerState.required_attributes.map((x: any) => {
+          return (
+            <AttributeEntryField
+              setValue={(v: string) => setAttrs({ ...attrs, [x.name]: v })}
+              spec={x}
+              value={attrs[x.name]}
+            />
+          );
+        })}
+      </div>
+      <button
+        onClick={() =>
+          reducer.transition("enter_user_attributes", {
+            identity_attributes: attrs,
+          })
+        }
+      >
+        Next
+      </button>
+      <div>
+        <button onClick={() => reducer.back()}>Back</button>
+      </div>
+    </div>
+  );
+}
+
+export interface AttributeEntryFieldProps {
+  value: string;
+  setValue: (newValue: string) => void;
+  spec: any;
+}
+
+function AttributeEntryField(props: AttributeEntryFieldProps) {
+  return (
+    <div>
+      <label>{props.spec.label}</label>
+      <input
+        type="text"
+        value={props.value}
+        onChange={(e) => props.setValue((e as any).target.value)}
+      />
+    </div>
+  );
+}
+
+interface ErrorBannerProps {
+  reducer: AnastasisReducerApi;
+}
+
+/**
+ * Show a dismissable error banner if there is a current error.
+ */
+function ErrorBanner(props: ErrorBannerProps) {
+  const currentError = props.reducer.currentError;
+  if (currentError) {
+    return <div>Error: {JSON.stringify(currentError)}</div>;
+  }
+  return null;
+}
+
+export default Home;
diff --git a/packages/anastasis-webui/src/routes/home/style.css 
b/packages/anastasis-webui/src/routes/home/style.css
new file mode 100644
index 00000000..f052d254
--- /dev/null
+++ b/packages/anastasis-webui/src/routes/home/style.css
@@ -0,0 +1,5 @@
+.home {
+       padding: 56px 20px;
+       min-height: 100%;
+       width: 100%;
+}
diff --git a/packages/anastasis-webui/src/routes/notfound/index.tsx 
b/packages/anastasis-webui/src/routes/notfound/index.tsx
new file mode 100644
index 00000000..444e03d4
--- /dev/null
+++ b/packages/anastasis-webui/src/routes/notfound/index.tsx
@@ -0,0 +1,17 @@
+import { FunctionalComponent, h } from 'preact';
+import { Link } from 'preact-router/match';
+import style from './style.css';
+
+const Notfound: FunctionalComponent = () => {
+    return (
+        <div class={style.notfound}>
+            <h1>Error 404</h1>
+            <p>That page doesn&apos;t exist.</p>
+            <Link href="/">
+                <h4>Back to Home</h4>
+            </Link>
+        </div>
+    );
+};
+
+export default Notfound;
diff --git a/packages/anastasis-webui/src/routes/notfound/style.css 
b/packages/anastasis-webui/src/routes/notfound/style.css
new file mode 100644
index 00000000..3b493280
--- /dev/null
+++ b/packages/anastasis-webui/src/routes/notfound/style.css
@@ -0,0 +1,4 @@
+.notfound {
+    padding: 0 5%;
+    margin: 100px 0;
+}
\ No newline at end of file
diff --git a/packages/anastasis-webui/src/routes/profile/index.tsx 
b/packages/anastasis-webui/src/routes/profile/index.tsx
new file mode 100644
index 00000000..023b56c9
--- /dev/null
+++ b/packages/anastasis-webui/src/routes/profile/index.tsx
@@ -0,0 +1,44 @@
+import { FunctionalComponent, h } from 'preact';
+import { useEffect, useState } from 'preact/hooks';
+import style from './style.css';
+
+interface Props {
+    user: string;
+}
+
+const Profile: FunctionalComponent<Props> = (props: Props) => {
+    const { user } = props;
+    const [time, setTime] = useState<number>(Date.now());
+    const [count, setCount] = useState<number>(0);
+
+    // gets called when this route is navigated to
+    useEffect(() => {
+        const timer = window.setInterval(() => setTime(Date.now()), 1000);
+
+        // gets called just before navigating away from the route
+        return (): void => {
+            clearInterval(timer);
+        };
+    }, []);
+
+    // update the current time
+    const increment = (): void => {
+        setCount(count + 1);
+    };
+
+    return (
+        <div class={style.profile}>
+            <h1>Profile: {user}</h1>
+            <p>This is the user profile for a user named {user}.</p>
+
+            <div>Current time: {new Date(time).toLocaleString()}</div>
+
+            <p>
+                <button onClick={increment}>Click Me</button> Clicked 
{count}{' '}
+                times.
+            </p>
+        </div>
+    );
+};
+
+export default Profile;
diff --git a/packages/anastasis-webui/src/routes/profile/style.css 
b/packages/anastasis-webui/src/routes/profile/style.css
new file mode 100644
index 00000000..fcb12962
--- /dev/null
+++ b/packages/anastasis-webui/src/routes/profile/style.css
@@ -0,0 +1,5 @@
+.profile {
+       padding: 56px 20px;
+       min-height: 100%;
+       width: 100%;
+}
diff --git a/packages/anastasis-webui/src/style/index.css 
b/packages/anastasis-webui/src/style/index.css
new file mode 100644
index 00000000..5fe95de6
--- /dev/null
+++ b/packages/anastasis-webui/src/style/index.css
@@ -0,0 +1,20 @@
+html, body {
+       height: 100%;
+       width: 100%;
+       padding: 0;
+       margin: 0;
+       background: #FAFAFA;
+       font-family: 'Helvetica Neue', arial, sans-serif;
+       font-weight: 400;
+       color: #444;
+       -webkit-font-smoothing: antialiased;
+       -moz-osx-font-smoothing: grayscale;
+}
+
+* {
+       box-sizing: border-box;
+}
+
+#app {
+       height: 100%;
+}
diff --git a/packages/anastasis-webui/src/sw.js 
b/packages/anastasis-webui/src/sw.js
new file mode 100644
index 00000000..146aa01d
--- /dev/null
+++ b/packages/anastasis-webui/src/sw.js
@@ -0,0 +1,4 @@
+import { getFiles, setupPrecaching, setupRouting } from 'preact-cli/sw/';
+
+setupRouting();
+setupPrecaching(getFiles());
diff --git a/packages/anastasis-webui/src/template.html 
b/packages/anastasis-webui/src/template.html
new file mode 100644
index 00000000..770c48b2
--- /dev/null
+++ b/packages/anastasis-webui/src/template.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+       <head>
+               <meta charset="utf-8">
+               <title><% preact.title %></title>
+               <meta name="viewport" 
content="width=device-width,initial-scale=1">
+               <meta name="mobile-web-app-capable" content="yes">
+               <meta name="apple-mobile-web-app-capable" content="yes">
+               <link rel="apple-touch-icon" 
href="/assets/icons/apple-touch-icon.png">
+               <% preact.headEnd %>
+       </head>
+       <body>
+               <% preact.bodyEnd %>
+       </body>
+</html>
diff --git a/packages/anastasis-webui/tests/__mocks__/browserMocks.ts 
b/packages/anastasis-webui/tests/__mocks__/browserMocks.ts
new file mode 100644
index 00000000..5be8c3ce
--- /dev/null
+++ b/packages/anastasis-webui/tests/__mocks__/browserMocks.ts
@@ -0,0 +1,21 @@
+// Mock Browser API's which are not supported by JSDOM, e.g. ServiceWorker, 
LocalStorage
+/**
+ * An example how to mock localStorage is given below 👇
+ */
+
+/* 
+// Mocks localStorage
+const localStorageMock = (function() {
+       let store = {};
+
+       return {
+               getItem: (key) => store[key] || null,
+               setItem: (key, value) => store[key] = value.toString(),
+               clear: () => store = {}
+       };
+
+})();
+
+Object.defineProperty(window, 'localStorage', {
+       value: localStorageMock
+}); */
diff --git a/packages/anastasis-webui/tests/__mocks__/fileMocks.ts 
b/packages/anastasis-webui/tests/__mocks__/fileMocks.ts
new file mode 100644
index 00000000..87109e35
--- /dev/null
+++ b/packages/anastasis-webui/tests/__mocks__/fileMocks.ts
@@ -0,0 +1,3 @@
+// This fixed an error related to the CSS and loading gif breaking my Jest test
+// See 
https://facebook.github.io/jest/docs/en/webpack.html#handling-static-assets
+export default 'test-file-stub';
diff --git a/packages/anastasis-webui/tests/__mocks__/setupTests.ts 
b/packages/anastasis-webui/tests/__mocks__/setupTests.ts
new file mode 100644
index 00000000..01dc92a2
--- /dev/null
+++ b/packages/anastasis-webui/tests/__mocks__/setupTests.ts
@@ -0,0 +1,6 @@
+import { configure } from 'enzyme';
+import Adapter from 'enzyme-adapter-preact-pure';
+
+configure({
+    adapter: new Adapter()
+});
diff --git a/packages/anastasis-webui/tests/declarations.d.ts 
b/packages/anastasis-webui/tests/declarations.d.ts
new file mode 100644
index 00000000..67e94027
--- /dev/null
+++ b/packages/anastasis-webui/tests/declarations.d.ts
@@ -0,0 +1,3 @@
+// Enable enzyme adapter's integration with TypeScript
+// See: 
https://github.com/preactjs/enzyme-adapter-preact-pure#usage-with-typescript
+/// <reference types="enzyme-adapter-preact-pure" />
diff --git a/packages/anastasis-webui/tests/header.test.tsx 
b/packages/anastasis-webui/tests/header.test.tsx
new file mode 100644
index 00000000..b2cfc2f4
--- /dev/null
+++ b/packages/anastasis-webui/tests/header.test.tsx
@@ -0,0 +1,12 @@
+import { h } from 'preact';
+import Header from '../src/components/header';
+// See: https://github.com/preactjs/enzyme-adapter-preact-pure
+import { shallow } from 'enzyme';
+
+describe('Initial Test of the Header', () => {
+    test('Header renders 3 nav items', () => {
+        const context = shallow(<Header />);
+        expect(context.find('h1').text()).toBe('Preact App');
+        expect(context.find('Link').length).toBe(3);
+    });
+});
diff --git a/packages/anastasis-webui/tsconfig.json 
b/packages/anastasis-webui/tsconfig.json
new file mode 100644
index 00000000..14d4d047
--- /dev/null
+++ b/packages/anastasis-webui/tsconfig.json
@@ -0,0 +1,60 @@
+{
+    "compilerOptions": {
+        /* Basic Options */
+        "target": "ES5",                          /* Specify ECMAScript target 
version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
+        "module": "ESNext",                       /* Specify module code 
generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
+        // "lib": [],                             /* Specify library files to 
be included in the compilation:  */
+        "allowJs": true,                          /* Allow javascript files to 
be compiled. */
+        // "checkJs": true,                       /* Report errors in .js 
files. */
+        "jsx": "react",                           /* Specify JSX code 
generation: 'preserve', 'react-native', or 'react'. */
+        "jsxFactory": "h",                        /* Specify the JSX factory 
function to use when targeting react JSX emit, e.g. React.createElement or h. */
+        // "declaration": true,                   /* Generates corresponding 
'.d.ts' file. */
+        // "sourceMap": true,                     /* Generates corresponding 
'.map' file. */
+        // "outFile": "./",                       /* Concatenate and emit 
output to single file. */
+        // "outDir": "./",                        /* Redirect output structure 
to the directory. */
+        // "rootDir": "./",                       /* Specify the root 
directory of input files. Use to control the output directory structure with 
--outDir. */
+        // "removeComments": true,                /* Do not emit comments to 
output. */
+        "noEmit": true,                           /* Do not emit outputs. */
+        // "importHelpers": true,                 /* Import emit helpers from 
'tslib'. */
+        // "downlevelIteration": true,            /* Provide full support for 
iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. 
*/
+        // "isolatedModules": true,               /* Transpile each file as a 
separate module (similar to 'ts.transpileModule'). */
+
+        /* Strict Type-Checking Options */
+        "strict": true,                           /* Enable all strict 
type-checking options. */
+        // "noImplicitAny": true,                 /* Raise error on 
expressions and declarations with an implied 'any' type. */
+        // "strictNullChecks": true,              /* Enable strict null 
checks. */
+        // "noImplicitThis": true,                /* Raise error on 'this' 
expressions with an implied 'any' type. */
+        // "alwaysStrict": true,                  /* Parse in strict mode and 
emit "use strict" for each source file. */
+
+        /* Additional Checks */
+        // "noUnusedLocals": true,                /* Report errors on unused 
locals. */
+        // "noUnusedParameters": true,            /* Report errors on unused 
parameters. */
+        // "noImplicitReturns": true,             /* Report error when not all 
code paths in function return a value. */
+        // "noFallthroughCasesInSwitch": true,    /* Report errors for 
fallthrough cases in switch statement. */
+
+        /* Module Resolution Options */
+        "moduleResolution": "node",               /* Specify module resolution 
strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
+        "esModuleInterop": true,                  /* */
+        // "baseUrl": "./",                       /* Base directory to resolve 
non-absolute module names. */
+        // "paths": {},                           /* A series of entries which 
re-map imports to lookup locations relative to the 'baseUrl'. */
+        // "rootDirs": [],                        /* List of root folders 
whose combined content represents the structure of the project at runtime. */
+        // "typeRoots": [],                       /* List of folders to 
include type definitions from. */
+        // "types": [],                           /* Type declaration files to 
be included in compilation. */
+        // "allowSyntheticDefaultImports": true,  /* Allow default imports 
from modules with no default export. This does not affect code emit, just 
typechecking. */
+        // "preserveSymlinks": true,              /* Do not resolve the real 
path of symlinks. */
+
+        /* Source Map Options */
+        // "sourceRoot": "./",                    /* Specify the location 
where debugger should locate TypeScript files instead of source locations. */
+        // "mapRoot": "./",                       /* Specify the location 
where debugger should locate map files instead of generated locations. */
+        // "inlineSourceMap": true,               /* Emit a single file with 
source maps instead of having a separate file. */
+        // "inlineSources": true,                 /* Emit the source alongside 
the sourcemaps within a single file; requires '--inlineSourceMap' or 
'--sourceMap' to be set. */
+
+        /* Experimental Options */
+        // "experimentalDecorators": true,        /* Enables experimental 
support for ES7 decorators. */
+        // "emitDecoratorMetadata": true,         /* Enables experimental 
support for emitting type metadata for decorators. */
+
+        /* Advanced Options */
+        "skipLibCheck": true                      /* Skip type checking of 
declaration files. */
+    },
+    "include": ["src/**/*", "tests/**/*"]
+}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]