• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / gui / 897326496

pending completion
897326496

Pull #3752

gitlab-ci

mzedel
chore(e2e): made use of shared timeout & login checking values to remove code duplication

Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #3752: chore(e2e-tests): slightly simplified log in test + separated log out test

4395 of 6392 branches covered (68.76%)

8060 of 9780 relevant lines covered (82.41%)

126.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

47.5
/src/js/components/settings/upgrade.js
1
// Copyright 2020 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14
import React, { useEffect, useState } from 'react';
15
import { connect } from 'react-redux';
16
import { useNavigate } from 'react-router-dom';
17

18
import { InfoOutlined as InfoOutlinedIcon, LocalOffer as LocalOfferIcon } from '@mui/icons-material';
19

20
import moment from 'moment';
21

22
import { setSnackbar } from '../../actions/appActions';
23
import { getDeviceLimit } from '../../actions/deviceActions';
24
import { cancelUpgrade, completeUpgrade, getUserOrganization, requestPlanChange, startUpgrade } from '../../actions/organizationActions';
25
import { PLANS, TIMEOUTS } from '../../constants/appConstants';
26
import InfoText from '../common/infotext';
27
import Loader from '../common/loader';
28
import AddOnSelection from './addonselection';
29
import CardSection from './cardsection';
30
import PlanSelection from './planselection';
31
import QuoteRequestForm from './quoterequestform';
32

33
const offerTag = (
34
  <span className="offerTag">
5✔
35
    <LocalOfferIcon /> End of year offer
36
  </span>
37
);
38

39
export const PostUpgradeNote = ({ newPlan }) => (
5✔
40
  <div style={{ maxWidth: 750 }} className="margin-top-small">
1✔
41
    <h2 style={{ marginTop: 15 }}>Upgrade now</h2>
42
    <div>
43
      <p>
44
        <b>Your upgrade was successful! </b>You are now signed up to the <b>{newPlan}</b> plan.
45
      </p>
46
      <p>Redirecting you to your organization page...</p>
47
      <Loader show={true} />
48
    </div>
49
  </div>
50
);
51

52
export const PricingContactNote = () => (
5✔
53
  <InfoText>
1✔
54
    <InfoOutlinedIcon style={{ fontSize: '14px', margin: '0 4px 4px 0', verticalAlign: 'middle' }} />
55
    If you have any questions about the plan pricing or device limits,{' '}
56
    <a href="mailto:contact@mender.io" target="_blank" rel="noopener noreferrer">
57
      contact our team
58
    </a>
59
    .
60
  </InfoText>
61
);
62

63
const upgradeNotes = {
5✔
64
  default: {
65
    title: 'Upgrades and add-ons',
66
    description: 'Upgrade your plan or purchase an add-on to connect more devices, access more features and advanced support.'
67
  },
68
  trial: {
69
    title: 'Upgrade now',
70
    description: 'Upgrade to one of our plans to connect more devices, continue using advanced features, and get access to support.'
71
  }
72
};
73

