问题描述
我有一个代码,可以在Cards中呈现多个计划。这是代码:
import React,{ useEffect,useState } from 'react';
import { I18nText,Card,BaseModal,Button } from '@wtag/react-comp-lib';
import PropTypes from 'prop-types';
import greenCheck from 'affiliateIcons/green-check.svg';
import doneMark from '../../../../assets/images/done-24px.svg';
import routes from '../../../shared/routes';
import httpClient from '../../../shared/libraries/httpClient';
const Plans = ({ affiliateId }) => {
const [plans,setPlans] = useState([]);
const [currentPlan,setCurrentPlan] = useState([]);
const [modalOpen,setModalOpen] = useState(false);
const fetchPlans = async () => {
const { data } = await httpClient.get(
routes.billing.changePlan.fetch({ affiliate_id: affiliateId }),);
setPlans(data.plans);
setCurrentPlan(data.currentPlan);
};
const selectPlan = async plan => {
const { data } = await httpClient.put(
routes.billing.changePlan.update({
id: plan.id,affiliate_id: affiliateId,}),);
if (data.error === null) {
fetchPlans(data.currentPlan);
setModalOpen(false);
}
};
useEffect(() => {
fetchPlans();
},[]);
const data = [
{
id: 0,identifier: 'free-2020',name: <I18nText id="pricing.plans.name.free" />,planTitle: 'free',price: '00',freeSearches: <I18nText id="pricing.plans.features.unlimited" />,freeBookings: <I18nText id="pricing.plans.features.unlimited" />,travelerProfiles: <I18nText id="pricing.plans.features.unlimited" />,supportTickets: <I18nText id="pricing.plans.features.available" />,supportByPhone: '-',supplierChannels: '-',customDomain: '-',active: true,},{
id: 1,identifier: 'basic-2020',name: <I18nText id="pricing.plans.name.basic" />,planTitle: 'basic',price: '29',supplierChannels: '1',active: false,{
id: 2,identifier: 'standard-2020',name: <I18nText id="pricing.plans.name.standard" />,planTitle: 'standard',price: '59',supportByPhone: '1hr/mo',supplierChannels: '2',{
id: 3,identifier: 'professional-2020',name: <I18nText id="pricing.plans.name.professional" />,planTitle: 'professional',price: '99',supportByPhone: '3hr/mo',supplierChannels: '5',customDomain: 'Yes',{
id: 4,identifier: 'custom-2020',name: <I18nText id="pricing.plans.name.custom" />,planTitle: 'custom',price: '-',supportByPhone: <I18nText id="pricing.plans.features.unlimited" />,supplierChannels: <I18nText id="pricing.plans.features.unlimited" />,customDomain: <I18nText id="pricing.plans.features.available" />,];
const planData = data.map(d => {
const correspondingPlan = plans.filter(
plan => d.identifier === plan.identifier,)[0];
if (correspondingPlan) {
return { ...d,...correspondingPlan };
}
return d;
});
const tableHeader = [
{ id: 0,name: <I18nText id="pricing.table.header.free" /> },{ id: 1,name: <I18nText id="pricing.table.header.basic" /> },{ id: 2,name: <I18nText id="pricing.table.header.standard" /> },{ id: 3,name: <I18nText id="pricing.table.header.professional" /> },{ id: 4,name: <I18nText id="pricing.table.header.custom" /> },];
const planOptions = [
{
id: 0,name: <I18nText id="pricing.table.feature.subscription.search" />,isFree: doneMark,isBasic: doneMark,isStandard: doneMark,isProfessional: doneMark,isCustom: doneMark,name: <I18nText id="pricing.table.feature.subscription.bookings" />,name: <I18nText id="pricing.table.feature.subscription.traveler" />,name: <I18nText id="pricing.table.feature.subscription.corporate" />,name: <I18nText id="pricing.table.feature.subscription.quotes" />,{
id: 5,name: <I18nText id="pricing.table.feature.subscription.ndc" />,];
const getCurrentPlan = currentPlan && currentPlan.name;
const newPlansCard = planData.map(plan => {
const matchPlan = plan.name === getCurrentPlan;
return (
<>
<Card
className="billing-plans__plans-card"
size="normal"
version="v2"
title={plan.name}
headerCenter={true}
key={plan.id}
>
{matchPlan ? (
<div className="billing-plans__current-plan-icon">
<img src={greenCheck} alt="check" />
</div>
) : null}
<div className="billing-plans__plans-card-title">
<sup>US$</sup>
{plan.price}
<sub>
/<I18nText id="pricing.plans.misc.month" />
</sub>
</div>
<div className="billing-plans__plans-card-features-wrapper">
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.searches" />
<span className="billing-plans__features-access">
{plan.freeSearches}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.bookings" />
<span className="billing-plans__features-access">
{plan.freeBookings}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.profiles" />
<span className="billing-plans__features-access">
{plan.travelerProfiles}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.tickets" />
<span className="billing-plans__features-access">
{plan.supportTickets}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.phone" />
<span className="billing-plans__features-access">
{plan.supportByPhone}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.channels" />
<span className="billing-plans__features-access">
{plan.supplierChannels}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.domain" />
<span className="billing-plans__features-access">
{plan.customDomain}
</span>
</div>
</div>
<div className="billing-plans__plans-card-actions">
{!matchPlan ? (
<div>
<BaseModal
linkText={<I18nText id="pricing.plans.actions.select" />}
linkClassName="billing-plans__plans-card-actions-button"
open={modalOpen}
onModalClose={() => setModalOpen(false)}
onModalOpen={() => setModalOpen(true)}
header={
<I18nText id="pricing.plans.actions.confirmationText" />
}
size="small"
showCloseIcon={false}
key={plan.id}
>
<div className="col-12">
<Button
version="v2"
type="accent"
size="normal"
label={I18n.t('shared.action.confirm')}
key={plan.id}
onClick={() => {
selectPlan(plan);
}}
/>
<Button
version="v2"
size="normal"
label={I18n.t('shared.action.cancel')}
onClick={() => setModalOpen(false)}
/>
</div>
</BaseModal>
</div>
) : null}
</div>
</Card>
</>
);
});
const pricingTable = () => {
return (
<div>
<div className="container-full billing-plans__pricing-table">
<Card size="full" version="v2" key={planOptions.id}>
<div className="billing-plans__table-header">
<I18nText id="pricing.plans.sub_title" />
</div>
<table className="billing-plans__table-body">
<thead>
<tr>
<th className="billing-plans__table-sub-header">
<I18nText id="pricing.table.feature.header" />
</th>
{tableHeader.map(({ name,id }) => (
<th className="billing-plans__table-sub-header" key={id}>
{name}
</th>
))}
</tr>
</thead>
<tbody>
{planOptions.map(
({
id,name,isFree,isBasic,isStandard,isProfessional,isCustom,}) => (
<tr key={id}>
<td className="billing-plans__table-data">{name}</td>
<td className="billing-plans__table-plan">
<img src={isFree} alt="check" />
</td>
<td className="billing-plans__table-plan">
<img src={isBasic} alt="check" />
</td>
<td className="billing-plans__table-plan">
<img src={isStandard} alt="check" />
</td>
<td className="billing-plans__table-plan">
<img src={isProfessional} alt="check" />
</td>
<td className="billing-plans__table-plan">
<img src={isCustom} alt="check" />
</td>
</tr>
),)}
</tbody>
</table>
</Card>
</div>
</div>
);
};
return (
<div className="billing-plans">
<div>
<div className="grid">
<div className="col-12 offset-xlg-1 offset-lg-1 offset-md-1 offset-sm-1 offset-xs-1 offset-xxs-1">
<div className="billing-plans__plans-header">
<I18nText id="pricing.plans.title" />
</div>
</div>
</div>
<div className="billing-plans__plans-wrapper">
{currentPlan && newPlansCard}
</div>
</div>
{pricingTable()}
</div>
);
};
Plans.propTypes = {
currentPlan: PropTypes.shape({
name: PropTypes.string,identifier: PropTypes.string,id: PropTypes.number,}).isRequired,affiliateId: PropTypes.number.isRequired,};
export default Plans;
我想获取所选卡的ID并将其传递给模式。在单击第一个按钮即卡片模式的确认按钮时,卡片将显示为选中状态,并带有勾号。像每张卡中一样,都有“选择计划”按钮,可打开模式对话框以确认用户是否确实要选择计划。如果他选择是,则获取特定卡的ID,然后将该ID传递给selectPlan函数以选择特定卡作为计划。在模式的第一个按钮中的现有代码库中,我具有一个onClick函数,该函数将特定的选定计划发送到selectPlan(plan)
这样的selectPlan函数。但是,尽管我使用相应的模态选择了哪张卡,但现在我只得到ID为2或6的卡,尽管有5张ID为2、3、4、5、6的卡。这意味着在获取特定卡时会遇到一些问题在当前实施中选择了卡ID。我想知道我应该在当前代码中进行哪些更改,以获取特定的所选Card ID,并使用onClick函数将其传递到相应的模式按钮,以表示使用selectPlan(plan)
函数选择的计划。这是“计划”用户界面:
解决方法
const [plans,setPlans] = useState([]);
const [currentPlan,setCurrentPlan] = useState([]);
const [modalOpen,setModalOpen] = useState(false);
const [selectedPlan,setSelectedPlan] = useState();
const fetchPlans = async () => {
const { data } = await httpClient.get(
const Plans = ({ affiliateId }) => {
linkClassName="billing-plans__plans-card-actions-button"
open={modalOpen}
onModalClose={() => setModalOpen(false)}
onModalOpen={() => {
setSelectedPlan(plan);
setModalOpen(true);
}}
header={
<I18nText id="pricing.plans.actions.confirmationText" />
}
const Plans = ({ affiliateId }) => {
label={I18n.t('shared.action.confirm')}
key={plan.id}
onClick={() => {
selectPlan(selectedPlan);
}}
/>
<Button
,
import React,{ useEffect,useState } from 'react';
import { I18nText,Card,BaseModal,Button } from '@wtag/react-comp-lib';
import PropTypes from 'prop-types';
import greenCheck from 'affiliateIcons/green-check.svg';
import doneMark from '../../../../assets/images/done-24px.svg';
import routes from '../../../shared/routes';
import httpClient from '../../../shared/libraries/httpClient';
const Plans = ({ affiliateId }) => {
const [plans,setSelectedPlan] = useState();
const fetchPlans = async () => {
const { data } = await httpClient.get(
routes.billing.changePlan.fetch({ affiliate_id: affiliateId }),);
setPlans(data.plans);
setCurrentPlan(data.currentPlan);
};
const selectPlan = async plan => {
const { data } = await httpClient.put(
routes.billing.changePlan.update({
id: plan.id,affiliate_id: affiliateId,}),);
if (data.error === null) {
fetchPlans(data.currentPlan);
setModalOpen(false);
}
};
useEffect(() => {
fetchPlans();
},[]);
const data = [
{
id: 0,identifier: 'free-2020',name: <I18nText id="pricing.plans.name.free" />,planTitle: 'free',price: '00',freeSearches: <I18nText id="pricing.plans.features.unlimited" />,freeBookings: <I18nText id="pricing.plans.features.unlimited" />,travelerProfiles: <I18nText id="pricing.plans.features.unlimited" />,supportTickets: <I18nText id="pricing.plans.features.available" />,supportByPhone: '-',supplierChannels: '-',customDomain: '-',active: true,},{
id: 1,identifier: 'basic-2020',name: <I18nText id="pricing.plans.name.basic" />,planTitle: 'basic',price: '29',supplierChannels: '1',active: false,{
id: 2,identifier: 'standard-2020',name: <I18nText id="pricing.plans.name.standard" />,planTitle: 'standard',price: '59',supportByPhone: '1hr/mo',supplierChannels: '2',{
id: 3,identifier: 'professional-2020',name: <I18nText id="pricing.plans.name.professional" />,planTitle: 'professional',price: '99',supportByPhone: '3hr/mo',supplierChannels: '5',customDomain: 'Yes',{
id: 4,identifier: 'custom-2020',name: <I18nText id="pricing.plans.name.custom" />,planTitle: 'custom',price: '-',supportByPhone: <I18nText id="pricing.plans.features.unlimited" />,supplierChannels: <I18nText id="pricing.plans.features.unlimited" />,customDomain: <I18nText id="pricing.plans.features.available" />,];
const planData = data.map(d => {
const correspondingPlan = plans.filter(
plan => d.identifier === plan.identifier,)[0];
if (correspondingPlan) {
return { ...d,...correspondingPlan };
}
return d;
});
const tableHeader = [
{ id: 0,name: <I18nText id="pricing.table.header.free" /> },{ id: 1,name: <I18nText id="pricing.table.header.basic" /> },{ id: 2,name: <I18nText id="pricing.table.header.standard" /> },{ id: 3,name: <I18nText id="pricing.table.header.professional" /> },{ id: 4,name: <I18nText id="pricing.table.header.custom" /> },];
const planOptions = [
{
id: 0,name: <I18nText id="pricing.table.feature.subscription.search" />,isFree: doneMark,isBasic: doneMark,isStandard: doneMark,isProfessional: doneMark,isCustom: doneMark,name: <I18nText id="pricing.table.feature.subscription.bookings" />,name: <I18nText id="pricing.table.feature.subscription.traveler" />,name: <I18nText id="pricing.table.feature.subscription.corporate" />,name: <I18nText id="pricing.table.feature.subscription.quotes" />,{
id: 5,name: <I18nText id="pricing.table.feature.subscription.ndc" />,];
const getCurrentPlan = currentPlan && currentPlan.name;
const newPlansCard = planData.map(plan => {
const matchPlan = plan.name === getCurrentPlan;
return (
<>
<Card
className="billing-plans__plans-card"
size="normal"
version="v2"
title={plan.name}
headerCenter={true}
key={plan.id}
>
{matchPlan ? (
<div className="billing-plans__current-plan-icon">
<img src={greenCheck} alt="check" />
</div>
) : null}
<div className="billing-plans__plans-card-title">
<sup>US$</sup>
{plan.price}
<sub>
/<I18nText id="pricing.plans.misc.month" />
</sub>
</div>
<div className="billing-plans__plans-card-features-wrapper">
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.searches" />
<span className="billing-plans__features-access">
{plan.freeSearches}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.bookings" />
<span className="billing-plans__features-access">
{plan.freeBookings}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.profiles" />
<span className="billing-plans__features-access">
{plan.travelerProfiles}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.tickets" />
<span className="billing-plans__features-access">
{plan.supportTickets}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.phone" />
<span className="billing-plans__features-access">
{plan.supportByPhone}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.channels" />
<span className="billing-plans__features-access">
{plan.supplierChannels}
</span>
</div>
<div className="billing-plans__plans-card-features">
<I18nText id="pricing.plans.features.domain" />
<span className="billing-plans__features-access">
{plan.customDomain}
</span>
</div>
</div>
<div className="billing-plans__plans-card-actions">
{!matchPlan ? (
<div>
<BaseModal
linkText={<I18nText id="pricing.plans.actions.select" />}
linkClassName="billing-plans__plans-card-actions-button"
open={modalOpen}
onModalClose={() => setModalOpen(false)}
onModalOpen={() => {
setSelectedPlan(plan);
setModalOpen(true);
}}
header={
<I18nText id="pricing.plans.actions.confirmationText" />
}
size="small"
showCloseIcon={false}
key={plan.id}
>
<div className="col-12">
<Button
version="v2"
type="accent"
size="normal"
label={I18n.t('shared.action.confirm')}
key={plan.id}
onClick={() => {
selectPlan(selectedPlan);
}}
/>
<Button
version="v2"
size="normal"
label={I18n.t('shared.action.cancel')}
onClick={() => setModalOpen(false)}
/>
</div>
</BaseModal>
</div>
) : null}
</div>
</Card>
</>
);
});
const pricingTable = () => {
return (
<div>
<div className="container-full billing-plans__pricing-table">
<Card size="full" version="v2" key={planOptions.id}>
<div className="billing-plans__table-header">
<I18nText id="pricing.plans.sub_title" />
</div>
<table className="billing-plans__table-body">
<thead>
<tr>
<th className="billing-plans__table-sub-header">
<I18nText id="pricing.table.feature.header" />
</th>
{tableHeader.map(({ name,id }) => (
<th className="billing-plans__table-sub-header" key={id}>
{name}
</th>
))}
</tr>
</thead>
<tbody>
{planOptions.map(
({
id,name,isFree,isBasic,isStandard,isProfessional,isCustom,}) => (
<tr key={id}>
<td className="billing-plans__table-data">{name}</td>
<td className="billing-plans__table-plan">
<img src={isFree} alt="check" />
</td>
<td className="billing-plans__table-plan">
<img src={isBasic} alt="check" />
</td>
<td className="billing-plans__table-plan">
<img src={isStandard} alt="check" />
</td>
<td className="billing-plans__table-plan">
<img src={isProfessional} alt="check" />
</td>
<td className="billing-plans__table-plan">
<img src={isCustom} alt="check" />
</td>
</tr>
),)}
</tbody>
</table>
</Card>
</div>
</div>
);
};
return (
<div className="billing-plans">
<div>
<div className="grid">
<div className="col-12 offset-xlg-1 offset-lg-1 offset-md-1 offset-sm-1 offset-xs-1 offset-xxs-1">
<div className="billing-plans__plans-header">
<I18nText id="pricing.plans.title" />
</div>
</div>
</div>
<div className="billing-plans__plans-wrapper">
{currentPlan && newPlansCard}
</div>
</div>
{pricingTable()}
</div>
);
};
Plans.propTypes = {
currentPlan: PropTypes.shape({
name: PropTypes.string,identifier: PropTypes.string,id: PropTypes.number,}).isRequired,affiliateId: PropTypes.number.isRequired,};
export default Plans;