Commit 9d23afe5 authored by Laurent Wouters's avatar Laurent Wouters
Browse files

Refactored rendering

parent 3ce97a46ea78
type state =
| ShowingRoot
| ShowingCollection(string);
| Loading(list(string))
| Failed
| LoadedInitialSchema(list(string), Hypermedia.schemaType)
| LoadedWithData(
list(string),
Hypermedia.schemaType,
Hypermedia.entityValue,
);
type action =
| GoToRoot
| GoToCollection(string);
| LoadingFailed
| LoadedSchema(Hypermedia.schemaType)
| LoadedData(Hypermedia.entityValue)
| Goto(list(string));
let component = ReasonReact.reducerComponent("Page");
let handleGoToCollection = (_event, _self, link: Hypermedia.schemaLink) =>
ReasonReact.Router.push(link.href);
let rec getTarget = path =>
switch (path) {
| [] => ""
| [first] => first
| [first, ...others] => first ++ "/" ++ getTarget(others)
};
let handleGoToEntity = (_event, _self, entity_name, id) =>
ReasonReact.Router.push("/" ++ entity_name ++ "/" ++ id);
let fetchSchema = path =>
Js.Promise.(
Fetch.fetchWithInit(
Hypermedia.baseUrl ++ getTarget(path) ++ "/schema",
Fetch.RequestInit.make(
~headers=Fetch.HeadersInit.makeWithArray(Hypermedia.headersForSchema),
(),
),
)
|> then_(Fetch.Response.json)
|> then_(json =>
json
|> Hypermedia.Decode.schemaType
|> (schema => Some(schema) |> resolve)
)
|> catch(_err => resolve(None))
);
let doFetchSchema = (self: ReasonReact.self('state, 'retainedProps, 'action), path: list(string)) =>
Js.Promise.(
fetchSchema(path)
|> then_(result =>
switch (result) {
| Some(schema) => resolve(self.send(LoadedSchema(schema)))
| None => resolve(self.send(LoadingFailed))
}
)
|> ignore
);
let fetchData = path =>
Js.Promise.(
Fetch.fetchWithInit(
Hypermedia.baseUrl ++ getTarget(path),
Fetch.RequestInit.make(
~headers=
Fetch.HeadersInit.makeWithArray(Hypermedia.headersForResources),
(),
),
)
|> then_(Fetch.Response.json)
|> then_(json =>
json
|> Hypermedia.Decode.entityValue
|> (value => Some(value) |> resolve)
)
|> catch(_err => resolve(None))
);
let doFetchData = (self: ReasonReact.self(_, _, _), path: list(string)) =>
Js.Promise.(
fetchData(path)
|> then_(result =>
switch (result) {
| Some(data) => resolve(self.send(LoadedData(data)))
| None => resolve(self.send(LoadingFailed))
}
)
|> ignore
);
let onSchemaLoaded = (self: ReasonReact.self(_, _, _), path: list(string), schema: Hypermedia.schemaType) =>
switch schema {
| Hypermedia.ArrayType(_) => doFetchData(self, path)
| Hypermedia.ObjectType(_) => doFetchData(self, path)
| _ => ()
}
let goto = (_event, _self, link) => ReasonReact.Router.push(link);
let renderLoadedInitialSchema = (self: ReasonReact.self(_, _, _), schema: Hypermedia.schemaType) =>
switch schema {
| Hypermedia.ArrayType(_) => <div> (ReasonReact.string("Loading")) </div>
| Hypermedia.ObjectType(_) => <div> (ReasonReact.string("Loading")) </div>
| Hypermedia.RootType(rootSchema) => Root.renderRoot(self, goto, rootSchema)
| Hypermedia.PrimitiveType(ptype) => <div> (ReasonReact.string(ptype)) </div>
}
let renderLoadedWithData =
(self: ReasonReact.self(_, _, _), schema: Hypermedia.schemaType, data: Hypermedia.entityValue) =>
<div />;
let make = _children => {
...component,
didMount: self => {
let url = ReasonReact.Router.dangerouslyGetInitialUrl();
doFetchSchema(self, url.path);
let watcherID =
ReasonReact.Router.watchUrl(url =>
switch (url.path) {
| [first] => self.send(GoToCollection(first))
| _ => self.send(GoToRoot)
}
);
ReasonReact.Router.watchUrl(url => self.send(Goto(url.path)));
self.onUnmount(() => ReasonReact.Router.unwatchUrl(watcherID));
},
initialState: () => {
let url = ReasonReact.Router.dangerouslyGetInitialUrl();
switch (url.path) {
| [first] => ShowingCollection(first)
| _ => ShowingRoot
};
Loading(url.path);
},
reducer: (action, _state) =>
reducer: (action, state) =>
switch (action) {
| GoToRoot => ReasonReact.Update(ShowingRoot)
| GoToCollection(name) => ReasonReact.Update(ShowingCollection(name))
| LoadingFailed => ReasonReact.Update(Failed)
| LoadedSchema(schema) =>
switch (state) {
| Loading(path) =>
ReasonReact.Update(LoadedInitialSchema(path, schema));
| _ => ReasonReact.Update(Failed)
}
| LoadedData(value) =>
switch (state) {
| LoadedInitialSchema(path, schema) =>
ReasonReact.Update(LoadedWithData(path, schema, value))
| _ => ReasonReact.Update(Failed)
}
| Goto(path) => ReasonReact.Update(Loading(path))
},
didUpdate: oldNewSelf =>
switch (oldNewSelf.oldSelf.state, oldNewSelf.newSelf.state) {
| (Loading(_), LoadedInitialSchema(path, schema)) => onSchemaLoaded(oldNewSelf.newSelf, path, schema)
| _ => ()
},
render: self =>
switch (self.state) {
| ShowingRoot => <Root gotoCollectionHandler=handleGoToCollection />
| ShowingCollection(x) => <Collection gotoEntityHandler=handleGoToEntity name=x />
| Loading(_) => <div> (ReasonReact.string("Loading")) </div>
| Failed => <div> (ReasonReact.string("Failed")) </div>
| LoadedInitialSchema(_, schema) => renderLoadedInitialSchema(self, schema)
| LoadedWithData(_, schema, data) => renderLoadedWithData(self, schema, data)
},
};
\ No newline at end of file
type state =
| Loading
| PartialPreviews(list(Hypermedia.entityPreview))
| PartialSchema(Hypermedia.arraySchema)
| Ready(list(Hypermedia.entityPreview))
| Failed;
type action =
| LoadingFailed
| LoadedPreviews(list(Hypermedia.entityPreview))
| LoadedSchema(Hypermedia.arraySchema);
let fetchPreviews = name =>
Js.Promise.(
Fetch.fetchWithInit(
Hypermedia.baseUrl ++ "/" ++ name ++ "/",
Fetch.RequestInit.make(
~headers=Fetch.HeadersInit.makeWithArray(Hypermedia.headersForResources),
(),
),
)
|> then_(Fetch.Response.json)
|> then_(json =>
json
|> Hypermedia.Decode.entityPreviews
|> (previews => Some(previews) |> resolve)
)
|> catch(_err => resolve(None))
);
let component = ReasonReact.reducerComponent("Collection");
let make = (~gotoEntityHandler, ~name, _children) => {
...component,
initialState: () => Loading,
didMount: self =>
Js.Promise.(
fetchPreviews(name)
|> then_(result =>
switch (result) {
| Some(previews) => resolve(self.send(LoadedPreviews(previews)))
| None => resolve(self.send(LoadingFailed))
}
)
|> ignore
),
reducer: (action, state) =>
switch (action) {
| LoadingFailed => ReasonReact.Update(Failed)
| LoadedPreviews(previews) =>
switch (state) {
| Loading => ReasonReact.Update(Ready(previews))
| PartialSchema(schema) => ReasonReact.Update(Ready(previews))
| _ => ReasonReact.NoUpdate
}
| LoadedSchema(schema) =>
switch (state) {
| Loading => ReasonReact.Update(PartialSchema(schema))
| PartialPreviews(previews) => ReasonReact.Update(Ready(previews))
| _ => ReasonReact.NoUpdate
}
},
render: self =>
switch (self.state) {
| Ready(previews) =>
<div>
<h1 />
(
previews
|> List.map((preview: Hypermedia.entityPreview) =>
<li>
<a
href=("/" ++ name ++ "/" ++ preview.id)
onClick=(
self.handle((event, self) =>
gotoEntityHandler(event, self, name, preview.id)
)
)>
(ReasonReact.string(preview.title))
</a>
</li>
)
|> Array.of_list
|> ReasonReact.array
)
</div>
| Failed => <div> (ReasonReact.string("Failed")) </div>
| _ => <div> (ReasonReact.string("Loading")) </div>
},
};
\ No newline at end of file
type state =
| Loading
| Ready(Hypermedia.rootSchema)
| Failed;
type action =
| LoadingFailed
| Loaded(Hypermedia.rootSchema);
let fetchRootSchema = () =>
Js.Promise.(
Fetch.fetchWithInit(
Hypermedia.baseUrl ++ "/schema",
Fetch.RequestInit.make(
~headers=Fetch.HeadersInit.makeWithArray(Hypermedia.headersForSchema),
(),
),
let renderRoot =
(self: ReasonReact.self(_, _, _), goto, schema: Hypermedia.schemaRoot) =>
<div>
<h1> (ReasonReact.string(schema.title)) </h1>
(
schema.links
|> List.map((link: Hypermedia.schemaLink) => {
let link_href =
switch (link.href) {
| Some(x) => x
| None => ""
};
let title =
switch (link.title) {
| Some(x) => x
| None => ""
};
<li>
<a
href=link_href
onClick=(
self.handle((event, self) => goto(event, self, link_href))
)>
(ReasonReact.string(title))
</a>
</li>;
})
|> Array.of_list
|> ReasonReact.array
)
|> then_(Fetch.Response.json)
|> then_(json =>
json
|> Hypermedia.Decode.rootSchema
|> (rootSchema => Some(rootSchema) |> resolve)
)
|> catch(_err => resolve(None))
);
let component = ReasonReact.reducerComponent("Root");
let make = (~gotoCollectionHandler, _children) => {
...component,
initialState: () => Loading,
didMount: self =>
Js.Promise.(
fetchRootSchema()
|> then_(result =>
switch (result) {
| Some(rootSchema) => resolve(self.send(Loaded(rootSchema)))
| None => resolve(self.send(LoadingFailed))
}
)
|> ignore
),
reducer: (action, _state) =>
switch (action) {
| LoadingFailed => ReasonReact.Update(Failed)
| Loaded(schema) => ReasonReact.Update(Ready(schema))
},
render: self =>
switch (self.state) {
| Loading => <div> (ReasonReact.string("Loading")) </div>
| Ready(schema) =>
<div>
<h1> (ReasonReact.string(schema.title)) </h1>
(
schema.links
|> List.map((link: Hypermedia.schemaLink) =>
<li>
<a
href=link.href
onClick=(
self.handle((event, self) =>
gotoCollectionHandler(event, self, link)
)
)>
(ReasonReact.string(link.title))
</a>
</li>
)
|> Array.of_list
|> ReasonReact.array
)
</div>
| Failed => <div> (ReasonReact.string("Failed")) </div>
},
};
\ No newline at end of file
</div>;
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment