From 38f2a777874922c92e8f8b24fe5e19561c56eea0 Mon Sep 17 00:00:00 2001 From: Rune Rasmussen Date: Fri, 29 Oct 2021 07:27:09 +1300 Subject: [PATCH] another braindump --- .../component/AuthenticatedRoute/index.tsx | 16 --- packages/connector/readme.md | 1 - packages/connector/useDependencies/index.ts | 4 - .../DependencyManager/index.ts | 13 +- .../EventHub/index.ts | 0 .../core/_framework/FeatureRegistry/index.ts | 14 ++ .../core/_framework/Navigation/index.test.ts | 22 ++++ packages/core/_framework/Navigation/index.ts | 72 ++++++++++ .../ObservableState/index.ts | 5 +- .../{appShell => _framework}/Worker/index.ts | 0 packages/core/appShell/index.ts | 24 ---- packages/core/appShellContext/index.ts | 11 ++ packages/core/appShellEvents/index.ts | 13 ++ packages/core/history/index.test.ts | 22 ---- packages/core/history/index.ts | 93 ------------- packages/core/navigation/index.ts | 3 + packages/core/registry/index.ts | 27 +--- packages/core/service/Authorization/index.ts | 3 + .../core/service/PersonalProfile/index.ts | 7 + packages/core/service/index.ts | 21 +-- packages/feature/index.ts | 3 + packages/layout/App.test.tsx | 9 ++ packages/layout/App.tsx | 9 ++ packages/lib/component/LoginPage/index.tsx | 124 ++++++++++++++++++ packages/lib/component/LoginPage/styles.css | 14 ++ .../usePromise => lib/util/useData}/index.ts | 6 +- 26 files changed, 324 insertions(+), 212 deletions(-) delete mode 100644 packages/component/AuthenticatedRoute/index.tsx delete mode 100644 packages/connector/readme.md delete mode 100644 packages/connector/useDependencies/index.ts rename packages/core/{service => _framework}/DependencyManager/index.ts (55%) rename packages/core/{appShell => _framework}/EventHub/index.ts (100%) create mode 100644 packages/core/_framework/FeatureRegistry/index.ts create mode 100644 packages/core/_framework/Navigation/index.test.ts create mode 100644 packages/core/_framework/Navigation/index.ts rename packages/core/{appShell => _framework}/ObservableState/index.ts (85%) rename packages/core/{appShell => _framework}/Worker/index.ts (100%) delete mode 100644 packages/core/appShell/index.ts create mode 100644 packages/core/appShellContext/index.ts create mode 100644 packages/core/appShellEvents/index.ts delete mode 100644 packages/core/history/index.test.ts delete mode 100644 packages/core/history/index.ts create mode 100644 packages/core/navigation/index.ts create mode 100644 packages/core/service/Authorization/index.ts create mode 100644 packages/core/service/PersonalProfile/index.ts create mode 100644 packages/feature/index.ts create mode 100644 packages/layout/App.test.tsx create mode 100644 packages/layout/App.tsx create mode 100644 packages/lib/component/LoginPage/index.tsx create mode 100644 packages/lib/component/LoginPage/styles.css rename packages/{connector/usePromise => lib/util/useData}/index.ts (80%) diff --git a/packages/component/AuthenticatedRoute/index.tsx b/packages/component/AuthenticatedRoute/index.tsx deleted file mode 100644 index 7a822cb..0000000 --- a/packages/component/AuthenticatedRoute/index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React, { useState, useEffect } from "react"; - -interface AuthenticatedRoute { - onboardingRequired: boolean; - children: any; -} - -export default function AuthenticatedRoute(props) { - const [state, setState] = useState(false); - - useEffect(function () { - // here we check onboarding required and then auth state and that stuff - }, []); - - return state ?? props.children; -} diff --git a/packages/connector/readme.md b/packages/connector/readme.md deleted file mode 100644 index 5f2fa84..0000000 --- a/packages/connector/readme.md +++ /dev/null @@ -1 +0,0 @@ -// utils connected to react or "application" \ No newline at end of file diff --git a/packages/connector/useDependencies/index.ts b/packages/connector/useDependencies/index.ts deleted file mode 100644 index e1b6354..0000000 --- a/packages/connector/useDependencies/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export function useDependencies() { - - -} diff --git a/packages/core/service/DependencyManager/index.ts b/packages/core/_framework/DependencyManager/index.ts similarity index 55% rename from packages/core/service/DependencyManager/index.ts rename to packages/core/_framework/DependencyManager/index.ts index bad84c2..6ad4128 100644 --- a/packages/core/service/DependencyManager/index.ts +++ b/packages/core/_framework/DependencyManager/index.ts @@ -2,21 +2,22 @@ type Fetchers = { [P in keyof T]?: () => Promise }; type Promised = { [P in keyof T]?: Promise }; export class DependencyManager { - #factories: Fetchers = {}; - #singletons: Promised = {}; + private factories: Fetchers = {}; + private singletons: Promised = {}; register( serviceName: K, factory: () => Promise ) { - this.#factories[serviceName] = factory; + this.factories[serviceName] = factory; } resolve( serviceName: K ): Promise { - if (!this.#singletons[serviceName]) { - this.#singletons[serviceName] = this.#factories[serviceName](); + if (!this.singletons[serviceName]) { + // handle grazefully + this.singletons[serviceName] = this.factories[serviceName]!(); } - return this.#singletons[serviceName]; + return this.singletons[serviceName]!; } } diff --git a/packages/core/appShell/EventHub/index.ts b/packages/core/_framework/EventHub/index.ts similarity index 100% rename from packages/core/appShell/EventHub/index.ts rename to packages/core/_framework/EventHub/index.ts diff --git a/packages/core/_framework/FeatureRegistry/index.ts b/packages/core/_framework/FeatureRegistry/index.ts new file mode 100644 index 0000000..badd5b8 --- /dev/null +++ b/packages/core/_framework/FeatureRegistry/index.ts @@ -0,0 +1,14 @@ +export interface LayoutConfig { + path: string; + params?: T; +} + +export class FeatureRegistry { + private routes: Array> = []; + register(layoutConfig: LayoutConfig, handler: (params: T) => R) { + this.routes.push(layoutConfig); + } + getRoutes() { + return this.routes; + } +} diff --git a/packages/core/_framework/Navigation/index.test.ts b/packages/core/_framework/Navigation/index.test.ts new file mode 100644 index 0000000..7a041fb --- /dev/null +++ b/packages/core/_framework/Navigation/index.test.ts @@ -0,0 +1,22 @@ +import { LayoutConfig } from "../FeatureRegistry"; +import { Navigation } from "."; + +const navigation = new Navigation(); + +const service_propertyDetail_scoreAdd: LayoutConfig<{ + propertyPreference: number; +}> = { + path: ":propertyPreference", +}; + +navigation.push( + service_propertyDetail_scoreAdd, + { + propertyPreference: 123, + }, + { root: "Hello" } +); + +navigation.back(service_propertyDetail_scoreAdd, { + propertyPreference: 123, +}); diff --git a/packages/core/_framework/Navigation/index.ts b/packages/core/_framework/Navigation/index.ts new file mode 100644 index 0000000..8229312 --- /dev/null +++ b/packages/core/_framework/Navigation/index.ts @@ -0,0 +1,72 @@ +import { LayoutConfig } from "../FeatureRegistry"; +import { createBrowserHistory } from "history"; +import * as pathToRegexp from "path-to-regexp"; + +export type LayoutParams = T extends LayoutConfig ? R : T; + +export class Navigation { + public history = createBrowserHistory(); + private root?: { + title?: string; + stackReference?: number; + }; + constructor() { + this.history.listen((update: any) => { + if (this.root?.stackReference === undefined) { + return; + } + + switch (update.action) { + case "PUSH": + this.root.stackReference--; + break; + case "POP": { + this.root.stackReference++; + break; + } + default: + } + }); + } + rootTitle(defaultTitle: string): string | undefined { + return this.root?.title ?? defaultTitle; + } + push>( + feature: T, + params: LayoutParams, + options?: { + root?: string; + } + ) { + const { _unsafe, ...safeParams } = params; + + const url = pathToRegexp.compile(feature.path)(safeParams); + + if (options?.root) { + this.root = { + title: options.root, + stackReference: 1, + }; + } + + this.history.push(url, _unsafe); + } + goRoot>(feature: T, params: LayoutParams) { + if (this.root?.stackReference !== undefined) { + this.history.go(this.root.stackReference); + } else { + const { _unsafe, ...safeParams } = params; + const url = pathToRegexp.compile(feature.path)(safeParams); + this.history.replace(url, _unsafe); + } + } + back>(feature: T, params: LayoutParams) { + if (document.referrer.length && document.referrer === document.location.hostname) { + this.history.goBack(); + } else { + const { _unsafe, ...safeParams } = params; + const url = pathToRegexp.compile(feature.path)(safeParams); + this.history.replace(url, _unsafe); + } + } +} diff --git a/packages/core/appShell/ObservableState/index.ts b/packages/core/_framework/ObservableState/index.ts similarity index 85% rename from packages/core/appShell/ObservableState/index.ts rename to packages/core/_framework/ObservableState/index.ts index 4333e8c..c407efe 100644 --- a/packages/core/appShell/ObservableState/index.ts +++ b/packages/core/_framework/ObservableState/index.ts @@ -30,7 +30,10 @@ export class ObservableState { mutateSet(valueSet: Partial) { this.value = { ...this.value, ...valueSet }; for (let key of Object.keys(valueSet)) { - this.listeners[key]?.forEach((listener) => listener(this.value[key])); + // due to lack of type inference i have to manually cast + this.listeners[key as keyof T]?.forEach((listener) => + listener(this.value[key as keyof T]) + ); } } } diff --git a/packages/core/appShell/Worker/index.ts b/packages/core/_framework/Worker/index.ts similarity index 100% rename from packages/core/appShell/Worker/index.ts rename to packages/core/_framework/Worker/index.ts diff --git a/packages/core/appShell/index.ts b/packages/core/appShell/index.ts deleted file mode 100644 index a6e4f66..0000000 --- a/packages/core/appShell/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ObservableState } from "./ObservableState"; -import { EventHub } from "./EventHub"; - -export interface AppShellContext { - title: string; - container: "none" | "main"; -} - -export const appShellContext = new ObservableState({ - title: "Loading", - container: "none", -}); - -const DISPLAY_SNACKBAR = "DISPLAY_SNACKBAR"; - -export interface DisplaySnackbarEventDetail { - message: string; -} - -interface AppShellEventMap { - [DISPLAY_SNACKBAR]: DisplaySnackbarEventDetail; -} - -export const appshellEventHub = new EventHub(); \ No newline at end of file diff --git a/packages/core/appShellContext/index.ts b/packages/core/appShellContext/index.ts new file mode 100644 index 0000000..bf7cec1 --- /dev/null +++ b/packages/core/appShellContext/index.ts @@ -0,0 +1,11 @@ +import { ObservableState } from "../_framework/ObservableState"; + +export interface AppShellContext { + title: string; + container: "none" | "main"; +} + +export const appShellContext = new ObservableState({ + title: "Loading", + container: "none", +}); diff --git a/packages/core/appShellEvents/index.ts b/packages/core/appShellEvents/index.ts new file mode 100644 index 0000000..70df18b --- /dev/null +++ b/packages/core/appShellEvents/index.ts @@ -0,0 +1,13 @@ +import { EventHub } from "../_framework/EventHub"; + +const DISPLAY_SNACKBAR = "DISPLAY_SNACKBAR"; + +export interface DisplaySnackbarEventDetail { + message: string; +} + +interface AppShellEventMap { + [DISPLAY_SNACKBAR]: DisplaySnackbarEventDetail; +} + +export const appshellEventHub = new EventHub(); diff --git a/packages/core/history/index.test.ts b/packages/core/history/index.test.ts deleted file mode 100644 index 1801bfe..0000000 --- a/packages/core/history/index.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { LayoutConfig, pushNavigate, navigateBack } from "."; - -type service_propertyDetail_scoreAdd = { - propertyPreference: number; -}; - -const service_propertyDetail_scoreAdd: LayoutConfig = - { - path: ":propertyPreference", - }; - -pushNavigate( - service_propertyDetail_scoreAdd, - { - propertyPreference: 123, - }, - { root: "Hello" } -); - -navigateBack(service_propertyDetail_scoreAdd, { - propertyPreference: 123, -}); diff --git a/packages/core/history/index.ts b/packages/core/history/index.ts deleted file mode 100644 index b847317..0000000 --- a/packages/core/history/index.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { createBrowserHistory } from "history"; -import pathToRegexp from "path-to-regexp"; - -export const history = createBrowserHistory(); - -export interface LayoutConfig { - path: string; - params?: T; -} - -export type LayoutParams = T extends LayoutConfig ? R : T; - -export interface NavigationOptions { - root?: string; -} - -interface RootReference { - title: string; - historyStackReference?: number; -} - -let root: RootReference = { - title: "", -}; - -let historyStackLength = 0; - -history.listen(function trackRoot(update) { - switch (update.action) { - case "PUSH": - root.historyStackReference--; - historyStackLength++; - break; - case "POP": { - root.historyStackReference++; - historyStackLength--; - break; - } - default: - } -}); - -export function pushNavigate>( - feature: T, - params: LayoutParams, - options?: NavigationOptions -) { - const { _unsafe, ...safeParams } = params; - - const url = pathToRegexp.compile(feature.path)(safeParams); - - if (options?.root) { - root = { - title: options.root, - // 1 as it will instantly be changed to 0 by listener - historyStackReference: 1, - }; - } - - history.push(url, _unsafe); -} - -export function navigateBack>( - feature: T, - params: LayoutParams -) { - return function navigate() { - const inAppReferrer = document.referrer === location.hostname; - - if (inAppReferrer && historyStackLength) { - history.back(); - } else { - const { _unsafe, ...safeParams } = params; - const url = pathToRegexp.compile(feature.path)(safeParams); - history.replace(url, _unsafe); - } - }; -} - -export function navigateRoot>( - feature: T, - params: LayoutParams -) { - return function navigate() { - if (root.historyStackReference !== undefined) { - history.go(root.historyStackReference); - } else { - const { _unsafe, ...safeParams } = params; - const url = pathToRegexp.compile(feature.path)(safeParams); - history.replace(url, _unsafe); - } - }; -} diff --git a/packages/core/navigation/index.ts b/packages/core/navigation/index.ts new file mode 100644 index 0000000..f6cab30 --- /dev/null +++ b/packages/core/navigation/index.ts @@ -0,0 +1,3 @@ +import { Navigation } from "../_framework/Navigation"; + +export const navigation = new Navigation(); diff --git a/packages/core/registry/index.ts b/packages/core/registry/index.ts index 99fcd11..e91d804 100644 --- a/packages/core/registry/index.ts +++ b/packages/core/registry/index.ts @@ -1,25 +1,4 @@ -type GuardedPromise = () => Promise; +import { FeatureRegistry } from "../_framework/FeatureRegistry"; -class GuardError extends Error { - public type: "UNAUTHENTICATED" | "ONBOARDING_REQUIRED"; - constructor(message: string) { - super(message); - } -} - -interface LazyLoad { - (): Promise; -} - -export const routes = []; - -export function registerFeature(paths: Array, lazyLoad: LazyLoad) { - -} - -export function guardOnboarded(guardedPromise: GuardedPromise) { - // lookup - Promise.resolve() - .then(guardedPromise) - .catch((e: GuardError) => {}); -} +// could update to react only here? +export const registy = new FeatureRegistry(); diff --git a/packages/core/service/Authorization/index.ts b/packages/core/service/Authorization/index.ts new file mode 100644 index 0000000..4dbfe92 --- /dev/null +++ b/packages/core/service/Authorization/index.ts @@ -0,0 +1,3 @@ +export interface Authorization { + authenticated: boolean; +} diff --git a/packages/core/service/PersonalProfile/index.ts b/packages/core/service/PersonalProfile/index.ts new file mode 100644 index 0000000..3c130a3 --- /dev/null +++ b/packages/core/service/PersonalProfile/index.ts @@ -0,0 +1,7 @@ +export interface PersonalProfile { + /** + * Group which this profile belongs to + */ + groupCode: number; + onboardingCompleted: boolean; +} diff --git a/packages/core/service/index.ts b/packages/core/service/index.ts index 83899ef..1b9fee8 100644 --- a/packages/core/service/index.ts +++ b/packages/core/service/index.ts @@ -1,24 +1,9 @@ -import { DependencyManager } from "./DependencyManager"; +import { DependencyManager } from "../_framework/DependencyManager"; -export interface Authorization { - authenticated: boolean; -} - -export interface PersonalProfile { - /** - * Group which this profile belongs to - */ - groupCode: number; - onboardingCompleted: boolean; -} +import { Authorization } from "./Authorization"; +import { PersonalProfile } from "./PersonalProfile"; export const dependencyManager = new DependencyManager<{ authorization: Authorization; personalProfile: PersonalProfile; }>(); - -async function resolve() { - const data = await dependencyManager.resolve("personalProfile"); - - data.groupCode; -} diff --git a/packages/feature/index.ts b/packages/feature/index.ts new file mode 100644 index 0000000..ecbe108 --- /dev/null +++ b/packages/feature/index.ts @@ -0,0 +1,3 @@ +// imports registry and the feature modules + +export function feature() {} diff --git a/packages/layout/App.test.tsx b/packages/layout/App.test.tsx new file mode 100644 index 0000000..2a68616 --- /dev/null +++ b/packages/layout/App.test.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + render(); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/packages/layout/App.tsx b/packages/layout/App.tsx new file mode 100644 index 0000000..28f3051 --- /dev/null +++ b/packages/layout/App.tsx @@ -0,0 +1,9 @@ +import React from "react"; + +import LoadingPage from "../lib/component/LoginPage"; + +function App() { + return ; +} + +export default App; diff --git a/packages/lib/component/LoginPage/index.tsx b/packages/lib/component/LoginPage/index.tsx new file mode 100644 index 0000000..bed2671 --- /dev/null +++ b/packages/lib/component/LoginPage/index.tsx @@ -0,0 +1,124 @@ +import React, { useEffect } from "react"; +import CircularProgress from "@mui/material/CircularProgress"; +import Box from "@mui/material/Box"; +import { SxProps } from "@mui/system"; + +import { CSSTransition } from "react-transition-group"; +import { Router, Switch, Route, Link } from "react-router-dom"; +import { keyframes } from "@emotion/react"; + +import { navigation } from "../../../core/navigation"; + +import "./styles.css"; + +const bounce = keyframes` + from, 20%, 53%, 80%, to { + transform: translate3d(0,0,0); + } + + 40%, 43% { + transform: translate3d(0, -30px, 0); + } + + 70% { + transform: translate3d(0, -15px, 0); + } + + 90% { + transform: translate3d(0,-4px,0); + } +`; + +export default function PageTransitionExamples() { + useEffect(function () { + const interval = setInterval(() => { + console.log("toggle"); + if (document.location.href.endsWith("/second")) { + navigation.history.push("/first"); + } else { + navigation.history.push("/second"); + } + }, 2000); + + return () => clearInterval(interval); + }); + + return ( + + + { + console.log(props); + return ; + }} + /> + { + console.log(props); + return ; + }} + /> + + + ); +} + +interface PageProperties { + timeout?: number; + mounted?: boolean; + children: React.ReactNode; + sx?: SxProps; +} + +function Page({ children, sx, timeout, mounted }: PageProperties) { + return ( + + + {children} + + + ); +} + +function FirstPage(props: any) { + return ( + + HEEELO + + ); +} + +function LoadingPage(props: any) { + return ( + + + + + + ); +} diff --git a/packages/lib/component/LoginPage/styles.css b/packages/lib/component/LoginPage/styles.css new file mode 100644 index 0000000..cb19a4d --- /dev/null +++ b/packages/lib/component/LoginPage/styles.css @@ -0,0 +1,14 @@ +.item-enter { + opacity: 0; +} +.item-enter-active { + opacity: 1; + transition: opacity 500ms ease-in; +} +.item-exit { + opacity: 1; +} +.item-exit-active { + opacity: 0; + transition: opacity 500ms ease-in; +} diff --git a/packages/connector/usePromise/index.ts b/packages/lib/util/useData/index.ts similarity index 80% rename from packages/connector/usePromise/index.ts rename to packages/lib/util/useData/index.ts index a431ad7..0bf4452 100644 --- a/packages/connector/usePromise/index.ts +++ b/packages/lib/util/useData/index.ts @@ -1,14 +1,14 @@ import { useState, useEffect, useRef } from "react"; -interface DataResult { +interface Data { data?: T; error?: string; loading: boolean; } -export function usePromise(fetchPromise: Promise) { +export function useData(fetchPromise: Promise) { const isMounted = useRef(true); - const [result, setResult] = useState>({ + const [result, setResult] = useState>({ loading: true, });