From 97393f60d4c4ba573d08e0784f35923a67f7568a Mon Sep 17 00:00:00 2001 From: Dominik Horn Date: Wed, 26 Feb 2020 17:35:08 +0100 Subject: [PATCH] implement basic @Routed annotation idea #13 --- packages/frontend/src/components/App.tsx | 11 ++- .../src/components/pages/HomePage.tsx | 26 ++++--- .../src/components/pages/LinkPage.tsx | 28 +++++--- .../pages/support/LinkDirectory.tsx | 2 +- packages/frontend/src/util/approutes.tsx | 70 ------------------- packages/frontend/src/util/routing.tsx | 62 ++++++++++++++++ packages/frontend/tsconfig.json | 3 +- 7 files changed, 106 insertions(+), 96 deletions(-) delete mode 100644 packages/frontend/src/util/approutes.tsx create mode 100644 packages/frontend/src/util/routing.tsx diff --git a/packages/frontend/src/components/App.tsx b/packages/frontend/src/components/App.tsx index 67f2538..dd2be52 100644 --- a/packages/frontend/src/components/App.tsx +++ b/packages/frontend/src/components/App.tsx @@ -1,12 +1,16 @@ import * as React from 'react'; import { hot } from 'react-hot-loader'; -import { Route, Switch } from 'react-router'; +import { Route, Switch, Redirect } from 'react-router'; import { Router } from 'react-router-dom'; -import { APP_ROUTES, ERROR_404_PAGE } from '../util/approutes'; import history from '../util/history'; import { FeatureFlagsProvider } from 'elite-feature-flags'; import { Configuration } from 'elite-types'; import { getConfiguration } from 'elite-configuration'; +import { APP_ROUTES } from '../util/routing'; + +// Files must be required for decorator to work +require('../components/pages/HomePage'); +require('../components/pages/LinkPage'); const configuration: Configuration = getConfiguration(); @@ -17,7 +21,8 @@ export const AppComponent = () => ( {APP_ROUTES.map((routeProps, index) => ( ))} - + {/* Error 404 Fallback */} + diff --git a/packages/frontend/src/components/pages/HomePage.tsx b/packages/frontend/src/components/pages/HomePage.tsx index f3e3656..ec66118 100644 --- a/packages/frontend/src/components/pages/HomePage.tsx +++ b/packages/frontend/src/components/pages/HomePage.tsx @@ -3,16 +3,22 @@ import { RouteComponentProps } from 'react-router'; import { LinkDirectory } from './support/LinkDirectory'; import { Divider } from '@material-ui/core'; import { FeatureFlag } from 'elite-feature-flags'; +import { Routed } from '../../util/routing'; export interface HomePageProps extends RouteComponentProps {} -export const HomePage = (props: HomePageProps) => ( - <> -

Main Page