74
export const Upgrade = ({
5✔
75
  cancelUpgrade,
76
  completeUpgrade,
77
  features,
78
  getDeviceLimit,
79
  getUserOrganization,
80
  org,
81
  requestPlanChange,
82
  setSnackbar,
83
  startUpgrade
84
}) => {
85
  const offerValid = moment().isBefore('2021-01-01');
2✔
86

87
  const [addOns, setAddOns] = useState([]);
2✔
88
  const [updatedPlan, setUpdatedPlan] = useState('os');
2✔
89
  const [upgraded, setUpgraded] = useState(false);
2✔
90
  const navigate = useNavigate();
2✔
91

92
  useEffect(() => {
2✔
93
    getUserOrganization();
1✔
94
  }, []);
95

96
  useEffect(() => {
2✔
97
    const { addons: orgAddOns = [], plan: orgPlan = 'os', trial = false } = org;
1!
98
    const currentAddOns = orgAddOns.reduce((accu, addon) => {
1✔
99
      if (addon.enabled) {
×
100
        accu.push(addon);
×
101
      }
102
      return accu;
×
103
    }, []);
104
    const plan = Object.values(PLANS).find(plan => plan.value === (trial ? 'os' : orgPlan));
1!
105
    setAddOns(currentAddOns);
1✔
106
    setUpdatedPlan(plan.value);
1✔
107
  }, [org]);
108

109
  if (upgraded) {
2!
110
    return <PostUpgradeNote newPlan={PLANS[updatedPlan].name} />;
×
111
  }
112

113
  const handleUpgrade = async () =>
2✔
114
    completeUpgrade(org.id, updatedPlan).then(() => {
×
115
      setUpgraded(true);
×
116
      setTimeout(() => {
×
117
        getDeviceLimit();
×
118
        navigate('/settings/organization-and-billing');
×
119
      }, TIMEOUTS.threeSeconds);
120
    });
121

122
  const addOnsToString = (addons = []) =>
2!
123
    addons
×
124
      .reduce((accu, item) => {
125
        if (item.enabled) {
×
126
          accu.push(item.name);
×
127
        }
128
        return accu;
×
129
      }, [])
130
      .join(', ');
131

132
  const onSendRequest = (message, addons = addOns) =>
2!
133
    requestPlanChange(org.id, {
×
134
      current_plan: PLANS[org.plan || 'os'].name,
×
135
      requested_plan: PLANS[updatedPlan].name,
136
      current_addons: addOnsToString(org.addons) || '-',
×
137
      requested_addons: addOnsToString(addons) || '-',
×
138
      user_message: message
139
    });
140

141
  const { plan: currentPlan = 'os', trial: isTrial = true } = org;
2!
142
  const { description, title } = isTrial ? upgradeNotes.trial : upgradeNotes.default;
2!
143
  return (
2✔
144
    <div style={{ maxWidth: 750 }} className="margin-top-small">
145
      <h2 style={{ marginTop: 15 }}>{title}</h2>
146
      <p>{description}</p>
147
      <p>
148
        Learn more about the different plans and at{' '}
149
        <a href="https://mender.io/plans/pricing" target="_blank" rel="noopener noreferrer">
150
          mender.io/plans/pricing
151
        </a>
152
        . Prices can change at larger device counts, please see our{' '}
153
        <a href="https://mender.io/plans/pricing#calculator" target="_blank" rel="noopener noreferrer">
154
          price calculator
155
        </a>{' '}
156
        for more.
157
      </p>
158
      <PlanSelection
159
        currentPlan={currentPlan}
160
        isTrial={isTrial}
161
        offerValid={offerValid}
162
        offerTag={offerTag}
163
        setUpdatedPlan={setUpdatedPlan}
164
        updatedPlan={updatedPlan}
165
      />
166
      {isTrial && offerValid && (
2!
167
        <p className="offerBox">
168
          {offerTag} – upgrade before December 31st to get a 20% discount for 6 months on Mender Basic and Mender Professional plans. The discount will be
169
          automatically applied to your account.
170
        </p>
171
      )}
172
      {isTrial ? <PricingContactNote /> : <AddOnSelection addons={addOns} features={features} updatedPlan={updatedPlan} onChange={setAddOns} />}
2!
173
      {isTrial && updatedPlan !== PLANS.enterprise.value && (
2!
174
        <>
175
          <h3 className="margin-top-large">2. Enter your payment details</h3>
176
          <p>
177
            You are upgrading to{' '}
178
            <b>
179
              Mender <span className="capitalized-start">{PLANS[updatedPlan].name}</span>
180
            </b>{' '}
181
            for <b>{PLANS[updatedPlan].price}</b>
182
          </p>
183
          <CardSection
184
            onCancel={() => Promise.resolve(cancelUpgrade(org.id))}
×
185
            onComplete={handleUpgrade}
186
            onSubmit={() => Promise.resolve(startUpgrade(org.id))}
×
187
            setSnackbar={setSnackbar}
188
            isSignUp={true}
189
          />
190
        </>
191
      )}
192
      {(!isTrial || updatedPlan === PLANS.enterprise.value) && (
4!
193
        <QuoteRequestForm addOns={addOns} currentPlan={currentPlan} isTrial={isTrial} updatedPlan={updatedPlan} onSendMessage={onSendRequest} />
194
      )}
195
    </div>
196
  );
197
};
198

199
const actionCreators = { cancelUpgrade, completeUpgrade, getDeviceLimit, getUserOrganization, requestPlanChange, setSnackbar, startUpgrade };
5✔
200

201
const mapStateToProps = state => {
5✔
202
  return {
1✔
203
    features: state.app.features,
204
    org: state.organization.organization
205
  };
206
};
207

208
export default connect(mapStateToProps, actionCreators)(Upgrade);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc