diff --git a/packages/backend/src/graphql/mutations/delete-user.ee.ts b/packages/backend/src/graphql/mutations/delete-user.ee.ts index b1f83097..3e894030 100644 --- a/packages/backend/src/graphql/mutations/delete-user.ee.ts +++ b/packages/backend/src/graphql/mutations/delete-user.ee.ts @@ -1,20 +1,11 @@ -import User from '../../models/user'; +import Context from '../../types/express/context'; import deleteUserQueue from '../../queues/delete-user.ee'; import { Duration } from 'luxon'; -type Params = { - input: { - id: string; - }; -}; +const deleteUser = async (_parent: unknown, params: never, context: Context) => { + const id = context.currentUser.id; -const deleteUser = async (_parent: unknown, params: Params) => { - const { id } = params.input; - await User - .query() - .findById(id) - .delete() - .throwIfNotFound(); + await context.currentUser.$query().delete(); const jobName = `Delete user - ${id}`; const jobPayload = { id }; diff --git a/packages/backend/src/graphql/schema.graphql b/packages/backend/src/graphql/schema.graphql index d40af41f..7e421f6e 100644 --- a/packages/backend/src/graphql/schema.graphql +++ b/packages/backend/src/graphql/schema.graphql @@ -54,7 +54,7 @@ type Mutation { updateStep(input: UpdateStepInput): Step deleteStep(input: DeleteStepInput): Step createUser(input: CreateUserInput): User - deleteUser(input: DeleteUserInput): Boolean + deleteUser: Boolean updateUser(input: UpdateUserInput): User forgotPassword(input: ForgotPasswordInput): Boolean resetPassword(input: ResetPasswordInput): Boolean @@ -340,10 +340,6 @@ input CreateUserInput { password: String! } -input DeleteUserInput { - id: String -} - input UpdateUserInput { email: String password: String diff --git a/packages/web/src/components/DeleteAccountDialog/index.ee.tsx b/packages/web/src/components/DeleteAccountDialog/index.ee.tsx new file mode 100644 index 00000000..59b9f308 --- /dev/null +++ b/packages/web/src/components/DeleteAccountDialog/index.ee.tsx @@ -0,0 +1,56 @@ +import * as React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useMutation } from '@apollo/client'; +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; + +import * as URLS from 'config/urls'; +import apolloClient from 'graphql/client'; +import { DELETE_USER } from 'graphql/mutations/delete-user.ee'; +import useAuthentication from 'hooks/useAuthentication'; +import useFormatMessage from 'hooks/useFormatMessage'; +import useCurrentUser from 'hooks/useCurrentUser'; + +type TDeleteAccountDialogProps = { + onClose: () => void; +} + +export default function DeleteAccountDialog(props: TDeleteAccountDialogProps) { + const [deleteUser] = useMutation(DELETE_USER); + const formatMessage = useFormatMessage(); + const currentUser = useCurrentUser(); + const authentication = useAuthentication(); + const navigate = useNavigate(); + + const handleConfirm = React.useCallback(async () => { + await deleteUser(); + + authentication.updateToken(''); + await apolloClient.clearStore(); + + navigate(URLS.LOGIN); + }, [deleteUser, currentUser]); + + return ( + + + {formatMessage('deleteAccountDialog.title')} + + + + {formatMessage('deleteAccountDialog.description')} + + + + + + + + ); +} diff --git a/packages/web/src/graphql/mutations/delete-user.ee.ts b/packages/web/src/graphql/mutations/delete-user.ee.ts new file mode 100644 index 00000000..462174eb --- /dev/null +++ b/packages/web/src/graphql/mutations/delete-user.ee.ts @@ -0,0 +1,7 @@ +import { gql } from '@apollo/client'; + +export const DELETE_USER = gql` + mutation DeleteUser { + deleteUser + } +`; diff --git a/packages/web/src/locales/en.json b/packages/web/src/locales/en.json index e900e543..0130b34f 100644 --- a/packages/web/src/locales/en.json +++ b/packages/web/src/locales/en.json @@ -89,6 +89,17 @@ "profileSettings.updatedEmail": "Your email has been updated.", "profileSettings.updatedPassword": "Your password has been updated.", "profileSettings.updatePassword": "Update password", + "profileSettings.deleteMyAccount": "Delete my account", + "profileSettings.deleteAccount": "Delete account", + "profileSettings.deleteAccountSubtitle": "This will permanently delete...", + "profileSettings.deleteAccountResult1": "Your account", + "profileSettings.deleteAccountResult2": "All your flows", + "profileSettings.deleteAccountResult3": "All your connections", + "profileSettings.deleteAccountResult4": "All execution history", + "deleteAccountDialog.title": "Delete account?", + "deleteAccountDialog.description": "This will permanently delete your account and all the associated data with it.", + "deleteAccountDialog.cancel": "Cancel?", + "deleteAccountDialog.confirm": "Yes, delete it", "notifications.title": "Notifications", "notification.releasedAt": "Released {relativeDate}", "webhookUrlInfo.title": "Your webhook URL", diff --git a/packages/web/src/pages/ProfileSettings/index.tsx b/packages/web/src/pages/ProfileSettings/index.tsx index 0c9580c4..9d1aa9a0 100644 --- a/packages/web/src/pages/ProfileSettings/index.tsx +++ b/packages/web/src/pages/ProfileSettings/index.tsx @@ -1,5 +1,8 @@ import * as React from 'react'; import { useMutation } from '@apollo/client'; +import Alert from '@mui/material/Alert'; +import AlertTitle from '@mui/material/AlertTitle'; +import Typography from '@mui/material/Typography'; import { styled } from '@mui/material/styles'; import Grid from '@mui/material/Grid'; import Button from '@mui/material/Button'; @@ -11,6 +14,7 @@ import PageTitle from 'components/PageTitle'; import Container from 'components/Container'; import Form from 'components/Form'; import TextField from 'components/TextField'; +import DeleteAccountDialog from 'components/DeleteAccountDialog/index.ee'; import { UPDATE_USER } from 'graphql/mutations/update-user'; import useFormatMessage from 'hooks/useFormatMessage'; import useCurrentUser from 'hooks/useCurrentUser'; @@ -38,6 +42,7 @@ const StyledForm = styled(Form)` `; function ProfileSettings() { + const [showDeleteAccountConfirmation, setShowDeleteAccountConfirmation] = React.useState(false); const [passwordDefaultValues, setPasswordDefaultValues] = React.useState({}); const { enqueueSnackbar } = useSnackbar(); const currentUser = useCurrentUser(); @@ -179,6 +184,40 @@ function ProfileSettings() { )} /> + + + + {formatMessage('profileSettings.deleteMyAccount')} + + + {formatMessage('profileSettings.deleteAccountSubtitle')} + + +
    +
  1. {formatMessage('profileSettings.deleteAccountResult1')}
  2. +
  3. {formatMessage('profileSettings.deleteAccountResult2')}
  4. +
  5. {formatMessage('profileSettings.deleteAccountResult3')}
  6. +
  7. {formatMessage('profileSettings.deleteAccountResult4')}
  8. +
+ + + + {showDeleteAccountConfirmation && ( + setShowDeleteAccountConfirmation(false)} + /> + )} +
+
);