Initial rendering for signup controls.
[?]
Sep 2, 2020, 4:53 AM
5R2Z7FSXJD7Z53QSU2NSTEBONTYK43FIJOSOMUST5XMYIWRXY2HQCDependencies
- [2]
PT4276XCAdd logout functionality. - [3]
WRPIYG3EUse project listing functionality to check for whether we have a cookie. - [*]
EA5BFM5GSplit Login component into its own module. - [*]
RB2ETNIFAdd skeletal PureScript client project.
Change contents
- file addition: Signup.purs[5.1]
module Aftok.Signup whereimport Prelude-- import Control.Monad.Trans.Class (lift)import Data.Maybe (Maybe(..), fromMaybe)-- import Affjax (post, get, printError)import Affjax.StatusCode (StatusCode)-- import Affjax.RequestBody as RB-- import Affjax.ResponseFormat as RFimport Halogen as Himport Halogen.HTML.Core (AttrName(..), ClassName(..))import Halogen.HTML as HH-- import Halogen.HTML.CSS as CSSimport Halogen.HTML.Events as Eimport Web.UIEvent.MouseEvent as MEimport Web.Event.Event as WEimport Halogen.HTML.Properties as P-- import CSS (backgroundImage, url)import Aftok.Types (System)data SignupResponse= OK| Error { status :: Maybe StatusCode, message :: String }data RecoveryType= RecoveryEmail| RecoveryZAddrderive instance recoveryTypeEq :: Eq RecoveryTypetype SignupState ={ username :: Maybe String, password :: Maybe String, passwordConfirm :: Maybe String, recoveryType :: RecoveryType, recoveryEmail :: Maybe String, recoveryZAddr :: Maybe String, loginResponse :: Maybe SignupResponse}data SignupAction= SetUsername String| SetPassword String| ConfirmPassword String| SetRecoveryType RecoveryType| SetRecoveryEmail String| SetRecoveryZAddr String| Signin ME.MouseEvent| Signup WE.Eventdata SignupResult= SignupComplete { username :: String }| LoginSwitchtype Slot id = forall query. H.Slot query SignupResult idtype Capability m ={ signup :: String -> String -> m SignupResponse}type Config ={ recaptchaKey :: String}component:: forall query input m. Monad m=> System m-> Capability m-> Config-> H.Component HH.HTML query input SignupResult mcomponent system caps conf = H.mkComponent{ initialState, render, eval: H.mkEval $ H.defaultEval { handleAction = eval }} whereinitialState :: input -> SignupStateinitialState _ ={ username: Nothing, password: Nothing, passwordConfirm: Nothing, recoveryType: RecoveryEmail, recoveryEmail: Nothing, recoveryZAddr: Nothing, loginResponse: Nothing}render :: forall slots. SignupState -> H.ComponentHTML SignupAction slots mrender st =HH.section[ P.classes (ClassName <$> ["section-border", "border-primary"]) ][ HH.div[ P.classes (ClassName <$> ["container", "d-flex", "flex-column"]) ][ HH.div[ P.classes (ClassName <$> ["align-items-center", "pt-6"]) ][ HH.h1[ P.classes (ClassName <$> ["mb-0", "font-weight-bold", "text-center"]) ][ HH.text "Sign up" ], HH.p[ P.classes (ClassName <$> ["text-center", "text-muted", "col-md-5", "mx-auto"]) ][ HH.text "You can use either an email address or zcash payment address for account recovery." ]], HH.div[ P.classes (ClassName <$> ["align-items-center", "justify-content-center", "no-gutters"]) ][ HH.div[ P.classes (ClassName <$> ["col-12", "col-lg-4", "py-8", "py-md-0"]) ][ HH.form[ P.classes (ClassName <$> ["mb-6"]) ][ HH.div[ P.classes (ClassName <$> ["form-group"]) ][ HH.label [ P.for "username" ] [ HH.text "Username" ], HH.input[ P.type_ P.InputText, P.classes (ClassName <$> ["form-control"]), P.id_ "username", P.placeholder "Choose a handle (username)", P.required true, P.autofocus true, P.value (fromMaybe "" st.username), E.onValueInput (Just <<< SetUsername)]], HH.div[ P.classes (ClassName <$> ["form-group"]) ][ HH.label [ P.for "password" ] [ HH.text "Password" ], HH.input[ P.type_ P.InputPassword, P.classes (ClassName <$> ["form-control"]), P.id_ "password", P.placeholder "Enter a unique password", P.required true, P.value (fromMaybe "" st.password), E.onValueInput (Just <<< SetPassword)], HH.input[ P.type_ P.InputPassword, P.classes (ClassName <$> ["form-control"]), P.id_ "password", P.placeholder "Enter a unique password", P.required true, P.value (fromMaybe "" st.passwordConfirm), E.onValueInput (Just <<< ConfirmPassword)]], recoverySwitch st.recoveryType, recoveryField st, HH.div[ P.classes (ClassName <$> ["form-group", "mb-3"]) ][ HH.div[ P.classes (ClassName <$> ["form-group", "mb-3"]), P.attr (AttrName "data-sitekey") conf.recaptchaKey] []], HH.button[ P.classes (ClassName <$> ["btn", "btn-block", "btn-primary"]) ][ HH.text "Sign up" ]], HH.p[ P.classes (ClassName <$> ["mb-0", "font-size-sm", "text-center", "text-muted"]) ][ HH.text "Alreay have an account? ", HH.a[ P.href "#", E.onClick (Just <<< Signin) ][ HH.text "Sign in" ]]]]]]eval :: SignupAction -> H.HalogenM SignupState SignupAction () SignupResult m Uniteval = case _ ofSetUsername user -> H.modify_ (_ { username = Just user })SetPassword pass -> H.modify_ (_ { password = Just pass })ConfirmPassword pass -> H.modify_ (_ { passwordConfirm = Just pass })_ -> pure unitrecoverySwitch :: forall i. RecoveryType -> HH.HTML i SignupActionrecoverySwitch rt =HH.div[ P.classes (ClassName <$> ["form-group", "mb-3"]) ][ HH.label[ P.for "recoverySwitch" ][ HH.text "Choose a recovery method" ], HH.div[ P.classes (ClassName <$> ["form-group", "mb-3"]) ][ HH.span[ P.classes (ClassName <$> [ if rt == RecoveryEmail then "text-success" else "text-muted"]) ][ HH.text "Email" ], HH.div[ P.classes (ClassName <$> ["custom-control", "custom-switch", "custom-switch-light", "mx-3"]) ][ HH.input[ P.type_ P.InputCheckbox, P.classes (ClassName <$> ["custom-control-input"]), P.id_ "recoverySwitch", E.onChecked (\b -> Just <<< SetRecoveryType $ if b then RecoveryZAddr else RecoveryEmail)]], HH.span[ P.classes (ClassName <$> [if rt == RecoveryZAddr then "text-success" else "text-muted"]) ][ HH.text "Z-Address" ]]]recoveryField :: forall i. SignupState -> HH.HTML i SignupActionrecoveryField st = case st.recoveryType ofRecoveryEmail ->HH.div[ P.id_ "recoveryEmail" ][ HH.label [ P.for "email" ] [ HH.text "Email Address" ], HH.input[ P.type_ P.InputEmail, P.classes (ClassName <$> ["form-control"]), P.id_ "email", P.placeholder "name@address.com", P.value (fromMaybe "" st.recoveryEmail), E.onValueInput (Just <<< SetRecoveryEmail)]]RecoveryZAddr ->HH.div[ P.id_ "recoveryZAddr" ][ HH.label[ P.for "zaddr" ][ HH.text "Zcash Shielded Address", HH.a[ P.attr (AttrName "data-toggle") "modal", P.href "#modalAboutZAddr"][ HH.img [ P.src "./assets/img/icons/duotone-icons/Code/Info-circle.svg" ]]], HH.input[ P.type_ P.InputText, P.classes (ClassName <$> ["form-control"]), P.id_ "email", P.placeholder "Enter a Zcash shielded address", P.value (fromMaybe "" st.recoveryZAddr), E.onValueInput (Just <<< SetRecoveryZAddr)]] - edit in client/src/Main.purs at line 129
-- <!-- Navigation -->-- <ul class="navbar-nav ml-auto">-- <li class="nav-item dropdown">-- <a class="nav-link dropdown-toggle" id="navbarAccount" data-toggle="dropdown" href="#" aria-haspopup="true" aria-expanded="false">-- Guidebook-- </a>-- <ul class="dropdown-menu" aria-labelledby="navbarAccount">-- <li class="dropdown-item dropright">-- <a class="dropdown-link dropdown-toggle" data-toggle="dropdown" href="#">-- Getting Started-- </a>-- <div class="dropdown-menu">-- <a class="dropdown-item" href="@@webRoot/guide-foundation.html">-- Foundational Principles-- </a>-- <a class="dropdown-item" href="@@webRoot/guide-time.html">-- Measuring Contributions-- </a>-- <a class="dropdown-item" href="@@webRoot/guide-revenue.html">-- Revenue Sharing-- </a>-- <a class="dropdown-item" href="@@webRoot/guide-tithing.html">-- Varying Compensation-- </a>-- </div>-- </li>-- <!---- <li class="dropdown-item dropright">-- <a class="dropdown-link dropdown-toggle" data-toggle="dropdown" href="#">-- Up And Running-- </a>-- <div class="dropdown-menu">-- <a class="dropdown-item" href="@@webRoot/guide-voting.html">-- Share-Weighted Voting-- </a>-- <a class="dropdown-item" href="@@webRoot/guide-auctions.html">-- Expense Auctions-- </a>-- <a class="dropdown-item" href="@@webRoot/guide-forks.html">-- Project Forks & Merges-- </a>-- </div>-- </li>-- <li class="dropdown-item dropright">-- <a class="dropdown-link dropdown-toggle" data-toggle="dropdown" href="#">-- Coming Soon!-- </a>-- <div class="dropdown-menu">-- <a class="dropdown-item" href="@@webRoot/guide-debt-contracts.html">-- 3rd-party Contracts-- </a>-- <a class="dropdown-item" href="@@webRoot/guide-delegative-voting.html">-- Delegative Voting-- </a>-- </div>-- </li>-- <li class="dropdown-item dropright">-- <a class="dropdown-item" href="@@webRoot/blog.html">-- Blog-- </a>-- </li>-- -->-- </ul>-- </li>-- <li class="nav-item dropdown">-- <a class="nav-link dropdown-toggle" id="navbarAccount" data-toggle="dropdown" href="#" aria-haspopup="true" aria-expanded="false">-- My Account-- </a>-- <ul class="dropdown-menu" aria-labelledby="navbarAccount">-- <li class="dropdown-item dropright">-- <a class="dropdown-item" data-toggle="modal" href="#modalSigninHorizontal">-- Sign In-- </a>-- </li>-- <!---- <li class="dropdown-item dropright">-- <a class="dropdown-item" href="@@webRoot/account-revenue.html">-- Revenue Dashboard-- </a>-- </li>-- <li class="dropdown-item dropright">-- <a class="dropdown-item" href="@@webRoot/account-auctions.html">-- Active Expense Auctions-- </a>-- </li>-- <li class="dropdown-item dropright">-- <a class="dropdown-item" href="@@webRoot/account-general.html">-- Project List-- </a>-- </li>-- <li class="dropdown-item dropright">-- <a class="dropdown-item" href="@@webRoot/account-tithes.html">-- My Tithes-- </a>-- </li>-- <li class="dropdown-item dropright">-- <a class="dropdown-item" href="@@webRoot/account-keys.html">-- Manage Payment Keys-- </a>-- </li>-- <li class="dropdown-item dropright">-- <a class="dropdown-item" href="@@webRoot/account-billing.html">-- Billing Center-- </a>-- </li>-- -->-- </ul>-- </li>-- <li class="nav-item dropdown">-- <a class="nav-link dropdown-toggle" id="navbarDocumentation" data-toggle="dropdown" href="#" aria-haspopup="true" aria-expanded="false">-- Documentation-- </a>-- <div class="dropdown-menu dropdown-menu-md" aria-labelledby="navbarDocumentation">-- <div class="list-group list-group-flush">-- <a class="list-group-item" href="@@webRoot/docs/index.html">---- <!-- Icon -->-- <div class="icon icon-sm text-primary">-- @@include("../assets/img/icons/duotone-icons/General/Clipboard.svg")-- </div>---- <!-- Content -->-- <div class="ml-4">---- <!-- Heading -->-- <h6 class="font-weight-bold text-uppercase text-primary mb-0">-- Documentation-- </h6>---- <!-- Text -->-- <p class="font-size-sm text-gray-700 mb-0">-- CLI & API user guide-- </p>---- </div>---- </a>-- <a class="list-group-item" href="@@webRoot/faq.html">---- <!-- Icon -->-- <div class="icon icon-sm text-primary">-- @@include("../assets/img/icons/duotone-icons/Code/Question-circle.svg")-- </div>---- <!-- Content -->-- <div class="ml-4">---- <!-- Heading -->-- <h6 class="font-weight-bold text-uppercase text-primary mb-0">-- FAQ-- </h6>---- <!-- Text -->-- <p class="font-size-sm text-gray-700 mb-0">-- Common problems & solutions-- </p>---- </div>---- </a>-- <a class="list-group-item" href="https://discord.gg/wbhCGjw" target="_blank">---- <!-- Icon -->-- <div class="icon icon-sm text-primary">-- @@include("../assets/img/icons/social/discord.svg")-- </div>---- <!-- Content -->-- <div class="ml-4">---- <!-- Heading -->-- <h6 class="font-weight-bold text-uppercase text-primary mb-0">-- Community-- </h6>---- <!-- Text -->-- <p class="font-size-sm text-gray-700 mb-0">-- Join our Discord chat-- </p>---- </div>---- </a>-- <!---- <a class="list-group-item" href="@@webRoot/docs/changelog.html">---- <div class="icon icon-sm text-primary">-- @@include("../assets/img/icons/duotone-icons/Files/File.svg")-- </div>---- <div class="ml-4">---- <h6 class="font-weight-bold text-uppercase text-primary mb-0">-- Changelog-- </h6>---- <p class="font-size-sm text-gray-700 mb-0">-- Project history-- </p>-- </div>-- </a>-- -->-- </div>-- </div>-- </li>-- </ul>