Skip to content

Commit

Permalink
Combine Results module into Search
Browse files Browse the repository at this point in the history
  • Loading branch information
theprash committed Feb 5, 2018
1 parent 682bf24 commit 07c5537
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 137 deletions.
28 changes: 6 additions & 22 deletions src/client/App.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,26 @@ open Fable.Helpers.React.Props
open Pages

type Model =
{ SearchModel : Search.Model
ResultsModel : Results.Model }
{ SearchModel : Search.Model }

type AppMsg =
| SearchMsg of Search.Msg
| ResultsMsg of Results.Msg

let update msg model =
let updateSearch msg model =
match msg with
| SearchMsg msg ->
let searchModel, searchCmd = Search.update msg model.SearchModel
{ model with SearchModel = searchModel }, Cmd.map SearchMsg searchCmd
match msg with
| SearchMsg (Search.SearchCompleted(term, response) as msg) ->
let model, cmd = model |> updateSearch msg
{ model with ResultsModel = Results.update (Results.DisplayResults(term, response)) model.ResultsModel }, cmd
| SearchMsg msg -> model |> updateSearch msg
| ResultsMsg (Results.FilterSet(facet, value)) -> model |> updateSearch (Search.ApplyFilter (facet, value))
| ResultsMsg (Results.ChangePage page) -> model |> updateSearch (Search.ChangePage page)
| ResultsMsg (Results.SetPostcode postcode) -> model |> updateSearch (Search.DoSearch (Postcode postcode))
| ResultsMsg (Results.SelectTransaction _ as msg) -> { model with ResultsModel = Results.update msg model.ResultsModel }, Cmd.none
| ResultsMsg (Results.DisplayResults _) -> model, Cmd.none

let init _ =
let model =
{ SearchModel = Search.init ()
ResultsModel = Results.init () }
{ SearchModel = Search.init () }
model, Cmd.none

let view model dispatch =
let toTh c = th [ Scope "col" ] [ str c ]
let toTd c = td [ Scope "row" ] [ str c ]

div [ ClassName "container-fluid" ] [
div [ ClassName "row" ] [ div [ ClassName "col" ] [ h1 [] [ str "Property Search" ] ] ]
div [ ClassName "row" ] [ Pages.Search.view model.SearchModel (SearchMsg >> dispatch) ]
div [ ClassName "row" ] [ Pages.Results.view model.ResultsModel (ResultsMsg >> dispatch) ]
div [ ClassName "row" ] [ div [ ClassName "col" ] [ h1 [] [ str "Property Search" ] ] ]
div [ ClassName "row" ] [ Search.view model.SearchModel (SearchMsg >> dispatch) ]
]

JsInterop.importSideEffects "whatwg-fetch"
Expand Down
3 changes: 1 addition & 2 deletions src/client/client.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
<Compile Include="../server/Contracts.fs" />
<Compile Include="pages/Shared.fs" />
<Compile Include="pages/Details.fs" />
<Compile Include="pages/Search.fs" />
<Compile Include="pages/Filter.fs" />
<Compile Include="pages/Results.fs" />
<Compile Include="pages/Search.fs" />
<Compile Include="App.fs" />
</ItemGroup>
<Import Project="..\..\.paket\Paket.Restore.targets" />
Expand Down
85 changes: 0 additions & 85 deletions src/client/pages/Results.fs

This file was deleted.

137 changes: 109 additions & 28 deletions src/client/pages/Search.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,57 +10,134 @@ open PropertyMapper.Contracts
type SearchState = Searching | Displaying

type SearchParameters = { Facet : (string * string) option; Page : int }
type SearchResults = { SearchTerm : SearchTerm; Response : SearchResponse }

type Model =
{ Text : SearchTerm
LastSearch : SearchTerm
Status : SearchState
Parameters : SearchParameters }
Parameters : SearchParameters
SearchResults : SearchResults option
Selected : PropertyResult option }

