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-03-07 00:33:45 +08:00
|
|
|
import {Button, Descriptions, Spin} from "antd";
|
2022-02-27 23:50:35 +08:00
|
|
|
import i18next from "i18next";
|
|
|
|
import * as ProductBackend from "./backend/ProductBackend";
|
|
|
|
import * as ProviderBackend from "./backend/ProviderBackend";
|
|
|
|
import * as Provider from "./auth/Provider";
|
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,
|
|
|
|
providers: [],
|
2022-03-07 00:33:45 +08:00
|
|
|
isPlacingOrder: false,
|
2022-02-27 23:50:35 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
UNSAFE_componentWillMount() {
|
|
|
|
this.getProduct();
|
|
|
|
this.getPaymentProviders();
|
|
|
|
}
|
|
|
|
|
|
|
|
getProduct() {
|
|
|
|
ProductBackend.getProduct("admin", this.state.productName)
|
|
|
|
.then((product) => {
|
|
|
|
this.setState({
|
|
|
|
product: product,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getPaymentProviders() {
|
|
|
|
ProviderBackend.getProviders("admin")
|
|
|
|
.then((res) => {
|
|
|
|
this.setState({
|
|
|
|
providers: res.filter(provider => provider.category === "Payment"),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
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)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getProviders(product) {
|
|
|
|
if (this.state.providers.length === 0 || product.providers.length === 0) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
let providerMap = {};
|
|
|
|
this.state.providers.forEach(provider => {
|
|
|
|
providerMap[provider.name] = provider;
|
|
|
|
})
|
|
|
|
|
|
|
|
return product.providers.map(providerName => providerMap[providerName]);
|
|
|
|
}
|
|
|
|
|
|
|
|
getPayUrl(product, provider) {
|
|
|
|
if (product === null || provider === null) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
return `https://${provider.type}`;
|
|
|
|
// if (provider.type === "WeChat") {
|
|
|
|
// return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${scope}&response_type=code&state=${state}`;
|
|
|
|
// } else if (provider.type === "GitHub") {
|
|
|
|
// return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${scope}&response_type=code&state=${state}`;
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
2022-03-06 22:46:02 +08:00
|
|
|
buyProduct(product, provider) {
|
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.msg === "") {
|
|
|
|
const payUrl = res.data;
|
|
|
|
Setting.goToLink(payUrl);
|
|
|
|
} else {
|
|
|
|
Setting.showMessage("error", 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", `Failed to connect to server: ${error}`);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
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={Provider.getProviderLogo(provider)} alt={provider.displayName} />
|
|
|
|
} size={"large"} >
|
|
|
|
{
|
|
|
|
text
|
|
|
|
}
|
|
|
|
</Button>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
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>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
renderPay(product) {
|
|
|
|
if (product === undefined || product === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (product.state !== "Published") {
|
|
|
|
return i18next.t("product:This product is currently not in sale.");
|
|
|
|
}
|
|
|
|
if (product.providers.length === 0) {
|
|
|
|
return i18next.t("product:There is no payment channel for this product.");
|
|
|
|
}
|
|
|
|
|
|
|
|
const providers = this.getProviders(product);
|
|
|
|
return providers.map(provider => {
|
|
|
|
return this.renderProviderButton(provider, product);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
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}>
|
2022-02-27 23:50:35 +08:00
|
|
|
<span style={{fontSize: 28}}>
|
|
|
|
{product?.displayName}
|
|
|
|
</span>
|
2022-03-07 00:33:45 +08:00
|
|
|
</Descriptions.Item>
|
|
|
|
<Descriptions.Item label={i18next.t("product:Detail")}><span style={{fontSize: 16}}>{product?.detail}</span></Descriptions.Item>
|
|
|
|
<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?.image} height={90} style={{marginBottom: '20px'}}/>
|
|
|
|
</Descriptions.Item>
|
|
|
|
<Descriptions.Item label={i18next.t("product:Price")}>
|
2022-02-27 23:50:35 +08:00
|
|
|
<span style={{fontSize: 28, color: "red", fontWeight: "bold"}}>
|
|
|
|
{`${this.getCurrencySymbol(product)}${product?.price} (${this.getCurrencyText(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-02-27 23:50:35 +08:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default ProductBuyPage;
|