Skip to content

Commit

Permalink
UI: WIP, added CSS in header component
Browse files Browse the repository at this point in the history
  • Loading branch information
tusharad committed Sep 9, 2024
1 parent 8233928 commit 2bc1488
Show file tree
Hide file tree
Showing 15 changed files with 260 additions and 179 deletions.
2 changes: 2 additions & 0 deletions haskread-platform-be/src/Platform/API.hs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ type FetchAllThreadsAPI =
:> "v1"
:> "thread"
:> "all"
:> QueryParam "limit" Int
:> QueryParam "offset" Int
:> Get '[JSON] FetchAllThreadsResponse

type FetchThreadAPI =
Expand Down
20 changes: 11 additions & 9 deletions haskread-platform-be/src/Platform/User/Thread/DB.hs
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,22 @@ fetchThreadInfoByIDQ tID = do
res <-
executeAndDecode
SelectQuery
(fetchThreadInfoExpr (Just $ whereThreadIdIs tID))
(fetchThreadInfoExpr (Just $ whereThreadIdIs tID) Nothing Nothing)
(annotateSqlMarshallerEmptyAnnotation threadInfoMarshaller)
case res of
[] -> pure Nothing
(x : _) -> pure $ Just x

fetchThreadInfoQ :: (MonadOrville m) => m [ThreadInfo]
fetchThreadInfoQ =
fetchThreadInfoQ :: (MonadOrville m) => Int -> Int -> m [ThreadInfo]
fetchThreadInfoQ limit offset =
executeAndDecode
SelectQuery
(fetchThreadInfoExpr Nothing)
(fetchThreadInfoExpr Nothing (Just (limitExpr limit)) (Just (offsetExpr offset)))
(annotateSqlMarshallerEmptyAnnotation threadInfoMarshaller)

fetchThreadInfoExpr :: Maybe WhereClause -> QueryExpr
fetchThreadInfoExpr wClause =
queryExpr selectClauseDefault selectedColumns (Just (fromTable wClause))
fetchThreadInfoExpr :: Maybe WhereClause -> Maybe LimitExpr -> Maybe OffsetExpr -> QueryExpr
fetchThreadInfoExpr wClause lClause oClause =
queryExpr selectClauseDefault selectedColumns (Just (fromTable wClause lClause oClause))
where
selectedColumns =
selectColumns
Expand Down Expand Up @@ -199,9 +199,11 @@ fetchThreadInfoExpr wClause =
joinExpr leftJoinType voteCountTable (joinOnConstraint threadIDConstraint),
joinExpr leftJoinType commentCountTable (joinOnConstraint commentConstraint)
]
fromTable wClause =
fromTable wClause lClause oClause =
mkTableExpr
(threadTableName `appendJoinFromItem` joinList)
defaultClauses
{ _whereClause = wClause
{ _whereClause = wClause,
_limitExpr = lClause,
_offSetExpr = oClause
}
12 changes: 8 additions & 4 deletions haskread-platform-be/src/Platform/User/Thread/Handler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ where

import Control.Monad (void, when)
import qualified Data.ByteString.Lazy.Char8 as BSL
import Data.Maybe (isNothing)
import Data.Maybe (isNothing,fromMaybe)
import qualified Data.Text as T
import Platform.Auth.Types
import Platform.Common.AppM
Expand Down Expand Up @@ -115,9 +115,13 @@ deleteThreadH (Authenticated UserInfo {..}) threadID = do
Right _ -> return $ DeleteThreadResponse "Thread deleted successfully!"
deleteThreadH _ _ = throw401Err "Please login first"

fetchAllThreadsH :: (MonadUnliftIO m) => AppM m FetchAllThreadsResponse
fetchAllThreadsH = do
threadInfoList <- queryWrapper fetchThreadInfoQ
fetchAllThreadsH ::
(MonadUnliftIO m) =>
(Maybe Int) -> (Maybe Int) ->
AppM m FetchAllThreadsResponse
fetchAllThreadsH mLimit mOffSet = do
threadInfoList <- queryWrapper (
fetchThreadInfoQ (fromMaybe 10 mLimit) (fromMaybe 0 mOffSet))
return $ FetchAllThreadsResponse (length threadInfoList) threadInfoList

fetchThreadH :: (MonadUnliftIO m) => ThreadID -> AppM m ThreadInfo
Expand Down
3 changes: 2 additions & 1 deletion haskread-platform-ui/spago.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ workspace:
registry: 57.1.0
extraPackages:
bulma:
path: /home/user/Documents/github/purescript-bulma
git: https://github.com/tusharad/purescript-bulma/
ref: 8b1c922562cc158ae65b6ac376d83254bb460d89
15 changes: 12 additions & 3 deletions haskread-platform-ui/src/Common/Types.purs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ module Common.Types
, updateThreadCodec
, profileCodec
, communitiesCodec
, Pagination(..)
)
where

Expand All @@ -50,7 +51,7 @@ import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe)
import Data.Newtype (class Newtype)
import Data.Profunctor (wrapIso)
import Routing.Duplex (RouteDuplex', path, root, int, segment)
import Routing.Duplex (RouteDuplex', path, root, int, segment,optional, string)
import Routing.Duplex.Generic (noArgs, sum)
import Routing.Duplex.Generic as G
import Routing.Duplex.Generic.Syntax ((/), (?))
Expand Down Expand Up @@ -104,7 +105,7 @@ type RequestOptions =
}

data MyRoute
= Home
= Home Pagination
| Login
| Register
| OTP Int
Expand All @@ -123,9 +124,17 @@ derive instance eqToken :: Eq Token
instance showToken :: Show Token where
show (Token _) = "TOKEN"

type Pagination = {
limit :: Maybe Int
, offset :: Maybe Int
}

myRoute :: RouteDuplex' MyRoute
myRoute = root $ G.sum
{ "Home": G.noArgs
{ "Home": "Home" ? {
offset: optional <<< int
, limit: optional <<< int
}
, "Login": path "login" G.noArgs
, "Register": path "register" G.noArgs
, "OTP": "otp" / (int segment)
Expand Down
7 changes: 6 additions & 1 deletion haskread-platform-ui/src/Common/Utils.purs
Original file line number Diff line number Diff line change
Expand Up @@ -347,4 +347,9 @@ getCommunities ::
getCommunities = do
let method = Get
mJson <- mkRequest { endpoint: Community, method }
decode communitiesCodec mJson
decode communitiesCodec mJson

defaultPagination :: Pagination
defaultPagination = { limit : Just 10
, offset : Just 0
}
213 changes: 130 additions & 83 deletions haskread-platform-ui/src/Component/Header.purs
Original file line number Diff line number Diff line change
@@ -1,48 +1,54 @@
module Component.Header where

import Prelude
import Data.Maybe (Maybe(..),fromMaybe,isJust)
import Common.Types (Profile,MyRoute(..))
import Halogen.Store.Monad (class MonadStore)
import Capability.Resource (class Navigate,navigate)

import Bulma.CSS.Spacing as B
import Bulma.Common as B
import Bulma.Components.Navbar as B
import Bulma.Form.General as B
import Bulma.Modifiers.Typography as B
import Bulma.Elements.Button as Button
import Bulma.Modifiers.Helpers as B
import Capability.Resource (class Navigate, navigate)
import Common.BulmaUtils as BU
import Common.Types (Profile, MyRoute(..))
import Common.Utils (defaultPagination, whenElem)
import Data.Maybe (Maybe(..), fromMaybe, isJust)
import Effect.Aff.Class (class MonadAff)
import Halogen.Store.Connect (connect)
import Halogen.Store.Select (selectEq)
import Store as Store
import Halogen as H
import Halogen.HTML as HH
import Halogen.HTML.Core as HC
import Halogen.HTML.Events as HE
import Halogen.HTML.Properties as HP
import Halogen.Store.Connect (connect)
import Halogen.Store.Monad (class MonadStore)
import Halogen.Store.Select (selectEq)
import Store as Store
import Undefined (undefined)
import Web.Event.Event (Event)
import Web.Event.Event as Event
import Common.Utils (whenElem)

-- Bulma
import Bulma.Components.Navbar as B
import Bulma.Common as B
import Common.BulmaUtils as BU
import Bulma.Layout.Layout as B
import Bulma.CSS.Spacing as B

type State = {
currentUser :: Maybe Profile
, searchError :: Maybe String
, searchInput :: String
}
type State =
{ currentUser :: Maybe Profile
, searchError :: Maybe String
, searchInput :: String
}

data Action = Initialize
| GoToLogin
| GoToRegister
| HandleSearch Event
| GoToMyProfile
| SetSearchInput String
data Action
= Initialize
| GoToLogin
| GoToRegister
| HandleSearch Event
| GoToMyProfile
| SetSearchInput String
| GoToHome

component
:: forall query output m
.MonadAff m
=> Navigate m
=> MonadStore Store.Action Store.Store m
=> H.Component query Unit output m
component
:: forall query output m
. MonadAff m
=> Navigate m
=> MonadStore Store.Action Store.Store m
=> H.Component query Unit output m
component = connect (selectEq _.currentUser) $ H.mkComponent
{ initialState
, render
Expand All @@ -52,66 +58,107 @@ component = connect (selectEq _.currentUser) $ H.mkComponent
}
}
where
initialState { context : currentUser } = {
currentUser
, searchError : Nothing
, searchInput : ""
}
initialState { context: currentUser } =
{ currentUser
, searchError: Nothing
, searchInput: ""
}

handleAction :: forall slots. Action -> H.HalogenM State Action slots output m Unit
handleAction =
case _ of
Initialize -> do
-- nothing here right now!
pure unit
GoToLogin -> navigate Login
GoToRegister -> navigate Register
GoToMyProfile -> navigate Home -- TODO: Add myProfile page and add here
SetSearchInput searchInput ->
H.modify_ _ { searchInput = searchInput }
HandleSearch event -> do
H.liftEffect $ Event.preventDefault event
{ searchInput } <- H.get
-- TODO: Add Search page and API
navigate Home
handleAction :: forall slots. Action -> H.HalogenM State Action slots output m Unit
handleAction =
case _ of
Initialize -> do
-- nothing here right now!
pure unit
GoToLogin -> navigate Login
GoToRegister -> navigate Register
GoToMyProfile -> navigate $ Home defaultPagination -- TODO: Add myProfile page and add here
SetSearchInput searchInput ->
H.modify_ _ { searchInput = searchInput }
GoToHome -> navigate $ Home defaultPagination
HandleSearch event -> do
H.liftEffect $ Event.preventDefault event
-- _ <- H.get
-- TODO: Add Search page and API
navigate $ Home defaultPagination

render :: State -> H.ComponentHTML Action () m
render { currentUser,searchError,searchInput } = do
HH.nav [
BU.classNames [
B.navbar,
B.isFixedTop,
B.px6
]
] [
logoAndTitle,
searchBar searchError searchInput,
case currentUser of
Nothing -> loginRegisterButtons
Just currUser -> profileButton currUser
]
render :: State -> H.ComponentHTML Action () m
render { currentUser, searchError, searchInput } = do
HH.nav
[ BU.classNames
[ B.navbar
, B.isFixedTop
, B.px6
, B.hasShadow
]
]
[ logoAndTitle
, searchBar searchError searchInput
, loginSignupButtons currentUser
-- case currentUser of
-- Nothing -> loginRegisterButtons
-- Just currUser -> profileButton currUser
]

loginSignupButtons currUser =
HH.div [ HP.id "navbarBasicExample", BU.className B.navbarMenu ]
[ HH.div [ BU.className B.navbarEnd ]
[ HH.div [ BU.className B.navbarItem ]
[ HH.div [ BU.className Button.buttons ]
[ HH.a
[ HE.onClick \_ -> GoToLogin
, BU.classNames [ Button.button, B.isPrimary ]
]
[ HH.text "Login" ]
]
]
]
]

logoAndTitle = HH.div_ [HH.h3_ [ HH.text "HaskRead" ]]
navbarBurger = HH.a
[ HP.attr (HC.AttrName "area-label") "Close"
, BU.className B.navbarBurger
, HP.attr (HC.AttrName "area-label") "menu"
, HP.attr (HC.AttrName "area-expanded") "false"
, HP.attr (HC.AttrName "data-target") "navbarBasicExample"
]
[ HH.span [ HP.attr (HC.AttrName "area-hidden") "true" ] []
, HH.span [ HP.attr (HC.AttrName "area-hidden") "true" ] []
, HH.span [ HP.attr (HC.AttrName "area-hidden") "true" ] []
, HH.span [ HP.attr (HC.AttrName "area-hidden") "true" ] []
]

searchBar searchError searchInput = HH.div_ [
HH.form
logoAndTitle = HH.div [ BU.className B.navbarBrand ]
[ HH.a [ HE.onClick \_ -> GoToHome, BU.className B.navbarItem ]
[ HH.p [ BU.classNames [ B.hasWeight B.Bold ] ] [ HH.text "HaskRead" ] ]
, navbarBurger
]

searchBar searchError searchInput = HH.div
[ BU.className B.navbarItem ]
[ HH.div [ BU.classNames [ B.field, B.hasAddons ] ]
[ HH.form
[ HE.onSubmit HandleSearch ]
[ whenElem (isJust searchError)
(\_ -> HH.div_ [ HH.text (fromMaybe "" searchError) ])
, HH.input [
HP.placeholder "Search threads, community, users etc."
, HP.type_ HP.InputText
, HE.onValueInput SetSearchInput
, HP.value searchInput ]
, HH.button [ HP.type_ HP.ButtonSubmit ] [ HH.text "Search" ]
(\_ -> HH.div_ [ HH.text (fromMaybe "" searchError) ])
, HH.div [ BU.className B.control ]
[ HH.input
[ HP.placeholder "Search threads, community, users etc."
, HP.type_ HP.InputText
, HE.onValueInput SetSearchInput
, HP.value searchInput
]
]
, HH.div [ BU.className B.control ] [ HH.button [ HP.type_ HP.ButtonSubmit ] [ HH.text "Search" ] ]
]
]
]

loginRegisterButtons = HH.div_ [
HH.button [ HE.onClick \_ -> GoToLogin ] [HH.text "Login"]
, HH.button [ HE.onClick \_ -> GoToRegister ] [HH.text "Register"]
loginRegisterButtons = HH.div_
[ HH.button [ HE.onClick \_ -> GoToLogin ] [ HH.text "Login" ]
, HH.button [ HE.onClick \_ -> GoToRegister ] [ HH.text "Register" ]
]

profileButton currUser = HH.div_ [
HH.button [ HE.onClick \_ -> GoToMyProfile ] [HH.text currUser.userName]
profileButton currUser = HH.div_
[ HH.button [ HE.onClick \_ -> GoToMyProfile ] [ HH.text currUser.userName ]
]
Loading

0 comments on commit 2bc1488

Please sign in to comment.