type Msg =
| SetSearch of string
| DoSearch of SearchTerm
| ApplyFilter of string * string
| SetFilter of string * string
| ChangePage of int
| SearchCompleted of SearchTerm * SearchResponse
| SearchError of exn
| SelectTransaction of PropertyResult

let init _ = { Text = SearchTerm.Empty; LastSearch = SearchTerm.Empty; Status = SearchState.Displaying; Parameters = { Facet = None; Page = 0 } }
let init _ =
{ Text = SearchTerm.Empty
LastSearch = SearchTerm.Empty
Status = SearchState.Displaying
Parameters = { Facet = None; Page = 0 }
SearchResults = None
Selected = None }

let view model dispatch =
div [ ClassName "col border rounded m-3 p-3 bg-light" ] [
let progressBarVisibility = match model.Status with | Searching -> "visible" | Displaying -> "invisible"
yield div [ ClassName "form-group" ] [
label [ HtmlFor "searchValue" ] [ str "Search for" ]
input [
ClassName "form-control"
Id "searchValue"
Placeholder "Enter Search"
OnChange (fun ev -> dispatch (SetSearch !!ev.target?value))
Client.Style.onEnter (DoSearch model.Text) dispatch
]
let viewResults searchResults dispatch =
let toTh c = th [ Scope "col" ] [ str c ]
let toDetailsLink row c =
td [ Scope "row" ] [
a [ Href "#"
DataToggle "modal"
unbox ("data-target", "#exampleModal")
OnClick(fun _ -> dispatch (SelectTransaction row)) ] [ str c ]
]
yield div [ ClassName "form-group" ] [
div [ ClassName "progress" ] [
div [ ClassName (sprintf "progress-bar progress-bar-striped progress-bar-animated %s" progressBarVisibility)
Role "progressbar"
Style [ Width "100%" ] ]
[ str <| sprintf "Searching for '%s'..." model.LastSearch.Description ]
let toTd c = td [ Scope "row" ] [ str c ]
div [ ClassName "border rounded m-3 p-3 bg-light" ] [
match searchResults with
| None -> yield div [ ClassName "row" ] [ div [ ClassName "col" ] [ h3 [] [ str "Please perform a search!" ] ] ]
| Some { Response = { Results = [||] } } -> yield div [ ClassName "row" ] [ div [ ClassName "col" ] [ h3 [] [ str "Your search yielded no results." ] ] ]
| Some { SearchTerm = term; Response = response } ->
let hits = response.TotalTransactions |> Option.map (commaSeparate >> sprintf " (%s hits)") |> Option.defaultValue ""
let description =
match term with
| Term term -> sprintf "Search results for '%s'%s." term hits
| Postcode postcode -> sprintf "Showing properties within a 1km radius of '%s'%s." postcode hits

yield div [ ClassName "row" ] [
div [ ClassName "col-2" ] [ Filter.createFilters (SetFilter >> dispatch) response.Facets ]
div [ ClassName "col-10" ] [
div [ ClassName "row" ] [ div [ ClassName "col" ] [ h4 [] [ str description ] ] ]
table [ ClassName "table table-bordered table-hover" ] [
thead [] [
tr [] [ toTh "Street"
toTh "Town"
toTh "Postcode"
toTh "Date"
toTh "Price" ]
]
tbody [] [
for row in response.Results ->
let postcodeLink =
a
[ Href "#"; OnClick(fun _ -> row.Address.PostCode |> Option.iter(Postcode >> DoSearch >> dispatch)) ]
[ row.Address.PostCode |> Option.defaultValue "" |> str ]
tr [] [ toDetailsLink row row.Address.FirstLine
toTd row.Address.TownCity
td [ Scope "row" ] [ postcodeLink ]
toTd (row.DateOfTransfer.ToShortDateString())
toTd (sprintf "£%s" (commaSeparate row.Price)) ]
]
]
nav [] [
ul [ ClassName "pagination" ] [
let buildPager enabled content current page =
li [ ClassName ("page-item" + (if enabled then "" else " disabled") + (if current then " active" else "")) ] [
button [ ClassName "page-link"; Style [ Cursor "pointer" ]; OnClick (fun _ -> dispatch (ChangePage page)) ] [ str content ]
]
let currentPage = response.Page
let totalPages = int ((response.TotalTransactions |> Option.defaultValue 0 |> float) / 20.)
yield buildPager (currentPage > 0) "Previous" false (currentPage - 1)
yield!
[ for page in 0 .. totalPages ->
buildPager true (string (page + 1)) (page = currentPage) page ]
yield buildPager (currentPage < totalPages) "Next" false (currentPage + 1)
]
]
]
]
]
yield button [ ClassName "btn btn-primary"; OnClick (fun _ -> dispatch (DoSearch model.Text)) ] [ str "Search!" ]
]

let view model dispatch =
let progressBarVisibility = match model.Status with | Searching -> "visible" | Displaying -> "invisible"
div [ ClassName "col" ] [
yield! model.Selected |> function Some property -> [ Details.view property ] | None -> []
yield div [ ClassName "border rounded m-3 p-3 bg-light" ] [
div [ ClassName "form-group" ] [
label [ HtmlFor "searchValue" ] [ str "Search for" ]
input [
ClassName "form-control"
Id "searchValue"
Placeholder "Enter Search"
OnChange (fun ev -> dispatch (SetSearch !!ev.target?value))
Client.Style.onEnter (DoSearch model.Text) dispatch
]
]
div [ ClassName "form-group" ] [
div [ ClassName "progress" ] [
div [ ClassName (sprintf "progress-bar progress-bar-striped progress-bar-animated %s" progressBarVisibility)
Role "progressbar"
Style [ Width "100%" ] ]
[ str <| sprintf "Searching for '%s'..." model.LastSearch.Description ]
]
]
button [ ClassName "btn btn-primary"; OnClick (fun _ -> dispatch (DoSearch model.Text)) ] [ str "Search!" ] ]
yield viewResults model.SearchResults dispatch ]

let findTransactions (text, filter, page) =
let filter = filter |> Option.map(fun (facet, value) -> sprintf "?%s=%s" facet value) |> Option.defaultValue ""
Fetch.fetchAs<SearchResponse> (sprintf "http://localhost:5000/property/find/%s/%d%s" text page filter) []

let findByPostcode (postCode, page) =
let findByPostcode (postCode, page) =
Fetch.fetchAs<SearchResponse> (sprintf "http://localhost:5000/property/%s/1/%d" postCode page) []

let update msg model : Model * Cmd<Msg> =
let initiateSearch model term facet page =
let cmd =
let cmd =
match term with
| Term text -> Cmd.ofPromise findTransactions (text, facet, page)
| Postcode postcode -> Cmd.ofPromise findByPostcode (postcode, page)
Expand All @@ -73,8 +150,12 @@ let update msg model : Model * Cmd<Msg> =
| SetSearch text -> { model with Text = Term text }, Cmd.none
| DoSearch (Term text) when System.String.IsNullOrWhiteSpace text || text.Length <= 3 -> model, Cmd.none
| DoSearch term -> initiateSearch model term None 0
| ApplyFilter (facet, value) -> initiateSearch model model.LastSearch (Some(facet, value)) model.Parameters.Page
| SetFilter (facet, value) -> initiateSearch model model.LastSearch (Some(facet, value)) model.Parameters.Page
| ChangePage page -> initiateSearch model model.LastSearch model.Parameters.Facet page
| SearchCompleted _ -> { model with Status = Displaying }, Cmd.none
| SearchCompleted (term, response) ->
{ model with
Status = Displaying
SearchResults = Some { SearchTerm = term; Response = response }
Selected = None }, Cmd.none
| SearchError _ -> model, Cmd.none

| SelectTransaction transaction -> { model with Selected = Some transaction }, Cmd.none

0 comments on commit 07c5537

Please sign in to comment.