Skip to content

Commit ed5a668

Browse files
feat(accounts): move Delete Account button to Account settings page (#6441)
* feat: move DeleteAccountOverlay out of OrgProfilePage * feat: add DeleteFreeAccountBtn to AccountPage * chore: rebase with master * feat: move deleteFreeAccount files into account folder * chore: update css impoty * fix: update org count condition * chore: update about test deleteFreeAccount * chore: update test ids in new delete acct overlay * chore: update event names from org to acct * chore: clean up DeletePanel component * chore: show delete org btn for non free acct with one org * test: move account deletion test to userAccounts.test * chore: remove inline styling * chore: update test to wait for api request * chore: replace timed cy.waits with waits on intercepts * chore: fix testid as testID * chore: update event names Co-authored-by: wdoconnell <91283923+wdoconnell@users.noreply.github.com>
1 parent 84d39bc commit ed5a668

File tree

13 files changed

+344
-235
lines changed

13 files changed

+344
-235
lines changed

cypress/e2e/cloud/about.test.ts

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -134,33 +134,6 @@ const createOrg = (accountType: string) => {
134134
})
135135
}
136136

137-
const deleteFreeAccount = () => {
138-
cy.getByTestID('delete-org--button').should('be.visible').click()
139-
cy.getByTestID('notification-warning').should('not.exist')
140-
141-
cy.url()
142-
.should('include', `/org-settings/delete`)
143-
.then(() => {
144-
cy.getByTestID('delete-org--overlay').should('be.visible')
145-
cy.getByTestID('delete-organization--button').should('be.disabled')
146-
147-
cy.getByTestID('agree-terms--input').click()
148-
cy.getByTestID('agree-terms--checkbox').should('be.checked')
149-
cy.getByTestID('variable-type-dropdown--button')
150-
.should('be.visible')
151-
.click()
152-
cy.contains("It doesn't work for my use case")
153-
.should('be.visible')
154-
.click()
155-
cy.getByTestID('delete-organization--button')
156-
.should('not.be.disabled')
157-
.click()
158-
cy.location().should(loc => {
159-
expect(loc.href).to.eq(`https://www.influxdata.com/mkt_cancel/`)
160-
})
161-
})
162-
}
163-
164137
const deleteOrg = () => {
165138
cy.getByTestID('delete-org--button').should('be.visible').click()
166139
cy.get('.org-delete-overlay--conditions-instruction').within(() => {
@@ -231,28 +204,6 @@ const upgradeAccount = () => {
231204
}
232205

233206
describe('Free account', () => {
234-
it('allows the user to delete a free account if there is only one org, with only one user', () => {
235-
setupTest({
236-
accountType: 'free',
237-
canCreateOrgs: false,
238-
orgHasOtherUsers: false,
239-
orgCount: 1,
240-
})
241-
242-
deleteFreeAccount()
243-
})
244-
245-
it('displays a `must remove users` warning if trying to delete a free account with a single org, which has multiple users', () => {
246-
setupTest({
247-
accountType: 'free',
248-
canCreateOrgs: false,
249-
orgHasOtherUsers: true,
250-
orgCount: 1,
251-
})
252-
253-
displayRemoveUsersWarning()
254-
})
255-
256207
it('displays a `must remove users` warning if trying to delete an org with multiple users in a multi-org free account', () => {
257208
setupTest({
258209
accountType: 'free',

cypress/e2e/cloud/userAccounts.test.ts

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,71 @@
11
import {Organization} from '../../../src/types'
2+
import {makeQuartzUseIDPEOrgID} from 'cypress/support/Utils'
3+
4+
// This variable stores the current IDPE orgid and syncs it with the quartz-mock orgid.
5+
let idpeOrgID: string
6+
7+
interface SetupParams {
8+
accountType: string
9+
orgHasOtherUsers: boolean
10+
orgCount?: number
11+
orgIsSuspendable?: boolean
12+
}
13+
14+
const setupTest = (setupParams: SetupParams) => {
15+
cy.flush().then(() =>
16+
cy.signin().then(() => {
17+
cy.request({
18+
method: 'GET',
19+
url: 'api/v2/orgs',
20+
}).then(res => {
21+
// Store the IDPE org ID so that it can be cloned when intercepting quartz.
22+
if (res.body.orgs) {
23+
idpeOrgID = res.body.orgs[0].id
24+
}
25+
const {accountType, orgCount, orgHasOtherUsers} = setupParams
26+
27+
makeQuartzUseIDPEOrgID(idpeOrgID, accountType, orgCount)
28+
29+
cy.intercept('GET', 'api/v2/quartz/orgs/**/users').as('getOrgsUsers')
30+
31+
if (orgHasOtherUsers) {
32+
cy.intercept('GET', `api/v2/quartz/orgs/**/users`, {
33+
body: [
34+
{
35+
id: '234234324',
36+
firstName: 'User',
37+
lastName: 'McUserface',
38+
email: 'user@influxdata.com',
39+
role: 'owner',
40+
},
41+
{
42+
id: '234234234324',
43+
firstName: 'Josh',
44+
lastName: 'Ritter',
45+
email: 'josh@influxdata.com',
46+
role: 'owner',
47+
},
48+
],
49+
}).as('getOrgsUsers')
50+
}
51+
52+
cy.visit(`orgs/${idpeOrgID}/accounts/settings`)
53+
54+
cy.wait('@getOrgsUsers')
55+
56+
cy.getByTestID('account-settings--header')
57+
})
58+
})
59+
)
60+
}
261

362
const doSetup = cy => {
463
cy.flush().then(() => {
564
cy.signin().then(() => {
665
cy.get('@org').then(({id}: Organization) => {
66+
cy.intercept('GET', 'api/v2/quartz/orgs/**/users').as('getOrgsUsers')
767
cy.visit(`/orgs/${id}/accounts/settings`)
8-
cy.wait(300)
68+
cy.wait('@getOrgsUsers')
969
})
1070
})
1171
})
@@ -82,3 +142,66 @@ describe('Account Page tests', () => {
82142
})
83143
})
84144
})
145+
146+
describe('Free account Deletion', () => {
147+
const deleteFreeAccount = () => {
148+
cy.getByTestID('delete-free-account--button').should('be.visible').click()
149+
cy.getByTestID('notification-warning').should('not.exist')
150+
151+
cy.url()
152+
.should('include', `/accounts/settings/delete`)
153+
.then(() => {
154+
cy.getByTestID('delete-free-account--overlay')
155+
.should('be.visible')
156+
.within(() => {
157+
cy.getByTestID('delete-free-account--button').should('be.disabled')
158+
159+
cy.getByTestID('agree-terms--input').click()
160+
cy.getByTestID('agree-terms--checkbox').should('be.checked')
161+
cy.getByTestID('variable-type-dropdown--button')
162+
.should('be.visible')
163+
.click()
164+
cy.contains("It doesn't work for my use case")
165+
.should('be.visible')
166+
.click()
167+
cy.getByTestID('delete-free-account--button')
168+
.should('not.be.disabled')
169+
.click()
170+
})
171+
cy.location().should(loc => {
172+
expect(loc.href).to.eq(`https://www.influxdata.com/mkt_cancel/`)
173+
})
174+
})
175+
}
176+
177+
const displayRemoveUsersWarning = () => {
178+
cy.getByTestID('delete-free-account--button').should('exist').click()
179+
180+
cy.getByTestID('notification-warning')
181+
.should('exist')
182+
.contains('All additional users must be removed')
183+
184+
cy.getByTestID('go-to-users--link').click()
185+
186+
cy.url().should('include', `/members`)
187+
}
188+
189+
it('allows the user to delete a free account if there is only one org, with only one user', () => {
190+
setupTest({
191+
accountType: 'free',
192+
orgHasOtherUsers: false,
193+
orgCount: 1,
194+
})
195+
196+
deleteFreeAccount()
197+
})
198+
199+
it('displays a `must remove users` warning if trying to delete a free account with a single org, which has multiple users', () => {
200+
setupTest({
201+
accountType: 'free',
202+
orgHasOtherUsers: true,
203+
orgCount: 1,
204+
})
205+
displayRemoveUsersWarning()
206+
})
207+
})

src/accounts/AccountPage.tsx

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// Libraries
22
import React, {ChangeEvent, FC, useContext, useEffect, useState} from 'react'
3+
import {useSelector} from 'react-redux'
4+
import {Switch, Route} from 'react-router-dom'
35

46
import {
57
Button,
@@ -15,13 +17,22 @@ import {LeaveOrgButton} from 'src/organizations/components/OrgProfileTab/LeaveOr
1517

1618
// Context
1719
import {UsersContext, UsersProvider} from 'src/users/context/users'
20+
import {DeleteFreeAccountButton} from 'src/accounts/DeleteFreeAccount'
21+
import {DeleteFreeAccountOverlay} from 'src/accounts/DeleteFreeAccountOverlay'
22+
23+
// Selectors
24+
import {selectCurrentIdentity} from 'src/identity/selectors'
25+
26+
// Constants
27+
import {CLOUD} from 'src/shared/constants'
1828

1929
// Utils
2030
import {isFlagEnabled} from 'src/shared/utils/featureFlag'
2131
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'
2232
import {UserAccountContext} from 'src/accounts/context/userAccount'
2333
import AccountTabContainer from 'src/accounts/AccountTabContainer'
2434
import AccountHeader from 'src/accounts/AccountHeader'
35+
import {DeleteFreeAccountProvider} from 'src/accounts/context/DeleteFreeAccountContext'
2536

2637
import CancellationOverlay from './CancellationOverlay'
2738
import CancelServiceProvider from 'src/billing/components/PayAsYouGo/CancelServiceContext'
@@ -47,15 +58,12 @@ const AccountAboutPage: FC = () => {
4758
setActiveAcctName(activeAccount?.name)
4859
}, [activeAccount])
4960

61+
const {user, account} = useSelector(selectCurrentIdentity)
62+
5063
const updateAcctName = (evt: ChangeEvent<HTMLInputElement>) => {
5164
setActiveAcctName(evt.target.value)
5265
}
5366

54-
const inputStyle = {width: 250}
55-
const labelStyle = {marginBottom: '10px', maxWidth: '500px'}
56-
const dividerStyle = {marginTop: '32px', maxWidth: '500px'}
57-
const actionButtonStyle = {marginTop: '24px'}
58-
5967
const showDeactivateAccountOverlay = () => {
6068
setDeactivateAccountVisible(true)
6169
}
@@ -67,6 +75,8 @@ const AccountAboutPage: FC = () => {
6775
const onRenameAccountBtnClick = () => {
6876
handleRenameActiveAccount(activeAccount.id, activeAcctName)
6977
}
78+
const shouldShowDeleteFreeAccountButton =
79+
CLOUD && account.type === 'free' && user.orgCount === 1
7080

7181
const showDeactivateAccountSection = isFlagEnabled('freeAccountCancellation')
7282
const showLeaveOrgButton = !isFlagEnabled('createDeleteOrgs')
@@ -81,16 +91,16 @@ const AccountAboutPage: FC = () => {
8191
>
8292
Account Details
8393
</h4>
84-
<div style={labelStyle}>Account Name</div>
94+
<div className="account-settings--account-name">Account Name</div>
8595
<FlexBox direction={FlexDirection.Row} margin={ComponentSize.Medium}>
8696
<Input
8797
name="accountName"
8898
testID="input--active-account-name"
99+
className="account-settings--name-input"
89100
type={InputType.Text}
90101
value={activeAcctName}
91102
onChange={updateAcctName}
92103
size={ComponentSize.Medium}
93-
style={inputStyle}
94104
/>
95105
<Button
96106
onClick={onRenameAccountBtnClick}
@@ -100,29 +110,29 @@ const AccountAboutPage: FC = () => {
100110
</FlexBox>
101111
{allowSelfRemoval && showLeaveOrgButton && (
102112
<>
103-
<hr style={dividerStyle} />
113+
<hr className="account-settings--divider" />
104114
<LeaveOrgButton />
105115
</>
106116
)}
107117
{showDeactivateAccountSection && (
108118
<>
109-
<hr style={dividerStyle} />
119+
<hr className="account-settings--divider" />
110120
<h4
111121
data-testid="account-settings--header"
112122
className="account-settings--header"
113123
>
114124
Deactivate Account
115125
</h4>
116-
<div style={labelStyle}>
126+
<div className="account-settings--deactivate-description">
117127
If you decide to deactivate this account, all your writes,
118128
queries, and tasks will be suspended immediately.
119129
</div>
120130
<FlexBox direction={FlexDirection.Row} margin={ComponentSize.Large}>
121131
<Button
132+
className="account-settings--deactivate-button"
122133
onClick={showDeactivateAccountOverlay}
123134
testID="deactivate-account--button"
124135
text="DEACTIVATE ACCOUNT"
125-
style={actionButtonStyle}
126136
/>
127137
</FlexBox>
128138
</>
@@ -132,19 +142,36 @@ const AccountAboutPage: FC = () => {
132142
<CancellationOverlay onHideOverlay={hideDeactivateAccountOverlay} />
133143
</Overlay>
134144
</CancelServiceProvider>
145+
{shouldShowDeleteFreeAccountButton && <DeleteFreeAccountButton />}
135146
</>
136147
</AccountTabContainer>
137148
)
138149
}
139150

140151
const AccountPage: FC = () => {
152+
const {account, user} = useSelector(selectCurrentIdentity)
153+
const freeAccountWithOneOrg =
154+
CLOUD && account.type === 'free' && user.orgCount === 1
155+
141156
return (
142-
<Page titleTag={pageTitleSuffixer(['Account Settings Page'])}>
143-
<AccountHeader testID="account-page--header" />
144-
<UsersProvider>
145-
<AccountAboutPage />
146-
</UsersProvider>
147-
</Page>
157+
<>
158+
<Page titleTag={pageTitleSuffixer(['Account Settings Page'])}>
159+
<AccountHeader testID="account-page--header" />
160+
<UsersProvider>
161+
<AccountAboutPage />
162+
</UsersProvider>
163+
</Page>
164+
<Switch>
165+
{freeAccountWithOneOrg && (
166+
<DeleteFreeAccountProvider>
167+
<Route
168+
path="/orgs/:orgID/accounts/settings/delete"
169+
component={DeleteFreeAccountOverlay}
170+
/>
171+
</DeleteFreeAccountProvider>
172+
)}
173+
</Switch>
174+
</>
148175
)
149176
}
150177

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,36 @@
11
.account-settings--header {
22
margin-bottom: 25px;
33
}
4+
5+
.account-settings--account-name {
6+
margin-bottom: 8px;
7+
}
8+
9+
.account-settings--name-input {
10+
width: 250px !important;
11+
}
12+
.account-settings--deactivate-description {
13+
margin-top: 20px;
14+
max-width: 550px;
15+
}
16+
17+
.account-settings--divider {
18+
margin-top: 32px;
19+
max-width: 550px;
20+
}
21+
22+
.account-settings--deactivate-button {
23+
margin-top: 15px;
24+
}
25+
26+
.account-settings-deleteAccount {
27+
margin-top: 30px;
28+
}
29+
.account-settings--deleteHeading {
30+
margin-bottom: 16px;
31+
margin-top: 24px;
32+
}
33+
34+
.account-settings-deleteAccount--overlay {
35+
margin: 32px 0;
36+
}

0 commit comments

Comments
 (0)