casdoor/web/src/ProductBuyPage.js

249 lines
7.7 KiB
JavaScript
Raw Normal View History

2022-02-27 23:50:35 +08:00
// 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 React from "react";
2022-12-12 00:42:45 +08:00
import {Button, Descriptions, Modal, Spin} from "antd";
import {CheckCircleTwoTone} from "@ant-design/icons";
2022-02-27 23:50:35 +08:00
import i18next from "i18next";
import * as ProductBackend from "./backend/ProductBackend";
2022-03-06 22:46:02 +08:00
import * as Setting from "./Setting";
2022-02-27 23:50:35 +08:00
class ProductBuyPage extends React.Component {
constructor(props) {
super(props);
this.state = {
classes: props,
productName: props.match?.params.productName,
product: null,
2022-03-07 00:33:45 +08:00
isPlacingOrder: false,
2022-12-12 00:42:45 +08:00
qrCodeModalProvider: null,
2022-02-27 23:50:35 +08:00
};
}
UNSAFE_componentWillMount() {
this.getProduct();
}
getProduct() {
2022-12-16 23:09:48 +08:00
if (this.state.productName === undefined) {
return;
}
2022-02-27 23:50:35 +08:00
ProductBackend.getProduct("admin", this.state.productName)
.then((product) => {
this.setState({
product: product,
});
});
}
getProductObj() {
if (this.props.product !== undefined) {
return this.props.product;
} else {
return this.state.product;
}
}
getCurrencySymbol(product) {
if (product?.currency === "USD") {
return "$";
} else if (product?.currency === "CNY") {
return "¥";
} else {
return "(Unknown currency)";
}
}
getCurrencyText(product) {
if (product?.currency === "USD") {
return i18next.t("product:USD");
} else if (product?.currency === "CNY") {
return i18next.t("product:CNY");
} else {
return "(Unknown currency)";
}
}
2022-03-26 16:42:25 +08:00
getPrice(product) {
return `${this.getCurrencySymbol(product)}${product?.price} (${this.getCurrencyText(product)})`;
}
2022-03-06 22:46:02 +08:00
buyProduct(product, provider) {
2022-12-12 00:42:45 +08:00
if (provider.clientId.startsWith("http")) {
this.setState({
qrCodeModalProvider: provider,
});
return;
}
2022-03-07 00:33:45 +08:00
this.setState({
isPlacingOrder: true,
});
2022-03-06 22:46:02 +08:00
ProductBackend.buyProduct(this.state.product.owner, this.state.productName, provider.name)
.then((res) => {
if (res.status === "ok") {
2022-03-06 22:46:02 +08:00
const payUrl = res.data;
Setting.goToLink(payUrl);
} else {
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
2022-03-07 00:33:45 +08:00
this.setState({
isPlacingOrder: false,
});
2022-03-06 22:46:02 +08:00
}
})
.catch(error => {
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
2022-03-06 22:46:02 +08:00
});
}
2022-12-12 00:42:45 +08:00
renderQrCodeModal() {
2022-12-16 23:09:48 +08:00
if (this.state.qrCodeModalProvider === undefined || this.state.qrCodeModalProvider === null) {
return null;
}
2022-12-12 00:42:45 +08:00
return (
<Modal title={
<div>
<CheckCircleTwoTone twoToneColor="rgb(45,120,213)" />
{" " + i18next.t("product:Please scan the QR code to pay")}
</div>
}
2022-12-16 23:09:48 +08:00
open={this.state.qrCodeModalProvider !== undefined && this.state.qrCodeModalProvider !== null}
2022-12-12 00:42:45 +08:00
onOk={() => {
Setting.goToLink(this.state.product.returnUrl);
}}
onCancel={() => {
this.setState({
qrCodeModalProvider: null,
});
}}
okText={i18next.t("product:I have completed the payment")}
cancelText={i18next.t("general:Cancel")}>
<p key={this.state.qrCodeModalProvider?.name}>
{
i18next.t("product:Please provide your username in the remark")
}
:&nbsp;&nbsp;
{
Setting.getTag("default", this.props.account.name)
}
<br />
<br />
<img src={this.state.qrCodeModalProvider?.clientId} alt={this.state.qrCodeModalProvider?.name} width={"472px"} style={{marginBottom: "20px"}} />
</p>
</Modal>
);
}
2022-02-27 23:50:35 +08:00
getPayButton(provider) {
let text = provider.type;
if (provider.type === "Alipay") {
text = i18next.t("product:Alipay");
} else if (provider.type === "WeChat Pay") {
text = i18next.t("product:WeChat Pay");
} else if (provider.type === "Paypal") {
text = i18next.t("product:Paypal");
}
return (
<Button style={{height: "50px", borderWidth: "2px"}} shape="round" icon={
<img style={{marginRight: "10px"}} width={36} height={36} src={Setting.getProviderLogoURL(provider)} alt={provider.displayName} />
2022-02-27 23:50:35 +08:00
} size={"large"} >
{
text
}
</Button>
);
2022-02-27 23:50:35 +08:00
}
renderProviderButton(provider, product) {
return (
<span key={provider.name} style={{width: "200px", marginRight: "20px", marginBottom: "10px"}}>
2022-03-06 22:46:02 +08:00
<span style={{width: "200px", cursor: "pointer"}} onClick={() => this.buyProduct(product, provider)}>
2022-02-27 23:50:35 +08:00
{
this.getPayButton(provider)
}
2022-03-06 22:46:02 +08:00
</span>
2022-02-27 23:50:35 +08:00
</span>
);
2022-02-27 23:50:35 +08:00
}
renderPay(product) {
if (product === undefined || product === null) {
return null;
}
if (product.state !== "Published") {
return i18next.t("product:This product is currently not in sale.");
}
2022-08-07 15:44:57 +08:00
if (product.providerObjs.length === 0) {
2022-02-27 23:50:35 +08:00
return i18next.t("product:There is no payment channel for this product.");
}
2022-08-07 15:44:57 +08:00
return product.providerObjs.map(provider => {
2022-02-27 23:50:35 +08:00
return this.renderProviderButton(provider, product);
});
2022-02-27 23:50:35 +08:00
}
render() {
const product = this.getProductObj();
2022-03-13 16:25:54 +08:00
if (product === null) {
return null;
}
2022-02-27 23:50:35 +08:00
return (
<div>
2022-03-07 00:33:45 +08:00
<Spin spinning={this.state.isPlacingOrder} size="large" tip={i18next.t("product:Placing order...")} style={{paddingTop: "10%"}} >
<Descriptions title={i18next.t("product:Buy Product")} bordered>
<Descriptions.Item label={i18next.t("general:Name")} span={3}>
<span style={{fontSize: 28}}>
2022-12-07 01:53:03 +08:00
{Setting.getLanguageText(product?.displayName)}
</span>
2022-03-07 00:33:45 +08:00
</Descriptions.Item>
2022-12-07 01:53:03 +08:00
<Descriptions.Item label={i18next.t("product:Detail")}><span style={{fontSize: 16}}>{Setting.getLanguageText(product?.detail)}</span></Descriptions.Item>
2022-03-07 00:33:45 +08:00
<Descriptions.Item label={i18next.t("product:Tag")}><span style={{fontSize: 16}}>{product?.tag}</span></Descriptions.Item>
<Descriptions.Item label={i18next.t("product:SKU")}><span style={{fontSize: 16}}>{product?.name}</span></Descriptions.Item>
<Descriptions.Item label={i18next.t("product:Image")} span={3}>
<img src={product?.image} alt={product?.name} height={90} style={{marginBottom: "20px"}} />
2022-03-07 00:33:45 +08:00
</Descriptions.Item>
<Descriptions.Item label={i18next.t("product:Price")}>
<span style={{fontSize: 28, color: "red", fontWeight: "bold"}}>
{
this.getPrice(product)
}
</span>
2022-03-07 00:33:45 +08:00
</Descriptions.Item>
<Descriptions.Item label={i18next.t("product:Quantity")}><span style={{fontSize: 16}}>{product?.quantity}</span></Descriptions.Item>
<Descriptions.Item label={i18next.t("product:Sold")}><span style={{fontSize: 16}}>{product?.sold}</span></Descriptions.Item>
<Descriptions.Item label={i18next.t("product:Pay")} span={3}>
{
this.renderPay(product)
}
</Descriptions.Item>
</Descriptions>
</Spin>
2022-12-12 00:42:45 +08:00
{
this.renderQrCodeModal()
}
2022-02-27 23:50:35 +08:00
</div>
);
2022-02-27 23:50:35 +08:00
}
}
export default ProductBuyPage;