205 lines
6.5 KiB
JavaScript
Executable File

import React from "react"
import * as antd from "antd"
import debounce from "lodash/debounce"
import { Translation } from "react-i18next"
import { ActionsBar } from "components"
import { Icons } from "components/Icons"
import "./index.less"
export const EditAccountField = ({ id, component, props, header, handleChange, delay, defaultValue, allowEmpty }) => {
const [currentValue, setCurrentValue] = React.useState(defaultValue)
const [emittedValue, setEmittedValue] = React.useState(null)
const debouncedHandleChange = React.useCallback(
debounce((value) => handleChange({ id, value }), delay ?? 300),
[],
)
const handleDiscard = (event) => {
if (typeof event !== "undefined") {
event.target.blur()
}
setCurrentValue(defaultValue)
handleChange({ id, value: defaultValue })
}
React.useEffect(() => {
debouncedHandleChange(currentValue)
}, [emittedValue])
const onChange = (event) => {
event.persist()
let { value } = event.target
if (typeof value === "string") {
if (value.length === 0) {
// if is not allowed to be empty, discard modifications
if (!allowEmpty) {
return handleDiscard(event)
}
}
}
setCurrentValue(value)
setEmittedValue(value)
}
const handleKeyDown = (event) => {
if (event.keyCode === 27) {
// "escape" pressed, reset to default value
handleDiscard(event)
}
}
const RenderComponent = component
return (
<div key={id} className="edit_account_field">
{header ? header : null}
<RenderComponent {...props} value={currentValue} id={id} onChange={onChange} onKeyDown={handleKeyDown} />
</div>
)
}
export default class UserDataManager extends React.Component {
state = {
data: this.props.user,
changes: [],
loading: false,
}
api = window.app.api.withEndpoints("main")
componentDidMount = async () => {
if (!this.props.user && this.props.userId) {
// TODO: Fetch from API
}
}
handleSave = async () => {
if (!Array.isArray(this.state.changes)) {
antd.message.error("Something went wrong")
console.error("Changes should be an array")
return false
}
await this.setState({ loading: true })
const update = {}
this.state.changes.forEach((change) => {
update[change.id] = change.value
})
const result = await this.api.post.updateUser({ _id: this.state.data._id, update }).catch((err) => {
antd.message.error(err.message)
console.error(err)
return false
})
await this.setState({ changes: [], loading: false })
if (typeof this.props.onSave === "function") {
await this.props.onSave(this.state.changes)
}
if (result) {
if (typeof this.props.handleDone === "function") {
this.props.handleDone(result)
}
}
}
handleChange = (event) => {
const { id, value } = event
let changes = [...this.state.changes]
changes = changes.filter((change) => change.id !== id)
if (this.state.data[id] !== value) {
changes.push({ id, value })
}
this.setState({ changes })
}
render() {
return (
<div className="edit_account">
<div className="edit_account_wrapper">
<div className="edit_account_category">
<h2>
<Icons.User /> Account information
</h2>
<EditAccountField
id="username"
defaultValue={this.state.data.username}
header={
<div>
<Icons.Tag /> Username
</div>
}
component={antd.Input}
props={{
placeholder: "Username",
disabled: true,
}}
handleChange={this.handleChange}
/>
<EditAccountField
id="fullName"
defaultValue={this.state.data.fullName}
header={
<div>
<Icons.User /> Name
</div>
}
component={antd.Input}
props={{
placeholder: "Your full name",
}}
handleChange={this.handleChange}
/>
<EditAccountField
id="email"
defaultValue={this.state.data.email}
header={
<div>
<Icons.Mail /> Email
</div>
}
component={antd.Input}
props={{
placeholder: "Your email address",
type: "email",
}}
handleChange={this.handleChange}
/>
</div>
</div>
<ActionsBar spaced>
<div>
{this.state.changes.length} <Translation>
{(t) => t("Changes")}
</Translation>
</div>
<div>
<antd.Button
type="primary"
loading={this.state.loading}
disabled={this.state.loading}
onClick={this.handleSave}
>
<Translation>
{(t) => t("Save")}
</Translation>
</antd.Button>
</div>
</ActionsBar>
</div>
)
}
}