Merge pull request #1717 from automatisch/AUT-829
refactor: rewrite useCurrentUser with RQ
This commit is contained in:
@@ -1,5 +0,0 @@
|
|||||||
const getCurrentUser = async (_parent, _params, context) => {
|
|
||||||
return context.currentUser;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getCurrentUser;
|
|
@@ -1,79 +0,0 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
|
||||||
import request from 'supertest';
|
|
||||||
import app from '../../app';
|
|
||||||
import createAuthTokenByUserId from '../../helpers/create-auth-token-by-user-id';
|
|
||||||
import { createRole } from '../../../test/factories/role';
|
|
||||||
import { createUser } from '../../../test/factories/user';
|
|
||||||
|
|
||||||
describe('graphQL getCurrentUser query', () => {
|
|
||||||
let role, currentUser, token, requestObject;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
role = await createRole({
|
|
||||||
key: 'sample',
|
|
||||||
name: 'sample',
|
|
||||||
});
|
|
||||||
|
|
||||||
currentUser = await createUser({
|
|
||||||
roleId: role.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
token = createAuthTokenByUserId(currentUser.id);
|
|
||||||
requestObject = request(app).post('/graphql').set('Authorization', token);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return user data', async () => {
|
|
||||||
const query = `
|
|
||||||
query {
|
|
||||||
getCurrentUser {
|
|
||||||
id
|
|
||||||
email
|
|
||||||
fullName
|
|
||||||
email
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
role {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const response = await requestObject.send({ query }).expect(200);
|
|
||||||
|
|
||||||
const expectedResponsePayload = {
|
|
||||||
data: {
|
|
||||||
getCurrentUser: {
|
|
||||||
createdAt: currentUser.createdAt.getTime().toString(),
|
|
||||||
email: currentUser.email,
|
|
||||||
fullName: currentUser.fullName,
|
|
||||||
id: currentUser.id,
|
|
||||||
role: { id: role.id, name: role.name },
|
|
||||||
updatedAt: currentUser.updatedAt.getTime().toString(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(response.body).toEqual(expectedResponsePayload);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not return user password', async () => {
|
|
||||||
const query = `
|
|
||||||
query {
|
|
||||||
getCurrentUser {
|
|
||||||
id
|
|
||||||
email
|
|
||||||
password
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const response = await requestObject.send({ query }).expect(400);
|
|
||||||
|
|
||||||
expect(response.body.errors).toBeDefined();
|
|
||||||
expect(response.body.errors[0].message).toEqual(
|
|
||||||
'Cannot query field "password" on type "User".'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -4,7 +4,6 @@ import getAppAuthClients from './queries/get-app-auth-clients.ee.js';
|
|||||||
import getBillingAndUsage from './queries/get-billing-and-usage.ee.js';
|
import getBillingAndUsage from './queries/get-billing-and-usage.ee.js';
|
||||||
import getConfig from './queries/get-config.ee.js';
|
import getConfig from './queries/get-config.ee.js';
|
||||||
import getConnectedApps from './queries/get-connected-apps.js';
|
import getConnectedApps from './queries/get-connected-apps.js';
|
||||||
import getCurrentUser from './queries/get-current-user.js';
|
|
||||||
import getDynamicData from './queries/get-dynamic-data.js';
|
import getDynamicData from './queries/get-dynamic-data.js';
|
||||||
import getDynamicFields from './queries/get-dynamic-fields.js';
|
import getDynamicFields from './queries/get-dynamic-fields.js';
|
||||||
import getFlow from './queries/get-flow.js';
|
import getFlow from './queries/get-flow.js';
|
||||||
@@ -26,7 +25,6 @@ const queryResolvers = {
|
|||||||
getBillingAndUsage,
|
getBillingAndUsage,
|
||||||
getConfig,
|
getConfig,
|
||||||
getConnectedApps,
|
getConnectedApps,
|
||||||
getCurrentUser,
|
|
||||||
getDynamicData,
|
getDynamicData,
|
||||||
getDynamicFields,
|
getDynamicFields,
|
||||||
getFlow,
|
getFlow,
|
||||||
|
@@ -24,7 +24,6 @@ type Query {
|
|||||||
parameters: JSONObject
|
parameters: JSONObject
|
||||||
): [SubstepArgument]
|
): [SubstepArgument]
|
||||||
getBillingAndUsage: GetBillingAndUsage
|
getBillingAndUsage: GetBillingAndUsage
|
||||||
getCurrentUser: User
|
|
||||||
getConfig(keys: [String]): JSONObject
|
getConfig(keys: [String]): JSONObject
|
||||||
getPermissionCatalog: PermissionCatalog
|
getPermissionCatalog: PermissionCatalog
|
||||||
getNotifications: [Notification]
|
getNotifications: [Notification]
|
||||||
|
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useMutation } from '@apollo/client';
|
import { useMutation } from '@apollo/client';
|
||||||
|
|
||||||
import * as URLS from 'config/urls';
|
import * as URLS from 'config/urls';
|
||||||
import ConfirmationDialog from 'components/ConfirmationDialog';
|
import ConfirmationDialog from 'components/ConfirmationDialog';
|
||||||
import apolloClient from 'graphql/client';
|
import apolloClient from 'graphql/client';
|
||||||
@@ -13,15 +14,19 @@ import useCurrentUser from 'hooks/useCurrentUser';
|
|||||||
function DeleteAccountDialog(props) {
|
function DeleteAccountDialog(props) {
|
||||||
const [deleteCurrentUser] = useMutation(DELETE_CURRENT_USER);
|
const [deleteCurrentUser] = useMutation(DELETE_CURRENT_USER);
|
||||||
const formatMessage = useFormatMessage();
|
const formatMessage = useFormatMessage();
|
||||||
const currentUser = useCurrentUser();
|
const { data } = useCurrentUser();
|
||||||
|
const currentUser = data?.data;
|
||||||
|
|
||||||
const authentication = useAuthentication();
|
const authentication = useAuthentication();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handleConfirm = React.useCallback(async () => {
|
const handleConfirm = React.useCallback(async () => {
|
||||||
await deleteCurrentUser();
|
await deleteCurrentUser();
|
||||||
authentication.updateToken('');
|
authentication.updateToken('');
|
||||||
await apolloClient.clearStore();
|
await apolloClient.clearStore();
|
||||||
navigate(URLS.LOGIN);
|
navigate(URLS.LOGIN);
|
||||||
}, [deleteCurrentUser, currentUser]);
|
}, [deleteCurrentUser, currentUser]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmationDialog
|
<ConfirmationDialog
|
||||||
title={formatMessage('deleteAccountDialog.title')}
|
title={formatMessage('deleteAccountDialog.title')}
|
||||||
|
@@ -1,22 +1,28 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useTheme } from '@mui/material/styles';
|
import { useTheme } from '@mui/material/styles';
|
||||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||||
|
|
||||||
import appConfig from 'config/app';
|
import appConfig from 'config/app';
|
||||||
import useCurrentUser from 'hooks/useCurrentUser';
|
import useCurrentUser from 'hooks/useCurrentUser';
|
||||||
|
|
||||||
const Chatwoot = ({ ready }) => {
|
const Chatwoot = ({ ready }) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const currentUser = useCurrentUser();
|
const { data } = useCurrentUser();
|
||||||
|
const currentUser = data?.data;
|
||||||
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'));
|
const matchSmallScreens = useMediaQuery(theme.breakpoints.down('md'));
|
||||||
|
|
||||||
React.useEffect(function initiateChatwoot() {
|
React.useEffect(function initiateChatwoot() {
|
||||||
window.chatwootSDK.run({
|
window.chatwootSDK.run({
|
||||||
websiteToken: 'EFyq5MTsvS7XwUrwSH36VskT',
|
websiteToken: 'EFyq5MTsvS7XwUrwSH36VskT',
|
||||||
baseUrl: appConfig.chatwootBaseUrl,
|
baseUrl: appConfig.chatwootBaseUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
return function removeChatwoot() {
|
return function removeChatwoot() {
|
||||||
window.$chatwoot.reset();
|
window.$chatwoot.reset();
|
||||||
window.$chatwoot.toggleBubbleVisibility('hide');
|
window.$chatwoot.toggleBubbleVisibility('hide');
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(
|
||||||
function initiateUser() {
|
function initiateUser() {
|
||||||
if (!currentUser?.id || !ready) return;
|
if (!currentUser?.id || !ready) return;
|
||||||
@@ -24,6 +30,7 @@ const Chatwoot = ({ ready }) => {
|
|||||||
email: currentUser.email,
|
email: currentUser.email,
|
||||||
name: currentUser.fullName,
|
name: currentUser.fullName,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!matchSmallScreens) {
|
if (!matchSmallScreens) {
|
||||||
window.$chatwoot.toggleBubbleVisibility('show');
|
window.$chatwoot.toggleBubbleVisibility('show');
|
||||||
}
|
}
|
||||||
@@ -40,6 +47,7 @@ const Chatwoot = ({ ready }) => {
|
|||||||
},
|
},
|
||||||
[matchSmallScreens],
|
[matchSmallScreens],
|
||||||
);
|
);
|
||||||
|
|
||||||
return <React.Fragment />;
|
return <React.Fragment />;
|
||||||
};
|
};
|
||||||
export default Chatwoot;
|
export default Chatwoot;
|
||||||
|
@@ -21,7 +21,8 @@ import usePaddle from 'hooks/usePaddle.ee';
|
|||||||
|
|
||||||
export default function UpgradeFreeTrial() {
|
export default function UpgradeFreeTrial() {
|
||||||
const { data: plans, isLoading: isPaymentPlansLoading } = usePaymentPlans();
|
const { data: plans, isLoading: isPaymentPlansLoading } = usePaymentPlans();
|
||||||
const currentUser = useCurrentUser();
|
const { data } = useCurrentUser();
|
||||||
|
const currentUser = data?.data;
|
||||||
const { loaded: paddleLoaded } = usePaddle();
|
const { loaded: paddleLoaded } = usePaddle();
|
||||||
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
||||||
const selectedPlan = plans?.data?.[selectedIndex];
|
const selectedPlan = plans?.data?.[selectedIndex];
|
||||||
@@ -30,10 +31,10 @@ export default function UpgradeFreeTrial() {
|
|||||||
const handleCheckout = React.useCallback(() => {
|
const handleCheckout = React.useCallback(() => {
|
||||||
window.Paddle.Checkout?.open({
|
window.Paddle.Checkout?.open({
|
||||||
product: selectedPlan.productId,
|
product: selectedPlan.productId,
|
||||||
email: currentUser.email,
|
email: currentUser?.email,
|
||||||
passthrough: JSON.stringify({
|
passthrough: JSON.stringify({
|
||||||
id: currentUser.id,
|
id: currentUser?.id,
|
||||||
email: currentUser.email,
|
email: currentUser?.email,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}, [selectedPlan, currentUser]);
|
}, [selectedPlan, currentUser]);
|
||||||
|
@@ -1,20 +0,0 @@
|
|||||||
import { gql } from '@apollo/client';
|
|
||||||
export const GET_CURRENT_USER = gql`
|
|
||||||
query GetCurrentUser {
|
|
||||||
getCurrentUser {
|
|
||||||
id
|
|
||||||
fullName
|
|
||||||
email
|
|
||||||
role {
|
|
||||||
id
|
|
||||||
isAdmin
|
|
||||||
}
|
|
||||||
permissions {
|
|
||||||
id
|
|
||||||
action
|
|
||||||
subject
|
|
||||||
conditions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,6 +1,18 @@
|
|||||||
import { useQuery } from '@apollo/client';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { GET_CURRENT_USER } from 'graphql/queries/get-current-user';
|
|
||||||
|
import api from 'helpers/api';
|
||||||
|
|
||||||
export default function useCurrentUser() {
|
export default function useCurrentUser() {
|
||||||
const { data } = useQuery(GET_CURRENT_USER);
|
const query = useQuery({
|
||||||
return data?.getCurrentUser;
|
queryKey: ['currentUser'],
|
||||||
|
queryFn: async ({ signal }) => {
|
||||||
|
const { data } = await api.get(`/v1/users/me`, {
|
||||||
|
signal,
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return query;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
import userAbility from 'helpers/userAbility';
|
import userAbility from 'helpers/userAbility';
|
||||||
import useCurrentUser from 'hooks/useCurrentUser';
|
import useCurrentUser from 'hooks/useCurrentUser';
|
||||||
|
|
||||||
export default function useCurrentUserAbility() {
|
export default function useCurrentUserAbility() {
|
||||||
const currentUser = useCurrentUser();
|
const { data: currentUser } = useCurrentUser();
|
||||||
return userAbility(currentUser);
|
|
||||||
|
return userAbility(currentUser?.data);
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@ import { styled } from '@mui/material/styles';
|
|||||||
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
|
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import * as yup from 'yup';
|
import * as yup from 'yup';
|
||||||
|
|
||||||
import Container from 'components/Container';
|
import Container from 'components/Container';
|
||||||
import DeleteAccountDialog from 'components/DeleteAccountDialog/index.ee';
|
import DeleteAccountDialog from 'components/DeleteAccountDialog/index.ee';
|
||||||
import Form from 'components/Form';
|
import Form from 'components/Form';
|
||||||
@@ -17,6 +18,7 @@ import TextField from 'components/TextField';
|
|||||||
import { UPDATE_CURRENT_USER } from 'graphql/mutations/update-current-user';
|
import { UPDATE_CURRENT_USER } from 'graphql/mutations/update-current-user';
|
||||||
import useCurrentUser from 'hooks/useCurrentUser';
|
import useCurrentUser from 'hooks/useCurrentUser';
|
||||||
import useFormatMessage from 'hooks/useFormatMessage';
|
import useFormatMessage from 'hooks/useFormatMessage';
|
||||||
|
|
||||||
const validationSchema = yup
|
const validationSchema = yup
|
||||||
.object({
|
.object({
|
||||||
fullName: yup.string().required(),
|
fullName: yup.string().required(),
|
||||||
@@ -27,27 +29,33 @@ const validationSchema = yup
|
|||||||
.oneOf([yup.ref('password')], 'Passwords must match'),
|
.oneOf([yup.ref('password')], 'Passwords must match'),
|
||||||
})
|
})
|
||||||
.required();
|
.required();
|
||||||
|
|
||||||
const StyledForm = styled(Form)`
|
const StyledForm = styled(Form)`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: end;
|
align-items: end;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function ProfileSettings() {
|
function ProfileSettings() {
|
||||||
const [showDeleteAccountConfirmation, setShowDeleteAccountConfirmation] =
|
const [showDeleteAccountConfirmation, setShowDeleteAccountConfirmation] =
|
||||||
React.useState(false);
|
React.useState(false);
|
||||||
const enqueueSnackbar = useEnqueueSnackbar();
|
const enqueueSnackbar = useEnqueueSnackbar();
|
||||||
const currentUser = useCurrentUser();
|
const { data } = useCurrentUser();
|
||||||
|
const currentUser = data?.data;
|
||||||
const formatMessage = useFormatMessage();
|
const formatMessage = useFormatMessage();
|
||||||
const [updateCurrentUser] = useMutation(UPDATE_CURRENT_USER);
|
const [updateCurrentUser] = useMutation(UPDATE_CURRENT_USER);
|
||||||
|
|
||||||
const handleProfileSettingsUpdate = async (data) => {
|
const handleProfileSettingsUpdate = async (data) => {
|
||||||
const { fullName, password, email } = data;
|
const { fullName, password, email } = data;
|
||||||
const mutationInput = {
|
const mutationInput = {
|
||||||
fullName,
|
fullName,
|
||||||
email,
|
email,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (password) {
|
if (password) {
|
||||||
mutationInput.password = password;
|
mutationInput.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateCurrentUser({
|
await updateCurrentUser({
|
||||||
variables: {
|
variables: {
|
||||||
input: mutationInput,
|
input: mutationInput,
|
||||||
@@ -55,12 +63,13 @@ function ProfileSettings() {
|
|||||||
optimisticResponse: {
|
optimisticResponse: {
|
||||||
updateCurrentUser: {
|
updateCurrentUser: {
|
||||||
__typename: 'User',
|
__typename: 'User',
|
||||||
id: currentUser.id,
|
id: currentUser?.id,
|
||||||
fullName,
|
fullName,
|
||||||
email,
|
email,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
enqueueSnackbar(formatMessage('profileSettings.updatedProfile'), {
|
enqueueSnackbar(formatMessage('profileSettings.updatedProfile'), {
|
||||||
variant: 'success',
|
variant: 'success',
|
||||||
SnackbarProps: {
|
SnackbarProps: {
|
||||||
@@ -68,6 +77,7 @@ function ProfileSettings() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container sx={{ py: 3, display: 'flex', justifyContent: 'center' }}>
|
<Container sx={{ py: 3, display: 'flex', justifyContent: 'center' }}>
|
||||||
<Grid container item xs={12} sm={9} md={8} lg={6}>
|
<Grid container item xs={12} sm={9} md={8} lg={6}>
|
||||||
|
Reference in New Issue
Block a user