Skip to content

Commit a63c5a1

Browse files
ChitlangeSahasOfTheDelmerabshierjoel
authored
feat: Multi-Account Deactivation UI (#3770)
Co-authored-by: Delmer Reed <delmer814+1@gmail.com> Co-authored-by: Joel Abshier <jabshier@influxdata.com>
1 parent 7f533c5 commit a63c5a1

File tree

5 files changed

+301
-10
lines changed

5 files changed

+301
-10
lines changed

src/accounts/AccountPage.tsx

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,20 @@ import AccountTabContainer from 'src/accounts/AccountTabContainer'
2222
import AccountHeader from 'src/accounts/AccountHeader'
2323

2424
import {SwitchAccountOverlay} from 'src/accounts/SwitchAccountOverlay'
25+
import CancellationOverlay from './CancellationOverlay'
26+
import CancelServiceProvider from 'src/billing/components/PayAsYouGo/CancelServiceContext'
27+
28+
// Styles
29+
import './AccountPageStyles.scss'
2530

2631
const AccountAboutPage: FC = () => {
2732
const {userAccounts, handleRenameActiveAccount} = useContext(
2833
UserAccountContext
2934
)
3035
const [isSwitchAccountVisible, setSwitchAccountVisible] = useState(false)
36+
const [isDeactivateAccountVisible, setDeactivateAccountVisible] = useState(
37+
false
38+
)
3139

3240
/**
3341
* confirmed with @Grace and @distortia that there is guaranteed
@@ -62,8 +70,21 @@ const AccountAboutPage: FC = () => {
6270
}
6371

6472
const inputStyle = {width: 250}
65-
const labelStyle = {marginBottom: 8}
66-
const dividerStyle = {marginTop: '32px'}
73+
const labelStyle = {marginBottom: 8, maxWidth: '500px'}
74+
const dividerStyle = {marginTop: '32px', maxWidth: '500px'}
75+
const actionButtonStyle = {marginTop: '24px'}
76+
77+
const showDeactivateAccountOverlay = () => {
78+
setDeactivateAccountVisible(true)
79+
}
80+
81+
const hideDeactivateAccountOverlay = () => {
82+
setDeactivateAccountVisible(false)
83+
}
84+
85+
const onRenameAccountBtnClick = () => {
86+
handleRenameActiveAccount(activeAccount.id, activeAcctName)
87+
}
6788

6889
return (
6990
<AccountTabContainer activeTab="about">
@@ -80,7 +101,12 @@ const AccountAboutPage: FC = () => {
80101
</div>
81102
)}
82103

83-
<h4 data-testid="account-settings--header"> Account Details </h4>
104+
<h4
105+
data-testid="account-settings--header"
106+
className="account-settings--header"
107+
>
108+
Account Details
109+
</h4>
84110
<div style={labelStyle}>Account Name</div>
85111
<FlexBox direction={FlexDirection.Row} margin={ComponentSize.Medium}>
86112
<Input
@@ -93,16 +119,38 @@ const AccountAboutPage: FC = () => {
93119
style={inputStyle}
94120
/>
95121
<Button
96-
onClick={() =>
97-
handleRenameActiveAccount(activeAccount.id, activeAcctName)
98-
}
122+
onClick={onRenameAccountBtnClick}
99123
testID="rename-account--button"
100124
text="Save"
101125
/>
102126
</FlexBox>
127+
<hr style={dividerStyle} />
128+
<h4
129+
data-testid="account-settings--header"
130+
className="account-settings--header"
131+
>
132+
Deactivate Account
133+
</h4>
134+
<div style={labelStyle}>
135+
If you decide to deactivate this account, all your writes, queries,
136+
and tasks will be suspended immediately.
137+
</div>
138+
<FlexBox direction={FlexDirection.Row} margin={ComponentSize.Large}>
139+
<Button
140+
onClick={showDeactivateAccountOverlay}
141+
testID="deactivate-account--button"
142+
text="DEACTIVATE ACCOUNT"
143+
style={actionButtonStyle}
144+
/>
145+
</FlexBox>
103146
<Overlay visible={isSwitchAccountVisible}>
104147
<SwitchAccountOverlay onDismissOverlay={closeSwitchAccountDialog} />
105148
</Overlay>
149+
<CancelServiceProvider>
150+
<Overlay visible={isDeactivateAccountVisible}>
151+
<CancellationOverlay onHideOverlay={hideDeactivateAccountOverlay} />
152+
</Overlay>
153+
</CancelServiceProvider>
106154
</>
107155
</AccountTabContainer>
108156
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.account-settings--header {
2+
margin-bottom: 16px;
3+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// Libraries
2+
import React, {FC, useContext, useMemo, useState} from 'react'
3+
import {
4+
Overlay,
5+
Alert,
6+
ComponentColor,
7+
ComponentSize,
8+
IconFont,
9+
Button,
10+
ComponentStatus,
11+
} from '@influxdata/clockface'
12+
13+
// Components
14+
import CancellationTerms from './CancellationTerms'
15+
import {
16+
CancelServiceContext,
17+
VariableItems,
18+
} from 'src/billing/components/PayAsYouGo/CancelServiceContext'
19+
import {track} from 'rudder-sdk-js'
20+
import {event} from 'src/cloud/utils/reporting'
21+
import {useSelector} from 'react-redux'
22+
import {getQuartzMe} from 'src/me/selectors'
23+
import {getOrg} from 'src/organizations/selectors'
24+
import {isFlagEnabled} from 'src/shared/utils/featureFlag'
25+
import {postSignout} from 'src/client'
26+
import {UserAccountContext} from './context/userAccount'
27+
28+
interface Props {
29+
onHideOverlay: () => void
30+
}
31+
32+
const CancellationOverlay: FC<Props> = ({onHideOverlay}) => {
33+
const {handleCancelAccount} = useContext(UserAccountContext)
34+
const [hasAgreedToTerms, setHasAgreedToTerms] = useState(false)
35+
const [hasClickedCancel, setHasClickedCancel] = useState(false)
36+
const {
37+
reason,
38+
canContactForFeedback,
39+
suggestions,
40+
shortSuggestion,
41+
getRedirectLocation,
42+
} = useContext(CancelServiceContext)
43+
const quartzMe = useSelector(getQuartzMe)
44+
const org = useSelector(getOrg)
45+
46+
const handleCancelService = () => {
47+
if (!hasClickedCancel) {
48+
setHasClickedCancel(true)
49+
}
50+
51+
const payload = {
52+
org: org.id,
53+
tier: quartzMe?.accountType,
54+
email: quartzMe?.email,
55+
alternativeProduct: shortSuggestion,
56+
suggestions,
57+
reason: VariableItems[reason],
58+
canContactForFeedback: canContactForFeedback ? 'true' : 'false',
59+
}
60+
event('CancelServiceExecuted Event', payload)
61+
62+
if (
63+
isFlagEnabled('rudderstackReporting') &&
64+
isFlagEnabled('trackCancellations')
65+
) {
66+
// Send to Rudderstack
67+
track('CancelServiceExecuted', payload)
68+
}
69+
70+
handleCancelAccount()
71+
72+
if (isFlagEnabled('trackCancellations')) {
73+
postSignout({}).then(() => {
74+
window.location.href = getRedirectLocation()
75+
})
76+
}
77+
78+
event('Cancel Service Executed', payload)
79+
}
80+
81+
const handleDismiss = () => {
82+
const payload = {
83+
org: org.id,
84+
tier: quartzMe?.accountType,
85+
email: quartzMe?.email,
86+
}
87+
event('CancelServiceDismissed Event', payload)
88+
89+
if (
90+
isFlagEnabled('rudderstackReporting') &&
91+
isFlagEnabled('trackCancellations')
92+
) {
93+
// Send to Rudderstack
94+
track('CancelServiceDismissed', payload)
95+
}
96+
97+
setHasClickedCancel(false)
98+
onHideOverlay()
99+
}
100+
101+
const isFormValid = useMemo(() => {
102+
if (!isFlagEnabled('trackCancellations')) {
103+
return hasAgreedToTerms
104+
}
105+
106+
// Has Agreed to Terms & Conditions
107+
// as well as
108+
// Selected an option from the Reasons Dropdown
109+
return hasAgreedToTerms && VariableItems[reason] !== VariableItems.NO_OPTION
110+
}, [hasAgreedToTerms, reason])
111+
112+
return (
113+
<Overlay visible={true} className="cancellation-overlay">
114+
<Overlay.Container maxWidth={700}>
115+
<Overlay.Header title="Deactivate Account" onDismiss={handleDismiss} />
116+
<Overlay.Body>
117+
<Alert
118+
color={ComponentColor.Danger}
119+
icon={IconFont.AlertTriangle}
120+
testID="cancel-overlay--alert"
121+
>
122+
This action cannot be undone
123+
</Alert>
124+
<CancellationTerms
125+
hasAgreedToTerms={hasAgreedToTerms}
126+
onAgreedToTerms={() => setHasAgreedToTerms(prev => !prev)}
127+
/>
128+
</Overlay.Body>
129+
<Overlay.Footer>
130+
<Button
131+
color={ComponentColor.Danger}
132+
onClick={handleCancelService}
133+
text="Deactivate Account"
134+
size={ComponentSize.Small}
135+
status={
136+
isFormValid ? ComponentStatus.Default : ComponentStatus.Disabled
137+
}
138+
testID="cancel-service-confirmation--button"
139+
/>
140+
</Overlay.Footer>
141+
</Overlay.Container>
142+
</Overlay>
143+
)
144+
}
145+
146+
export default CancellationOverlay

src/accounts/CancellationTerms.tsx

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import React, {FC} from 'react'
2+
3+
import {
4+
ComponentSize,
5+
FlexBox,
6+
FlexDirection,
7+
JustifyContent,
8+
Input,
9+
InputType,
10+
InputLabel,
11+
AlignItems,
12+
} from '@influxdata/clockface'
13+
import CancelServiceReasonsForm from 'src/billing/components/PayAsYouGo/CancelServiceReasonsForm'
14+
15+
interface Props {
16+
hasAgreedToTerms: boolean
17+
onAgreedToTerms: () => void
18+
}
19+
20+
const cancellationReasonsStyles = {marginTop: '20px'}
21+
22+
const CancellationTerms: FC<Props> = ({hasAgreedToTerms, onAgreedToTerms}) => (
23+
<div className="cancellation-overlay--content">
24+
<ul>
25+
<li>
26+
The account and associated organizations will be deleted. This is
27+
irreversible and immediate action that cannot be undone.
28+
</li>
29+
<li>
30+
Before continuing, you are responsible for exporting any data or content
31+
(including dashboards, tasks and variables) you wish to keep. (edited)
32+
</li>
33+
</ul>
34+
<span onClick={onAgreedToTerms} data-testid="agree-terms--input">
35+
<FlexBox
36+
alignItems={AlignItems.Center}
37+
direction={FlexDirection.Row}
38+
justifyContent={JustifyContent.FlexStart}
39+
margin={ComponentSize.Medium}
40+
>
41+
<Input
42+
className="agree-terms-input"
43+
checked={hasAgreedToTerms}
44+
onChange={onAgreedToTerms}
45+
size={ComponentSize.Small}
46+
titleText="I have read the warnings above and would like to deactivate this account."
47+
type={InputType.Checkbox}
48+
testID="agree-terms--checkbox"
49+
/>
50+
<InputLabel active={hasAgreedToTerms} size={ComponentSize.Small}>
51+
I have read the warnings above and would like to deactivate this
52+
account.
53+
</InputLabel>
54+
</FlexBox>
55+
</span>
56+
<FlexBox
57+
alignItems={AlignItems.Center}
58+
direction={FlexDirection.Column}
59+
justifyContent={JustifyContent.Center}
60+
margin={ComponentSize.Large}
61+
style={cancellationReasonsStyles}
62+
>
63+
<CancelServiceReasonsForm />
64+
</FlexBox>
65+
</div>
66+
)
67+
68+
export default CancellationTerms

0 commit comments

Comments
 (0)