156 lines
5.1 KiB
Nim
156 lines
5.1 KiB
Nim
when defined(js):
|
|
import sugar, httpcore, options, json
|
|
import dom except Event, KeyboardEvent
|
|
import jsffi except `&`
|
|
|
|
include karax/prelude
|
|
import karax / [kajax, kdom]
|
|
|
|
import error
|
|
import karaxutils
|
|
|
|
type
|
|
ResetPassword* = ref object
|
|
loading: bool
|
|
status: HttpCode
|
|
error: Option[PostError]
|
|
newPassword: kstring
|
|
|
|
proc newResetPassword*(): ResetPassword =
|
|
ResetPassword(
|
|
status: Http200,
|
|
newPassword: ""
|
|
)
|
|
|
|
proc onPassChange(e: Event, n: VNode, state: ResetPassword) =
|
|
state.newPassword = n.value
|
|
|
|
proc onPost(httpStatus: int, response: kstring, state: ResetPassword) =
|
|
postFinished:
|
|
navigateTo(makeUri("/resetPassword/success"))
|
|
|
|
proc onSetClick(
|
|
ev: Event, n: VNode,
|
|
state: ResetPassword
|
|
) =
|
|
state.loading = true
|
|
state.error = none[PostError]()
|
|
|
|
let uri = makeUri("resetPassword", ("newPassword", $state.newPassword))
|
|
ajaxPost(uri, @[], "",
|
|
(s: int, r: kstring) => onPost(s, r, state))
|
|
|
|
proc render*(state: ResetPassword): VNode =
|
|
if state.loading:
|
|
return buildHtml(tdiv(class="loading"))
|
|
|
|
result = buildHtml():
|
|
section(class="container grid-xl"):
|
|
tdiv(id="resetpassword"):
|
|
tdiv(class="title"):
|
|
p(): text "Reset Password"
|
|
tdiv(class="content"):
|
|
label(class="form-label", `for`="password"):
|
|
text "Password"
|
|
input(class="form-input", `type`="password", name="password",
|
|
placeholder="Type your new password here",
|
|
oninput=(e: Event, n: VNode) => onPassChange(e, n, state))
|
|
if state.error.isSome():
|
|
p(class="text-error"):
|
|
text state.error.get().message
|
|
tdiv(class="footer"):
|
|
button(class=class(
|
|
{"loading": state.loading},
|
|
"btn btn-primary"
|
|
),
|
|
onClick=(ev: Event, n: VNode) =>
|
|
(onSetClick(ev, n, state))):
|
|
text "Set password"
|
|
|
|
|
|
type
|
|
ResetPasswordModal* = ref object
|
|
shown: bool
|
|
loading: bool
|
|
error: Option[PostError]
|
|
sent: bool
|
|
|
|
proc onPost(httpStatus: int, response: kstring, state: ResetPasswordModal) =
|
|
postFinished:
|
|
state.sent = true
|
|
|
|
proc onClick(ev: Event, n: VNode, state: ResetPasswordModal) =
|
|
state.loading = true
|
|
state.error = none[PostError]()
|
|
|
|
let uri = makeUri("sendResetPassword")
|
|
let form = dom.document.getElementById("resetpassword-form")
|
|
# TODO: This is a hack, karax should support this.
|
|
let formData = newFormData(form)
|
|
ajaxPost(uri, @[], formData.to(cstring),
|
|
(s: int, r: kstring) => onPost(s, r, state))
|
|
|
|
ev.preventDefault()
|
|
|
|
proc onClose(ev: Event, n: VNode, state: ResetPasswordModal) =
|
|
state.shown = false
|
|
ev.preventDefault()
|
|
|
|
proc newResetPasswordModal*(): ResetPasswordModal =
|
|
ResetPasswordModal(
|
|
shown: false
|
|
)
|
|
|
|
proc show*(state: ResetPasswordModal) =
|
|
state.shown = true
|
|
|
|
proc onKeyDown(e: Event, n: VNode, state: ResetPasswordModal) =
|
|
let event = cast[KeyboardEvent](e)
|
|
if event.key == "Enter":
|
|
onClick(e, n, state)
|
|
|
|
proc render*(state: ResetPasswordModal,
|
|
recaptchaSiteKey: Option[string]): VNode =
|
|
result = buildHtml():
|
|
tdiv(class=class({"active": state.shown}, "modal"),
|
|
id="resetpassword-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 "Reset your password"
|
|
tdiv(class="modal-body"):
|
|
tdiv(class="content"):
|
|
form(id="resetpassword-form",
|
|
onKeyDown=(ev: Event, n: VNode) => onKeyDown(ev, n, state)):
|
|
genFormField(
|
|
state.error,
|
|
"email",
|
|
"Enter your email or username and we will send you a " &
|
|
"password reset email.",
|
|
"text",
|
|
true,
|
|
placeholder="Username or email"
|
|
)
|
|
if recaptchaSiteKey.isSome:
|
|
tdiv(id="recaptcha"):
|
|
tdiv(class="g-recaptcha",
|
|
"data-sitekey"=recaptchaSiteKey.get())
|
|
script(src="https://www.google.com/recaptcha/api.js")
|
|
tdiv(class="modal-footer"):
|
|
if state.sent:
|
|
span(class="text-success"):
|
|
italic(class="fas fa-check-circle")
|
|
text " Sent"
|
|
else:
|
|
button(class=class(
|
|
{"loading": state.loading},
|
|
"btn btn-primary"
|
|
),
|
|
`type`="button",
|
|
onClick=(ev: Event, n: VNode) => onClick(ev, n, state)):
|
|
text "Reset password"
|