feat: add change password tab to user profile settings

This commit is contained in:
Jordan Knott 2020-08-12 14:09:12 -05:00
parent e64f6f8569
commit 6761d4571e
5 changed files with 152 additions and 4 deletions

View File

@ -4,8 +4,9 @@ import GlobalTopNavbar from 'App/TopNavbar';
import { Link } from 'react-router-dom';
import { getAccessToken } from 'shared/utils/accessToken';
import Settings from 'shared/components/Settings';
import { useMeQuery, useClearProfileAvatarMutation } from 'shared/generated/graphql';
import { useMeQuery, useClearProfileAvatarMutation, useUpdateUserPasswordMutation } from 'shared/generated/graphql';
import axios from 'axios';
import { useCurrentUser } from 'App/context';
const MainContent = styled.div`
padding: 0 0 50px 80px;
@ -16,10 +17,16 @@ const MainContent = styled.div`
const Projects = () => {
const $fileUpload = useRef<HTMLInputElement>(null);
const [clearProfileAvatar] = useClearProfileAvatarMutation();
const { user } = useCurrentUser();
const [updateUserPassword] = useUpdateUserPasswordMutation();
const { loading, data, refetch } = useMeQuery();
useEffect(() => {
document.title = 'Profile | Taskcafé';
}, []);
if (!user) {
return null;
}
return (
<>
<input
@ -57,6 +64,10 @@ const Projects = () => {
$fileUpload.current.click();
}
}}
onResetPassword={(password, done) => {
updateUserPassword({ variables: { userID: user.id, password } });
done();
}}
onProfileAvatarRemove={() => {
clearProfileAvatar();
}}

View File

@ -27,6 +27,7 @@ export const Default = () => {
<BaseStyles />
<Settings
profile={profile}
onResetPassword={action('reset password')}
onProfileAvatarRemove={action('remove')}
onProfileAvatarChange={action('profile avatar change')}
/>

View File

@ -3,6 +3,17 @@ import styled from 'styled-components';
import { User } from 'shared/icons';
import Input from 'shared/components/Input';
import Button from 'shared/components/Button';
import { useForm } from 'react-hook-form';
const PasswordInput = styled(Input)`
margin-top: 30px;
margin-bottom: 0;
`;
const FormError = styled.span`
font-size: 12px;
color: rgba(${props => props.theme.colors.warning});
`;
const ProfileContainer = styled.div`
display: flex;
@ -218,6 +229,7 @@ const SettingActions = styled.div`
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 12px;
`;
const SaveButton = styled(Button)`
@ -228,10 +240,73 @@ const SaveButton = styled(Button)`
type SettingsProps = {
onProfileAvatarChange: () => void;
onProfileAvatarRemove: () => void;
onResetPassword: (password: string, done: () => void) => void;
profile: TaskUser;
};
const Settings: React.FC<SettingsProps> = ({ onProfileAvatarRemove, onProfileAvatarChange, profile }) => {
type TabProps = {
tab: number;
currentTab: number;
};
const Tab: React.FC<TabProps> = ({ tab, currentTab, children }) => {
if (tab !== currentTab) {
return null;
}
return <TabContent>{children}</TabContent>;
};
type ResetPasswordTabProps = {
onResetPassword: (password: string, done: () => void) => void;
};
const ResetPasswordTab: React.FC<ResetPasswordTabProps> = ({ onResetPassword }) => {
const [active, setActive] = useState(true);
const { register, handleSubmit, errors, setError, reset } = useForm<{ password: string; password_confirm: string }>();
const done = () => {
reset();
setActive(true);
};
return (
<form
onSubmit={handleSubmit(data => {
console.log(`${data.password} !== ${data.password_confirm}`);
if (data.password !== data.password_confirm) {
setError('password', { message: 'Passwords must match!', type: 'error' });
setError('password_confirm', { message: 'Passwords must match!', type: 'error' });
} else {
onResetPassword(data.password, done);
}
})}
>
<PasswordInput
width="100%"
ref={register({ required: 'Password is required' })}
label="Password"
name="password"
/>
{errors.password && <FormError>{errors.password.message}</FormError>}
<PasswordInput
width="100%"
ref={register({ required: 'Password is required' })}
label="Password (confirm)"
name="password_confirm"
/>
{errors.password_confirm && <FormError>{errors.password_confirm.message}</FormError>}
<SettingActions>
<SaveButton disabled={!active} type="submit">
Save Change
</SaveButton>
</SettingActions>
</form>
);
};
const Settings: React.FC<SettingsProps> = ({
onProfileAvatarRemove,
onProfileAvatarChange,
onResetPassword,
profile,
}) => {
const [currentTab, setTab] = useState(0);
const [currentTop, setTop] = useState(0);
const $tabNav = useRef<HTMLDivElement>(null);
@ -257,7 +332,7 @@ const Settings: React.FC<SettingsProps> = ({ onProfileAvatarRemove, onProfileAva
</TabNavContent>
</TabNav>
<TabContentWrapper>
<TabContent>
<Tab tab={0} currentTab={currentTab}>
<AvatarSettings
onProfileAvatarRemove={onProfileAvatarRemove}
onProfileAvatarChange={onProfileAvatarChange}
@ -275,7 +350,10 @@ const Settings: React.FC<SettingsProps> = ({ onProfileAvatarRemove, onProfileAva
<SettingActions>
<SaveButton>Save Change</SaveButton>
</SettingActions>
</TabContent>
</Tab>
<Tab tab={1} currentTab={currentTab}>
<ResetPasswordTab onResetPassword={onResetPassword} />
</Tab>
</TabContentWrapper>
</Container>
);

View File

@ -1935,6 +1935,20 @@ export type DeleteUserAccountMutation = (
) }
);
export type UpdateUserPasswordMutationVariables = {
userID: Scalars['UUID'];
password: Scalars['String'];
};
export type UpdateUserPasswordMutation = (
{ __typename?: 'Mutation' }
& { updateUserPassword: (
{ __typename?: 'UpdateUserPasswordPayload' }
& Pick<UpdateUserPasswordPayload, 'ok'>
) }
);
export type UpdateUserRoleMutationVariables = {
userID: Scalars['UUID'];
roleCode: RoleCode;
@ -3975,6 +3989,39 @@ export function useDeleteUserAccountMutation(baseOptions?: ApolloReactHooks.Muta
export type DeleteUserAccountMutationHookResult = ReturnType<typeof useDeleteUserAccountMutation>;
export type DeleteUserAccountMutationResult = ApolloReactCommon.MutationResult<DeleteUserAccountMutation>;
export type DeleteUserAccountMutationOptions = ApolloReactCommon.BaseMutationOptions<DeleteUserAccountMutation, DeleteUserAccountMutationVariables>;
export const UpdateUserPasswordDocument = gql`
mutation updateUserPassword($userID: UUID!, $password: String!) {
updateUserPassword(input: {userID: $userID, password: $password}) {
ok
}
}
`;
export type UpdateUserPasswordMutationFn = ApolloReactCommon.MutationFunction<UpdateUserPasswordMutation, UpdateUserPasswordMutationVariables>;
/**
* __useUpdateUserPasswordMutation__
*
* To run a mutation, you first call `useUpdateUserPasswordMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useUpdateUserPasswordMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [updateUserPasswordMutation, { data, loading, error }] = useUpdateUserPasswordMutation({
* variables: {
* userID: // value for 'userID'
* password: // value for 'password'
* },
* });
*/
export function useUpdateUserPasswordMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<UpdateUserPasswordMutation, UpdateUserPasswordMutationVariables>) {
return ApolloReactHooks.useMutation<UpdateUserPasswordMutation, UpdateUserPasswordMutationVariables>(UpdateUserPasswordDocument, baseOptions);
}
export type UpdateUserPasswordMutationHookResult = ReturnType<typeof useUpdateUserPasswordMutation>;
export type UpdateUserPasswordMutationResult = ApolloReactCommon.MutationResult<UpdateUserPasswordMutation>;
export type UpdateUserPasswordMutationOptions = ApolloReactCommon.BaseMutationOptions<UpdateUserPasswordMutation, UpdateUserPasswordMutationVariables>;
export const UpdateUserRoleDocument = gql`
mutation updateUserRole($userID: UUID!, $roleCode: RoleCode!) {
updateUserRole(input: {userID: $userID, roleCode: $roleCode}) {

View File

@ -0,0 +1,11 @@
import gql from 'graphql-tag';
export const UPDATE_USER_PASSWORD_MUTATION = gql`
mutation updateUserPassword($userID: UUID!, $password: String!) {
updateUserPassword(input: { userID: $userID, password: $password }) {
ok
}
}
`;
export default UPDATE_USER_PASSWORD_MUTATION;