- - Elite Sexyz is currently under construction. See discord main channel for more information - - - - -); +@Routed({ path: '/home', displayName: 'Home' }) +export class HomePage extends React.PureComponent { + render() { + return ( + <> +

Main Page

+ + Elite Sexyz is currently under construction. See discord main channel for more information + + + + + ); + } +} diff --git a/packages/frontend/src/components/pages/LinkPage.tsx b/packages/frontend/src/components/pages/LinkPage.tsx index ef63230..717ba59 100644 --- a/packages/frontend/src/components/pages/LinkPage.tsx +++ b/packages/frontend/src/components/pages/LinkPage.tsx @@ -1,21 +1,27 @@ import { Divider, List } from '@material-ui/core'; import * as React from 'react'; import { RouteComponentProps } from 'react-router'; +import { Routed } from '../../util/routing'; import { LinkListItem } from '../general/LinkListItem'; import { LinkDirectory } from './support/LinkDirectory'; export interface LinkPageProps extends RouteComponentProps {} -export const LinkPage = (props: LinkPageProps) => ( - <> -

Useful Links List

- - - - +@Routed({ path: '/link', displayName: 'Useful Links' }) +export class LinkPage extends React.PureComponent { + render() { + return ( + <> +

Useful Links List

+ + + + - + - - -); + + + ); + } +} diff --git a/packages/frontend/src/components/pages/support/LinkDirectory.tsx b/packages/frontend/src/components/pages/support/LinkDirectory.tsx index b896837..8180d69 100644 --- a/packages/frontend/src/components/pages/support/LinkDirectory.tsx +++ b/packages/frontend/src/components/pages/support/LinkDirectory.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Link } from 'react-router-dom'; -import { APP_ROUTES, getLinkDisplayNameForPage, getLinkForPage } from '../../../util/approutes'; +import { APP_ROUTES, getLinkForPage, getLinkDisplayNameForPage } from '../../../util/routing'; export const LinkDirectory = () => (
    diff --git a/packages/frontend/src/util/approutes.tsx b/packages/frontend/src/util/approutes.tsx deleted file mode 100644 index e68b8cd..0000000 --- a/packages/frontend/src/util/approutes.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import * as H from 'history'; -import * as React from 'react'; -import { RouteProps, Redirect } from 'react-router'; -import { HomePage } from '../components/pages/HomePage'; -import { LinkPage } from '../components/pages/LinkPage'; - -// If necessary, add support for: H.LocationDescriptor | ((location: H.Location) => H.LocationDescriptor); -type LinkType = string; - -export interface AppRouteProps extends RouteProps { - // Use this if the link target differs from the path specification, - // i.e., if the path url contains paramter specifications etc - readonly link?: LinkType; - - // link text (Human readable!) - readonly linkDisplayName?: string; - - // AppRoutes must have a path - deoptionalize this property - readonly path: string; -} - -/** - * Retrieves the url which other pages can use - * to link to a certain route - * @param route the route to link to - */ -export function getLinkForPage(route: AppRouteProps): LinkType { - return route.link || route.path; -} - -/** - * Retrieves the humand readable link title/displayed name - * for a given route - * - * @param route - */ -export function getLinkDisplayNameForPage(route: AppRouteProps): string { - return route.linkDisplayName || getLinkForPage(route); -} - -/** - * Specify all pages in this file by defining - * a pages route props and adding it to the - * available APP_ROUTES array - */ - -// Landing/Home page -export const HOME_PAGE: AppRouteProps = { - path: '/home', - linkDisplayName: 'Home', - render: props => -}; - -// Page with searchable, useful links for elite-se-degree program -export const LINK_PAGE: AppRouteProps = { - path: '/links', - linkDisplayName: 'Useful Links', - render: props => -}; - -// Simply redirect to the main page on 404 -export const ERROR_404_PAGE: AppRouteProps = { - path: '/', - render: () => , -}; - -export const APP_ROUTES: AppRouteProps[] = [ - HOME_PAGE, - LINK_PAGE -]; \ No newline at end of file diff --git a/packages/frontend/src/util/routing.tsx b/packages/frontend/src/util/routing.tsx new file mode 100644 index 0000000..b659120 --- /dev/null +++ b/packages/frontend/src/util/routing.tsx @@ -0,0 +1,62 @@ +import * as React from 'react'; +import { RouteProps } from 'react-router'; + +// TODO: move to separate package + +/** + * The Routed decorator automatically creates a route for + * the annotated top level page component + * + * @param props route properties + */ +export function Routed(props: AppRouteProps) { + console.log('producing route decorator:', props); + return (constructor: any) => { + APP_ROUTES.push({ + render: p => React.createElement(constructor, p), + ...props, + }); + console.log('added route for', constructor.name); + return constructor; + }; +} + +// If necessary, add support for: H.LocationDescriptor | ((location: H.Location) => H.LocationDescriptor); +type LinkType = string; + +// TODO: Add documentation +export interface AppRouteProps extends RouteProps { + // Use this if the link target differs from the path specification, + // i.e., if the path url contains paramter specifications etc + readonly link?: LinkType; + + // link text (Human readable!) + readonly displayName?: string; + + // AppRoutes must have a path - deoptionalize this property + readonly path: string; +} + +// TODO: replace with proper container/service class +/** + * Retrieves the url which other pages can use + * to link to a certain route + * @param route the route to link to + */ +export function getLinkForPage(route: AppRouteProps): LinkType { + return route.link || route.path; +} + +// TODO: replace with proper container/service class +/** + * Retrieves the humand readable link title/displayed name + * for a given route + * + * @param route + */ +export function getLinkDisplayNameForPage(route: AppRouteProps): string { + return route.displayName || getLinkForPage(route); +} + +// TODO: replace with proper container/service class +export const APP_ROUTES: AppRouteProps[] = []; diff --git a/packages/frontend/tsconfig.json b/packages/frontend/tsconfig.json index c4af582..1d4b811 100644 --- a/packages/frontend/tsconfig.json +++ b/packages/frontend/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "rootDir": "src", "outDir": "dist", - "baseUrl": "src" + "baseUrl": "src", + "experimentalDecorators": true }, "include": ["src/**/*"], "references": [