Reimplement sign up form.

This commit is contained in:
Dominik Picheta 2018-05-11 16:15:13 +01:00
commit 01253244f7
5 changed files with 136 additions and 63 deletions

View file

@ -1,3 +1,4 @@
import options
type type
PostError* = object PostError* = object
errorFields*: seq[string] ## IDs of the fields with an error. errorFields*: seq[string] ## IDs of the fields with an error.
@ -7,6 +8,8 @@ when defined(js):
include karax/prelude include karax/prelude
import karax / [vstyles, kajax, kdom] import karax / [vstyles, kajax, kdom]
import karaxutils
proc renderError*(message: string): VNode = proc renderError*(message: string): VNode =
result = buildHtml(): result = buildHtml():
tdiv(class="empty error"): tdiv(class="empty error"):
@ -20,3 +23,21 @@ when defined(js):
a(href="https://github.com/nim-lang/nimforum/issues", target="_blank"): a(href="https://github.com/nim-lang/nimforum/issues", target="_blank"):
button(class="btn btn-primary"): button(class="btn btn-primary"):
text "Report issue" text "Report issue"
proc genFormField*(error: Option[PostError], name, label, typ: string,
isLast: bool): VNode =
let hasError =
not error.isNone and (
name in error.get().errorFields or
error.get().errorFields.len == 0)
result = buildHtml():
tdiv(class=class({"has-error": hasError}, "form-group")):
label(class="form-label", `for`=name):
text label
input(class="form-input", `type`="text", name=name)
if not error.isNone:
let e = error.get()
if (e.errorFields.len == 1 and e.errorFields[0] == name) or isLast:
p(class="form-input-hint"):
text e.message

View file

@ -9,7 +9,7 @@ when defined(js):
include karax/prelude include karax/prelude
import karax / [kajax] import karax / [kajax]
import login import login, signup
import karaxutils import karaxutils
from dom import setTimeout, window, document, getElementById, focus from dom import setTimeout, window, document, getElementById, focus
@ -21,6 +21,7 @@ when defined(js):
status: HttpCode status: HttpCode
lastUpdate: Time lastUpdate: Time
loginModal: LoginModal loginModal: LoginModal
signupModal: SignupModal
proc newState(): State proc newState(): State
var var
@ -33,7 +34,12 @@ when defined(js):
loading: false, loading: false,
status: Http200, status: Http200,
loginModal: newLoginModal( loginModal: newLoginModal(
() => (state.lastUpdate = fromUnix(0); getStatus()) () => (state.lastUpdate = fromUnix(0); getStatus()),
() => state.signupModal.show()
),
signupModal: newSignupModal(
() => (state.lastUpdate = fromUnix(0); getStatus()),
() => state.loginModal.show()
) )
) )
@ -57,37 +63,6 @@ when defined(js):
let uri = makeUri("status.json") let uri = makeUri("status.json")
ajaxGet(uri, @[], onStatus) ajaxGet(uri, @[], onStatus)
proc genSignUpModal(): VNode =
result = buildHtml():
tdiv(class="modal", id="signup-modal"):
a(href="#", class="modal-overlay", "aria-label"="close")
tdiv(class="modal-container"):
tdiv(class="modal-header"):
a(href="#", class="btn btn-clear float-right", "aria-label"="close")
tdiv(class="modal-title h5"):
text "Create a new account"
tdiv(class="modal-body"):
tdiv(class="content"):
form():
tdiv(class="form-group"):
label(class="form-label", `for`="email"):
text "Email"
input(class="form-input", `type`="text", name="email")
tdiv(class="form-group"):
label(class="form-label", `for`="regusername"):
text "Username"
input(class="form-input", `type`="text", name="username")
tdiv(class="form-group"):
label(class="form-label", `for`="regpassword"):
text "Password"
input(class="form-input", `type`="password", name="password")
tdiv(class="modal-footer"):
button(class="btn btn-primary"):
text "Create account"
a(href="#login-modal"):
button(class="btn"):
text "Log in"
proc renderHeader*(): VNode = proc renderHeader*(): VNode =
if state.data.isNone: if state.data.isNone:
getStatus() getStatus()
@ -107,10 +82,10 @@ when defined(js):
if state.loading: if state.loading:
tdiv(class="loading") tdiv(class="loading")
elif user.isNone: elif user.isNone:
a(href="#signup-modal", id="signup-btn"): button(class="btn btn-primary btn-sm",
button(class="btn btn-primary btn-sm"): onClick=(e: Event, n: VNode) => state.signupModal.show()):
italic(class="fas fa-user-plus") italic(class="fas fa-user-plus")
text " Sign up" text " Sign up"
button(class="btn btn-primary btn-sm", button(class="btn btn-primary btn-sm",
onClick=(e: Event, n: VNode) => state.loginModal.show()): onClick=(e: Event, n: VNode) => state.loginModal.show()):
italic(class="fas fa-sign-in-alt") italic(class="fas fa-sign-in-alt")
@ -121,4 +96,4 @@ when defined(js):
# Modals # Modals
render(state.loginModal) render(state.loginModal)
genSignUpModal() render(state.signupModal)

View file

