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
|
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"):
|
||||||
|
|
@ -19,4 +22,22 @@ when defined(js):
|
||||||
tdiv(class="empty-action"):
|
tdiv(class="empty-action"):
|
||||||
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
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import strutils
|
import strutils, options
|
||||||
import dom except window
|
import dom except window
|
||||||
|
|
||||||
include karax/prelude
|
include karax/prelude
|
||||||
|
|
|
||||||
|
|
@ -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
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