Skip to content

Commit

Permalink
Feature/password reset and change (#146)
Browse files Browse the repository at this point in the history
* feat: password reset

* feat: password reset and password change
  • Loading branch information
danilolutz authored Feb 16, 2022
1 parent 44121ac commit 596e94e
Show file tree
Hide file tree
Showing 15 changed files with 476 additions and 61 deletions.
30 changes: 30 additions & 0 deletions src/app/components/LoggedUser/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { useCallback, useState } from 'react';
import { FiUser } from 'react-icons/fi';
import { useAuth } from '../../hooks/auth';
import LoggedUserModal from '../LoggedUserModal';

import { Container } from './styles';

const LoggedUser: React.FC = () => {
const { user } = useAuth();
const [loggedUserModal, setLoggedUserModal] = useState(false);

const handleloggedUserModal = useCallback(() => {
setLoggedUserModal((oldState) => !oldState);
}, []);

return (
<>
<Container onClick={handleloggedUserModal}>
<FiUser size={16} />
<span>{user && user.name}</span>
</Container>
<LoggedUserModal
isOpen={loggedUserModal}
setOpen={handleloggedUserModal}
/>
</>
);
};

export default LoggedUser;
13 changes: 13 additions & 0 deletions src/app/components/LoggedUser/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { tint } from 'polished';
import styled from 'styled-components';

export const Container = styled.div`
display: flex;
padding: 6px;
height: 100%;
cursor: pointer;
&:hover {
background-color: ${(props) => tint(0.4 ,props.theme.colors.background)};
}
`;
160 changes: 160 additions & 0 deletions src/app/components/LoggedUserModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import React, { useCallback, useState } from 'react';
import { FiLogOut, FiRefreshCw } from 'react-icons/fi';
import ReactModal from 'react-modal';
import { useToast } from '../../hooks/toast';
import { useAuth } from '../../hooks/auth';
import { useNavigate } from 'react-router-dom';
import i18n from '../../i18n';
import Button from '../Button';
import Input from '../Input';
import { Container, Row } from './styles';

interface ModalProps {
isOpen: boolean;
setOpen: () => void;
}

const LoggedUserModal: React.FC<ModalProps> = ({ isOpen, setOpen }) => {
const { user, signOut } = useAuth();
const { addToast } = useToast();
const navigate = useNavigate();

const [oldPassword, setOldPassword] = useState('');
const [newPassword, setNewPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');

const handleUpdatePassword = useCallback(() => {
if (!oldPassword) {
addToast({
title: i18n.t('notifications.warning'),
type: 'error',
description: i18n.t('profile.typePassword'),
});
return;
}
if (!newPassword) {
addToast({
title: i18n.t('notifications.warning'),
type: 'error',
description: i18n.t('profile.typeNewPassword'),
});
return;
}

if (!confirmPassword) {
addToast({
title: i18n.t('notifications.warning'),
type: 'error',
description: i18n.t('profile.typeConfirmPassword'),
});
return;
}

if (newPassword !== confirmPassword) {
addToast({
title: i18n.t('notifications.warning'),
type: 'error',
description: i18n.t('profile.newAndConfirmPassword'),
});
return;
}

const changed = window.api.sendSync('changePassword', {
entity: 'User',
value: {
userId: user.id,
password: oldPassword,
newPassword,
},
}) as { id: string };

if (!changed) {
addToast({
title: i18n.t('notifications.warning'),
type: 'error',
description: i18n.t('profile.oldPasswordInvalid'),
});
return;
}

addToast({
title: i18n.t('notifications.success'),
type: 'success',
description: i18n.t('profile.successPasswordChange'),
});

setOldPassword('');
setNewPassword('');
setConfirmPassword('');
}, [addToast, confirmPassword, newPassword, oldPassword, user.id]);

return (
<ReactModal
shouldCloseOnOverlayClick={true}
onRequestClose={setOpen}
isOpen={isOpen}
ariaHideApp={false}
className={'password-modal'}
overlayClassName="modal-overlay"
>
<Container>
<h2>{user.name}</h2>
<Row>
<h3>{i18n.t('button.changePassword')}</h3>
</Row>
<Row>
<Input
type="password"
name="oldPassword"
placeholder={i18n.t('person.password')}
value={oldPassword}
onChange={(e) => setOldPassword(e.target.value)}
/>
</Row>
<Row>
<Input
type="password"
name="newPassword"
placeholder={i18n.t('person.newPassword')}
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
/>
</Row>
<Row>
<Input
type="password"
name="confirmPassword"
placeholder={i18n.t('person.confirmPassword')}
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
</Row>
<Row>
<Button
color="primary"
title={i18n.t('button.changePassword')}
onClick={handleUpdatePassword}
>
<FiRefreshCw size={20} />
&nbsp;
{i18n.t('button.changePassword')}
</Button>
</Row>

<Row>
<Button
color="primary"
title={i18n.t('button.logout')}
onClick={signOut}
>
<FiLogOut size={20} />
&nbsp;
{i18n.t('button.logout')}
</Button>
</Row>
</Container>
</ReactModal>
);
};

export default LoggedUserModal;
14 changes: 14 additions & 0 deletions src/app/components/LoggedUserModal/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import styled from 'styled-components';

export const Container = styled.div`
display: flex;
flex-direction: column;
padding: 24px;
`;

export const Row = styled.div`
display: flex;
flex-direction: column;
padding: 16px;
`;
2 changes: 1 addition & 1 deletion src/app/components/Login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const Login: React.FC = () => {
<Container>
<Center>
<Card>
<Form>
<Form onSubmit={e => e.preventDefault()}>
<img src={logoImg} alt="Librarian" width="64" />

<Input
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Person/Create/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ const CreatePerson: React.FC = () => {
return;
}

const result = window.api.sendSync('create', {
const result = window.api.sendSync('userCreate', {
entity: 'User',
value: {
name,
Expand Down
56 changes: 32 additions & 24 deletions src/app/components/Person/List/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,24 @@ const PersonList: React.FC = () => {

useEffect(() => {
try {
setLoading(true);
const response = window.api.sendSync('listPerson', {
entity: 'User',
value: {
where: null,
pageStart: 0,
pageSize: rowsPerPage,
},
}) as PaginatedSearch<Person>;
setList(response.data);
setLoading(false);
} catch (err) {
console.error(err);
}

setLoading(true);
const response = window.api.sendSync('listPerson', {
entity: 'User',
value: {
where: null,
pageStart: 0,
pageSize: rowsPerPage,
},
}) as PaginatedSearch<Person>;
setList(response.data);
setLoading(false);
} catch (err) {
console.error(err);
}
}, [rowsPerPage]);

const handleUpdate = (item: Person): void => {
trigger(AppEvent.personTab, { action: Actions.update, value: item});
trigger(AppEvent.personTab, { action: Actions.update, value: item });
};

const handleRowClick = (item: Person) => {
Expand All @@ -65,16 +64,25 @@ const PersonList: React.FC = () => {
id: 'edit',
Cell: (row: Cell<Person>) => {
return (
<ColumWrapper>
<FaPen size={20} title={i18n.t('person.edit')} onClick={(event) => { event.stopPropagation(); handleUpdate(row.row.original)}} />
</ColumWrapper>)
}
}
<ColumWrapper>
{row.row.original.login !== 'admin' && (
<FaPen
size={20}
title={i18n.t('person.edit')}
onClick={(event) => {
event.stopPropagation();
handleUpdate(row.row.original);
}}
/>
)}
</ColumWrapper>
);
},
},
],
[],
[]
);


const handleSubmit = useCallback(
async ({ pageIndex = 0 }: Search) => {
try {
Expand Down Expand Up @@ -102,7 +110,7 @@ const PersonList: React.FC = () => {
});
}
},
[addToast, rowsPerPage],
[addToast, rowsPerPage]
);

return (
Expand Down
49 changes: 38 additions & 11 deletions src/app/components/Person/Update/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const PersonUpdate: React.FC<{ item: Person }> = ({ item }) => {
const [document, setDocument] = useState('');
const [notes, setNotes] = useState('');
const [contact, setContact] = useState('');
const [password, setPassword] = useState('');

const [complement, setComplement] = useState('');
const [zipcode, setZipcode] = useState('');
Expand Down Expand Up @@ -256,17 +257,22 @@ const PersonUpdate: React.FC<{ item: Person }> = ({ item }) => {
return;
}

const result = window.api.sendSync('update', {
let insertEntity = {
id: item.id,
name,
login,
language: i18n.language,
notes,
document,
userTypeId: userType.id,
};
if (password) {
insertEntity = { ...insertEntity, ...{ password } };
}

const result = window.api.sendSync('userUpdate', {
entity: 'User',
value: {
id: item.id,
name,
login,
language: i18n.language,
notes,
document,
userTypeId: userType.id,
},
value: insertEntity,
}) as { id: string };

['Contact', 'Address'].map((tableName) => {
Expand Down Expand Up @@ -317,7 +323,17 @@ const PersonUpdate: React.FC<{ item: Person }> = ({ item }) => {
action: Actions.read,
value: insertedPerson,
});
}, [addToast, addresses, contacts, document, item.id, login, name, notes]);
}, [
addToast,
addresses,
contacts,
document,
item.id,
login,
name,
notes,
password,
]);

const handleCityModal = useCallback(() => {
setAddingCity((oldState) => !oldState);
Expand Down Expand Up @@ -372,6 +388,17 @@ const PersonUpdate: React.FC<{ item: Person }> = ({ item }) => {
placeholder={i18n.t('person.login')}
/>
</Column>
<Column>
<Input
type="password"
name="password"
label={i18n.t('person.password')}
onChange={(e) => setPassword(e.target.value)}
value={password}
required={false}
placeholder={i18n.t('person.password')}
/>
</Column>
<Column>
<Input
type="text"
Expand Down
Loading

0 comments on commit 596e94e

Please sign in to comment.