diff --git a/src/scenes/AccountManagement/components/AddAccountForm/index.test.tsx b/src/scenes/AccountManagement/components/AddAccountForm/index.test.tsx index d6a6849d720544cf2e0c525eb8ac1b47630ac805..e5fc3a60a62fbdf5b00ad55a888b48d9e9a0af75 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(''); }); diff --git a/src/scenes/AccountManagement/components/AddAccountForm/index.tsx b/src/scenes/AccountManagement/components/AddAccountForm/index.tsx index 51ba43330c63e6f0fece20876754b98ddf3c3c54..23aec8a7b034a5caceddbea2993c47e771eac746 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` @@ -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({ @@ -149,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} diff --git a/src/scenes/AccountManagement/components/UserProfile/index.test.tsx b/src/scenes/AccountManagement/components/UserProfile/index.test.tsx index 1d373b532023179c3b839f75cbdad59224539839..4d721012a48f2821f72ac6d564b6699196065b41 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', () => { @@ -128,7 +137,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); }) ); diff --git a/src/scenes/AccountManagement/components/UserProfile/index.tsx b/src/scenes/AccountManagement/components/UserProfile/index.tsx index 49dc757806df591d431f8b24a7e1d72a29f584fe..381ba3a2a9ab00e78685942f5cc595fcc7062e6d 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,42 @@ 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); + const isAdmin = is_admin; - 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 +143,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,9 +210,9 @@ 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('username', value)} /> - + setUserField('email', value)} - information={isFirstTime || userForm.fields.email.isValid ? '' : 'Harus diisi dengan email yang valid'} + information={errors.email} + /> + + @@ -225,9 +248,9 @@ 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} /> - + + + {!shouldEdit ? {`${editStatus}`} : <>} diff --git a/src/scenes/AccountManagement/index.tsx b/src/scenes/AccountManagement/index.tsx index 838b619bdf6534f535353592ecbe704e7b3612ec..15b8ef5024cacc57c5672356e704f438fef34b1b 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());}} /> diff --git a/src/scenes/AccountManagement/components/AddAccountForm/utils.tsx b/src/scenes/AccountManagement/utilities/utils.tsx similarity index 95% rename from src/scenes/AccountManagement/components/AddAccountForm/utils.tsx rename to src/scenes/AccountManagement/utilities/utils.tsx index b1332da9a21faf417c966a99a2d338112bd36c9c..0dee68142efb5b0ef435f5e71e724c7288a65b39 100644 --- a/src/scenes/AccountManagement/components/AddAccountForm/utils.tsx +++ b/src/scenes/AccountManagement/utilities/utils.tsx @@ -1,7 +1,7 @@ function singleErrorTranslate(value:string): string { switch(value) { case 'This field may not be blank.': - return 'Informasi tidak boleh kosong. '; + return 'Informasi tidak boleh kosong.'; case 'This password is entirely numeric.': return 'Password tidak boleh berupa angka semua.'; case 'This password is too common.':