@ -1,4 +1,4 @@
import strutils import strutils, options
import dom except window import dom except window
include karax/prelude include karax/prelude

View file

@ -12,6 +12,7 @@ when defined(js):
LoginModal* = ref object LoginModal* = ref object
shown: bool shown: bool
onLogIn: proc () onLogIn: proc ()
onSignUp: proc ()
error: Option[PostError] error: Option[PostError]
proc onLogInPost(httpStatus: int, response: kstring, state: LoginModal) = proc onLogInPost(httpStatus: int, response: kstring, state: LoginModal) =
@ -47,33 +48,16 @@ when defined(js):
state.shown = false state.shown = false
ev.preventDefault() ev.preventDefault()
proc newLoginModal*(onLogIn: proc ()): LoginModal = proc newLoginModal*(onLogIn, onSignUp: proc ()): LoginModal =
LoginModal( LoginModal(
shown: false, shown: false,
onLogIn: onLogIn onLogIn: onLogIn,
onSignUp: onSignUp
) )
proc show*(state: LoginModal) = proc show*(state: LoginModal) =
state.shown = true state.shown = true
proc genFormField(error: Option[PostError], name, label, typ: string,
isLast: bool): VNode =
let hasError =
not error.isNone and (
name in error.get().errorFields or
error.get().errorFields.len == 0)
result = buildHtml():
tdiv(class=class({"has-error": hasError}, "form-group")):
label(class="form-label", `for`=name):
text "Username"
input(class="form-input", `type`="text", name=name)
if not error.isNone:
let e = error.get()
if (e.errorFields.len == 1 and e.errorFields[0] == name) or isLast:
p(class="form-input-hint"):
text e.message
proc render*(state: LoginModal): VNode = proc render*(state: LoginModal): VNode =
result = buildHtml(): result = buildHtml():
tdiv(class=class({"active": state.shown}, "modal modal-sm"), tdiv(class=class({"active": state.shown}, "modal modal-sm"),
@ -104,6 +88,7 @@ when defined(js):
button(class="btn btn-primary", button(class="btn btn-primary",
onClick=(ev: Event, n: VNode) => onLogInClick(ev, n, state)): onClick=(ev: Event, n: VNode) => onLogInClick(ev, n, state)):
text "Log in" text "Log in"
a(href="#signup-modal"): button(class="btn",
button(class="btn"): onClick=(ev: Event, n: VNode) =>
text "Create account" (state.onSignUp(); state.shown = false)):
text "Create account"

92
redesign/signup.nim Normal file
View file

@ -0,0 +1,92 @@
when defined(js):
import sugar, httpcore, options, json
import dom except Event
include karax/prelude
import karax / [kajax, kdom]
import error
import karaxutils
type
SignupModal* = ref object
shown: bool
onSignUp, onLogIn: proc ()
error: Option[PostError]
proc onSignUpPost(httpStatus: int, response: kstring, state: SignupModal) =
let status = httpStatus.HttpCode
if status == Http200:
state.shown = false
state.onSignUp()
else:
# TODO: Karax should pass the content-type...
try:
let parsed = parseJson($response)
let error = to(parsed, PostError)
state.error = some(error)
except:
kout(getCurrentExceptionMsg().cstring)
state.error = some(PostError(
errorFields: @[],
message: "Unknown error occurred."
))
proc onSignUpClick(ev: Event, n: VNode, state: SignupModal) =
state.error = none[PostError]()
let uri = makeUri("signup")
let form = dom.document.getElementById("signup-form")
# TODO: This is a hack, karax should support this.
let formData = newFormData(form)
ajaxPost(uri, @[], cast[cstring](formData),
(s: int, r: kstring) => onSignUpPost(s, r, state))
proc onClose(ev: Event, n: VNode, state: SignupModal) =
state.shown = false
ev.preventDefault()
proc newSignupModal*(onSignUp, onLogIn: proc ()): SignupModal =
SignupModal(
shown: false,
onLogIn: onLogIn,
onSignUp: onSignUp
)
proc show*(state: SignupModal) =
state.shown = true
proc render*(state: SignupModal): VNode =
result = buildHtml():
tdiv(class=class({"active": state.shown}, "modal modal-sm"),
id="signup-modal"):
a(href="", class="modal-overlay", "aria-label"="close",
onClick=(ev: Event, n: VNode) => onClose(ev, n, state))
tdiv(class="modal-container"):
tdiv(class="modal-header"):
a(href="", class="btn btn-clear float-right",
"aria-label"="close",
onClick=(ev: Event, n: VNode) => onClose(ev, n, state))
tdiv(class="modal-title h5"):
text "Create a new account"
tdiv(class="modal-body"):
tdiv(class="content"):
form(id="signup-form"):
genFormField(state.error, "email", "Email", "email", false)
genFormField(state.error, "username", "Username", "text", false)
genFormField(
state.error,
"password",
"Password",
"password",
true
)
tdiv(class="modal-footer"):
button(class="btn btn-primary",
onClick=(ev: Event, n: VNode) => onSignUpClick(ev, n, state)):
text "Create account"
button(class="btn",
onClick=(ev: Event, n: VNode) =>
(state.onLogIn(); state.shown = false)):
text "Log in"