diff --git a/package.json b/package.json index ca5a400..fff8207 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-helmet": "^6.1.0", - "react-hook-form": "^7.12.1", + "react-hook-form": "^7.22.0", "react-hot-toast": "^2.0.0", "react-markdown": "^7.0.1", "react-redux": "^7.2.4", diff --git a/src/components/Form/Input/Input.tsx b/src/components/Form/Input/Input.tsx new file mode 100644 index 0000000..aa7cdd4 --- /dev/null +++ b/src/components/Form/Input/Input.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { useController } from 'react-hook-form'; + +/* eslint-disable react/react-in-jsx-scope */ +export const Input = ({ control, name, type = 'text', label, ...props }: InputProps) => { + const { + field, + // fieldState: { invalid, isTouched, isDirty }, + // formState: { touchedFields, dirtyFields }, + } = useController({ + name, + control, + rules: { required: true }, + defaultValue: '', + }); + + return ( + <> + {label && ( + + )} + + + ); +}; + +type InputProps = { + control: any; + name: string; + type?: string; + label?: string; +} & React.HTMLProps; diff --git a/src/components/Form/Input/index.ts b/src/components/Form/Input/index.ts new file mode 100644 index 0000000..6322cf3 --- /dev/null +++ b/src/components/Form/Input/index.ts @@ -0,0 +1 @@ +export { Input } from './Input'; diff --git a/src/components/Form/Select/Select.tsx b/src/components/Form/Select/Select.tsx new file mode 100644 index 0000000..ab9b238 --- /dev/null +++ b/src/components/Form/Select/Select.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { useController } from 'react-hook-form'; + +/* eslint-disable react/react-in-jsx-scope */ +export const Select = ({ control, name, label, options }: SelectProps) => { + const { + field, + // fieldState: { invalid, isTouched, isDirty }, + // formState: { touchedFields, dirtyFields }, + } = useController({ + name, + control, + rules: { required: true }, + defaultValue: '', + }); + + return ( + <> + {label && ( + + )} + + + ); +}; + +type SelectProps = { + control: any; + name: string; + label?: string; + options?: any[]; +}; diff --git a/src/components/Form/Select/index.ts b/src/components/Form/Select/index.ts new file mode 100644 index 0000000..205709b --- /dev/null +++ b/src/components/Form/Select/index.ts @@ -0,0 +1 @@ +export { Select } from './Select'; diff --git a/src/components/Form/index.ts b/src/components/Form/index.ts new file mode 100644 index 0000000..ad493dd --- /dev/null +++ b/src/components/Form/index.ts @@ -0,0 +1,2 @@ +export { Input } from './Input'; +export { Select } from './Select'; diff --git a/src/components/Modal/Modal/Modal.tsx b/src/components/Modal/Modal/Modal.tsx index 0b316da..048b315 100644 --- a/src/components/Modal/Modal/Modal.tsx +++ b/src/components/Modal/Modal/Modal.tsx @@ -10,8 +10,11 @@ export const Modal: React.FC = ({ children, title = '', useCancelButton = false, + isLoading = false, + leftActions = <>, }) => { const cancelButtonRef = useRef(null); + const saveButtonRef = useRef(null); return ( @@ -42,7 +45,25 @@ export const Modal: React.FC = ({ leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > -
+
+ {isLoading && ( + + + + + + + )} + {!useCancelButton && (
{title}
@@ -60,24 +81,28 @@ export const Modal: React.FC = ({
{children}
{onSave && ( -
- - {useCancelButton && ( +
+ {leftActions} +
- )} + {useCancelButton && ( + + )} +
)}
diff --git a/src/components/Modal/Modal/types.ts b/src/components/Modal/Modal/types.ts index 9fd3eee..afd720c 100644 --- a/src/components/Modal/Modal/types.ts +++ b/src/components/Modal/Modal/types.ts @@ -1,7 +1,11 @@ +import React from 'react'; + export type ModalProps = { open: boolean; onClose: () => void; title?: string; onSave?: () => void; useCancelButton?: boolean; + isLoading?: boolean; + leftActions?: React.ReactNode; }; diff --git a/src/modules/users/Users.tsx b/src/modules/users/Users.tsx index 9c6da4e..eeca632 100644 --- a/src/modules/users/Users.tsx +++ b/src/modules/users/Users.tsx @@ -6,6 +6,7 @@ import { CogIcon, TrashIcon } from '@heroicons/react/outline'; import { useUsers } from 'src/services/users'; import { Table } from 'src/components'; import { ConfirmationModal } from 'src/components/Modal'; +import { debounce } from 'lodash'; import { UserModal } from './components/UserModal'; const pages = [{ name: 'Users', href: '#', current: true }]; @@ -14,37 +15,35 @@ export const Users: React.FC = () => { const [selectedRowsIds, setSelectedRowsIds] = useState({}); const [deleteModal, setDeleteModal] = useState(false); const [configureModal, setConfigureModal] = useState(false); + const [userId, setUserId] = useState(null); const [search, setSearch] = useState(''); - const { loadUsers, users } = useUsers(); + const { users, loadUsers } = useUsers(); - const handleSearch = useCallback((event: any) => { + const handleSearch = (event: any) => { setSearch(event.target.value); - }, []); + }; - // TODO: Check why it needs any - const allUsers: any = users.items; + const debouncedSearch = useCallback(debounce(handleSearch, 250), []); useEffect(() => { - const asyncFc = async () => { - try { - await loadUsers(); - } catch { - // continue - } - }; + loadUsers(); - asyncFc(); - /* eslint-disable-next-line react-hooks/exhaustive-deps */ + return () => { + debouncedSearch.cancel(); + }; }, []); const filterSearch = useMemo(() => { - return allUsers.filter((item: any) => item.name?.toLowerCase().includes(search.toLowerCase())); - }, [search, allUsers]); + return users.filter((item: any) => item.email?.toLowerCase().includes(search.toLowerCase())); + }, [search, users]); const deleteModalOpen = () => setDeleteModal(true); const deleteModalClose = () => setDeleteModal(false); - const configureModalOpen = () => setConfigureModal(true); + const configureModalOpen = (id: any) => { + setUserId(id); + setConfigureModal(true); + }; const configureModalClose = () => setConfigureModal(false); const columns: any = React.useMemo( @@ -64,18 +63,15 @@ export const Users: React.FC = () => { accessor: 'status', width: 'auto', }, - { - Header: 'Last Sign-In', - accessor: 'last_login', - width: 'auto', - }, { Header: ' ', - Cell: () => { + Cell: (props: any) => { + const { row } = props; + return (