UNSTABLE BUT FIXES THE ANIMATION ISSUES

pull/991/head
Rick Carlino 2018-09-20 18:09:05 -05:00
parent 37a07747ec
commit 30d18947bf
4 changed files with 141 additions and 174 deletions

View File

@ -1,8 +1,8 @@
import * as React from "react";
import { RouteConfig } from "takeme";
import { FarmDesigner } from "../farm_designer";
// import { connect } from "react-redux";
// import { Everything } from "../interfaces";
import { connect } from "react-redux";
import { Everything } from "../interfaces";
import { CowardlyDictionary } from "../util";
export enum DesignerRouteName {
DESIGNER_ROOT = "/designer",
@ -26,20 +26,89 @@ export enum DesignerRouteName {
SAVED_GARDEN_SHOW = "/designer/saved_gardens/:saved_garden_id",
}
export const DESIGNER_ROUTES: DesignerRouteName[] =
Object.values(DesignerRouteName);
export const BIG_LOOKUP: CowardlyDictionary<() => Promise<React.ComponentType>> = {
"/designer":
async () => (await import("../farm_designer")).FarmDesigner,
"/designer/farm_events": async () => {
return (await import("../farm_designer/farm_events/farm_events")).FarmEvents;
},
"/designer/farm_events/add": async () => {
const mod = (await import("../farm_designer/farm_events/add_farm_event"));
return mod.AddFarmEvent;
},
"/designer/farm_events/:farm_event_id": async () => {
const mod = await import("../farm_designer/farm_events/edit_farm_event");
return mod.EditFarmEvent;
},
"/designer/plants": async () => {
const mod = await import("../farm_designer/plants/plant_inventory");
return mod.Plants;
},
"/designer/plants/move_to": async () => {
const mod = await import("../farm_designer/plants/move_to");
return mod.MoveTo;
},
"/designer/plants/saved_gardens": async () => {
const mod = await import("../farm_designer/saved_gardens/saved_gardens");
return mod.SavedGardens;
},
"/designer/plants/select": async () => {
const mod = await import("../farm_designer/plants/select_plants");
return mod.SelectPlants;
},
"/designer/plants/create_point": async () => {
const mod = await import("../farm_designer/plants/create_points");
return mod.CreatePoints;
},
"/designer/plants/crop_search": async () => {
const mod = await import("../farm_designer/plants/crop_catalog");
return mod.CropCatalog;
},
"/designer/plants/crop_search/:crop/add": async () => {
const mod = await import("../farm_designer/plants/add_plant");
return mod.AddPlant;
},
"/designer/plants/crop_search/:crop": async () => {
const mod = await import("../farm_designer/plants/crop_info");
return mod.CropInfo;
},
"/designer/plants/:plant_id/edit": async () => {
const mod = await import("../farm_designer/plants/edit_plant_info");
return mod.EditPlantInfo;
},
"/designer/plants/:plant_id": async () => {
const mod = await import("../farm_designer/plants/plant_info");
return mod.PlantInfo;
},
"/designer/saved_gardens": async () => {
const mod = await import("../farm_designer/saved_gardens/saved_gardens");
return mod.SavedGardens;
},
"/designer/saved_gardens/templates": async () => {
const mod = await import("../farm_designer/plants/plant_inventory");
return mod.Plants;
},
"/designer/saved_gardens/templates/:plant_template_id/edit": async () => {
const mod = await import("../farm_designer/plants/edit_plant_info");
return mod.EditPlantInfo;
},
"/designer/saved_gardens/templates/:plant_template_id": async () => {
const mod = await import("../farm_designer/plants/plant_info");
return mod.PlantInfo;
},
"/designer/saved_gardens/:saved_garden_id": async () => {
const mod = await import("../farm_designer/saved_gardens/saved_gardens");
return mod.SavedGardens;
},
};
interface ExperimentalProps {
route: RouteConfig;
localConfig: {};
}
export const DESIGNER_ROUTES: DesignerRouteName[] = Object
.values(DesignerRouteName);
interface ExperimentalState {
MapContents: React.ComponentType;
}
interface ExperimentalProps { route: string | undefined; }
interface ExperimentalState { MapContents: React.ComponentType; }
type P = ExperimentalProps;
type S = ExperimentalState;
// @connect()ed components don't need props passed to them.
@ -47,12 +116,24 @@ type S = ExperimentalState;
// Some day, I will migrate to a typescript friendly react-redux alternative.
const NOT_TYPE_SAFE: any = {};
@connect((s: Everything): P => {
return { route: s.route.$ };
})
export class Experimental extends React.Component<P, S> {
state: S = { MapContents: () => <div>Loading...</div> };
Default = () => <div>
<br />
<br />
<br />
<br />
<br />
<br />
Could not load {this.props.route}...
</div>;
render() {
return <FarmDesigner {...NOT_TYPE_SAFE}>
<this.state.MapContents />
<this.Content />
</FarmDesigner>;
}
}

View File

@ -1,12 +1,15 @@
import { generateReducer } from "../redux/generate_reducer";
import { Actions } from "../constants";
export interface RouterState { current: string; }
export interface RouterState { $: string; }
export const routeReducerDefaultState: RouterState = {
current: "/not_ready"
$: "/not_ready"
};
export const routeChange =
(payload: string) => ({ type: Actions.ROUTE_CHANGE, payload });
export const routeReducer = generateReducer<RouterState>(routeReducerDefaultState)
.add<string>(Actions.ROUTE_CHANGE,
(_, { payload }) => ({ current: payload }));
(_, { payload }) => ({ $: payload }));

