mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-04 05:10:19 +08:00
feat: refactor agreement modal and create folders to classify components (#1686)
* refactor: refactor agreement modal and create folders to classify components * fix: i18 * fix: i18 * fix: i18n
This commit is contained in:
126
web/src/common/modal/AgreementModal.js
Normal file
126
web/src/common/modal/AgreementModal.js
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import {Checkbox, Form, Modal} from "antd";
|
||||
import i18next from "i18next";
|
||||
import React, {useEffect, useState} from "react";
|
||||
|
||||
export const AgreementModal = (props) => {
|
||||
const {open, onOk, onCancel, application} = props;
|
||||
const [doc, setDoc] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
getTermsOfUseContent(application.termsOfUseUrl).then((data) => {
|
||||
setDoc(data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
<Modal
|
||||
title={i18next.t("signup:Terms of Use")}
|
||||
open={open}
|
||||
width={"55vw"}
|
||||
closable={false}
|
||||
okText={i18next.t("signup:Accept")}
|
||||
cancelText={i18next.t("signup:Decline")}
|
||||
onOk={onOk}
|
||||
onCancel={onCancel}
|
||||
>
|
||||
<iframe title={"terms"} style={{border: 0, width: "100%", height: "60vh"}} srcDoc={doc} />
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
function getTermsOfUseContent(url) {
|
||||
return fetch(url, {
|
||||
method: "GET",
|
||||
}).then(r => r.text());
|
||||
}
|
||||
|
||||
export function isAgreementRequired(application) {
|
||||
if (application) {
|
||||
const agreementItem = application.signupItems.find(item => item.name === "Agreement");
|
||||
if (!agreementItem || agreementItem.rule === "None" || !agreementItem.rule) {
|
||||
return false;
|
||||
}
|
||||
if (agreementItem.required) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function initDefaultValue(application) {
|
||||
const agreementItem = application.signupItems.find(item => item.name === "Agreement");
|
||||
|
||||
return isAgreementRequired(application) && agreementItem.rule === "Signin (Default True)";
|
||||
}
|
||||
|
||||
export function renderAgreementFormItem(application, required, layout, ths) {
|
||||
return (<React.Fragment>
|
||||
<Form.Item
|
||||
name="agreement"
|
||||
key="agreement"
|
||||
valuePropName="checked"
|
||||
rules={[
|
||||
{
|
||||
required: required,
|
||||
},
|
||||
() => ({
|
||||
validator: (_, value) => {
|
||||
if (!required) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
return Promise.reject(i18next.t("signup:Please accept the agreement!"));
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
}),
|
||||
]
|
||||
}
|
||||
{...layout}
|
||||
initialValue={initDefaultValue(application)}
|
||||
>
|
||||
<Checkbox style={{float: "left"}}>
|
||||
{i18next.t("signup:Accept")}
|
||||
<a onClick={() => {
|
||||
ths.setState({
|
||||
isTermsOfUseVisible: true,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{i18next.t("signup:Terms of Use")}
|
||||
</a>
|
||||
</Checkbox>
|
||||
</Form.Item>
|
||||
<AgreementModal application={application} layout={layout} open={ths.state.isTermsOfUseVisible}
|
||||
onOk={() => {
|
||||
ths.form.current.setFieldsValue({agreement: true});
|
||||
ths.setState({
|
||||
isTermsOfUseVisible: false,
|
||||
});
|
||||
}}
|
||||
onCancel={() => {
|
||||
ths.form.current.setFieldsValue({agreement: false});
|
||||
ths.setState({
|
||||
isTermsOfUseVisible: false,
|
||||
});
|
||||
}} />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
172
web/src/common/modal/CaptchaModal.js
Normal file
172
web/src/common/modal/CaptchaModal.js
Normal file
@ -0,0 +1,172 @@
|
||||
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import {Button, Col, Input, Modal, Row} from "antd";
|
||||
import i18next from "i18next";
|
||||
import React, {useEffect} from "react";
|
||||
import * as UserBackend from "../../backend/UserBackend";
|
||||
import {CaptchaWidget} from "../CaptchaWidget";
|
||||
import {SafetyOutlined} from "@ant-design/icons";
|
||||
|
||||
export const CaptchaModal = (props) => {
|
||||
const {owner, name, visible, onOk, onCancel, isCurrentProvider} = props;
|
||||
|
||||
const [captchaType, setCaptchaType] = React.useState("none");
|
||||
const [clientId, setClientId] = React.useState("");
|
||||
const [clientSecret, setClientSecret] = React.useState("");
|
||||
const [subType, setSubType] = React.useState("");
|
||||
const [clientId2, setClientId2] = React.useState("");
|
||||
const [clientSecret2, setClientSecret2] = React.useState("");
|
||||
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [captchaImg, setCaptchaImg] = React.useState("");
|
||||
const [captchaToken, setCaptchaToken] = React.useState("");
|
||||
|
||||
const defaultInputRef = React.useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
loadCaptcha();
|
||||
} else {
|
||||
handleCancel();
|
||||
setOpen(false);
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
const handleOk = () => {
|
||||
onOk?.(captchaType, captchaToken, clientSecret);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setCaptchaToken("");
|
||||
onCancel?.();
|
||||
};
|
||||
|
||||
const loadCaptcha = () => {
|
||||
UserBackend.getCaptcha(owner, name, isCurrentProvider).then((res) => {
|
||||
if (res.type === "none") {
|
||||
handleOk();
|
||||
} else if (res.type === "Default") {
|
||||
setOpen(true);
|
||||
setClientSecret(res.captchaId);
|
||||
setCaptchaImg(res.captchaImage);
|
||||
setCaptchaType("Default");
|
||||
} else {
|
||||
setOpen(true);
|
||||
setCaptchaType(res.type);
|
||||
setClientId(res.clientId);
|
||||
setClientSecret(res.clientSecret);
|
||||
setSubType(res.subType);
|
||||
setClientId2(res.clientId2);
|
||||
setClientSecret2(res.clientSecret2);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const renderDefaultCaptcha = () => {
|
||||
return (
|
||||
<Col style={{textAlign: "center"}}>
|
||||
<div style={{display: "inline-block"}}>
|
||||
<Row
|
||||
style={{
|
||||
backgroundImage: `url('data:image/png;base64,${captchaImg}')`,
|
||||
backgroundRepeat: "no-repeat",
|
||||
height: "80px",
|
||||
width: "200px",
|
||||
borderRadius: "5px",
|
||||
border: "1px solid #ccc",
|
||||
marginBottom: "20px",
|
||||
}}
|
||||
/>
|
||||
<Row>
|
||||
<Input
|
||||
ref={defaultInputRef}
|
||||
style={{width: "200px"}}
|
||||
value={captchaToken}
|
||||
prefix={<SafetyOutlined />}
|
||||
placeholder={i18next.t("general:Captcha")}
|
||||
onPressEnter={handleOk}
|
||||
onChange={(e) => setCaptchaToken(e.target.value)}
|
||||
/>
|
||||
</Row>
|
||||
</div>
|
||||
</Col>
|
||||
);
|
||||
};
|
||||
|
||||
const onChange = (token) => {
|
||||
setCaptchaToken(token);
|
||||
};
|
||||
|
||||
const renderCaptcha = () => {
|
||||
if (captchaType === "Default") {
|
||||
return renderDefaultCaptcha();
|
||||
} else {
|
||||
return (
|
||||
<Col>
|
||||
<Row>
|
||||
<CaptchaWidget
|
||||
captchaType={captchaType}
|
||||
subType={subType}
|
||||
siteKey={clientId}
|
||||
clientSecret={clientSecret}
|
||||
onChange={onChange}
|
||||
clientId2={clientId2}
|
||||
clientSecret2={clientSecret2}
|
||||
/>
|
||||
</Row>
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const renderFooter = () => {
|
||||
let isOkDisabled = false;
|
||||
if (captchaType === "Default") {
|
||||
const regex = /^\d{5}$/;
|
||||
if (!regex.test(captchaToken)) {
|
||||
isOkDisabled = true;
|
||||
}
|
||||
} else if (captchaToken === "") {
|
||||
isOkDisabled = true;
|
||||
}
|
||||
|
||||
return [
|
||||
<Button key="cancel" onClick={handleCancel}>{i18next.t("general:Cancel")}</Button>,
|
||||
<Button key="ok" disabled={isOkDisabled} type="primary" onClick={handleOk}>{i18next.t("general:OK")}</Button>,
|
||||
];
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
closable={false}
|
||||
maskClosable={false}
|
||||
destroyOnClose={true}
|
||||
title={i18next.t("general:Captcha")}
|
||||
open={open}
|
||||
okText={i18next.t("general:OK")}
|
||||
cancelText={i18next.t("general:Cancel")}
|
||||
width={350}
|
||||
footer={renderFooter()}
|
||||
onCancel={handleCancel}
|
||||
onOk={handleOk}
|
||||
>
|
||||
<div style={{marginTop: "20px", marginBottom: "50px"}}>
|
||||
{
|
||||
renderCaptcha()
|
||||
}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
190
web/src/common/modal/CropperDivModal.js
Normal file
190
web/src/common/modal/CropperDivModal.js
Normal file
@ -0,0 +1,190 @@
|
||||
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React, {useEffect, useState} from "react";
|
||||
import Cropper from "react-cropper";
|
||||
import "cropperjs/dist/cropper.css";
|
||||
import * as Setting from "../../Setting";
|
||||
import {Button, Col, Modal, Row, Select} from "antd";
|
||||
import i18next from "i18next";
|
||||
import * as ResourceBackend from "../../backend/ResourceBackend";
|
||||
|
||||
export const CropperDivModal = (props) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [options, setOptions] = useState([]);
|
||||
const [image, setImage] = useState("");
|
||||
const [cropper, setCropper] = useState();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [confirmLoading, setConfirmLoading] = useState(false);
|
||||
const {title} = props;
|
||||
const {user} = props;
|
||||
const {buttonText} = props;
|
||||
const {organization} = props;
|
||||
let uploadButton;
|
||||
|
||||
const onChange = (e) => {
|
||||
e.preventDefault();
|
||||
let files;
|
||||
if (e.dataTransfer) {
|
||||
files = e.dataTransfer.files;
|
||||
} else if (e.target) {
|
||||
files = e.target.files;
|
||||
}
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
setImage(reader.result);
|
||||
};
|
||||
if (!(files[0] instanceof Blob)) {
|
||||
return;
|
||||
}
|
||||
reader.readAsDataURL(files[0]);
|
||||
};
|
||||
|
||||
const uploadAvatar = () => {
|
||||
cropper.getCroppedCanvas().toBlob(blob => {
|
||||
if (blob === null) {
|
||||
Setting.showMessage("error", "You must select a picture first!");
|
||||
return false;
|
||||
}
|
||||
// Setting.showMessage("success", "uploading...");
|
||||
const extension = image.substring(image.indexOf("/") + 1, image.indexOf(";base64"));
|
||||
const fullFilePath = `avatar/${user.owner}/${user.name}.${extension}`;
|
||||
ResourceBackend.uploadResource(user.owner, user.name, "avatar", "CropperDivModal", fullFilePath, blob)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
window.location.href = window.location.pathname;
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
const showModal = () => {
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
setConfirmLoading(true);
|
||||
if (!uploadAvatar()) {
|
||||
setConfirmLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
const selectFile = () => {
|
||||
uploadButton.click();
|
||||
};
|
||||
|
||||
const getOptions = (data) => {
|
||||
const options = [];
|
||||
options.push({value: organization?.defaultAvatar});
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i].fileType === "image") {
|
||||
const url = `${data[i].url}`;
|
||||
options.push({
|
||||
value: url,
|
||||
});
|
||||
}
|
||||
}
|
||||
return options;
|
||||
};
|
||||
|
||||
const getBase64Image = (src) => {
|
||||
return new Promise((resolve) => {
|
||||
const image = new Image();
|
||||
image.src = src;
|
||||
image.setAttribute("crossOrigin", "anonymous");
|
||||
image.onload = () => {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(image, 0, 0, image.width, image.height);
|
||||
const dataURL = canvas.toDataURL("image/png");
|
||||
resolve(dataURL);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
ResourceBackend.getResources(user.owner, user.name, "", "", "", "", "", "")
|
||||
.then((res) => {
|
||||
setLoading(false);
|
||||
setOptions(getOptions(res));
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button type="default" onClick={showModal}>
|
||||
{buttonText}
|
||||
</Button>
|
||||
<Modal
|
||||
maskClosable={false}
|
||||
title={title}
|
||||
open={visible}
|
||||
okText={i18next.t("user:Upload a photo")}
|
||||
confirmLoading={confirmLoading}
|
||||
onCancel={handleCancel}
|
||||
width={600}
|
||||
footer={
|
||||
[<Button block key="submit" type="primary" onClick={handleOk}>{i18next.t("user:Set new profile picture")}</Button>]
|
||||
}
|
||||
>
|
||||
<Col style={{margin: "0px auto 60px auto", width: 1000, height: 350}}>
|
||||
<Row style={{width: "100%", marginBottom: "20px"}}>
|
||||
<input style={{display: "none"}} ref={input => uploadButton = input} type="file" accept="image/*" onChange={onChange} />
|
||||
<Button block onClick={selectFile}>{i18next.t("user:Select a photo...")}</Button>
|
||||
<Select virtual={false}
|
||||
style={{width: "100%"}}
|
||||
loading={loading}
|
||||
placeholder={i18next.t("user:Please select avatar from resources")}
|
||||
onChange={(async value => {
|
||||
setImage(await getBase64Image(value));
|
||||
})}
|
||||
options={options}
|
||||
allowClear={true}
|
||||
/>
|
||||
</Row>
|
||||
<Cropper
|
||||
style={{height: "100%"}}
|
||||
initialAspectRatio={1}
|
||||
preview=".img-preview"
|
||||
src={image}
|
||||
viewMode={1}
|
||||
guides={true}
|
||||
minCropBoxHeight={10}
|
||||
minCropBoxWidth={10}
|
||||
background={false}
|
||||
responsive={true}
|
||||
autoCropArea={1}
|
||||
checkOrientation={false}
|
||||
onInitialized={(instance) => {
|
||||
setCropper(instance);
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CropperDivModal;
|
93
web/src/common/modal/PasswordModal.js
Normal file
93
web/src/common/modal/PasswordModal.js
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import {Button, Col, Input, Modal, Row} from "antd";
|
||||
import i18next from "i18next";
|
||||
import React from "react";
|
||||
import * as UserBackend from "../../backend/UserBackend";
|
||||
import * as Setting from "../../Setting";
|
||||
|
||||
export const PasswordModal = (props) => {
|
||||
const [visible, setVisible] = React.useState(false);
|
||||
const [confirmLoading, setConfirmLoading] = React.useState(false);
|
||||
const [oldPassword, setOldPassword] = React.useState("");
|
||||
const [newPassword, setNewPassword] = React.useState("");
|
||||
const [rePassword, setRePassword] = React.useState("");
|
||||
const {user} = props;
|
||||
const {account} = props;
|
||||
|
||||
const showModal = () => {
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
if (newPassword === "" || rePassword === "") {
|
||||
Setting.showMessage("error", i18next.t("user:Empty input!"));
|
||||
return;
|
||||
}
|
||||
if (newPassword !== rePassword) {
|
||||
Setting.showMessage("error", i18next.t("user:Two passwords you typed do not match."));
|
||||
return;
|
||||
}
|
||||
setConfirmLoading(true);
|
||||
UserBackend.setPassword(user.owner, user.name, oldPassword, newPassword).then((res) => {
|
||||
setConfirmLoading(false);
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("user:Password set successfully"));
|
||||
setVisible(false);
|
||||
} else {Setting.showMessage("error", i18next.t(`user:${res.msg}`));}
|
||||
});
|
||||
};
|
||||
|
||||
const hasOldPassword = user.password !== "";
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Button type="default" disabled={props.disabled} onClick={showModal}>
|
||||
{hasOldPassword ? i18next.t("user:Modify password...") : i18next.t("user:Set password...")}
|
||||
</Button>
|
||||
<Modal
|
||||
maskClosable={false}
|
||||
title={i18next.t("general:Password")}
|
||||
open={visible}
|
||||
okText={i18next.t("user:Set Password")}
|
||||
cancelText={i18next.t("general:Cancel")}
|
||||
confirmLoading={confirmLoading}
|
||||
onCancel={handleCancel}
|
||||
onOk={handleOk}
|
||||
width={600}
|
||||
>
|
||||
<Col style={{margin: "0px auto 40px auto", width: 1000, height: 300}}>
|
||||
{(hasOldPassword && !Setting.isAdminUser(account)) ? (
|
||||
<Row style={{width: "100%", marginBottom: "20px"}}>
|
||||
<Input.Password addonBefore={i18next.t("user:Old Password")} placeholder={i18next.t("user:input password")} onChange={(e) => setOldPassword(e.target.value)} />
|
||||
</Row>
|
||||
) : null}
|
||||
<Row style={{width: "100%", marginBottom: "20px"}}>
|
||||
<Input.Password addonBefore={i18next.t("user:New Password")} placeholder={i18next.t("user:input password")} onChange={(e) => setNewPassword(e.target.value)} />
|
||||
</Row>
|
||||
<Row style={{width: "100%", marginBottom: "20px"}}>
|
||||
<Input.Password addonBefore={i18next.t("user:Re-enter New")} placeholder={i18next.t("user:input password")} onChange={(e) => setRePassword(e.target.value)} />
|
||||
</Row>
|
||||
</Col>
|
||||
</Modal>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default PasswordModal;
|
110
web/src/common/modal/ResetModal.js
Normal file
110
web/src/common/modal/ResetModal.js
Normal file
@ -0,0 +1,110 @@
|
||||
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import {Button, Col, Input, Modal, Row} from "antd";
|
||||
import i18next from "i18next";
|
||||
import React from "react";
|
||||
import * as Setting from "../../Setting";
|
||||
import * as UserBackend from "../../backend/UserBackend";
|
||||
import {SendCodeInput} from "../SendCodeInput";
|
||||
import {MailOutlined, PhoneOutlined} from "@ant-design/icons";
|
||||
|
||||
export const ResetModal = (props) => {
|
||||
const [visible, setVisible] = React.useState(false);
|
||||
const [confirmLoading, setConfirmLoading] = React.useState(false);
|
||||
const [dest, setDest] = React.useState("");
|
||||
const [code, setCode] = React.useState("");
|
||||
const {buttonText, destType, application, countryCode} = props;
|
||||
|
||||
const showModal = () => {
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
if (dest === "") {
|
||||
if (destType === "phone") {
|
||||
Setting.showMessage("error", i18next.t("user:Phone cannot be empty"));
|
||||
} else {
|
||||
Setting.showMessage("error", i18next.t("user:Email cannot be empty"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (code === "") {
|
||||
Setting.showMessage("error", i18next.t("code:Empty code"));
|
||||
return;
|
||||
}
|
||||
setConfirmLoading(true);
|
||||
UserBackend.resetEmailOrPhone(dest, destType, code).then(res => {
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("user:Email/phone reset successfully"));
|
||||
window.location.reload();
|
||||
} else {
|
||||
Setting.showMessage("error", i18next.t("user:" + res.msg));
|
||||
setConfirmLoading(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let placeholder = "";
|
||||
if (destType === "email") {
|
||||
placeholder = i18next.t("user:Input your email");
|
||||
} else if (destType === "phone") {
|
||||
placeholder = i18next.t("user:Input your phone number");
|
||||
}
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Button type="default" onClick={showModal}>
|
||||
{buttonText}
|
||||
</Button>
|
||||
<Modal
|
||||
maskClosable={false}
|
||||
title={buttonText}
|
||||
open={visible}
|
||||
okText={buttonText}
|
||||
cancelText={i18next.t("general:Cancel")}
|
||||
confirmLoading={confirmLoading}
|
||||
onCancel={handleCancel}
|
||||
onOk={handleOk}
|
||||
width={600}
|
||||
>
|
||||
<Col style={{margin: "0px auto 40px auto", width: 1000, height: 300}}>
|
||||
<Row style={{width: "100%", marginBottom: "20px"}}>
|
||||
<Input
|
||||
addonBefore={destType === "email" ? i18next.t("user:New Email") : i18next.t("user:New phone")}
|
||||
prefix={destType === "email" ? <React.Fragment><MailOutlined /> </React.Fragment> : (<React.Fragment><PhoneOutlined /> {countryCode !== "" ? "+" : null}{Setting.getCountryCode(countryCode)} </React.Fragment>)}
|
||||
placeholder={placeholder}
|
||||
onChange={e => setDest(e.target.value)}
|
||||
/>
|
||||
</Row>
|
||||
<Row style={{width: "100%", marginBottom: "20px"}}>
|
||||
<SendCodeInput
|
||||
textBefore={i18next.t("code:Code you received")}
|
||||
onChange={setCode}
|
||||
method={"reset"}
|
||||
onButtonClickArgs={[dest, destType, Setting.getApplicationName(application)]}
|
||||
application={application}
|
||||
/>
|
||||
</Row>
|
||||
</Col>
|
||||
</Modal>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResetModal;
|
Reference in New Issue
Block a user