Reimplement sign up form.
This commit is contained in:
parent
f9efbe04d3
commit
01253244f7
5 changed files with 136 additions and 63 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import options
|
||||
type
|
||||
PostError* = object
|
||||
errorFields*: seq[string] ## IDs of the fields with an error.
|
||||
|
|
@ -7,6 +8,8 @@ when defined(js):
|
|||
include karax/prelude
|
||||
import karax / [vstyles, kajax, kdom]
|
||||
|
||||
import karaxutils
|
||||
|
||||
proc renderError*(message: string): VNode =
|
||||
result = buildHtml():
|
||||
tdiv(class="empty error"):
|
||||
|
|
@ -19,4 +22,22 @@ when defined(js):
|
|||
tdiv(class="empty-action"):
|
||||
a(href="https://github.com/nim-lang/nimforum/issues", target="_blank"):
|
||||
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
|
||||
|
|
@ -9,7 +9,7 @@ when defined(js):
|
|||
include karax/prelude
|
||||
import karax / [kajax]
|
||||
|
||||
import login
|
||||
import login, signup
|
||||
import karaxutils
|
||||
|
||||
from dom import setTimeout, window, document, getElementById, focus
|
||||
|
|
@ -21,6 +21,7 @@ when defined(js):
|
|||
status: HttpCode
|
||||
lastUpdate: Time
|
||||
loginModal: LoginModal
|
||||
signupModal: SignupModal
|
||||
|
||||
proc newState(): State
|
||||
var
|
||||
|
|
@ -33,7 +34,12 @@ when defined(js):
|
|||
loading: false,
|
||||
status: Http200,
|
||||
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")
|
||||
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 =
|
||||
if state.data.isNone:
|
||||
getStatus()
|
||||
|
|
@ -107,10 +82,10 @@ when defined(js):
|
|||
if state.loading:
|
||||
tdiv(class="loading")
|
||||
elif user.isNone:
|
||||
a(href="#signup-modal", id="signup-btn"):
|
||||
button(class="btn btn-primary btn-sm"):
|
||||
italic(class="fas fa-user-plus")
|
||||
text " Sign up"
|
||||
button(class="btn btn-primary btn-sm",
|
||||
onClick=(e: Event, n: VNode) => state.signupModal.show()):
|
||||
italic(class="fas fa-user-plus")
|
||||
text " Sign up"
|
||||
button(class="btn btn-primary btn-sm",
|
||||
onClick=(e: Event, n: VNode) => state.loginModal.show()):
|
||||
italic(class="fas fa-sign-in-alt")
|
||||
|
|
@ -121,4 +96,4 @@ when defined(js):
|
|||
# Modals
|
||||
render(state.loginModal)
|
||||
|
||||
genSignUpModal()
|
||||
render(state.signupModal)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import strutils
|
||||
import strutils, options
|
||||
import dom except window
|
||||
|
||||
include karax/prelude
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ when defined(js):
|
|||
LoginModal* = ref object
|
||||
shown: bool
|
||||
onLogIn: proc ()
|
||||
onSignUp: proc ()
|
||||
error: Option[PostError]
|
||||
|
||||
proc onLogInPost(httpStatus: int, response: kstring, state: LoginModal) =
|
||||
|
|
@ -47,33 +48,16 @@ when defined(js):
|
|||
state.shown = false
|
||||
ev.preventDefault()
|
||||
|
||||
proc newLoginModal*(onLogIn: proc ()): LoginModal =
|
||||
proc newLoginModal*(onLogIn, onSignUp: proc ()): LoginModal =
|
||||
LoginModal(
|
||||
shown: false,
|
||||
onLogIn: onLogIn
|
||||
onLogIn: onLogIn,
|
||||
onSignUp: onSignUp
|
||||
)
|
||||
|
||||
proc show*(state: LoginModal) =
|
||||
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 =
|
||||
result = buildHtml():
|
||||
tdiv(class=class({"active": state.shown}, "modal modal-sm"),
|
||||
|
|
@ -104,6 +88,7 @@ when defined(js):
|
|||
button(class="btn btn-primary",
|
||||
onClick=(ev: Event, n: VNode) => onLogInClick(ev, n, state)):
|
||||
text "Log in"
|
||||
a(href="#signup-modal"):
|
||||
button(class="btn"):
|
||||
text "Create account"
|
||||
button(class="btn",
|
||||
onClick=(ev: Event, n: VNode) =>
|
||||
(state.onSignUp(); state.shown = false)):
|
||||
text "Create account"
|
||||
92
redesign/signup.nim
Normal file
92
redesign/signup.nim
Normal 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"
|
||||
Loading…
Add table
Add a link
Reference in a new issue