View File

@ -1,4 +1,3 @@
import * as React from "react";
import { RouteConfig } from "takeme";
import { Apology } from "./apology";
@ -8,12 +7,6 @@ interface UnboundRouteConfig<T> {
key: keyof T;
}
interface LegacyRouteCfg<T> {
$: string;
getChild: () => Promise<T>;
key: keyof T;
}
/** This is the preferred way to generate a route when there are no legacy
* concerns.
* PROBLEM:
@ -56,48 +49,9 @@ function route<T>(i: UnboundRouteConfig<T>) {
};
}
/** The FarmDesigner was the only part of the application that used child
* routes, a feature of our previous router package. Under the previous scheme,
* a child route would be rendered inside of a shared <FarmDesigner/> component
* to keep a consistent UI (the FarmDesigner side bar and floating menus, etc..)
*
* This was accomplished by passing the child route to <FarmDesigner/> via
* this.props.children.
*
* This is not how the current router works. Rather than re-write numerous
* FarmDesigner components to not use child routes, we instead have a
* `legacyRoute` helper that emulates the child route feature.
*
* Don't use this for new FarmDesigner pages.
* */
function legacyRoute<T>(i: LegacyRouteCfg<T>) {
return (callback: Function): RouteConfig => {
const { $, getChild, key } = i;
return {
$,
enter: async (info) => { // ===========
try {
// tslint:disable-next-line:no-any
const El: any = (await getChild())[key];
// ^ Let route() / legacyRoute() catch type issues.
// tslint:disable-next-line:no-any
const stub: any = { children: <El /> };
// ^ react-redux will mutate the real props behind the scenes.
const { FarmDesigner } = await import("./farm_designer");
callback(() => <FarmDesigner {...stub} />, info);
} catch (e) {
console.error(e);
callback(Apology, info);
}
}
};
};
}
/** The 404 handler. All unresolved routes end up here. MUST BE LAST ITEM IN
* ROUTE CONFIG!!! */
const NOT_FOUND = route({
export const NOT_FOUND_ROUTE = route({
$: "*",
getModule: () => import("./404"),
key: "FourOhFour"
@ -147,101 +101,4 @@ export const UNBOUND_ROUTES = [
getModule: () => import("./tools"),
key: "Tools"
}),
legacyRoute({
$: "/designer",
getChild: () => import("./farm_designer"),
key: "FarmDesigner"
}),
legacyRoute({
$: "/designer/farm_events",
getChild: () => import("./farm_designer/farm_events/farm_events"),
key: "FarmEvents"
}),
legacyRoute({
$: "/designer/farm_events/add",
getChild: () => import("./farm_designer/farm_events/add_farm_event"),
key: "AddFarmEvent"
}),
legacyRoute({
$: "/designer/farm_events/:farm_event_id",
getChild: () => import("./farm_designer/farm_events/edit_farm_event"),
key: "EditFarmEvent"
}),
// =================== PLANT ROUTES
legacyRoute({
$: "/designer/plants",
getChild: () => import("./farm_designer/plants/plant_inventory"),
key: "Plants"
}),
legacyRoute({
$: "/designer/plants/move_to",
getChild: () => import("./farm_designer/plants/move_to"),
key: "MoveTo"
}),
legacyRoute({
$: "/designer/plants/saved_gardens",
getChild: () => import("./farm_designer/saved_gardens/saved_gardens"),
key: "SavedGardens"
}),
legacyRoute({
$: "/designer/plants/select",
getChild: () => import("./farm_designer/plants/select_plants"),
key: "SelectPlants"
}),
legacyRoute({
$: "/designer/plants/create_point",
getChild: () => import("./farm_designer/plants/create_points"),
key: "CreatePoints"
}),
legacyRoute({
$: "/designer/plants/crop_search",
getChild: () => import("./farm_designer/plants/crop_catalog"),
key: "CropCatalog"
}),
legacyRoute({
$: "/designer/plants/crop_search/:crop/add",
getChild: () => import("./farm_designer/plants/add_plant"),
key: "AddPlant"
}),
legacyRoute({
$: "/designer/plants/crop_search/:crop",
getChild: () => import("./farm_designer/plants/crop_info"),
key: "CropInfo"
}),
legacyRoute({
$: "/designer/plants/:plant_id/edit",
getChild: () => import("./farm_designer/plants/edit_plant_info"),
key: "EditPlantInfo"
}),
legacyRoute({
$: "/designer/plants/:plant_id",
getChild: () => import("./farm_designer/plants/plant_info"),
key: "PlantInfo"
}),
legacyRoute({
$: "/designer/saved_gardens",
getChild: () => import("./farm_designer/saved_gardens/saved_gardens"),
key: "SavedGardens"
}),
legacyRoute({
$: "/designer/saved_gardens/templates",
getChild: () => import("./farm_designer/plants/plant_inventory"),
key: "Plants"
}),
legacyRoute({
$: "/designer/saved_gardens/templates/:plant_template_id/edit",
getChild: () => import("./farm_designer/plants/edit_plant_info"),
key: "EditPlantInfo"
}),
legacyRoute({
$: "/designer/saved_gardens/templates/:plant_template_id",
getChild: () => import("./farm_designer/plants/plant_info"),
key: "PlantInfo"
}),
legacyRoute({
$: "/designer/saved_gardens/:saved_garden_id",
getChild: () => import("./farm_designer/saved_gardens/saved_gardens"),
key: "SavedGardens"
}),
].concat([NOT_FOUND]);
];

View File

@ -9,10 +9,12 @@ import { Session } from "./session";
import { attachToRoot } from "./util";
import { Callback } from "i18next";
import { ErrorBoundary } from "./error_boundary";
import { Router } from "takeme";
import { UNBOUND_ROUTES } from "./route_config";
import { Router, RouteConfig } from "takeme";
import { UNBOUND_ROUTES, NOT_FOUND_ROUTE } from "./route_config";
import { App } from "./app";
// import { TransitionGroup, CSSTransition } from "react-transition-group";
import { Experimental, DesignerRouteName, BIG_LOOKUP } from "./experimental/experimental";
import { routeChange } from "./experimental/reducer";
import { FarmDesigner } from "./farm_designer";
interface RootComponentProps { store: Store; }
@ -23,11 +25,14 @@ export const attachAppToDom: Callback = () => {
};
interface RootComponentState {
CurrentRoute: React.ComponentType
Route: React.ComponentType;
ChildRoute?: React.ComponentType;
}
const FARM_DESIGNER = () => <FarmDesigner {...({} as any)} />;
export class RootComponent extends React.Component<RootComponentProps, RootComponentState> {
state: RootComponentState = { CurrentRoute: () => <div>Loading...</div> };
state: RootComponentState = { Route: () => <div>Loading...</div> };
componentWillMount() {
const notLoggedIn = !Session.fetchStoredToken();
@ -37,22 +42,43 @@ export class RootComponent extends React.Component<RootComponentProps, RootCompo
}
changeRoute =
(c: React.ComponentType) => {
this.setState({ CurrentRoute: c });
}
(Route: React.ComponentType, ChildRoute?: React.ComponentType) => {
this.setState({ Route: Route, ChildRoute });
};
componentDidMount() {
const routes = UNBOUND_ROUTES.map(bindTo => bindTo(this.changeRoute));
new Router(routes).enableHtml5Routing("/app").init();
const main_routes = UNBOUND_ROUTES.map(bindTo => bindTo(this.changeRoute));
const designer_routes = Object
.values(DesignerRouteName)
.map(($): RouteConfig => {
return {
$: $,
enter: async () => {
_store.dispatch(routeChange($));
const fn = BIG_LOOKUP[$];
if (fn) {
const child = await fn();
this.changeRoute(FARM_DESIGNER, child);
}
}
};
});
new Router([
...main_routes,
...designer_routes,
NOT_FOUND_ROUTE(this.changeRoute)
]).enableHtml5Routing("/app").init();
}
render() {
const { CurrentRoute } = this.state;
const { Route } = this.state;
const { ChildRoute } = this.state;
const props = ChildRoute ? { children: <ChildRoute /> } : {};
try {
return <ErrorBoundary>
<Provider store={_store}>
<App {...{} as App["props"]}>
<CurrentRoute />
<Route {...props} />
</App>
</Provider>
</ErrorBoundary>;