From bae94fa67ef00ec92779c1586bf30fc889c7b8f9 Mon Sep 17 00:00:00 2001 From: Jonathanjojo Date: Fri, 8 May 2020 11:57:36 +0700 Subject: [PATCH 1/9] [RED] Add tests for empty fields after submit --- .../components/AddAccountForm/index.test.tsx | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/scenes/AccountManagement/components/AddAccountForm/index.test.tsx b/src/scenes/AccountManagement/components/AddAccountForm/index.test.tsx index d6a6849..e5fc3a6 100644 --- a/src/scenes/AccountManagement/components/AddAccountForm/index.test.tsx +++ b/src/scenes/AccountManagement/components/AddAccountForm/index.test.tsx @@ -34,7 +34,6 @@ describe('AddNewAccountForm', () => { expect(addAccountForm).toBeTruthy(); }); - it('submits on a valid submission', async () => { let val = 0; const addAccountForm = renderer.create( @@ -44,16 +43,16 @@ describe('AddNewAccountForm', () => { ); const nameField = addAccountForm.root.find((elem:Element) => elem.props.id === 'name'); - expect(nameField).toBeTruthy(); const usernameField = addAccountForm.root.find((elem:Element) => elem.props.id === 'username'); - expect(usernameField).toBeTruthy(); const passwordField = addAccountForm.root.find((elem:Element) => elem.props.id === 'password'); - expect(passwordField).toBeTruthy(); const emailField = addAccountForm.root.find((elem:Element) => elem.props.id === 'email'); - expect(emailField).toBeTruthy(); const phoneField = addAccountForm.root.find((elem:Element) => elem.props.id === 'phone'); - expect(phoneField).toBeTruthy(); const areaField = addAccountForm.root.find((elem:Element) => elem.props.id === 'area'); + expect(nameField).toBeTruthy(); + expect(usernameField).toBeTruthy(); + expect(passwordField).toBeTruthy(); + expect(emailField).toBeTruthy(); + expect(phoneField).toBeTruthy(); expect(areaField).toBeTruthy(); act(() => { @@ -93,15 +92,22 @@ describe('AddNewAccountForm', () => { expect(val).toEqual(1); const errorPassword = addAccountForm.root.find((elem:Element) => elem.props.id === 'errorPassword'); - expect(errorPassword.props.children).toEqual(''); const errorName = addAccountForm.root.find((elem:Element) => elem.props.id === 'errorName'); - expect(errorName.props.children).toEqual(''); const errorUsername = addAccountForm.root.find((elem:Element) => elem.props.id === 'errorUsername'); - expect(errorUsername.props.children).toEqual(''); const errorEmail = addAccountForm.root.find((elem:Element) => elem.props.id === 'errorEmail'); - expect(errorEmail.props.children).toEqual(''); const errorArea = addAccountForm.root.find((elem:Element) => elem.props.id === 'errorArea'); + expect(errorPassword.props.children).toEqual(''); + expect(errorName.props.children).toEqual(''); + expect(errorUsername.props.children).toEqual(''); + expect(errorEmail.props.children).toEqual(''); expect(errorArea.props.children).toEqual(''); + + expect(nameField.props.value).toEqual(''); + expect(usernameField.props.value).toEqual(''); + expect(passwordField.props.value).toEqual(''); + expect(emailField.props.value).toEqual(''); + expect(phoneField.props.value).toEqual(''); + expect(areaField.props.value).toEqual(''); }); -- GitLab From 73efa8a9b4302c741d70fff9665a4ae46a8ed103 Mon Sep 17 00:00:00 2001 From: Jonathanjojo Date: Fri, 8 May 2020 12:02:41 +0700 Subject: [PATCH 2/9] [GREEN] Reset fields on signup success --- .../components/AddAccountForm/index.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/scenes/AccountManagement/components/AddAccountForm/index.tsx b/src/scenes/AccountManagement/components/AddAccountForm/index.tsx index 51ba433..95896c3 100644 --- a/src/scenes/AccountManagement/components/AddAccountForm/index.tsx +++ b/src/scenes/AccountManagement/components/AddAccountForm/index.tsx @@ -41,7 +41,16 @@ export default function AddAccountForm(props: AddAccountFormProps) { area: { type: 'text' }, }); - const resetAccountFields = () => ({ + const resetFields = () => { + setField('name', ''); + setField('username', ''); + setField('password', ''); + setField('email', ''); + setField('phone_number', ''); + setField('area', ''); + }; + + const getInitialFields = () => ({ name: '', username: '', password: '', @@ -50,7 +59,7 @@ export default function AddAccountForm(props: AddAccountFormProps) { area: '', }); - const [errors, setErrors] = useState(resetAccountFields()); + const [errors, setErrors] = useState(getInitialFields()); const [isAdminSelected, setIsAdminSelected] = useState(''); const [isPasswordShown, setShowPassword] = useState(false); @@ -94,7 +103,8 @@ export default function AddAccountForm(props: AddAccountFormProps) { ); - resetAccountFields(); + resetFields(); + setErrors(getInitialFields()); setShowPassword(false); } else { setErrors({ -- GitLab From 5c8f64cff5f5daaceb675807097f7a492fd6a793 Mon Sep 17 00:00:00 2001 From: Jonathanjojo Date: Fri, 8 May 2020 12:18:19 +0700 Subject: [PATCH 3/9] [REFACTOR] Improve show password update flow --- .../AccountManagement/components/AddAccountForm/index.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scenes/AccountManagement/components/AddAccountForm/index.tsx b/src/scenes/AccountManagement/components/AddAccountForm/index.tsx index 95896c3..9162607 100644 --- a/src/scenes/AccountManagement/components/AddAccountForm/index.tsx +++ b/src/scenes/AccountManagement/components/AddAccountForm/index.tsx @@ -159,13 +159,14 @@ export default function AddAccountForm(props: AddAccountFormProps) { type={Field.Type.Text} isRequired placeholder='Masukan password akun' - shouldSecure={isPasswordShown} + shouldSecure={!isPasswordShown} value={addAccountForm.fields.password.value} updateValue={(value) => setField('password', value)} /> { setShowPassword(!isPasswordShown);}} + isChecked={isPasswordShown} + updateValue={(value) => { setShowPassword(value);}} /> {errors.password} -- GitLab From 9cee5f42ea91b5de35dc17a3f18849f436e865ad Mon Sep 17 00:00:00 2001 From: Irwanto Date: Fri, 8 May 2020 13:55:17 +0700 Subject: [PATCH 4/9] [REFACTOR] Move error translate utility from component level to AccountManagement directory --- .../AccountManagement/components/AddAccountForm/index.tsx | 2 +- .../{components/AddAccountForm => utilities}/utils.tsx | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/scenes/AccountManagement/{components/AddAccountForm => utilities}/utils.tsx (100%) diff --git a/src/scenes/AccountManagement/components/AddAccountForm/index.tsx b/src/scenes/AccountManagement/components/AddAccountForm/index.tsx index 9162607..23aec8a 100644 --- a/src/scenes/AccountManagement/components/AddAccountForm/index.tsx +++ b/src/scenes/AccountManagement/components/AddAccountForm/index.tsx @@ -16,7 +16,7 @@ import { AppContext } from 'contexts'; import { useFormState } from 'helper'; import { KELURAHAN_VALUES, SIGNUP_CATEGORY } from 'constant'; import { Account } from 'contexts/AppContext/types'; -import { errorTranslate } from './utils'; +import { errorTranslate } from '../../utilities/utils'; const ErrorMessage = styled.div` diff --git a/src/scenes/AccountManagement/components/AddAccountForm/utils.tsx b/src/scenes/AccountManagement/utilities/utils.tsx similarity index 100% rename from src/scenes/AccountManagement/components/AddAccountForm/utils.tsx rename to src/scenes/AccountManagement/utilities/utils.tsx -- GitLab From 99870a5419ae87b8360e04d4ab259cf3a2f0f446 Mon Sep 17 00:00:00 2001 From: Irwanto Date: Fri, 8 May 2020 14:33:36 +0700 Subject: [PATCH 5/9] [RED] Change user profile edit validation test --- .../components/UserProfile/index.test.tsx | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/scenes/AccountManagement/components/UserProfile/index.test.tsx b/src/scenes/AccountManagement/components/UserProfile/index.test.tsx index 1d373b5..6e9d004 100644 --- a/src/scenes/AccountManagement/components/UserProfile/index.test.tsx +++ b/src/scenes/AccountManagement/components/UserProfile/index.test.tsx @@ -128,7 +128,7 @@ it('can edit user succesfully', () => { expect(mockedAxios.request).toBeCalled(); }); -it('show information when edit user with invalid fields', () => { +it('show information when edit user with invalid fields', async () => { const userProfile = renderer.create( { const emailField = userProfile.root.find((elem:Element) => elem.props.name === 'Email'); const phoneField = userProfile.root.find((elem:Element) => elem.props.name === 'Nomor HP'); act(() => { - nameField.props.updateValue('Nama 123'); + nameField.props.updateValue(''); emailField.props.updateValue('aa'); phoneField.props.updateValue('0123'); }); - expect(nameField.props.value).toBe('Nama 123'); + expect(nameField.props.value).toBe(''); expect(emailField.props.value).toBe('aa'); expect(phoneField.props.value).toBe('0123'); - act(() => { + const mockedAxios = axios as jest.Mocked; + mockedAxios.request.mockImplementationOnce( + () => new Promise(resolve => { + resolve({ + status: 400, + data: { + 'name': ['This field may not be blank.'], + 'area': ['This field may not be blank.'], + 'email': ['Enter a valid email address.'], + 'phone_number': ['Phone number has 9-15 digits, allowed to have + prefix'], + }, + }); + }) + ); + + await act(async () => { editButton.props.onClick(); }); - expect(nameField.props.information).toBe('Nama tidak boleh kosong dan hanya mengandung alfabet'); - expect(emailField.props.information).toBe('Harus diisi dengan email yang valid'); - expect(phoneField.props.information).toBe('Harus diisi dengan nomor HP yang valid'); + expect(mockedAxios.request).toBeCalled(); + expect(nameField.props.information).toBe('Informasi tidak boleh kosong.'); + expect(emailField.props.information).toBe('Email tidak valid.'); + expect(phoneField.props.information).toBe('Nomor telepon harus terdiri dari 9-15 digit dan dapat diawali dengan +.'); }); -it('can handle when edit user failed', () => { +it('can handle when edit user failed with no response', () => { const userProfile = renderer.create( { const mockedAxios = axios as jest.Mocked; mockedAxios.request.mockImplementationOnce( () => new Promise(resolve => { - resolve({ - status: 400 - }); + resolve(null); }) ); -- GitLab From 3bf4e4069ce6d2587403121b1aa77b65666718de Mon Sep 17 00:00:00 2001 From: Irwanto Date: Fri, 8 May 2020 14:50:43 +0700 Subject: [PATCH 6/9] [GREEN] Change edit account validation to BE validation --- .../components/UserProfile/index.tsx | 70 ++++++++++++------- .../AccountManagement/utilities/utils.tsx | 2 +- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/scenes/AccountManagement/components/UserProfile/index.tsx b/src/scenes/AccountManagement/components/UserProfile/index.tsx index 49dc757..d51db36 100644 --- a/src/scenes/AccountManagement/components/UserProfile/index.tsx +++ b/src/scenes/AccountManagement/components/UserProfile/index.tsx @@ -4,6 +4,7 @@ import { KELURAHAN_VALUES } from 'constant'; import { Box, Image, Cloud, Button, Field, Gap, Text } from 'components'; import { useFormState } from 'helper'; import { AppContext } from 'contexts'; +import { errorTranslate } from '../../utilities/utils'; interface UserProfileProps { id: string; @@ -57,39 +58,41 @@ export default function UserProfile({ const [isVerified, setIsVerified] = useState(is_verified); const [editStatus, setEditStatus] = useState(''); const [deleteStatus, setDeleteStatus] = useState(''); - const [isFirstTime, setIsFirstTime] = useState(true); const [canDelete, setCanDelete] = useState(true); - useEffect(() => { - setUserField('name', name); - setUserField('username', username); - setUserField('email', email); - setUserField('phoneNumber', phoneNumber); - setUserField('area', area); - - if (id === user?.id) { - setCanDelete(false); - } - }, []); + const getInitialFields = () => ({ + name: '', + email: '', + phone_number: '', + area: '' + }); + const [errors, setErrors] = useState(getInitialFields()); const hanldeEditAccount = async () => { - setIsFirstTime(false); - if (userForm.isValid) { - const editBody = { - name: userForm.fields.name.value, - email: userForm.fields.email.value, - phone_number: userForm.fields.phoneNumber.value, - area: userForm.fields.area.value, - }; - const editResponse = await services.main.editAccount(id, editBody); + const editBody = { + name: userForm.fields.name.value, + email: userForm.fields.email.value, + phone_number: userForm.fields.phoneNumber.value, + area: userForm.fields.area.value, + }; + const editResponse = await services.main.editAccount(id, editBody); - if (editResponse && editResponse.status === 200) { + if (editResponse) { + if (editResponse.status === 200) { setEditStatus('Pengubahan data akun berhasil dilakukan.'); setShouldEdit(!shouldEdit); updateTable(); - } else { - setEditStatus('Pengubahan data akun gagal dilakukan.'); } + else { + setErrors({ + name: errorTranslate(editResponse.data.name || []), + email: errorTranslate(editResponse.data.email || []), + phone_number: errorTranslate(editResponse.data.phone_number || []), + area: errorTranslate(editResponse.data.area || []) + }); + } + } else { + setEditStatus('Pengubahan data akun gagal dilakukan.'); } }; @@ -139,6 +142,18 @@ export default function UserProfile({ updateTable(); }; + useEffect(() => { + setUserField('name', name); + setUserField('username', username); + setUserField('email', email); + setUserField('phoneNumber', phoneNumber); + setUserField('area', area); + + if (id === user?.id) { + setCanDelete(false); + } + }, []); + return ( @@ -194,7 +209,7 @@ export default function UserProfile({ value={userForm.fields.name.value} editable={shouldEdit} updateValue={(value) => setUserField('name', value)} - information={isFirstTime || userForm.fields.name.isValid ? '' : 'Nama tidak boleh kosong dan hanya mengandung alfabet'} + information={errors.name} /> setUserField('email', value)} - information={isFirstTime || userForm.fields.email.isValid ? '' : 'Harus diisi dengan email yang valid'} + information={errors.email} /> @@ -225,7 +240,7 @@ export default function UserProfile({ editable={shouldEdit} value={userForm.fields.phoneNumber.value} updateValue={(value) => setUserField('phoneNumber', value)} - information={isFirstTime || userForm.fields.phoneNumber.isValid ? '' : 'Harus diisi dengan nomor HP yang valid'} + information={errors.phone_number} /> setUserField('area', value)} + information={errors.area} /> Date: Fri, 8 May 2020 16:52:25 +0700 Subject: [PATCH 7/9] [RED] Add show account status in profile test --- .../components/UserProfile/index.test.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/scenes/AccountManagement/components/UserProfile/index.test.tsx b/src/scenes/AccountManagement/components/UserProfile/index.test.tsx index 6e9d004..4d72101 100644 --- a/src/scenes/AccountManagement/components/UserProfile/index.test.tsx +++ b/src/scenes/AccountManagement/components/UserProfile/index.test.tsx @@ -48,9 +48,15 @@ it('renders correctly', () => { expect(areaField).toBeTruthy(); const activityField = userProfile.root.find((elem:Element) => elem.props.name === 'Jumlah Aktivitas'); expect(activityField).toBeTruthy(); + const accountField = userProfile.root.find((elem:Element) => elem.props.name === 'Jenis Akun'); + expect(accountField).toBeTruthy(); + expect(accountField.props.value).toBe('Kader'); + const statusField = userProfile.root.find((elem:Element) => elem.props.name === 'Status Akun'); + expect(statusField).toBeTruthy(); + expect(statusField.props.value).toBe('Tidak Aktif'); }); -it('can activate user', () => { +it('can activate user', async () => { const userProfile = renderer.create( { ); const activateButton = userProfile.root.find((elem:Element) => elem.props.id === 'activateButton'); - act(() => { + await act(async () => { activateButton.props.onClick(); }); expect(mockedAxios.request).toBeCalled(); + const statusField = userProfile.root.find((elem:Element) => elem.props.name === 'Status Akun'); + expect(statusField).toBeTruthy(); + expect(statusField.props.value).toBe('Aktif'); }); it('can edit user succesfully', () => { -- GitLab From af4259175a3ac7901ac6094d11a2a6e0a41d757f Mon Sep 17 00:00:00 2001 From: Irwanto Date: Fri, 8 May 2020 16:57:54 +0700 Subject: [PATCH 8/9] [GREEN] Show account status in profile --- .../components/UserProfile/index.tsx | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/scenes/AccountManagement/components/UserProfile/index.tsx b/src/scenes/AccountManagement/components/UserProfile/index.tsx index d51db36..381ba3a 100644 --- a/src/scenes/AccountManagement/components/UserProfile/index.tsx +++ b/src/scenes/AccountManagement/components/UserProfile/index.tsx @@ -59,6 +59,7 @@ export default function UserProfile({ const [editStatus, setEditStatus] = useState(''); const [deleteStatus, setDeleteStatus] = useState(''); const [canDelete, setCanDelete] = useState(true); + const isAdmin = is_admin; const getInitialFields = () => ({ name: '', @@ -211,7 +212,7 @@ export default function UserProfile({ updateValue={(value) => setUserField('name', value)} information={errors.name} /> - + setUserField('username', value)} /> - + setUserField('email', value)} information={errors.email} /> + + @@ -242,7 +250,7 @@ export default function UserProfile({ updateValue={(value) => setUserField('phoneNumber', value)} information={errors.phone_number} /> - + setUserField('area', value)} information={errors.area} /> - + + + {!shouldEdit ? {`${editStatus}`} : <>} -- GitLab From ef064a8e62bb02b8b08d7666bd5cc50435b76d1b Mon Sep 17 00:00:00 2001 From: Irwanto Date: Fri, 8 May 2020 17:05:16 +0700 Subject: [PATCH 9/9] [GREEN] Show account status in accounts table --- src/scenes/AccountManagement/index.tsx | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/scenes/AccountManagement/index.tsx b/src/scenes/AccountManagement/index.tsx index 838b619..15b8ef5 100644 --- a/src/scenes/AccountManagement/index.tsx +++ b/src/scenes/AccountManagement/index.tsx @@ -18,7 +18,7 @@ export default function AccountManagementPage() { const { setModal } = useContext(AppContext); const [page, setPage] = useState(1); const [accountCount, setAccountCount] = useState(0); - const [cleanedData, setCleanedData] = useState([['', '', '', '', '', '']]); + const [cleanedData, setCleanedData] = useState([['', '', '', '', '', '', '', '']]); const [afterEdit, setAfterEdit] = useState(0); const global = useContext(AppContext); @@ -41,6 +41,8 @@ export default function AccountManagementPage() { currentAccount.push(acc.email); currentAccount.push(acc.phone_number); currentAccount.push(acc.area); + currentAccount.push(acc.is_admin ? 'Admin' : 'Kader'); + currentAccount.push(acc.is_active && acc.is_verified ? 'Aktif' : 'Tidak Aktif'); currentAccount.push(String(0)); currentAccount.push(acc.id); currentAccount.push(acc.is_admin); @@ -51,7 +53,7 @@ export default function AccountManagementPage() { // Workaround, TODO need to handle empty table if (cleanedAccounts.length === 0) { - setCleanedData([['', '', '', '', '', '']]); + setCleanedData([['', '', '', '', '', '', '']]); } else { setCleanedData(cleanedAccounts); } @@ -69,6 +71,8 @@ export default function AccountManagementPage() { String(newAccount.email), String(newAccount.phone_number), String(newAccount.area), + String(newAccount.is_admin ? 'Admin' : 'Kader'), + String(newAccount.is_active && newAccount.is_verified ? 'Aktif' : 'Tidak Aktif'), String(0), String(newAccount.id), String(newAccount.is_admin), @@ -116,6 +120,8 @@ export default function AccountManagementPage() { 'Email', 'Nomor HP', 'Lokasi Cabang', + 'Jenis Akun', + 'Status Akun' ]} searchPlaceholder="Cari berdasarkan nama, username, atau email..." rowOnClick={(data) => { @@ -132,16 +138,16 @@ export default function AccountManagementPage() { crossAxis="center" > {setAfterEdit(Math.random());}} /> -- GitLab