Skip to content

Commit

Permalink
add change password using separate service
Browse files Browse the repository at this point in the history
  • Loading branch information
danieleguido committed Dec 16, 2024
1 parent b70d047 commit 9a609ba
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 5 deletions.
120 changes: 120 additions & 0 deletions src/components/ChangePasswordForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { BadRequest, type FeathersError } from "@feathersjs/errors"
import React, { useEffect, useRef, useState } from "react"
import { Form } from "react-bootstrap"
import ErrorManager, { type BadRequestData } from "./ErrorManager"
import { FloppyDiskArrowIn } from "iconoir-react"

export type ChangePasswordFormPayload = {
currentPassword: string
password: string
verifyPassword: string
}

export interface ChangePasswordFormProps {
className?: string
onSubmit: (payload: ChangePasswordFormPayload) => void
error?: FeathersError | null
}

const ChangePasswordForm: React.FC<ChangePasswordFormProps> = ({
className,
onSubmit,
error,
}) => {
const delayTimerRef = useRef<NodeJS.Timeout | null>(null)
const [formError, setFormError] = useState<Error | null>(null)

const formPayload = useRef<ChangePasswordFormPayload>({
currentPassword: "",
password: "",
verifyPassword: "",
})

const handleOnSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
console.info("[ChangePasswordForm] @handleOnSubmit")
const errorsAsData: { [key: string]: BadRequestData } = {}
if (formPayload.current.password !== formPayload.current.verifyPassword) {
errorsAsData.verifyPassword = {
label: "Verify password",
message: "The passwords you entered don't match. Please try again.",
}
}
if (Object.keys(errorsAsData).length > 0) {
setFormError(new BadRequest("Please check your entries.", errorsAsData))
return false
}
onSubmit(formPayload.current)
}

const updateValue = (key: keyof ChangePasswordFormPayload, value: string) => {
formPayload.current[key] = value
console.info("[RegisterForm] @updatePreview", key, value)
// handpick the fields to preview
delayTimerRef.current = setTimeout(() => {
setFormError(null)
}, 400)
}

console.info("[ChangePasswordForm] @render", { error })

useEffect(() => {
return () => {
if (delayTimerRef.current) {
clearTimeout(delayTimerRef.current)
}
}
}, [])

return (
<>
<Form
onSubmit={handleOnSubmit}
className={`ChangePasswordForm ${className}`}
>
<ErrorManager error={error || formError} />

<Form.Group
className="mb-3"
controlId="ModalChangePasswordorm.password"
>
<Form.Label className="font-weight-bold">Current Password</Form.Label>
<Form.Control
onChange={(e) => updateValue("currentPassword", e.target.value)}
type="password"
/>
</Form.Group>
<Form.Group className="mb-3" controlId="ModalChangePassword.password">
<Form.Label className="font-weight-bold">New Password</Form.Label>
<Form.Control
onChange={(e) => updateValue("password", e.target.value)}
type="password"
/>
</Form.Group>
<Form.Group
className="mb-3"
controlId="ModalChangePassword.verifyPassword"
>
<Form.Label className="font-weight-bold">
Verify New Password
</Form.Label>
<Form.Control
onChange={(e) => updateValue("verifyPassword", e.target.value)}
type="password"
/>
</Form.Group>
<button type="submit" className="btn btn-primary btn-lg px-4">
<FloppyDiskArrowIn /> <span className="ms-2">Register</span>
</button>
</Form>

<p className="mt-2">
Any Questions? <br />
Contact us at{" "}
<a href="mailto:[email protected]">[email protected]</a>
</p>
</>
)
}

export default ChangePasswordForm
53 changes: 53 additions & 0 deletions src/components/ChangePasswordModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Col, Container, Form, Modal, Row } from "react-bootstrap"
import { BrowserViewChangePassword } from "../constants"
import { useBrowserStore } from "../store"
import Alert from "./Alert"
import { useRef, useState } from "react"
import ChangePasswordForm, {
type ChangePasswordFormPayload,
} from "./ChangePasswordForm"
import type { FeathersError } from "@feathersjs/errors"
import { changePasswordService } from "../services"

