From bee6bc550a3150f4b6f3d26ba8a8e781a02f3306 Mon Sep 17 00:00:00 2001 From: lcampbell Date: Tue, 1 Nov 2022 12:46:15 -0300 Subject: [PATCH 01/14] add api bool value for insider status --- api/src/user/mutations/sign-up.js | 1 + api/src/user/mutations/update-user-profile.js | 14 +++++++++++++- api/src/user/objects/user-personal.js | 5 +++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/api/src/user/mutations/sign-up.js b/api/src/user/mutations/sign-up.js index 7953964518..d0f0331084 100644 --- a/api/src/user/mutations/sign-up.js +++ b/api/src/user/mutations/sign-up.js @@ -131,6 +131,7 @@ export const signUp = new mutationWithClientMutationId({ preferredLang: preferredLang, phoneValidated: false, emailValidated: false, + insideUser: false, failedLoginAttempts: 0, tfaSendMethod: 'none', refreshInfo: { diff --git a/api/src/user/mutations/update-user-profile.js b/api/src/user/mutations/update-user-profile.js index 497d8dacee..d41801c983 100644 --- a/api/src/user/mutations/update-user-profile.js +++ b/api/src/user/mutations/update-user-profile.js @@ -1,4 +1,4 @@ -import { GraphQLString } from 'graphql' +import { GraphQLString, GraphQLBoolean } from 'graphql' import { mutationWithClientMutationId } from 'graphql-relay' import { GraphQLEmailAddress } from 'graphql-scalars' import { t } from '@lingui/macro' @@ -29,6 +29,11 @@ export const updateUserProfile = new mutationWithClientMutationId({ description: 'The method in which the user wishes to have their TFA code sent via.', }, + insideUser: { + type: GraphQLBoolean, + description: + 'The updated boolean which represents if the user wants to see features in progress.', + }, }), outputFields: () => ({ result: { @@ -58,6 +63,7 @@ export const updateUserProfile = new mutationWithClientMutationId({ const userName = cleanseInput(args.userName).toLowerCase() const preferredLang = cleanseInput(args.preferredLang) const subTfaSendMethod = cleanseInput(args.tfaSendMethod) + const insideUserBool = args.insideUser // Get user info from DB const user = await userRequired() @@ -132,6 +138,8 @@ export const updateUserProfile = new mutationWithClientMutationId({ emailValidated = false } + console.log('insideUser', args.insideUser) + // Create object containing updated data const updatedUser = { displayName: displayName || user.displayName, @@ -139,6 +147,10 @@ export const updateUserProfile = new mutationWithClientMutationId({ preferredLang: preferredLang || user.preferredLang, tfaSendMethod: tfaSendMethod, emailValidated, + insideUser: + typeof insideUserBool !== 'undefined' + ? insideUserBool + : user?.insideUser, } // Setup Transaction diff --git a/api/src/user/objects/user-personal.js b/api/src/user/objects/user-personal.js index b2ecd376a1..3bb609f1da 100644 --- a/api/src/user/objects/user-personal.js +++ b/api/src/user/objects/user-personal.js @@ -55,6 +55,11 @@ export const userPersonalType = new GraphQLObjectType({ description: 'The method in which TFA codes are sent.', resolve: ({ tfaSendMethod }) => tfaSendMethod, }, + insideUser: { + type: GraphQLBoolean, + description: 'Does the user want to see new features in progress.', + resolve: ({ insideUser }) => insideUser, + }, affiliations: { type: affiliationConnection.connectionType, description: 'Users affiliations to various organizations.', From 1f8607eae41e7dc56fd8e429e31207b8a77ebc19 Mon Sep 17 00:00:00 2001 From: lcampbell Date: Tue, 1 Nov 2022 12:47:06 -0300 Subject: [PATCH 02/14] update queries and mutations --- frontend/src/graphql/fragments.js | 1 + frontend/src/graphql/mutations.js | 3 +++ frontend/src/graphql/queries.js | 1 + 3 files changed, 5 insertions(+) diff --git a/frontend/src/graphql/fragments.js b/frontend/src/graphql/fragments.js index 85dc7a21ec..619ba0d293 100644 --- a/frontend/src/graphql/fragments.js +++ b/frontend/src/graphql/fragments.js @@ -11,6 +11,7 @@ export const Authorization = { tfaSendMethod preferredLang emailValidated + insideUser } } `, diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index 25b5aad911..e27a72ab6b 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -150,6 +150,7 @@ export const UPDATE_USER_PROFILE = gql` $userName: EmailAddress $preferredLang: LanguageEnums $tfaSendMethod: TFASendMethodEnum + $insideUser: Boolean ) { updateUserProfile( input: { @@ -157,6 +158,7 @@ export const UPDATE_USER_PROFILE = gql` userName: $userName preferredLang: $preferredLang tfaSendMethod: $tfaSendMethod + insideUser: $insideUser } ) { result { @@ -168,6 +170,7 @@ export const UPDATE_USER_PROFILE = gql` userName preferredLang tfaSendMethod + insideUser } } ... on UpdateUserProfileError { diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 39bdd50bc7..7f7e8376d3 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -713,6 +713,7 @@ export const QUERY_CURRENT_USER = gql` tfaSendMethod phoneValidated emailValidated + insideUser } isUserAdmin } From 4f3144c2a218cc6ae25e2d4685281431dd879666 Mon Sep 17 00:00:00 2001 From: lcampbell Date: Tue, 1 Nov 2022 12:48:18 -0300 Subject: [PATCH 03/14] add insideUser value to userState --- frontend/src/auth/CreateUserPage.js | 1 + frontend/src/auth/SignInPage.js | 1 + frontend/src/auth/TwoFactorAuthenticatePage.js | 1 + frontend/src/index.js | 1 + frontend/src/user/EditableUserTFAMethod.js | 4 ++-- frontend/src/utilities/userState.js | 5 ++++- 6 files changed, 10 insertions(+), 3 deletions(-) diff --git a/frontend/src/auth/CreateUserPage.js b/frontend/src/auth/CreateUserPage.js index f58186f1f2..b36959d61f 100644 --- a/frontend/src/auth/CreateUserPage.js +++ b/frontend/src/auth/CreateUserPage.js @@ -51,6 +51,7 @@ export default function CreateUserPage() { tfaSendMethod: signUp.result.user.tfaSendMethod, userName: signUp.result.user.userName, emailValidated: signUp.result.user.emailValidated, + insideUser: signUp.result.user.insideUser, }) if (signUp.result.user.preferredLang === 'ENGLISH') activate('en') else if (signUp.result.user.preferredLang === 'FRENCH') activate('fr') diff --git a/frontend/src/auth/SignInPage.js b/frontend/src/auth/SignInPage.js index 9d1a97ffd1..e8af2e55fe 100644 --- a/frontend/src/auth/SignInPage.js +++ b/frontend/src/auth/SignInPage.js @@ -59,6 +59,7 @@ export default function SignInPage() { tfaSendMethod: signIn.result.user.tfaSendMethod, userName: signIn.result.user.userName, emailValidated: signIn.result.user.emailValidated, + insideUser: signIn.result.user.insideUser, }) if (signIn.result.user.preferredLang === 'ENGLISH') activate('en') else if (signIn.result.user.preferredLang === 'FRENCH') activate('fr') diff --git a/frontend/src/auth/TwoFactorAuthenticatePage.js b/frontend/src/auth/TwoFactorAuthenticatePage.js index a3acc02393..7397dc08d1 100644 --- a/frontend/src/auth/TwoFactorAuthenticatePage.js +++ b/frontend/src/auth/TwoFactorAuthenticatePage.js @@ -45,6 +45,7 @@ export default function TwoFactorAuthenticatePage() { tfaSendMethod: authenticate.result.user.tfaSendMethod, userName: authenticate.result.user.userName, emailValidated: authenticate.result.user.emailValidated, + insideUser: authenticate.result.user.insideUser, }) if (authenticate.result.user.preferredLang === 'ENGLISH') activate('en') else if (authenticate.result.user.preferredLang === 'FRENCH') diff --git a/frontend/src/index.js b/frontend/src/index.js index d76d6a942f..fef27e928e 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -42,6 +42,7 @@ const I18nApp = () => { tfaSendMethod: refreshTokens.result.user.tfaSendMethod, userName: refreshTokens.result.user.userName, emailValidated: refreshTokens.result.user.emailValidated, + insideUser: refreshTokens.result.user.insideUser, }) if (from.pathname !== '/') history.replace(from) } diff --git a/frontend/src/user/EditableUserTFAMethod.js b/frontend/src/user/EditableUserTFAMethod.js index 873aa6e76f..0646e06bb5 100644 --- a/frontend/src/user/EditableUserTFAMethod.js +++ b/frontend/src/user/EditableUserTFAMethod.js @@ -116,13 +116,13 @@ export function EditableUserTFAMethod({ ) : ( )} diff --git a/frontend/src/utilities/userState.js b/frontend/src/utilities/userState.js index 4ed2a08826..7eb1da0e31 100644 --- a/frontend/src/utilities/userState.js +++ b/frontend/src/utilities/userState.js @@ -13,6 +13,7 @@ export function UserVarProvider({ tfaSendMethod: null, userName: null, emailValidated: null, + insideUser: null, }), children, }) { @@ -24,7 +25,8 @@ export function UserVarProvider({ currentUser?.jwt || currentUser?.userName || currentUser?.tfaSendMethod || - currentUser?.emailValidated + currentUser?.emailValidated || + currentUser?.insideUser ) } @@ -46,6 +48,7 @@ export function UserVarProvider({ userName: null, tfaSendMethod: null, emailValidated: null, + insideUser: null, }) await client.resetStore() } From 90d9e58f19eb59a3cee76006e31300c63d5ee6b4 Mon Sep 17 00:00:00 2001 From: lcampbell Date: Tue, 1 Nov 2022 12:48:38 -0300 Subject: [PATCH 04/14] add frontend switch --- frontend/src/app/ABTestWrapper.js | 18 +++++-- frontend/src/user/InsideUserSwitch.js | 77 +++++++++++++++++++++++++++ frontend/src/user/UserPage.js | 3 ++ 3 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 frontend/src/user/InsideUserSwitch.js diff --git a/frontend/src/app/ABTestWrapper.js b/frontend/src/app/ABTestWrapper.js index 5f2d8022b1..25660a0be3 100644 --- a/frontend/src/app/ABTestWrapper.js +++ b/frontend/src/app/ABTestWrapper.js @@ -2,8 +2,8 @@ import React from 'react' import { any, string } from 'prop-types' import { useUserVar } from '../utilities/userState' -const isInsiderUser = ({ userName }) => { - return userName.endsWith('@tbs-sct.gc.ca') +const isInsiderUser = ({ userName, insideUser }) => { + return userName.endsWith('@tbs-sct.gc.ca') || insideUser } export function ABTestingWrapper({ children, insiderVariantName = 'B' }) { @@ -12,7 +12,12 @@ export function ABTestingWrapper({ children, insiderVariantName = 'B' }) { // only one variant if (!children.length) { - if (isInsiderUser({ userName: currentUser?.userName || '' })) { + if ( + isInsiderUser({ + userName: currentUser?.userName || '', + insideUser: currentUser?.insideUser || false, + }) + ) { if (children.props.name === insiderVariantName) return <>{children} else return <> } else { @@ -21,7 +26,12 @@ export function ABTestingWrapper({ children, insiderVariantName = 'B' }) { } } // A + B variants - if (isInsiderUser({ userName: currentUser?.userName || '' })) { + if ( + isInsiderUser({ + userName: currentUser?.userName || '', + insideUser: currentUser?.insideUser || false, + }) + ) { childIndex = children.findIndex( (variant) => variant.props.name === insiderVariantName, ) diff --git a/frontend/src/user/InsideUserSwitch.js b/frontend/src/user/InsideUserSwitch.js new file mode 100644 index 0000000000..e6eaf0db4f --- /dev/null +++ b/frontend/src/user/InsideUserSwitch.js @@ -0,0 +1,77 @@ +import { useMutation } from '@apollo/client' +import { Badge, Box, Switch, useToast } from '@chakra-ui/react' +import { Trans, t } from '@lingui/macro' +import { bool } from 'prop-types' +import React from 'react' +import { UPDATE_USER_PROFILE } from '../graphql/mutations' +export function InsideUserSwtich({ insideUser }) { + const toast = useToast() + const [updateUserProfile, { error: _updateUserProfileError }] = useMutation( + UPDATE_USER_PROFILE, + { + onError: ({ message }) => { + toast({ + title: t`An error occurred while updating your email address.`, + description: message, + status: 'error', + duration: 9000, + isClosable: true, + position: 'top-left', + }) + }, + onCompleted({ updateUserProfile }) { + console.log(updateUserProfile) + if (updateUserProfile.result.__typename === 'UpdateUserProfileResult') { + toast({ + title: t`Insider status changed`, + description: t`You have successfully updated your insider preference.`, + status: 'success', + duration: 9000, + isClosable: true, + position: 'top-left', + }) + } else if ( + updateUserProfile.result.__typename === 'UpdateUserProfileError' + ) { + toast({ + title: t`Unable to update to your insider status, please try again.`, + description: updateUserProfile.result.description, + status: 'error', + duration: 9000, + isClosable: true, + position: 'top-left', + }) + } else { + toast({ + title: t`Incorrect send method received.`, + description: t`Incorrect updateUserProfile.result typename.`, + status: 'error', + duration: 9000, + isClosable: true, + position: 'top-left', + }) + console.log('Incorrect updateUserProfile.result typename.') + } + }, + }, + ) + return ( + + + await updateUserProfile({ + variables: { insideUser: e.target.checked }, + }) + } + /> + + Inside User + + + ) +} + +InsideUserSwtich.propTypes = { + insideUser: bool.isRequired, +} diff --git a/frontend/src/user/UserPage.js b/frontend/src/user/UserPage.js index d78f65a1f5..072d5f3e22 100644 --- a/frontend/src/user/UserPage.js +++ b/frontend/src/user/UserPage.js @@ -42,6 +42,7 @@ import { SIGN_OUT, } from '../graphql/mutations' import { NotificationBanner } from '../app/NotificationBanner' +import { InsideUserSwtich } from './InsideUserSwitch' export default function UserPage() { const toast = useToast() @@ -163,6 +164,7 @@ export default function UserPage() { tfaSendMethod, emailValidated, phoneValidated, + insideUser, } = queryUserData?.userPage return ( @@ -210,6 +212,7 @@ export default function UserPage() { Verify Account )} + )} - + )} - + + + )} - + {/* */}