-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(operators): Add reactivate account button #6747
Changes from all commits
64945ab
3daea14
cd22d40
3a2c3e1
ece7f80
b0dcab4
1c70ed7
0f886b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import React, {FC, useContext} from 'react' | ||
import { | ||
Alert, | ||
ButtonBase, | ||
ButtonShape, | ||
ComponentColor, | ||
ComponentStatus, | ||
Gradients, | ||
IconFont, | ||
Overlay, | ||
RemoteDataState, | ||
} from '@influxdata/clockface' | ||
import {AccountContext} from 'src/operator/context/account' | ||
|
||
const ReactivateAccountOverlay: FC = () => { | ||
const { | ||
account, | ||
organizations, | ||
reactivateStatus, | ||
handleReactivateAccount, | ||
setReactivateOverlayVisible, | ||
reactivateOverlayVisible, | ||
} = useContext(AccountContext) | ||
|
||
const reactivateAccount = () => { | ||
if (account?.reactivatable) { | ||
try { | ||
handleReactivateAccount() | ||
} catch (e) { | ||
setReactivateOverlayVisible(false) | ||
} | ||
} | ||
} | ||
|
||
const message = ` | ||
This action will reactivate the Account | ||
${account?.id ?? 'N/A'} and unsuspend the organizations:` | ||
|
||
const active = reactivateStatus === RemoteDataState.NotStarted | ||
|
||
return ( | ||
<Overlay | ||
visible={reactivateOverlayVisible} | ||
renderMaskElement={() => ( | ||
<Overlay.Mask gradient={Gradients.DangerDark} style={{opacity: 0.5}} /> | ||
)} | ||
testID="reactivate-overlay" | ||
transitionDuration={0} | ||
> | ||
<Overlay.Container maxWidth={600}> | ||
<Overlay.Header | ||
title="Reactivate Account" | ||
style={{color: '#FFFFFF'}} | ||
onDismiss={() => setReactivateOverlayVisible(false)} | ||
/> | ||
<Overlay.Body> | ||
<Alert color={ComponentColor.Danger} icon={IconFont.AlertTriangle}> | ||
This action cannot be undone | ||
</Alert> | ||
<h4 style={{color: '#FFFFFF'}}> | ||
<strong>Warning</strong> | ||
</h4> | ||
{message} | ||
<ul> | ||
{organizations.map(o => ( | ||
<li key={o.id}>{o.name ?? 'N/A'} </li> | ||
))} | ||
</ul> | ||
</Overlay.Body> | ||
<Overlay.Footer> | ||
<ButtonBase | ||
color={ComponentColor.Primary} | ||
shape={ButtonShape.Default} | ||
onClick={reactivateAccount} | ||
testID="reactivate-account--confirmation-button" | ||
active={active} | ||
status={active ? ComponentStatus.Default : ComponentStatus.Disabled} | ||
> | ||
I understand, reactivate account. | ||
</ButtonBase> | ||
</Overlay.Footer> | ||
</Overlay.Container> | ||
</Overlay> | ||
) | ||
} | ||
|
||
export default ReactivateAccountOverlay |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ import {useDispatch} from 'react-redux' | |
// Utils | ||
import { | ||
patchOperatorAccountsConvert, | ||
patchOperatorAccountsReactivate, | ||
deleteOperatorAccount, | ||
getOperatorAccount, | ||
} from 'src/client/unityRoutes' | ||
|
@@ -14,6 +15,7 @@ import { | |
getAccountError, | ||
convertAccountError, | ||
deleteAccountError, | ||
reactivateAccountError, | ||
} from 'src/shared/copy/notifications' | ||
|
||
// Types | ||
|
@@ -28,33 +30,41 @@ export interface AccountContextType { | |
accountStatus: RemoteDataState | ||
convertStatus: RemoteDataState | ||
deleteStatus: RemoteDataState | ||
reactivateStatus: RemoteDataState | ||
handleConvertAccountToContract: (contractStartDate: string) => void | ||
handleDeleteAccount: () => void | ||
handleGetAccount: () => void | ||
handleReactivateAccount: () => void | ||
organizations: OperatorOrg[] | ||
setConvertToContractOverlayVisible: (vis: boolean) => void | ||
convertToContractOverlayVisible: boolean | ||
setCancelOverlayVisible: (vis: boolean) => void | ||
cancelOverlayVisible: boolean | ||
setDeleteOverlayVisible: (vis: boolean) => void | ||
deleteOverlayVisible: boolean | ||
setReactivateOverlayVisible: (vis: boolean) => void | ||
reactivateOverlayVisible: boolean | ||
} | ||
|
||
export const DEFAULT_CONTEXT: AccountContextType = { | ||
account: null, | ||
accountStatus: RemoteDataState.NotStarted, | ||
convertStatus: RemoteDataState.NotStarted, | ||
deleteStatus: RemoteDataState.NotStarted, | ||
reactivateStatus: RemoteDataState.NotStarted, | ||
handleConvertAccountToContract: () => {}, | ||
handleDeleteAccount: () => {}, | ||
handleGetAccount: () => {}, | ||
handleReactivateAccount: () => {}, | ||
organizations: null, | ||
setConvertToContractOverlayVisible: (_: boolean) => {}, | ||
convertToContractOverlayVisible: false, | ||
cancelOverlayVisible: false, | ||
setCancelOverlayVisible: (_: boolean) => {}, | ||
setDeleteOverlayVisible: (_: boolean) => {}, | ||
setReactivateOverlayVisible: (_: boolean) => {}, | ||
cancelOverlayVisible: false, | ||
deleteOverlayVisible: false, | ||
reactivateOverlayVisible: false, | ||
} | ||
|
||
export const AccountContext = | ||
|
@@ -67,9 +77,14 @@ export const AccountProvider: FC<Props> = React.memo(({children}) => { | |
useState(false) | ||
const [cancelOverlayVisible, setCancelOverlayVisible] = useState(false) | ||
const [deleteOverlayVisible, setDeleteOverlayVisible] = useState(false) | ||
const [reactivateOverlayVisible, setReactivateOverlayVisible] = | ||
useState(false) | ||
const [accountStatus, setAccountStatus] = useState(RemoteDataState.NotStarted) | ||
const [convertStatus, setConvertStatus] = useState(RemoteDataState.NotStarted) | ||
const [deleteStatus, setDeleteStatus] = useState(RemoteDataState.NotStarted) | ||
const [reactivateStatus, setReactivateStatus] = useState( | ||
RemoteDataState.NotStarted | ||
) | ||
|
||
const {accountID} = useParams<{accountID: string}>() | ||
const history = useHistory() | ||
|
@@ -138,23 +153,42 @@ export const AccountProvider: FC<Props> = React.memo(({children}) => { | |
} | ||
}, [dispatch, history, accountID]) | ||
|
||
const handleReactivateAccount = useCallback(async () => { | ||
try { | ||
setReactivateStatus(RemoteDataState.Loading) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I started to remove it, but I instead kept it to disable the reactivate button once they click it. Technically, the operation is idempotent, but it's probably better if they're not smashing it, since it can be a slow operation. |
||
const resp = await patchOperatorAccountsReactivate({accountId: accountID}) | ||
if (resp.status !== 200) { | ||
throw new Error(resp.data.message) | ||
} | ||
setReactivateStatus(RemoteDataState.Done) | ||
history.push('/operator') | ||
} catch (error) { | ||
console.error({error}) | ||
dispatch(notify(reactivateAccountError(accountID))) | ||
} | ||
}, [dispatch, history, accountID]) | ||
|
||
return ( | ||
<AccountContext.Provider | ||
value={{ | ||
account, | ||
accountStatus, | ||
convertStatus, | ||
deleteStatus, | ||
reactivateStatus, | ||
handleConvertAccountToContract, | ||
handleDeleteAccount, | ||
handleGetAccount, | ||
handleReactivateAccount, | ||
organizations, | ||
setConvertToContractOverlayVisible, | ||
convertToContractOverlayVisible, | ||
setCancelOverlayVisible, | ||
cancelOverlayVisible, | ||
setDeleteOverlayVisible, | ||
deleteOverlayVisible, | ||
setReactivateOverlayVisible, | ||
reactivateOverlayVisible, | ||
}} | ||
> | ||
{children} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this openapi SHA - it looks like the request body is just an
object
? Could we add a more specific type in openapi? I worry this is going to cause issues (or at min some warnings) with type validation on the UI side if we don't have a schema for the body.Example:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wdoconnell thanks! So what do we usually do whenever there's no request body necessary? IIRC, without a requestBody, OATS won't generate it right. But it's not strictly necessary, so that's why I ended up with
object
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@abshierjoel Oh, in that case, just ignore what I said 😓 - I had thought this would be relied on. If there's no
request body
being used I think it's fine to leave it asobject
.