const ChangePassword = () => {
const view = useBrowserStore((state) => state.view)
const setView = useBrowserStore((state) => state.setView)
const [error, setError] = useState<FeathersError | null>(null)

const handleOnSubmit = (payload: ChangePasswordFormPayload) => {
console.info("[ChangePasswordModal] @handleOnSubmit", payload)
changePasswordService
.create({
password: payload.password,
currentPassword: payload.currentPassword,
})
.then((data) => {
console.info(
"[ChangePasswordModal] Password changed successfully. data:",
data
)
setView(null)
})
.catch((err: FeathersError) => {
setError(err)
console.error("[ChangePasswordModal] create", err.message, err.data)
})
}

return (
<Modal
centered
show={view === BrowserViewChangePassword}
onHide={() => setView(null)}
>
<Modal.Header closeButton>
<Modal.Title>Change Password</Modal.Title>
</Modal.Header>
<Modal.Body className="p-3">
<ChangePasswordForm onSubmit={handleOnSubmit} error={error} />
</Modal.Body>
</Modal>
)
}

export default ChangePassword
4 changes: 3 additions & 1 deletion src/components/Modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ import LoginModal from "./LoginModal"
import RegisterModal from "./RegisterModal"
import ProfileModal from "./ProfileModal"
import TermsOfUseModal from "./TermsOfUseModal"
import ChangePasswordModal from "./ChangePasswordModal"

const Modals: React.FC<{ termsOfuseContent?: string }> = ({
termsOfuseContent='',
termsOfuseContent = "",
}) => {
return (
<div className="Modals">
<LoginModal />
<RegisterModal />
<ProfileModal />
<ChangePasswordModal />
<ConfirmRegistrationModal />
<TermsOfUseModal content={termsOfuseContent} autoOpenAfterDelay={false} />
</div>
Expand Down
15 changes: 12 additions & 3 deletions src/components/UserArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { userService } from "../services"
import { forwardRef, useEffect } from "react"
import { PageDown } from "iconoir-react"
import {
BrowserViewChangePassword,
BrowserViewLogin,
BrowserViewProfile,
BrowserViewRegister,
Expand Down Expand Up @@ -91,13 +92,21 @@ const UserArea = () => {
<Dropdown.Item onClick={() => setView(BrowserViewProfile)}>
Profile
</Dropdown.Item>
<Dropdown.Item href="/datalab/datasets">Datasets</Dropdown.Item>
<Dropdown.Item onClick={() => setView(BrowserViewTermsOfUse)}>
Terms Of Use
<Dropdown.Item onClick={() => setView(BrowserViewChangePassword)}>
Change Password
</Dropdown.Item>
<Dropdown.Item onClick={logout}>Log out</Dropdown.Item>
{/* add separator */}
<Dropdown.Divider />
{/* add separator */}
<Dropdown.Divider />
<Dropdown.Item href="/datalab/corpus-overview">
Corpus Overview
</Dropdown.Item>
<Dropdown.Item onClick={() => setView(BrowserViewTermsOfUse)}>
Terms Of Use
</Dropdown.Item>

<Dropdown.Item
target="_blank"
href="https://join.slack.com/t/impresso-community/shared_invite/enQtNTg5MzY2NDg2NTAyLTdiMmI2ZWU5ZjliNGNjN2M4NTgxM2UzOTQyYTkxYWU4MTgwN2I1MzQxMzg3N2Y0NGU3OGFjMzFmMGIyNGRlZmQ"
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,12 @@ export const BrowserViewRegister = "signup"
export const BrowserViewConfirmRegistration = "confirm-registration"
export const BrowserViewTermsOfUse = "terms-of-use"
export const BrowserViewProfile = "profile"
export const BrowserViewChangePassword = "change-password"
export const BrowserViews: string[] = [
BrowserViewLogin,
BrowserViewRegister,
BrowserViewProfile,
BrowserViewChangePassword,
]

export const BrowserWsStatusIdle = "idle"
Expand Down
1 change: 1 addition & 0 deletions src/services.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,6 @@ socket.on("reconnect", (attemptNumber) => {
export const versionService = app.service("version")
export const userService = app.service("me")
export const usersService = app.service("users")
export const changePasswordService = app.service("change-password")
export const termsOfUseService = app.service("terms-of-use")
export const loginService = app.service("authentication")
2 changes: 1 addition & 1 deletion src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ hr {
}
a.dropdown-item {
position: relative;
display: block;
display: inline-block;
width: auto;
}
a.dropdown-item::after {
Expand Down

0 comments on commit 9a609ba

Please sign in to comment.