Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f52e06af65 | |||
| 697a467780 | |||
| 9499422c9a | |||
| 148659b453 | |||
| 98454e2c80 | |||
| 8a96b10e4b | |||
| d17ca4f988 | |||
| ea90bd6fc5 | |||
| 4f99dacf76 | |||
| c970467f16 | |||
| 63090f0b74 | |||
| afa81eacd8 | |||
| eea90187e1 | |||
| 835cb6b074 | |||
| a44c898a66 | |||
| 6f616c34cc | |||
| dc5aa92085 | |||
| 58875df9be | |||
| d8c9b59cde | |||
| d53ad76e8b | |||
| 2688e224fd | |||
| f9e3674ece | |||
| 3b6b0b580c |
@@ -1,5 +1,10 @@
|
||||
const QUERIES = {
|
||||
USERS_LIST: 'users-list',
|
||||
STARTED_LIST: 'started-list',
|
||||
READY_LIST: 'ready-list',
|
||||
PENDING_LIST: 'pending-list',
|
||||
APPROVED_LIST: 'approved-list',
|
||||
REJECTED_LIST: 'rejected-list',
|
||||
EMPLOYERS_LIST: 'employers-list',
|
||||
SIGNATORY_LIST: 'signatory-list',
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ const SidebarMenuMain = () => {
|
||||
{/*<SidebarMenuItem to='/builder' icon='switch' title='Layout Builder' fontIcon='bi-layers' />*/}
|
||||
<div className='menu-item'>
|
||||
<div className='menu-content pt-8 pb-2'>
|
||||
<span className='menu-section text-muted text-uppercase fs-8 ls-1'>Crafted</span>
|
||||
<span className='menu-section text-muted text-uppercase fs-8 ls-1'>Loan</span>
|
||||
</div>
|
||||
</div>
|
||||
<SidebarMenuItemWithSub
|
||||
@@ -87,7 +87,7 @@ const SidebarMenuMain = () => {
|
||||
|
||||
<div className='menu-item'>
|
||||
<div className='menu-content pt-8 pb-2'>
|
||||
<span className='menu-section text-muted text-uppercase fs-8 ls-1'>Apps</span>
|
||||
<span className='menu-section text-muted text-uppercase fs-8 ls-1'>Tools</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -103,7 +103,7 @@ const SidebarMenuMain = () => {
|
||||
</SidebarMenuItemWithSub> */}
|
||||
|
||||
<SidebarMenuItem
|
||||
to='/apps/user-management/users'
|
||||
to='/tools/user-management/users'
|
||||
icon='abstract-28'
|
||||
title='User management'
|
||||
fontIcon='bi-layers'
|
||||
@@ -116,13 +116,13 @@ const SidebarMenuMain = () => {
|
||||
</div>
|
||||
</div>
|
||||
<SidebarMenuItem
|
||||
to='apps/employers-list/employers'
|
||||
to='employers/employerslist'
|
||||
icon='abstract-28'
|
||||
title='List'
|
||||
fontIcon='bi-layers'
|
||||
/>
|
||||
<SidebarMenuItem
|
||||
to='apps/employers-list/signatory'
|
||||
to='employers/signatory'
|
||||
icon='abstract-28'
|
||||
title='Signatory'
|
||||
fontIcon='bi-layers'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FC } from 'react';
|
||||
import { FC, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useAuth } from '../../../../app/modules/auth';
|
||||
import { Languages } from './Languages';
|
||||
@@ -6,6 +6,42 @@ import { toAbsoluteUrl } from '../../../helpers';
|
||||
|
||||
const HeaderUserMenu: FC = () => {
|
||||
const { currentUser, logout } = useAuth();
|
||||
|
||||
// Listen for user activity and trigger logout
|
||||
useEffect(() => {
|
||||
let timeout: number;
|
||||
const inactiveTime: number = 7 * 60 * 1000; //default inactive period (milliseconds)
|
||||
// Logout user after inactiveTime minutes of inactivity
|
||||
const resetTimeout = () => {
|
||||
clearTimeout(timeout);
|
||||
// Set logout timeout
|
||||
timeout = window.setTimeout(() => {
|
||||
logout();
|
||||
}, inactiveTime);
|
||||
};
|
||||
|
||||
const handleUserActivity: any = () => {
|
||||
resetTimeout(); // reset session on user activity
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', handleUserActivity);
|
||||
document.addEventListener('keydown', handleUserActivity);
|
||||
document.addEventListener('click', handleUserActivity);
|
||||
document.addEventListener('focus', handleUserActivity);
|
||||
|
||||
// Initialize timeout
|
||||
resetTimeout();
|
||||
|
||||
// Remove event listeners on unmount
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
document.removeEventListener('mousemove', handleUserActivity);
|
||||
document.removeEventListener('keydown', handleUserActivity);
|
||||
document.removeEventListener('click', handleUserActivity);
|
||||
document.removeEventListener('focus', handleUserActivity);
|
||||
};
|
||||
}, [logout]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="menu menu-sub menu-sub-dropdown menu-column menu-rounded menu-gray-600 menu-state-bg menu-state-primary fw-bold py-4 fs-6 w-275px"
|
||||
|
||||
+7
-4
@@ -5,6 +5,7 @@ import {LayoutProvider, LayoutSplashScreen} from '../_digifi/layout/core'
|
||||
import {MasterInit} from '../_digifi/layout/MasterInit'
|
||||
import {AuthInit} from './modules/auth'
|
||||
import {ThemeModeProvider} from '../_digifi/partials'
|
||||
import { CustomModalProvider } from '../context/CustomModal'
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
@@ -12,10 +13,12 @@ const App = () => {
|
||||
<I18nProvider>
|
||||
<LayoutProvider>
|
||||
<ThemeModeProvider>
|
||||
<AuthInit>
|
||||
<Outlet />
|
||||
<MasterInit />
|
||||
</AuthInit>
|
||||
<CustomModalProvider>
|
||||
<AuthInit>
|
||||
<Outlet />
|
||||
<MasterInit />
|
||||
</AuthInit>
|
||||
</CustomModalProvider>
|
||||
</ThemeModeProvider>
|
||||
</LayoutProvider>
|
||||
</I18nProvider>
|
||||
|
||||
@@ -5,7 +5,7 @@ import {UsersListWrapper} from './users-list/UsersList'
|
||||
const usersBreadcrumbs: Array<PageLink> = [
|
||||
{
|
||||
title: 'User Management',
|
||||
path: '/apps/user-management/users',
|
||||
path: '/tools/user-management/users',
|
||||
isSeparator: false,
|
||||
isActive: false,
|
||||
},
|
||||
@@ -31,7 +31,7 @@ const UsersPage = () => {
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route index element={<Navigate to='/apps/user-management/users' />} />
|
||||
<Route index element={<Navigate to='/tools/user-management/users' />} />
|
||||
</Routes>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {UsersListWrapper as SignatoryList} from './signatory-list/UsersList'
|
||||
const usersBreadcrumbs: Array<PageLink> = [
|
||||
{
|
||||
title: 'Employer Management',
|
||||
path: '/apps/employers-list/employers',
|
||||
path: '/employers/employerslist',
|
||||
isSeparator: false,
|
||||
isActive: false,
|
||||
},
|
||||
@@ -23,7 +23,7 @@ const EmployersPage = () => {
|
||||
<Routes>
|
||||
<Route element={<Outlet />}>
|
||||
<Route
|
||||
path='employers'
|
||||
path='employerslist'
|
||||
element={
|
||||
<>
|
||||
<PageTitle breadcrumbs={usersBreadcrumbs}>Employers list</PageTitle>
|
||||
@@ -41,7 +41,7 @@ const EmployersPage = () => {
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
<Route index element={<Navigate to='/apps/employers-list/employers' />} />
|
||||
<Route index element={<Navigate to='/employers/employerslist' />} />
|
||||
</Routes>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Content } from '../../../../../_digifi/layout/components/content'
|
||||
|
||||
const UsersList = () => {
|
||||
const response = useAllResponse()
|
||||
console.log('RESPONSE', response)
|
||||
// console.log('RESPONSE', response)
|
||||
const {itemIdForUpdate} = useListView()
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -4,16 +4,16 @@ export type User = {
|
||||
name?: string
|
||||
avatar?: string
|
||||
// email?: string
|
||||
position?: string
|
||||
role?: string
|
||||
last_login?: string
|
||||
two_steps?: boolean
|
||||
joined_day?: string
|
||||
online?: boolean
|
||||
initials?: {
|
||||
label: string
|
||||
state: string
|
||||
}
|
||||
// position?: string
|
||||
// role?: string
|
||||
// last_login?: string
|
||||
// two_steps?: boolean
|
||||
// joined_day?: string
|
||||
// online?: boolean
|
||||
// initials?: {
|
||||
// label: string
|
||||
// state: string
|
||||
// }
|
||||
uid?: string
|
||||
added?: string
|
||||
updated?: string
|
||||
@@ -27,8 +27,8 @@ export type UsersQueryResponse = Response<Array<User>>
|
||||
|
||||
export const initialUser: User = {
|
||||
avatar: 'avatars/300-6.jpg',
|
||||
position: 'Art Director',
|
||||
role: 'Administrator',
|
||||
// position: 'Art Director',
|
||||
// role: 'Administrator',
|
||||
name: '',
|
||||
email: '',
|
||||
}
|
||||
|
||||
+3
-3
@@ -56,12 +56,12 @@ const UserActionsCell: FC<Props> = ({id}) => {
|
||||
</div>
|
||||
{/* end::Menu item */}
|
||||
|
||||
{/* begin::Menu item */}
|
||||
<div className='menu-item px-3'>
|
||||
{/* begin::Menu item */}
|
||||
{/* <div className='menu-item px-3'>
|
||||
<a className='menu-link px-3' onClick={openEditModal}>
|
||||
Add Signatory
|
||||
</a>
|
||||
</div>
|
||||
</div> */}
|
||||
{/* end::Menu item */}
|
||||
|
||||
{/* begin::Menu item */}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ const UserEditModalHeader = () => {
|
||||
return (
|
||||
<div className='modal-header'>
|
||||
{/* begin::Modal title */}
|
||||
<h2 className='fw-bolder'>Add User</h2>
|
||||
<h2 className='fw-bolder'>Edit Signatory</h2>
|
||||
{/* end::Modal title */}
|
||||
|
||||
{/* begin::Close */}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import {ListViewProvider, useListView} from './core/ListViewProvider'
|
||||
import {QueryRequestProvider} from './core/QueryRequestProvider'
|
||||
import {QueryResponseProvider, useAllResponse} from './core/QueryResponseProvider'
|
||||
import {QueryResponseProvider} from './core/QueryResponseProvider'
|
||||
import {UsersListHeader} from './components/header/UsersListHeader'
|
||||
import {UsersTable} from './table/UsersTable'
|
||||
import {UserEditModal} from './user-edit-modal/UserEditModal'
|
||||
import {KTCard} from '../../../../../_digifi/helpers'
|
||||
import { ToolbarWrapper } from '../../../../../_digifi/layout/components/toolbar'
|
||||
import { Content } from '../../../../../_digifi/layout/components/content'
|
||||
import { AddSignatoryModal } from './add-signatory-modal/Modal'
|
||||
import { useCustomModal } from '../../../../../context/CustomModal'
|
||||
|
||||
const UsersList = () => {
|
||||
const response = useAllResponse()
|
||||
console.log('RESPONSE', response)
|
||||
const {itemIdForUpdate} = useListView()
|
||||
const {MODALNAMES, showCustomModal} = useCustomModal()
|
||||
|
||||
return (
|
||||
<>
|
||||
<KTCard>
|
||||
@@ -19,6 +21,7 @@ const UsersList = () => {
|
||||
<UsersTable />
|
||||
</KTCard>
|
||||
{itemIdForUpdate !== undefined && <UserEditModal />}
|
||||
{(showCustomModal && showCustomModal.name == MODALNAMES.addSignatory) && <AddSignatoryModal />}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import {useEffect} from 'react'
|
||||
import { ModalHeader } from './ModalHeader'
|
||||
import { ModalFormWrapper } from './ModalFormWrapper'
|
||||
|
||||
|
||||
const AddSignatoryModal = () => {
|
||||
|
||||
useEffect(() => {
|
||||
document.body.classList.add('modal-open')
|
||||
return () => {
|
||||
document.body.classList.remove('modal-open')
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className='modal fade show d-block'
|
||||
id='kt_modal_add_user'
|
||||
role='dialog'
|
||||
tabIndex={-1}
|
||||
aria-modal='true'
|
||||
>
|
||||
{/* begin::Modal dialog */}
|
||||
<div className='modal-dialog modal-dialog-centered mw-650px'>
|
||||
{/* begin::Modal content */}
|
||||
<div className='modal-content'>
|
||||
<ModalHeader />
|
||||
{/* begin::Modal body */}
|
||||
<div className='modal-body scroll-y mx-5 mx-xl-15 my-7'>
|
||||
<ModalFormWrapper />
|
||||
</div>
|
||||
{/* end::Modal body */}
|
||||
</div>
|
||||
{/* end::Modal content */}
|
||||
</div>
|
||||
{/* end::Modal dialog */}
|
||||
</div>
|
||||
{/* begin::Modal Backdrop */}
|
||||
<div className='modal-backdrop fade show'></div>
|
||||
{/* end::Modal Backdrop */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export {AddSignatoryModal}
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
import { FC, useState } from "react";
|
||||
import * as Yup from "yup";
|
||||
import { useFormik } from "formik";
|
||||
import { isNotEmpty, toAbsoluteUrl } from "../../../../../../_digifi/helpers";
|
||||
// import { initialUser, User } from "../core/_models";
|
||||
import { initialUser, User } from "../../signatory-list/core/_models";
|
||||
import clsx from "clsx";
|
||||
import { useListView } from "../core/ListViewProvider";
|
||||
import { UsersListLoading } from "../components/loading/UsersListLoading";
|
||||
import { createSignatory, updateUser } from "../core/_requests";
|
||||
import { useQueryResponse } from "../core/QueryResponseProvider";
|
||||
import { useCustomModal } from "../../../../../../context/CustomModal";
|
||||
|
||||
type Props = {
|
||||
isUserLoading: boolean;
|
||||
user: User;
|
||||
};
|
||||
|
||||
const editUserSchema = Yup.object().shape({
|
||||
email: Yup.string()
|
||||
.email('Wrong email format')
|
||||
.min(3, 'Minimum 3 symbols')
|
||||
.max(50, 'Maximum 50 symbols')
|
||||
.required('required'),
|
||||
name: Yup.string()
|
||||
.min(3, "Minimum 3 symbols")
|
||||
.max(50, "Maximum 50 symbols")
|
||||
.required("required"),
|
||||
phone: Yup.string()
|
||||
.min(11, "Minimum 11 symbols")
|
||||
.max(11, "Maximum 11 symbols")
|
||||
.required("required"),
|
||||
title: Yup.string()
|
||||
.min(2, "Minimum 2 symbols")
|
||||
.max(20, "Maximum 20 symbols")
|
||||
.required("required"),
|
||||
});
|
||||
|
||||
const ModalForm: FC<Props> = ({ user, isUserLoading }) => {
|
||||
|
||||
const {closeCustomModal, showCustomModal} = useCustomModal()
|
||||
|
||||
const { setItemIdForUpdate } = useListView();
|
||||
const { refetch, isLoading } = useQueryResponse();
|
||||
|
||||
const [userForEdit] = useState<User>({
|
||||
...user,
|
||||
avatar: user.avatar || initialUser.avatar,
|
||||
// role: user.role || initialUser.role,
|
||||
// position: user.position || initialUser.position,
|
||||
name: user.name || initialUser.name,
|
||||
// email: user.email || initialUser.email,
|
||||
});
|
||||
|
||||
const cancel = (withRefresh?: boolean) => {
|
||||
if (withRefresh) {
|
||||
refetch();
|
||||
}
|
||||
setItemIdForUpdate(undefined);
|
||||
closeCustomModal()
|
||||
};
|
||||
|
||||
const blankImg = toAbsoluteUrl("media/svg/avatars/blank.svg");
|
||||
const userAvatarImg = toAbsoluteUrl(`media/${userForEdit.avatar}`);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: userForEdit,
|
||||
validationSchema: editUserSchema,
|
||||
onSubmit: async (values, { setSubmitting }) => {
|
||||
setSubmitting(true);
|
||||
try {
|
||||
if (isNotEmpty(values.id)) {
|
||||
await updateUser(values);
|
||||
} else {
|
||||
await createSignatory({employer_uid:showCustomModal?.data?.id, ...values});
|
||||
}
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
} finally {
|
||||
setSubmitting(true);
|
||||
cancel(true);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<form
|
||||
id="kt_modal_add_user_form"
|
||||
className="form"
|
||||
onSubmit={formik.handleSubmit}
|
||||
noValidate
|
||||
>
|
||||
{/* begin::Scroll */}
|
||||
<div
|
||||
className="d-flex flex-column scroll-y me-n7 pe-7"
|
||||
id="kt_modal_add_user_scroll"
|
||||
data-kt-scroll="true"
|
||||
data-kt-scroll-activate="{default: false, lg: true}"
|
||||
data-kt-scroll-max-height="auto"
|
||||
data-kt-scroll-dependencies="#kt_modal_add_user_header"
|
||||
data-kt-scroll-wrappers="#kt_modal_add_user_scroll"
|
||||
data-kt-scroll-offset="300px"
|
||||
>
|
||||
{/* begin::Input group */}
|
||||
{/* <div className='fv-row mb-7'>
|
||||
|
||||
<label className='d-block fw-bold fs-6 mb-5'>Avatar</label>
|
||||
|
||||
<div
|
||||
className='image-input image-input-outline'
|
||||
data-kt-image-input='true'
|
||||
style={{backgroundImage: `url('${blankImg}')`}}
|
||||
>
|
||||
<div
|
||||
className='image-input-wrapper w-125px h-125px'
|
||||
style={{backgroundImage: `url('${userAvatarImg}')`}}
|
||||
></div>
|
||||
|
||||
<label
|
||||
className='btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow'
|
||||
data-kt-image-input-action='change'
|
||||
data-bs-toggle='tooltip'
|
||||
title='Change avatar'
|
||||
>
|
||||
<i className='bi bi-pencil-fill fs-7'></i>
|
||||
|
||||
<input type='file' name='avatar' accept='.png, .jpg, .jpeg' />
|
||||
<input type='hidden' name='avatar_remove' />
|
||||
</label>
|
||||
|
||||
<span
|
||||
className='btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow'
|
||||
data-kt-image-input-action='cancel'
|
||||
data-bs-toggle='tooltip'
|
||||
title='Cancel avatar'
|
||||
>
|
||||
<i className='bi bi-x fs-2'></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
className='btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow'
|
||||
data-kt-image-input-action='remove'
|
||||
data-bs-toggle='tooltip'
|
||||
title='Remove avatar'
|
||||
>
|
||||
<i className='bi bi-x fs-2'></i>
|
||||
</span>
|
||||
</div>
|
||||
<div className='form-text'>Allowed file types: png, jpg, jpeg.</div>
|
||||
</div> */}
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Name</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Full name"
|
||||
{...formik.getFieldProps("name")}
|
||||
type="text"
|
||||
name="name"
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.name && formik.errors.name },
|
||||
{
|
||||
"is-valid": formik.touched.name && !formik.errors.name,
|
||||
}
|
||||
)}
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{formik.touched.name && formik.errors.name && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* end::Input */}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Title</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="title"
|
||||
{...formik.getFieldProps("title")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.title && formik.errors.title },
|
||||
{
|
||||
"is-valid": formik.touched.title && !formik.errors.title,
|
||||
}
|
||||
)}
|
||||
type="text"
|
||||
name="title"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.title && formik.errors.title && (
|
||||
// <div className="fv-plugins-message-container">
|
||||
// <span role="alert">{formik.errors.title}</span>
|
||||
// </div>
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.title}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Phone</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Phone"
|
||||
{...formik.getFieldProps("phone")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.title && formik.errors.title },
|
||||
{
|
||||
"is-valid": formik.touched.title && !formik.errors.title,
|
||||
}
|
||||
)}
|
||||
type="text"
|
||||
name="phone"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.phone && formik.errors.phone && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.phone}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Email</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Email"
|
||||
{...formik.getFieldProps("email")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.email && formik.errors.email },
|
||||
{
|
||||
"is-valid": formik.touched.email && !formik.errors.email,
|
||||
}
|
||||
)}
|
||||
type="email"
|
||||
name="email"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.email && formik.errors.email && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
|
||||
</div>
|
||||
{/* end::Scroll */}
|
||||
|
||||
{/* begin::Actions */}
|
||||
<div className="text-center pt-15">
|
||||
<button
|
||||
type="reset"
|
||||
onClick={() => cancel()}
|
||||
className="btn btn-danger me-3"
|
||||
data-kt-users-modal-action="cancel"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-primary"
|
||||
data-kt-users-modal-action="submit"
|
||||
disabled={
|
||||
isUserLoading ||
|
||||
formik.isSubmitting ||
|
||||
!formik.isValid ||
|
||||
!formik.touched
|
||||
}
|
||||
>
|
||||
<span className="indicator-label">Add</span>
|
||||
{(formik.isSubmitting || isUserLoading) && (
|
||||
<span className="indicator-progress">
|
||||
Please wait...{" "}
|
||||
<span className="spinner-border spinner-border-sm align-middle ms-2"></span>
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
{/* end::Actions */}
|
||||
</form>
|
||||
{(formik.isSubmitting || isUserLoading) && <UsersListLoading />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export { ModalForm };
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
import {useQuery} from 'react-query'
|
||||
import {ModalForm} from './ModalForm'
|
||||
import {isNotEmpty, QUERIES} from '../../../../../../_digifi/helpers'
|
||||
import {useListView} from '../core/ListViewProvider'
|
||||
import {getUserById} from '../core/_requests'
|
||||
|
||||
const ModalFormWrapper = () => {
|
||||
const {itemIdForUpdate, setItemIdForUpdate} = useListView()
|
||||
const enabledQuery: boolean = isNotEmpty(itemIdForUpdate)
|
||||
const {
|
||||
isLoading,
|
||||
data: user,
|
||||
error,
|
||||
} = useQuery(
|
||||
`${QUERIES.USERS_LIST}-user-${itemIdForUpdate}`,
|
||||
() => {
|
||||
return getUserById(itemIdForUpdate)
|
||||
},
|
||||
{
|
||||
cacheTime: 0,
|
||||
enabled: enabledQuery,
|
||||
onError: (err) => {
|
||||
setItemIdForUpdate(undefined)
|
||||
console.error(err)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (!itemIdForUpdate) {
|
||||
return <ModalForm isUserLoading={isLoading} user={{id: undefined}} />
|
||||
}
|
||||
|
||||
if (!isLoading && !error && user) {
|
||||
return <ModalForm isUserLoading={isLoading} user={user} />
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export {ModalFormWrapper}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import {KTIcon} from '../../../../../../_digifi/helpers'
|
||||
import {useListView} from '../core/ListViewProvider'
|
||||
import { useCustomModal } from '../../../../../../context/CustomModal'
|
||||
|
||||
const ModalHeader = () => {
|
||||
const {setItemIdForUpdate, itemIdForUpdate} = useListView()
|
||||
const {closeCustomModal} = useCustomModal()
|
||||
|
||||
const onClose = () => {
|
||||
setItemIdForUpdate(undefined)
|
||||
closeCustomModal()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='modal-header'>
|
||||
{/* begin::Modal title */}
|
||||
<h2 className='fw-bolder'>Add Signatory</h2>
|
||||
{/* end::Modal title */}
|
||||
|
||||
{/* begin::Close */}
|
||||
<div
|
||||
className='btn btn-icon btn-sm btn-active-icon-primary'
|
||||
data-kt-users-modal-action='close'
|
||||
onClick={onClose}
|
||||
style={{cursor: 'pointer'}}
|
||||
>
|
||||
<KTIcon iconName='cross' className='fs-1' />
|
||||
</div>
|
||||
{/* end::Close */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export {ModalHeader}
|
||||
@@ -4,16 +4,16 @@ export type User = {
|
||||
name?: string
|
||||
avatar?: string
|
||||
// email?: string
|
||||
position?: string
|
||||
role?: string
|
||||
last_login?: string
|
||||
two_steps?: boolean
|
||||
joined_day?: string
|
||||
online?: boolean
|
||||
initials?: {
|
||||
label: string
|
||||
state: string
|
||||
}
|
||||
// position?: string
|
||||
// role?: string
|
||||
// last_login?: string
|
||||
// two_steps?: boolean
|
||||
// joined_day?: string
|
||||
// online?: boolean
|
||||
// initials?: {
|
||||
// label: string
|
||||
// state: string
|
||||
// }
|
||||
uid?: string
|
||||
percent_interest?: string
|
||||
max_loan?: string
|
||||
@@ -31,8 +31,8 @@ export type UsersQueryResponse = Response<Array<User>>
|
||||
|
||||
export const initialUser: User = {
|
||||
avatar: 'avatars/300-6.jpg',
|
||||
position: 'Art Director',
|
||||
role: 'Administrator',
|
||||
// position: 'Art Director',
|
||||
// role: 'Administrator',
|
||||
name: '',
|
||||
email: '',
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios, { AxiosResponse } from "axios";
|
||||
import { ID, Response } from "../../../../../../_digifi/helpers";
|
||||
import { User, UsersQueryResponse } from "./_models";
|
||||
import { UsersQueryResponse as SignatoryQueryResponse } from "../../signatory-list/core/_models";
|
||||
|
||||
const API_URL = import.meta.env.VITE_APP_THEME_API_URL;
|
||||
const USER_URL = `${API_URL}/user`;
|
||||
@@ -19,6 +20,44 @@ const getEmployersList = (query: string): Promise<UsersQueryResponse> => { // FU
|
||||
.then((d: AxiosResponse<UsersQueryResponse>) => d.data);
|
||||
};
|
||||
|
||||
// const createUser = (user: any): Promise<User | undefined> => { // FUNCTION TO ADD/CREATE NEW USER
|
||||
// const formData = new FormData();
|
||||
// delete user.email
|
||||
// delete user.role
|
||||
// delete user.position
|
||||
// delete user.avatar
|
||||
// delete user.id
|
||||
// for (let data in user) {
|
||||
// formData.append(data, user[data]);
|
||||
// }
|
||||
// return axios
|
||||
// .post(`${NEW_USER_ENDPOINT}/employer`, formData)
|
||||
// .then((response: AxiosResponse<Response<User>>) => response.data)
|
||||
// .then((response: Response<User>) => response.data);
|
||||
// };
|
||||
|
||||
const createUser = (user: any): Promise<UsersQueryResponse | undefined> => { // FUNCTION TO ADD/CREATE NEW USER
|
||||
const formData = new FormData();
|
||||
delete user.avatar
|
||||
delete user.id
|
||||
for (let data in user) {
|
||||
formData.append(data, user[data]);
|
||||
}
|
||||
return axios.post(`${NEW_USER_ENDPOINT}/employer`, formData)
|
||||
.then((response: AxiosResponse<UsersQueryResponse>) => response.data)
|
||||
};
|
||||
|
||||
const createSignatory = (user: any): Promise<SignatoryQueryResponse | undefined> => { // FUNCTION TO ADD/CREATE NEW Signatory
|
||||
const formData = new FormData();
|
||||
delete user.avatar
|
||||
delete user.id
|
||||
for (let data in user) {
|
||||
formData.append(data, user[data]);
|
||||
}
|
||||
return axios.post(`${NEW_USER_ENDPOINT}/employers/signatory`, formData)
|
||||
.then((response: AxiosResponse<SignatoryQueryResponse>) => response.data)
|
||||
};
|
||||
|
||||
const getUserById = (id: ID): Promise<User | undefined> => {
|
||||
return axios
|
||||
.get(`${USER_URL}/${id}`)
|
||||
@@ -26,13 +65,6 @@ const getUserById = (id: ID): Promise<User | undefined> => {
|
||||
.then((response: Response<User>) => response.data);
|
||||
};
|
||||
|
||||
const createUser = (user: User): Promise<User | undefined> => {
|
||||
return axios
|
||||
.put(USER_URL, user)
|
||||
.then((response: AxiosResponse<Response<User>>) => response.data)
|
||||
.then((response: Response<User>) => response.data);
|
||||
};
|
||||
|
||||
const updateUser = (user: User): Promise<User | undefined> => {
|
||||
return axios
|
||||
.post(`${USER_URL}/${user.id}`, user)
|
||||
@@ -51,9 +83,11 @@ const deleteSelectedUsers = (userIds: Array<ID>): Promise<void> => {
|
||||
|
||||
export {
|
||||
getEmployersList,
|
||||
createUser,
|
||||
createSignatory,
|
||||
|
||||
deleteUser,
|
||||
deleteSelectedUsers,
|
||||
getUserById,
|
||||
createUser,
|
||||
updateUser,
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import {ID, KTIcon, QUERIES} from '../../../../../../../_digifi/helpers'
|
||||
import {useListView} from '../../core/ListViewProvider'
|
||||
import {useQueryResponse} from '../../core/QueryResponseProvider'
|
||||
import {deleteUser} from '../../core/_requests'
|
||||
import { useCustomModal } from '../../../../../../../context/CustomModal'
|
||||
|
||||
type Props = {
|
||||
id: ID
|
||||
@@ -16,6 +17,8 @@ const UserActionsCell: FC<Props> = ({id}) => {
|
||||
const {query} = useQueryResponse()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const {MODALNAMES, openCustomModal} = useCustomModal()
|
||||
|
||||
useEffect(() => {
|
||||
MenuComponent.reinitialization()
|
||||
}, [])
|
||||
@@ -56,6 +59,17 @@ const UserActionsCell: FC<Props> = ({id}) => {
|
||||
</div>
|
||||
{/* end::Menu item */}
|
||||
|
||||
{/* begin::Menu item */}
|
||||
<div className='menu-item px-3'>
|
||||
<a className='menu-link px-3' onClick={()=>{openCustomModal(MODALNAMES.addSignatory, {id})}}>
|
||||
Add Signatory
|
||||
</a>
|
||||
</div>
|
||||
{/* end::Menu item */}
|
||||
<div className='px-3'>
|
||||
<div className='separator separator-dashed'></div>
|
||||
</div>
|
||||
|
||||
{/* begin::Menu item */}
|
||||
<div className='menu-item px-3'>
|
||||
<a
|
||||
|
||||
@@ -2,7 +2,9 @@ import {useEffect} from 'react'
|
||||
import {UserEditModalHeader} from './UserEditModalHeader'
|
||||
import {UserEditModalFormWrapper} from './UserEditModalFormWrapper'
|
||||
|
||||
|
||||
const UserEditModal = () => {
|
||||
|
||||
useEffect(() => {
|
||||
document.body.classList.add('modal-open')
|
||||
return () => {
|
||||
|
||||
+575
@@ -0,0 +1,575 @@
|
||||
import { FC, useState } from "react";
|
||||
import * as Yup from "yup";
|
||||
import { useFormik } from "formik";
|
||||
import { isNotEmpty, toAbsoluteUrl } from "../../../../../../_digifi/helpers";
|
||||
import { initialUser, User } from "../core/_models";
|
||||
import clsx from "clsx";
|
||||
import { useListView } from "../core/ListViewProvider";
|
||||
import { UsersListLoading } from "../components/loading/UsersListLoading";
|
||||
import { createUser, updateUser } from "../core/_requests";
|
||||
import { useAllResponse, useQueryResponse } from "../core/QueryResponseProvider";
|
||||
|
||||
type Props = {
|
||||
isUserLoading: boolean;
|
||||
user: User;
|
||||
};
|
||||
|
||||
const editUserSchema = Yup.object().shape({
|
||||
// email: Yup.string()
|
||||
// .email('Wrong email format')
|
||||
// .min(3, 'Minimum 3 symbols')
|
||||
// .max(50, 'Maximum 50 symbols')
|
||||
// .required('required'),
|
||||
name: Yup.string()
|
||||
.min(3, "Minimum 3 symbols")
|
||||
.max(50, "Maximum 50 symbols")
|
||||
.required("required"),
|
||||
percent_interest: Yup.string()
|
||||
.min(3, "Minimum 3 symbols")
|
||||
.max(50, "Maximum 50 symbols")
|
||||
.required("required"),
|
||||
max_loan: Yup.string()
|
||||
.min(3, "Minimum 3 symbols")
|
||||
.max(50, "Maximum 50 symbols")
|
||||
.required("required"),
|
||||
tenor: Yup.string()
|
||||
.min(3, "Minimum 3 symbols")
|
||||
.max(50, "Maximum 50 symbols")
|
||||
.required("required"),
|
||||
retirement_age: Yup.string()
|
||||
.min(3, "Minimum 3 symbols")
|
||||
.max(50, "Maximum 50 symbols")
|
||||
.required("is required"),
|
||||
sector: Yup.string()
|
||||
.min(3, "Minimum 3 symbols")
|
||||
.max(50, "Maximum 50 symbols")
|
||||
.required("required"),
|
||||
salary_source: Yup.string()
|
||||
.min(3, "Minimum 3 symbols")
|
||||
.max(50, "Maximum 50 symbols")
|
||||
.required("required"),
|
||||
});
|
||||
|
||||
const UserEditModalForm: FC<Props> = ({ user, isUserLoading }) => {
|
||||
const response:any = useAllResponse()
|
||||
console.log('response', response)
|
||||
|
||||
const { setItemIdForUpdate } = useListView();
|
||||
const { refetch, isLoading } = useQueryResponse();
|
||||
|
||||
const [userForEdit] = useState<User>({
|
||||
...user,
|
||||
avatar: user.avatar || initialUser.avatar,
|
||||
role: user.role || initialUser.role,
|
||||
position: user.position || initialUser.position,
|
||||
name: user.name || initialUser.name,
|
||||
email: user.email || initialUser.email,
|
||||
});
|
||||
|
||||
const cancel = (withRefresh?: boolean) => {
|
||||
if (withRefresh) {
|
||||
refetch();
|
||||
}
|
||||
setItemIdForUpdate(undefined);
|
||||
};
|
||||
|
||||
const blankImg = toAbsoluteUrl("media/svg/avatars/blank.svg");
|
||||
const userAvatarImg = toAbsoluteUrl(`media/${userForEdit.avatar}`);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: userForEdit,
|
||||
validationSchema: editUserSchema,
|
||||
onSubmit: async (values, { setSubmitting }) => {
|
||||
console.log('values', values)
|
||||
setSubmitting(true);
|
||||
// try {
|
||||
// if (isNotEmpty(values.id)) {
|
||||
// await updateUser(values);
|
||||
// } else {
|
||||
// await createUser(values);
|
||||
// }
|
||||
// } catch (ex) {
|
||||
// console.error(ex);
|
||||
// } finally {
|
||||
// setSubmitting(true);
|
||||
// cancel(true);
|
||||
// }
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<form
|
||||
id="kt_modal_add_user_form"
|
||||
className="form"
|
||||
onSubmit={formik.handleSubmit}
|
||||
noValidate
|
||||
>
|
||||
{/* begin::Scroll */}
|
||||
<div
|
||||
className="d-flex flex-column scroll-y me-n7 pe-7"
|
||||
id="kt_modal_add_user_scroll"
|
||||
data-kt-scroll="true"
|
||||
data-kt-scroll-activate="{default: false, lg: true}"
|
||||
data-kt-scroll-max-height="auto"
|
||||
data-kt-scroll-dependencies="#kt_modal_add_user_header"
|
||||
data-kt-scroll-wrappers="#kt_modal_add_user_scroll"
|
||||
data-kt-scroll-offset="300px"
|
||||
>
|
||||
{/* begin::Input group */}
|
||||
{/* <div className='fv-row mb-7'>
|
||||
|
||||
<label className='d-block fw-bold fs-6 mb-5'>Avatar</label>
|
||||
|
||||
<div
|
||||
className='image-input image-input-outline'
|
||||
data-kt-image-input='true'
|
||||
style={{backgroundImage: `url('${blankImg}')`}}
|
||||
>
|
||||
<div
|
||||
className='image-input-wrapper w-125px h-125px'
|
||||
style={{backgroundImage: `url('${userAvatarImg}')`}}
|
||||
></div>
|
||||
|
||||
<label
|
||||
className='btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow'
|
||||
data-kt-image-input-action='change'
|
||||
data-bs-toggle='tooltip'
|
||||
title='Change avatar'
|
||||
>
|
||||
<i className='bi bi-pencil-fill fs-7'></i>
|
||||
|
||||
<input type='file' name='avatar' accept='.png, .jpg, .jpeg' />
|
||||
<input type='hidden' name='avatar_remove' />
|
||||
</label>
|
||||
|
||||
<span
|
||||
className='btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow'
|
||||
data-kt-image-input-action='cancel'
|
||||
data-bs-toggle='tooltip'
|
||||
title='Cancel avatar'
|
||||
>
|
||||
<i className='bi bi-x fs-2'></i>
|
||||
</span>
|
||||
|
||||
<span
|
||||
className='btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow'
|
||||
data-kt-image-input-action='remove'
|
||||
data-bs-toggle='tooltip'
|
||||
title='Remove avatar'
|
||||
>
|
||||
<i className='bi bi-x fs-2'></i>
|
||||
</span>
|
||||
</div>
|
||||
<div className='form-text'>Allowed file types: png, jpg, jpeg.</div>
|
||||
</div> */}
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Full Name</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Full name"
|
||||
{...formik.getFieldProps("name")}
|
||||
type="text"
|
||||
name="name"
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.name && formik.errors.name },
|
||||
{
|
||||
"is-valid": formik.touched.name && !formik.errors.name,
|
||||
}
|
||||
)}
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{formik.touched.name && formik.errors.name && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* end::Input */}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Interest</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Interest"
|
||||
{...formik.getFieldProps("interest")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.percent_interest && formik.errors.percent_interest },
|
||||
{
|
||||
"is-valid": formik.touched.percent_interest && !formik.errors.percent_interest,
|
||||
}
|
||||
)}
|
||||
type="text"
|
||||
name="percent_interest"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.percent_interest && formik.errors.percent_interest && (
|
||||
// <div className="fv-plugins-message-container">
|
||||
// <span role="alert">{formik.errors.percent_interest}</span>
|
||||
// </div>
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.percent_interest}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Max Loan</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Max Loan"
|
||||
{...formik.getFieldProps("max_loan")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.max_loan && formik.errors.max_loan },
|
||||
{
|
||||
"is-valid": formik.touched.max_loan && !formik.errors.max_loan,
|
||||
}
|
||||
)}
|
||||
type="text"
|
||||
name="max_loan"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.max_loan && formik.errors.max_loan && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.max_loan}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Tenor</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Tenor"
|
||||
{...formik.getFieldProps("tenor")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.tenor && formik.errors.tenor },
|
||||
{
|
||||
"is-valid": formik.touched.tenor && !formik.errors.tenor,
|
||||
}
|
||||
)}
|
||||
type="text"
|
||||
name="tenor"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.tenor && formik.errors.tenor && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.tenor}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Ret Age</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Retirement Age"
|
||||
{...formik.getFieldProps("retirement_age")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.retirement_age && formik.errors.retirement_age },
|
||||
{
|
||||
"is-valid": formik.touched.retirement_age && !formik.errors.retirement_age,
|
||||
}
|
||||
)}
|
||||
type="text"
|
||||
name="retirement_age"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.retirement_age && formik.errors.retirement_age && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.retirement_age}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
<label className="required fw-bold fs-6 mb-2">Sector</label>
|
||||
<select
|
||||
{...formik.getFieldProps("sector")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.sector && formik.errors.sector },
|
||||
{
|
||||
"is-valid": formik.touched.sector && !formik.errors.sector,
|
||||
}
|
||||
)}
|
||||
name="sector"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
>
|
||||
{isLoading ?
|
||||
<option value=''>Loading...</option>
|
||||
:
|
||||
<>
|
||||
<option value=''>Select Sector</option>
|
||||
{response?.employer_sector?.map((item:any) => (
|
||||
<option value={item.uid}>{item.name}</option>
|
||||
))
|
||||
}
|
||||
</>
|
||||
}
|
||||
</select>
|
||||
{/* end::Input */}
|
||||
{formik.touched.sector && formik.errors.sector && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.sector}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Salary</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<select
|
||||
{...formik.getFieldProps("salary_source")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.salary_source && formik.errors.salary_source },
|
||||
{
|
||||
"is-valid": formik.touched.salary_source && !formik.errors.salary_source,
|
||||
}
|
||||
)}
|
||||
name="salary_source"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
>
|
||||
{isLoading ?
|
||||
<option value=''>Loading...</option>
|
||||
:
|
||||
<>
|
||||
<option value=''>Select Salary Source</option>
|
||||
{response?.salary_sources?.map((item:any) => (
|
||||
<option value={item.uid}>{item.name}</option>
|
||||
))
|
||||
}
|
||||
</>
|
||||
}
|
||||
</select>
|
||||
{/* end::Input */}
|
||||
{formik.touched.salary_source && formik.errors.salary_source && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.salary_source}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{/* begin::Input group */}
|
||||
{/* <div className='mb-7'>
|
||||
<label className='required fw-bold fs-6 mb-5'>Role</label>
|
||||
<div className='d-flex fv-row'>
|
||||
<div className='form-check form-check-custom form-check-solid'>
|
||||
<input
|
||||
className='form-check-input me-3'
|
||||
{...formik.getFieldProps('role')}
|
||||
name='role'
|
||||
type='radio'
|
||||
value='Administrator'
|
||||
id='kt_modal_update_role_option_0'
|
||||
checked={formik.values.role === 'Administrator'}
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
<label className='form-check-label' htmlFor='kt_modal_update_role_option_0'>
|
||||
<div className='fw-bolder text-gray-800'>Administrator</div>
|
||||
<div className='text-gray-600'>
|
||||
Best for business owners and company administrators
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className='separator separator-dashed my-5'></div>
|
||||
<div className='d-flex fv-row'>
|
||||
<div className='form-check form-check-custom form-check-solid'>
|
||||
<input
|
||||
className='form-check-input me-3'
|
||||
{...formik.getFieldProps('role')}
|
||||
name='role'
|
||||
type='radio'
|
||||
value='Developer'
|
||||
id='kt_modal_update_role_option_1'
|
||||
checked={formik.values.role === 'Developer'}
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
<label className='form-check-label' htmlFor='kt_modal_update_role_option_1'>
|
||||
<div className='fw-bolder text-gray-800'>Developer</div>
|
||||
<div className='text-gray-600'>
|
||||
Best for developers or people primarily using the API
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className='separator separator-dashed my-5'></div>
|
||||
<div className='d-flex fv-row'>
|
||||
<div className='form-check form-check-custom form-check-solid'>
|
||||
<input
|
||||
className='form-check-input me-3'
|
||||
{...formik.getFieldProps('role')}
|
||||
name='role'
|
||||
type='radio'
|
||||
value='Analyst'
|
||||
id='kt_modal_update_role_option_2'
|
||||
checked={formik.values.role === 'Analyst'}
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
<label className='form-check-label' htmlFor='kt_modal_update_role_option_2'>
|
||||
<div className='fw-bolder text-gray-800'>Analyst</div>
|
||||
<div className='text-gray-600'>
|
||||
Best for people who need full access to analytics data, but don't need to update
|
||||
business settings
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className='separator separator-dashed my-5'></div>
|
||||
<div className='d-flex fv-row'>
|
||||
<div className='form-check form-check-custom form-check-solid'>
|
||||
<input
|
||||
className='form-check-input me-3'
|
||||
{...formik.getFieldProps('role')}
|
||||
name='role'
|
||||
type='radio'
|
||||
value='Support'
|
||||
id='kt_modal_update_role_option_3'
|
||||
checked={formik.values.role === 'Support'}
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
<label className='form-check-label' htmlFor='kt_modal_update_role_option_3'>
|
||||
<div className='fw-bolder text-gray-800'>Support</div>
|
||||
<div className='text-gray-600'>
|
||||
Best for employees who regularly refund payments and respond to disputes
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className='separator separator-dashed my-5'></div>
|
||||
<div className='d-flex fv-row'>
|
||||
<div className='form-check form-check-custom form-check-solid'>
|
||||
<input
|
||||
className='form-check-input me-3'
|
||||
{...formik.getFieldProps('role')}
|
||||
name='role'
|
||||
type='radio'
|
||||
id='kt_modal_update_role_option_4'
|
||||
value='Trial'
|
||||
checked={formik.values.role === 'Trial'}
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
<label className='form-check-label' htmlFor='kt_modal_update_role_option_4'>
|
||||
<div className='fw-bolder text-gray-800'>Trial</div>
|
||||
<div className='text-gray-600'>
|
||||
Best for people who need to preview content data, but don't need to make any
|
||||
updates
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
{/* end::Input group */}
|
||||
</div>
|
||||
{/* end::Scroll */}
|
||||
|
||||
{/* begin::Actions */}
|
||||
<div className="text-center pt-15">
|
||||
<button
|
||||
type="reset"
|
||||
onClick={() => cancel()}
|
||||
className="btn btn-danger me-3"
|
||||
data-kt-users-modal-action="cancel"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-primary"
|
||||
data-kt-users-modal-action="submit"
|
||||
disabled={
|
||||
isUserLoading ||
|
||||
formik.isSubmitting ||
|
||||
!formik.isValid ||
|
||||
!formik.touched
|
||||
}
|
||||
>
|
||||
<span className="indicator-label">Add</span>
|
||||
{(formik.isSubmitting || isUserLoading) && (
|
||||
<span className="indicator-progress">
|
||||
Please wait...{" "}
|
||||
<span className="spinner-border spinner-border-sm align-middle ms-2"></span>
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
{/* end::Actions */}
|
||||
</form>
|
||||
{(formik.isSubmitting || isUserLoading) && <UsersListLoading />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export { UserEditModalForm };
|
||||
+321
-268
@@ -1,109 +1,137 @@
|
||||
import {FC, useState} from 'react'
|
||||
import * as Yup from 'yup'
|
||||
import {useFormik} from 'formik'
|
||||
import {isNotEmpty, toAbsoluteUrl} from '../../../../../../_digifi/helpers'
|
||||
import {initialUser, User} from '../core/_models'
|
||||
import clsx from 'clsx'
|
||||
import {useListView} from '../core/ListViewProvider'
|
||||
import {UsersListLoading} from '../components/loading/UsersListLoading'
|
||||
import {createUser, updateUser} from '../core/_requests'
|
||||
import {useQueryResponse} from '../core/QueryResponseProvider'
|
||||
import { FC, useState } from "react";
|
||||
import * as Yup from "yup";
|
||||
import { useFormik } from "formik";
|
||||
import { isNotEmpty, toAbsoluteUrl } from "../../../../../../_digifi/helpers";
|
||||
import { initialUser, User } from "../core/_models";
|
||||
import clsx from "clsx";
|
||||
import { useListView } from "../core/ListViewProvider";
|
||||
import { UsersListLoading } from "../components/loading/UsersListLoading";
|
||||
import { createUser, updateUser } from "../core/_requests";
|
||||
import { useAllResponse, useQueryResponse } from "../core/QueryResponseProvider";
|
||||
|
||||
type Props = {
|
||||
isUserLoading: boolean
|
||||
user: User
|
||||
}
|
||||
isUserLoading: boolean;
|
||||
user: User;
|
||||
};
|
||||
|
||||
const editUserSchema = Yup.object().shape({
|
||||
email: Yup.string()
|
||||
.email('Wrong email format')
|
||||
.min(3, 'Minimum 3 symbols')
|
||||
.max(50, 'Maximum 50 symbols')
|
||||
.required('Email is required'),
|
||||
// email: Yup.string()
|
||||
// .email('Wrong email format')
|
||||
// .min(3, 'Minimum 3 symbols')
|
||||
// .max(50, 'Maximum 50 symbols')
|
||||
// .required('required'),
|
||||
name: Yup.string()
|
||||
.min(3, 'Minimum 3 symbols')
|
||||
.max(50, 'Maximum 50 symbols')
|
||||
.required('Name is required'),
|
||||
})
|
||||
.min(3, "Minimum 3 symbols")
|
||||
.max(50, "Maximum 50 symbols")
|
||||
.required("required"),
|
||||
percent_interest: Yup.number()
|
||||
.typeError("Invalid number")
|
||||
.min(1, "must be greater than 0")
|
||||
// .test("no-e", "Invalid number", (value) => {
|
||||
// if (value && /\d+e/.test(value)) {
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// })
|
||||
.required("required"),
|
||||
max_loan: Yup.number()
|
||||
.typeError("Invalid number")
|
||||
.min(1, "must be greater than 0")
|
||||
.required("required"),
|
||||
tenor: Yup.number()
|
||||
.typeError("Invalid number")
|
||||
.min(1, "must be greater than 0")
|
||||
.required("required"),
|
||||
retirement_age: Yup.number()
|
||||
.typeError("Invalid number")
|
||||
.min(1, "must be greater than 0")
|
||||
.required("is required"),
|
||||
sector: Yup.string()
|
||||
.required("required"),
|
||||
salary_source: Yup.string()
|
||||
.required("required"),
|
||||
});
|
||||
|
||||
const UserEditModalForm: FC<Props> = ({user, isUserLoading}) => {
|
||||
const {setItemIdForUpdate} = useListView()
|
||||
const {refetch} = useQueryResponse()
|
||||
const UserEditModalForm: FC<Props> = ({ user, isUserLoading }) => {
|
||||
const response:any = useAllResponse()
|
||||
|
||||
const { setItemIdForUpdate } = useListView();
|
||||
const { refetch, isLoading } = useQueryResponse();
|
||||
|
||||
const [userForEdit] = useState<User>({
|
||||
...user,
|
||||
avatar: user.avatar || initialUser.avatar,
|
||||
role: user.role || initialUser.role,
|
||||
position: user.position || initialUser.position,
|
||||
// role: user.role || initialUser.role,
|
||||
// position: user.position || initialUser.position,
|
||||
name: user.name || initialUser.name,
|
||||
email: user.email || initialUser.email,
|
||||
})
|
||||
// email: user.email || initialUser.email,
|
||||
});
|
||||
|
||||
const cancel = (withRefresh?: boolean) => {
|
||||
if (withRefresh) {
|
||||
refetch()
|
||||
refetch();
|
||||
}
|
||||
setItemIdForUpdate(undefined)
|
||||
}
|
||||
setItemIdForUpdate(undefined);
|
||||
};
|
||||
|
||||
const blankImg = toAbsoluteUrl('media/svg/avatars/blank.svg')
|
||||
const userAvatarImg = toAbsoluteUrl(`media/${userForEdit.avatar}`)
|
||||
const blankImg = toAbsoluteUrl("media/svg/avatars/blank.svg");
|
||||
const userAvatarImg = toAbsoluteUrl(`media/${userForEdit.avatar}`);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: userForEdit,
|
||||
validationSchema: editUserSchema,
|
||||
onSubmit: async (values, {setSubmitting}) => {
|
||||
setSubmitting(true)
|
||||
onSubmit: async (values, { setSubmitting }) => {
|
||||
setSubmitting(true);
|
||||
try {
|
||||
if (isNotEmpty(values.id)) {
|
||||
await updateUser(values)
|
||||
await updateUser(values);
|
||||
} else {
|
||||
await createUser(values)
|
||||
await createUser(values);
|
||||
}
|
||||
} catch (ex) {
|
||||
console.error(ex)
|
||||
console.error(ex);
|
||||
} finally {
|
||||
setSubmitting(true)
|
||||
cancel(true)
|
||||
setSubmitting(true);
|
||||
cancel(true);
|
||||
}
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<form id='kt_modal_add_user_form' className='form' onSubmit={formik.handleSubmit} noValidate>
|
||||
<form
|
||||
id="kt_modal_add_user_form"
|
||||
className="form"
|
||||
onSubmit={formik.handleSubmit}
|
||||
noValidate
|
||||
>
|
||||
{/* begin::Scroll */}
|
||||
<div
|
||||
className='d-flex flex-column scroll-y me-n7 pe-7'
|
||||
id='kt_modal_add_user_scroll'
|
||||
data-kt-scroll='true'
|
||||
data-kt-scroll-activate='{default: false, lg: true}'
|
||||
data-kt-scroll-max-height='auto'
|
||||
data-kt-scroll-dependencies='#kt_modal_add_user_header'
|
||||
data-kt-scroll-wrappers='#kt_modal_add_user_scroll'
|
||||
data-kt-scroll-offset='300px'
|
||||
className="d-flex flex-column scroll-y me-n7 pe-7"
|
||||
id="kt_modal_add_user_scroll"
|
||||
data-kt-scroll="true"
|
||||
data-kt-scroll-activate="{default: false, lg: true}"
|
||||
data-kt-scroll-max-height="auto"
|
||||
data-kt-scroll-dependencies="#kt_modal_add_user_header"
|
||||
data-kt-scroll-wrappers="#kt_modal_add_user_scroll"
|
||||
data-kt-scroll-offset="300px"
|
||||
>
|
||||
{/* begin::Input group */}
|
||||
<div className='fv-row mb-7'>
|
||||
{/* begin::Label */}
|
||||
<label className='d-block fw-bold fs-6 mb-5'>Avatar</label>
|
||||
{/* end::Label */}
|
||||
{/* <div className='fv-row mb-7'>
|
||||
|
||||
<label className='d-block fw-bold fs-6 mb-5'>Avatar</label>
|
||||
|
||||
{/* begin::Image input */}
|
||||
<div
|
||||
className='image-input image-input-outline'
|
||||
data-kt-image-input='true'
|
||||
style={{backgroundImage: `url('${blankImg}')`}}
|
||||
>
|
||||
{/* begin::Preview existing avatar */}
|
||||
<div
|
||||
className='image-input-wrapper w-125px h-125px'
|
||||
style={{backgroundImage: `url('${userAvatarImg}')`}}
|
||||
></div>
|
||||
{/* end::Preview existing avatar */}
|
||||
|
||||
{/* begin::Label */}
|
||||
{/* <label
|
||||
<label
|
||||
className='btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow'
|
||||
data-kt-image-input-action='change'
|
||||
data-bs-toggle='tooltip'
|
||||
@@ -113,65 +141,56 @@ const UserEditModalForm: FC<Props> = ({user, isUserLoading}) => {
|
||||
|
||||
<input type='file' name='avatar' accept='.png, .jpg, .jpeg' />
|
||||
<input type='hidden' name='avatar_remove' />
|
||||
</label> */}
|
||||
{/* end::Label */}
|
||||
</label>
|
||||
|
||||
{/* begin::Cancel */}
|
||||
{/* <span
|
||||
<span
|
||||
className='btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow'
|
||||
data-kt-image-input-action='cancel'
|
||||
data-bs-toggle='tooltip'
|
||||
title='Cancel avatar'
|
||||
>
|
||||
<i className='bi bi-x fs-2'></i>
|
||||
</span> */}
|
||||
{/* end::Cancel */}
|
||||
</span>
|
||||
|
||||
{/* begin::Remove */}
|
||||
{/* <span
|
||||
<span
|
||||
className='btn btn-icon btn-circle btn-active-color-primary w-25px h-25px bg-body shadow'
|
||||
data-kt-image-input-action='remove'
|
||||
data-bs-toggle='tooltip'
|
||||
title='Remove avatar'
|
||||
>
|
||||
<i className='bi bi-x fs-2'></i>
|
||||
</span> */}
|
||||
{/* end::Remove */}
|
||||
</span>
|
||||
</div>
|
||||
{/* end::Image input */}
|
||||
|
||||
{/* begin::Hint */}
|
||||
{/* <div className='form-text'>Allowed file types: png, jpg, jpeg.</div> */}
|
||||
{/* end::Hint */}
|
||||
</div>
|
||||
<div className='form-text'>Allowed file types: png, jpg, jpeg.</div>
|
||||
</div> */}
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className='fv-row mb-7'>
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className='required fw-bold fs-6 mb-2'>Full Name</label>
|
||||
<label className="required fw-bold fs-6 mb-2">Full Name</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder='Full name'
|
||||
{...formik.getFieldProps('name')}
|
||||
type='text'
|
||||
name='name'
|
||||
placeholder="Full name"
|
||||
{...formik.getFieldProps("name")}
|
||||
type="text"
|
||||
name="name"
|
||||
className={clsx(
|
||||
'form-control form-control-solid mb-3 mb-lg-0',
|
||||
{'is-invalid': formik.touched.name && formik.errors.name},
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.name && formik.errors.name },
|
||||
{
|
||||
'is-valid': formik.touched.name && !formik.errors.name,
|
||||
"is-valid": formik.touched.name && !formik.errors.name,
|
||||
}
|
||||
)}
|
||||
autoComplete='off'
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{formik.touched.name && formik.errors.name && (
|
||||
<div className='fv-plugins-message-container'>
|
||||
<div className='fv-help-block'>
|
||||
<span role='alert'>{formik.errors.name}</span>
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -180,219 +199,253 @@ const UserEditModalForm: FC<Props> = ({user, isUserLoading}) => {
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className='fv-row mb-7'>
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className='required fw-bold fs-6 mb-2'>Email</label>
|
||||
<label className="required fw-bold fs-6 mb-2">Interest</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder='Email'
|
||||
{...formik.getFieldProps('email')}
|
||||
placeholder="Interest"
|
||||
{...formik.getFieldProps("percent_interest")}
|
||||
className={clsx(
|
||||
'form-control form-control-solid mb-3 mb-lg-0',
|
||||
{'is-invalid': formik.touched.email && formik.errors.email},
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.percent_interest && formik.errors.percent_interest },
|
||||
{
|
||||
'is-valid': formik.touched.email && !formik.errors.email,
|
||||
"is-valid": formik.touched.percent_interest && !formik.errors.percent_interest,
|
||||
}
|
||||
)}
|
||||
type='email'
|
||||
name='email'
|
||||
autoComplete='off'
|
||||
type="text"
|
||||
name="percent_interest"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.email && formik.errors.email && (
|
||||
<div className='fv-plugins-message-container'>
|
||||
<span role='alert'>{formik.errors.email}</span>
|
||||
{formik.touched.percent_interest && formik.errors.percent_interest && (
|
||||
// <div className="fv-plugins-message-container">
|
||||
// <span role="alert">{formik.errors.percent_interest}</span>
|
||||
// </div>
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.percent_interest}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className='mb-7'>
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className='required fw-bold fs-6 mb-5'>Role</label>
|
||||
<label className="required fw-bold fs-6 mb-2">Max Loan</label>
|
||||
{/* end::Label */}
|
||||
{/* begin::Roles */}
|
||||
{/* begin::Input row */}
|
||||
<div className='d-flex fv-row'>
|
||||
{/* begin::Radio */}
|
||||
<div className='form-check form-check-custom form-check-solid'>
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
className='form-check-input me-3'
|
||||
{...formik.getFieldProps('role')}
|
||||
name='role'
|
||||
type='radio'
|
||||
value='Administrator'
|
||||
id='kt_modal_update_role_option_0'
|
||||
checked={formik.values.role === 'Administrator'}
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
|
||||
{/* end::Input */}
|
||||
{/* begin::Label */}
|
||||
<label className='form-check-label' htmlFor='kt_modal_update_role_option_0'>
|
||||
<div className='fw-bolder text-gray-800'>Administrator</div>
|
||||
<div className='text-gray-600'>
|
||||
Best for business owners and company administrators
|
||||
</div>
|
||||
</label>
|
||||
{/* end::Label */}
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Max Loan"
|
||||
{...formik.getFieldProps("max_loan")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.max_loan && formik.errors.max_loan },
|
||||
{
|
||||
"is-valid": formik.touched.max_loan && !formik.errors.max_loan,
|
||||
}
|
||||
)}
|
||||
type="text"
|
||||
name="max_loan"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.max_loan && formik.errors.max_loan && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.max_loan}</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* end::Radio */}
|
||||
</div>
|
||||
{/* end::Input row */}
|
||||
<div className='separator separator-dashed my-5'></div>
|
||||
{/* begin::Input row */}
|
||||
<div className='d-flex fv-row'>
|
||||
{/* begin::Radio */}
|
||||
<div className='form-check form-check-custom form-check-solid'>
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
className='form-check-input me-3'
|
||||
{...formik.getFieldProps('role')}
|
||||
name='role'
|
||||
type='radio'
|
||||
value='Developer'
|
||||
id='kt_modal_update_role_option_1'
|
||||
checked={formik.values.role === 'Developer'}
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{/* begin::Label */}
|
||||
<label className='form-check-label' htmlFor='kt_modal_update_role_option_1'>
|
||||
<div className='fw-bolder text-gray-800'>Developer</div>
|
||||
<div className='text-gray-600'>
|
||||
Best for developers or people primarily using the API
|
||||
</div>
|
||||
</label>
|
||||
{/* end::Label */}
|
||||
</div>
|
||||
{/* end::Radio */}
|
||||
</div>
|
||||
{/* end::Input row */}
|
||||
<div className='separator separator-dashed my-5'></div>
|
||||
{/* begin::Input row */}
|
||||
<div className='d-flex fv-row'>
|
||||
{/* begin::Radio */}
|
||||
<div className='form-check form-check-custom form-check-solid'>
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
className='form-check-input me-3'
|
||||
{...formik.getFieldProps('role')}
|
||||
name='role'
|
||||
type='radio'
|
||||
value='Analyst'
|
||||
id='kt_modal_update_role_option_2'
|
||||
checked={formik.values.role === 'Analyst'}
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
|
||||
{/* end::Input */}
|
||||
{/* begin::Label */}
|
||||
<label className='form-check-label' htmlFor='kt_modal_update_role_option_2'>
|
||||
<div className='fw-bolder text-gray-800'>Analyst</div>
|
||||
<div className='text-gray-600'>
|
||||
Best for people who need full access to analytics data, but don't need to update
|
||||
business settings
|
||||
</div>
|
||||
</label>
|
||||
{/* end::Label */}
|
||||
</div>
|
||||
{/* end::Radio */}
|
||||
</div>
|
||||
{/* end::Input row */}
|
||||
<div className='separator separator-dashed my-5'></div>
|
||||
{/* begin::Input row */}
|
||||
<div className='d-flex fv-row'>
|
||||
{/* begin::Radio */}
|
||||
<div className='form-check form-check-custom form-check-solid'>
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
className='form-check-input me-3'
|
||||
{...formik.getFieldProps('role')}
|
||||
name='role'
|
||||
type='radio'
|
||||
value='Support'
|
||||
id='kt_modal_update_role_option_3'
|
||||
checked={formik.values.role === 'Support'}
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{/* begin::Label */}
|
||||
<label className='form-check-label' htmlFor='kt_modal_update_role_option_3'>
|
||||
<div className='fw-bolder text-gray-800'>Support</div>
|
||||
<div className='text-gray-600'>
|
||||
Best for employees who regularly refund payments and respond to disputes
|
||||
</div>
|
||||
</label>
|
||||
{/* end::Label */}
|
||||
</div>
|
||||
{/* end::Radio */}
|
||||
</div>
|
||||
{/* end::Input row */}
|
||||
<div className='separator separator-dashed my-5'></div>
|
||||
{/* begin::Input row */}
|
||||
<div className='d-flex fv-row'>
|
||||
{/* begin::Radio */}
|
||||
<div className='form-check form-check-custom form-check-solid'>
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
className='form-check-input me-3'
|
||||
{...formik.getFieldProps('role')}
|
||||
name='role'
|
||||
type='radio'
|
||||
id='kt_modal_update_role_option_4'
|
||||
value='Trial'
|
||||
checked={formik.values.role === 'Trial'}
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{/* begin::Label */}
|
||||
<label className='form-check-label' htmlFor='kt_modal_update_role_option_4'>
|
||||
<div className='fw-bolder text-gray-800'>Trial</div>
|
||||
<div className='text-gray-600'>
|
||||
Best for people who need to preview content data, but don't need to make any
|
||||
updates
|
||||
</div>
|
||||
</label>
|
||||
{/* end::Label */}
|
||||
</div>
|
||||
{/* end::Radio */}
|
||||
</div>
|
||||
{/* end::Input row */}
|
||||
{/* end::Roles */}
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Tenor</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Tenor"
|
||||
{...formik.getFieldProps("tenor")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.tenor && formik.errors.tenor },
|
||||
{
|
||||
"is-valid": formik.touched.tenor && !formik.errors.tenor,
|
||||
}
|
||||
)}
|
||||
type="text"
|
||||
name="tenor"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.tenor && formik.errors.tenor && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.tenor}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Ret Age</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<input
|
||||
placeholder="Retirement Age"
|
||||
{...formik.getFieldProps("retirement_age")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.retirement_age && formik.errors.retirement_age },
|
||||
{
|
||||
"is-valid": formik.touched.retirement_age && !formik.errors.retirement_age,
|
||||
}
|
||||
)}
|
||||
type="text"
|
||||
name="retirement_age"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
/>
|
||||
{/* end::Input */}
|
||||
{formik.touched.retirement_age && formik.errors.retirement_age && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.retirement_age}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
<label className="required fw-bold fs-6 mb-2">Sector</label>
|
||||
<select
|
||||
{...formik.getFieldProps("sector")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.sector && formik.errors.sector },
|
||||
{
|
||||
"is-valid": formik.touched.sector && !formik.errors.sector,
|
||||
}
|
||||
)}
|
||||
name="sector"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
>
|
||||
{isLoading ?
|
||||
<option value=''>Loading...</option>
|
||||
:
|
||||
<>
|
||||
<option value=''>Select Sector</option>
|
||||
{response?.employer_sector?.map((item:any) => (
|
||||
<option value={item.uid}>{item.name}</option>
|
||||
))
|
||||
}
|
||||
</>
|
||||
}
|
||||
</select>
|
||||
{/* end::Input */}
|
||||
{formik.touched.sector && formik.errors.sector && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.sector}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
{/* begin::Input group */}
|
||||
<div className="fv-row mb-7">
|
||||
{/* begin::Label */}
|
||||
<label className="required fw-bold fs-6 mb-2">Salary</label>
|
||||
{/* end::Label */}
|
||||
|
||||
{/* begin::Input */}
|
||||
<select
|
||||
{...formik.getFieldProps("salary_source")}
|
||||
className={clsx(
|
||||
"form-control form-control-solid mb-3 mb-lg-0",
|
||||
{ "is-invalid": formik.touched.salary_source && formik.errors.salary_source },
|
||||
{
|
||||
"is-valid": formik.touched.salary_source && !formik.errors.salary_source,
|
||||
}
|
||||
)}
|
||||
name="salary_source"
|
||||
autoComplete="off"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
>
|
||||
{isLoading ?
|
||||
<option value=''>Loading...</option>
|
||||
:
|
||||
<>
|
||||
<option value=''>Select Salary Source</option>
|
||||
{response?.salary_sources?.map((item:any) => (
|
||||
<option value={item.uid}>{item.name}</option>
|
||||
))
|
||||
}
|
||||
</>
|
||||
}
|
||||
</select>
|
||||
{/* end::Input */}
|
||||
{formik.touched.salary_source && formik.errors.salary_source && (
|
||||
<div className="fv-plugins-message-container">
|
||||
<div className="fv-help-block">
|
||||
<span role="alert">{formik.errors.salary_source}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* end::Input group */}
|
||||
|
||||
</div>
|
||||
{/* end::Scroll */}
|
||||
|
||||
{/* begin::Actions */}
|
||||
<div className='text-center pt-15'>
|
||||
<div className="text-center pt-15">
|
||||
<button
|
||||
type='reset'
|
||||
type="reset"
|
||||
onClick={() => cancel()}
|
||||
className='btn btn-light me-3'
|
||||
data-kt-users-modal-action='cancel'
|
||||
className="btn btn-danger me-3"
|
||||
data-kt-users-modal-action="cancel"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
>
|
||||
Discard
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
data-kt-users-modal-action='submit'
|
||||
disabled={isUserLoading || formik.isSubmitting || !formik.isValid || !formik.touched}
|
||||
type="submit"
|
||||
className="btn btn-primary"
|
||||
data-kt-users-modal-action="submit"
|
||||
disabled={
|
||||
isUserLoading ||
|
||||
formik.isSubmitting ||
|
||||
!formik.isValid ||
|
||||
!formik.touched
|
||||
}
|
||||
>
|
||||
<span className='indicator-label'>Submit</span>
|
||||
<span className="indicator-label">Add</span>
|
||||
{(formik.isSubmitting || isUserLoading) && (
|
||||
<span className='indicator-progress'>
|
||||
Please wait...{' '}
|
||||
<span className='spinner-border spinner-border-sm align-middle ms-2'></span>
|
||||
<span className="indicator-progress">
|
||||
Please wait...{" "}
|
||||
<span className="spinner-border spinner-border-sm align-middle ms-2"></span>
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
@@ -401,7 +454,7 @@ const UserEditModalForm: FC<Props> = ({user, isUserLoading}) => {
|
||||
</form>
|
||||
{(formik.isSubmitting || isUserLoading) && <UsersListLoading />}
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export {UserEditModalForm}
|
||||
export { UserEditModalForm };
|
||||
|
||||
+2
-2
@@ -2,12 +2,12 @@ import {KTIcon} from '../../../../../../_digifi/helpers'
|
||||
import {useListView} from '../core/ListViewProvider'
|
||||
|
||||
const UserEditModalHeader = () => {
|
||||
const {setItemIdForUpdate} = useListView()
|
||||
const {setItemIdForUpdate, itemIdForUpdate} = useListView()
|
||||
|
||||
return (
|
||||
<div className='modal-header'>
|
||||
{/* begin::Modal title */}
|
||||
<h2 className='fw-bolder'>Add User</h2>
|
||||
<h2 className='fw-bolder'>{itemIdForUpdate ? 'Edit Employer' : 'Add Employer'}</h2>
|
||||
{/* end::Modal title */}
|
||||
|
||||
{/* begin::Close */}
|
||||
|
||||
@@ -30,6 +30,7 @@ export type User = {
|
||||
status?: string
|
||||
added?: string
|
||||
updated?: string
|
||||
employer_name?: string
|
||||
}
|
||||
|
||||
export type UsersQueryResponse = Response<Array<User>>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios, { AxiosResponse } from "axios";
|
||||
import { ID, Response } from "../../../../_digifi/helpers"
|
||||
import { User, UsersQueryResponse } from "./_models";
|
||||
import { postAuxEnd } from "../../auth/core/AxiosCallHelper";
|
||||
|
||||
const API_URL = import.meta.env.VITE_APP_THEME_API_URL;
|
||||
const USER_URL = `${API_URL}/user`;
|
||||
@@ -43,6 +44,10 @@ const getApprovedUsers = (query: string): Promise<UsersQueryResponse> => { // FU
|
||||
.then((d: AxiosResponse<UsersQueryResponse>) => d.data);
|
||||
};
|
||||
|
||||
const employersVerify = (uid: ID): Promise<UsersQueryResponse> => { // FUNCTION FOR EMPLOYERS VERIFICATION
|
||||
return postAuxEnd('/employers/verify', {application_uid:uid})
|
||||
};
|
||||
|
||||
const getUserById = (id: ID): Promise<User | undefined> => {
|
||||
return axios
|
||||
.get(`${USER_URL}/${id}`)
|
||||
@@ -79,6 +84,7 @@ export {
|
||||
getPendingUsers,
|
||||
getReadyUsers,
|
||||
getApprovedUsers,
|
||||
employersVerify,
|
||||
deleteUser,
|
||||
deleteSelectedUsers,
|
||||
getUserById,
|
||||
|
||||
@@ -32,7 +32,7 @@ const QueryResponseProvider: FC<WithChildren> = ({ children }) => {
|
||||
refetch,
|
||||
data: response,
|
||||
} = useQuery(
|
||||
`${QUERIES.USERS_LIST}-${query}`,
|
||||
`${QUERIES.APPROVED_LIST}-${query}`,
|
||||
() => {
|
||||
return getApprovedUsers(query);
|
||||
},
|
||||
|
||||
@@ -32,7 +32,7 @@ const QueryResponseProvider: FC<WithChildren> = ({ children }) => {
|
||||
refetch,
|
||||
data: response,
|
||||
} = useQuery(
|
||||
`${QUERIES.USERS_LIST}-${query}`,
|
||||
`${QUERIES.PENDING_LIST}-${query}`,
|
||||
() => {
|
||||
return getPendingUsers(query);
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import { QueryRequestProvider } from "./core/QueryRequestProvider";
|
||||
import { QueryResponseProvider } from "./core/QueryResponseProvider";
|
||||
import { UsersListHeader } from "./components/header/UsersListHeader";
|
||||
import { UsersTable } from "./table/UsersTable";
|
||||
import { UserEditModal } from "./user-edit-modal/UserEditModal";
|
||||
import { EditLoanModal } from "./edit-loan-modal/EditLoanModal";
|
||||
import { KTCard } from "../../../../_digifi/helpers";
|
||||
import { ToolbarWrapper } from "../../../../_digifi/layout/components/toolbar";
|
||||
import { Content } from "../../../../_digifi/layout/components/content";
|
||||
@@ -16,7 +16,7 @@ const UsersList = () => {
|
||||
<UsersListHeader />
|
||||
<UsersTable />
|
||||
</KTCard>
|
||||
{itemIdForUpdate !== undefined && <UserEditModal />}
|
||||
{itemIdForUpdate !== undefined && <EditLoanModal />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -32,7 +32,7 @@ const QueryResponseProvider: FC<WithChildren> = ({ children }) => {
|
||||
refetch,
|
||||
data: response,
|
||||
} = useQuery(
|
||||
`${QUERIES.USERS_LIST}-${query}`,
|
||||
`${QUERIES.READY_LIST}-${query}`,
|
||||
() => {
|
||||
return getReadyUsers(query);
|
||||
},
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import {useEffect} from 'react'
|
||||
import {UserEditModalHeader} from './UserEditModalHeader'
|
||||
import {UserEditModalFormWrapper} from './UserEditModalFormWrapper'
|
||||
|
||||
const UserEditModal = () => {
|
||||
const EditLoanModal = () => {
|
||||
useEffect(() => {
|
||||
document.body.classList.add('modal-open')
|
||||
return () => {
|
||||
@@ -41,4 +41,4 @@ const UserEditModal = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export {UserEditModal}
|
||||
export {EditLoanModal}
|
||||
+4
-3
@@ -79,7 +79,8 @@ const UserEditModalForm: FC<Props> = ({ user, isUserLoading }) => {
|
||||
>
|
||||
{/* begin::Scroll */}
|
||||
<div
|
||||
className="d-flex flex-column scroll-y me-n7 pe-7"
|
||||
// className="d-flex flex-column scroll-y me-n7 pe-7"
|
||||
className="d-none flex-column scroll-y me-n7 pe-7"
|
||||
id="kt_modal_add_user_scroll"
|
||||
data-kt-scroll="true"
|
||||
data-kt-scroll-activate="{default: false, lg: true}"
|
||||
@@ -396,11 +397,11 @@ const UserEditModalForm: FC<Props> = ({ user, isUserLoading }) => {
|
||||
<button
|
||||
type="reset"
|
||||
onClick={() => cancel()}
|
||||
className="btn btn-light me-3"
|
||||
className="btn btn-danger me-3"
|
||||
data-kt-users-modal-action="cancel"
|
||||
disabled={formik.isSubmitting || isUserLoading}
|
||||
>
|
||||
Discard
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
<button
|
||||
+8
-4
@@ -2,7 +2,7 @@ import { useQuery } from "react-query";
|
||||
import { UserEditModalForm } from "./UserEditModalForm";
|
||||
import { isNotEmpty, QUERIES } from "../../../../../_digifi/helpers";
|
||||
import { useListView } from "../core/ListViewProvider";
|
||||
import { getUserById } from "../../core/_requests";
|
||||
import { getUserById, getApprovedUsers } from "../../core/_requests";
|
||||
|
||||
const UserEditModalFormWrapper = () => {
|
||||
const { itemIdForUpdate, setItemIdForUpdate } = useListView();
|
||||
@@ -12,9 +12,10 @@ const UserEditModalFormWrapper = () => {
|
||||
data: user,
|
||||
error,
|
||||
} = useQuery(
|
||||
`${QUERIES.USERS_LIST}-user-${itemIdForUpdate}`,
|
||||
`${QUERIES.READY_LIST}-user-${itemIdForUpdate}`,
|
||||
() => {
|
||||
return getUserById(itemIdForUpdate);
|
||||
// return getUserById(itemIdForUpdate);
|
||||
return getApprovedUsers('');
|
||||
},
|
||||
{
|
||||
cacheTime: 0,
|
||||
@@ -33,7 +34,10 @@ const UserEditModalFormWrapper = () => {
|
||||
}
|
||||
|
||||
if (!isLoading && !error && user) {
|
||||
return <UserEditModalForm isUserLoading={isLoading} user={user} />;
|
||||
// return <UserEditModalForm isUserLoading={isLoading} user={user} />;
|
||||
// REMOVE LATER AND ALLOW UP ALONE
|
||||
let newUser:any = user?.records
|
||||
return <UserEditModalForm isUserLoading={isLoading} user={newUser} />;
|
||||
}
|
||||
|
||||
return null;
|
||||
+1
-1
@@ -7,7 +7,7 @@ const UserEditModalHeader = () => {
|
||||
return (
|
||||
<div className="modal-header">
|
||||
{/* begin::Modal title */}
|
||||
<h2 className="fw-bolder">Add User</h2>
|
||||
<h2 className="fw-bolder">Edit Loan</h2>
|
||||
{/* end::Modal title */}
|
||||
|
||||
{/* begin::Close */}
|
||||
@@ -0,0 +1,11 @@
|
||||
import {FC} from 'react'
|
||||
|
||||
type Props = {
|
||||
employer_name?: string
|
||||
}
|
||||
|
||||
const EmployerCell: FC<Props> = ({employer_name}) => (
|
||||
<div className='badge badge-light fw-bolder'>{employer_name}</div>
|
||||
)
|
||||
|
||||
export {EmployerCell}
|
||||
@@ -4,7 +4,8 @@ import { MenuComponent } from "../../../../../../_digifi/assets/ts/components";
|
||||
import { ID, KTIcon, QUERIES } from "../../../../../../_digifi/helpers";
|
||||
import { useListView } from "../../core/ListViewProvider";
|
||||
import { useQueryResponse } from "../../core/QueryResponseProvider";
|
||||
import { deleteUser } from "../../../core/_requests";
|
||||
import { employersVerify } from "../../../core/_requests";
|
||||
import { User } from "../../../core/_models";
|
||||
|
||||
type Props = {
|
||||
id: ID;
|
||||
@@ -15,6 +16,8 @@ const UserActionsCell: FC<Props> = ({ id }) => {
|
||||
const { query } = useQueryResponse();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// let selectedUser = data?.filter((item:User) => item.uid == id)[0]
|
||||
|
||||
useEffect(() => {
|
||||
MenuComponent.reinitialization();
|
||||
}, []);
|
||||
@@ -23,14 +26,21 @@ const UserActionsCell: FC<Props> = ({ id }) => {
|
||||
setItemIdForUpdate(id);
|
||||
};
|
||||
|
||||
const deleteItem = useMutation(() => deleteUser(id), {
|
||||
const empsVerify = useMutation(() => employersVerify(id), {
|
||||
// 💡 response of the mutation is passed to onSuccess
|
||||
onSuccess: () => {
|
||||
// ✅ update detail view directly
|
||||
queryClient.invalidateQueries([`${QUERIES.USERS_LIST}-${query}`]);
|
||||
queryClient.invalidateQueries([`${QUERIES.READY_LIST}-${query}`]);
|
||||
},
|
||||
});
|
||||
|
||||
const resendVerification = async () => { // FUNCTION TO RESEND VERIFICATION
|
||||
let cont = confirm('Are you sure, you want to send resend verification?')
|
||||
if(cont){
|
||||
await empsVerify.mutateAsync()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<a
|
||||
@@ -44,7 +54,7 @@ const UserActionsCell: FC<Props> = ({ id }) => {
|
||||
</a>
|
||||
{/* begin::Menu */}
|
||||
<div
|
||||
className="menu menu-sub menu-sub-dropdown menu-column menu-rounded menu-gray-600 menu-state-bg-light-primary fw-bold fs-7 w-125px py-4"
|
||||
className="menu menu-sub menu-sub-dropdown menu-column menu-rounded menu-gray-600 menu-state-bg-light-primary fw-bold fs-7 w-175px py-4"
|
||||
data-kt-menu="true"
|
||||
>
|
||||
{/* begin::Menu item */}
|
||||
@@ -60,9 +70,9 @@ const UserActionsCell: FC<Props> = ({ id }) => {
|
||||
<a
|
||||
className="menu-link px-3"
|
||||
data-kt-users-table-filter="delete_row"
|
||||
onClick={async () => await deleteItem.mutateAsync()}
|
||||
onClick={async () => resendVerification()}
|
||||
>
|
||||
Delete
|
||||
Resend Verification
|
||||
</a>
|
||||
</div>
|
||||
{/* end::Menu item */}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {UserCustomHeader} from './UserCustomHeader'
|
||||
import {UserSelectionHeader} from './UserSelectionHeader'
|
||||
import {User} from '../../../core/_models'
|
||||
import { AddedCell } from './AddedCell'
|
||||
import { EmployerCell } from './EmployerCell'
|
||||
|
||||
const usersColumns: ReadonlyArray<Column<User>> = [
|
||||
{
|
||||
@@ -20,6 +21,13 @@ const usersColumns: ReadonlyArray<Column<User>> = [
|
||||
id: 'firstname',
|
||||
Cell: ({...props}) => <UserInfoCell user={props.data[props.row.index]} />,
|
||||
},
|
||||
{
|
||||
Header: (props) => (
|
||||
<UserCustomHeader tableProps={props} title='Employer' className='min-w-125px' />
|
||||
),
|
||||
id: 'employer_name',
|
||||
Cell: ({...props}) => <EmployerCell employer_name={props.data[props.row.index].employer_name} />,
|
||||
},
|
||||
{
|
||||
Header: (props) => <UserCustomHeader tableProps={props} title='Amount' className='min-w-125px' />,
|
||||
accessor: 'loan_amount',
|
||||
|
||||
@@ -32,7 +32,7 @@ const QueryResponseProvider: FC<WithChildren> = ({children}) => {
|
||||
refetch,
|
||||
data: response,
|
||||
} = useQuery(
|
||||
`${QUERIES.USERS_LIST}-${query}`,
|
||||
`${QUERIES.REJECTED_LIST}-${query}`,
|
||||
() => {
|
||||
return getRejectedUsers(query)
|
||||
},
|
||||
|
||||
@@ -32,7 +32,7 @@ const QueryResponseProvider: FC<WithChildren> = ({ children }) => {
|
||||
refetch,
|
||||
data: response,
|
||||
} = useQuery(
|
||||
`${QUERIES.USERS_LIST}-${query}`,
|
||||
`${QUERIES.STARTED_LIST}-${query}`,
|
||||
() => {
|
||||
return getStartedUsers(query);
|
||||
},
|
||||
|
||||
@@ -68,7 +68,7 @@ const PrivateRoutes = () => {
|
||||
}
|
||||
/> */}
|
||||
<Route
|
||||
path='apps/user-management/*'
|
||||
path='tools/user-management/*'
|
||||
element={
|
||||
<SuspensedView>
|
||||
<UsersPage />
|
||||
@@ -76,7 +76,7 @@ const PrivateRoutes = () => {
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path='/apps/employers-list/*'
|
||||
path='/employers/*'
|
||||
element={
|
||||
<SuspensedView>
|
||||
<EmployersPage />
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/* eslint-disable react-refresh/only-export-components */
|
||||
import {FC, useState, createContext, useContext, useMemo, ReactNode} from 'react'
|
||||
|
||||
type ContextProps = {
|
||||
showCustomModal: ShowModalProps
|
||||
closeCustomModal : ()=>void
|
||||
openCustomModal: (name: string, data: DataProps)=>void,
|
||||
MODALNAMES: ModalNames
|
||||
}
|
||||
|
||||
type ShowModalProps = {
|
||||
name?: string
|
||||
data?: {
|
||||
[index: string]: undefined | null | number | string;
|
||||
}
|
||||
}
|
||||
|
||||
type DataProps = {
|
||||
[index: string]: undefined | null | number | string;
|
||||
}
|
||||
|
||||
type ModalNames = {
|
||||
[index: string]: string;
|
||||
}
|
||||
|
||||
const MODALNAMES:ModalNames = {
|
||||
addSignatory: 'add signatory'
|
||||
}
|
||||
|
||||
const CustomModalContext = createContext<ContextProps>({
|
||||
MODALNAMES: {},
|
||||
openCustomModal: ()=>{},
|
||||
closeCustomModal: ()=>{},
|
||||
showCustomModal: {name: '', data: {}}
|
||||
})
|
||||
|
||||
const CustomModalProvider = ({children}:{children:ReactNode}) => {
|
||||
const [showCustomModal, setShowCustomModal] = useState<ShowModalProps>({
|
||||
name: '',
|
||||
data:{}
|
||||
})
|
||||
|
||||
const closeCustomModal = () => {
|
||||
setShowCustomModal({name: '', data:{}})
|
||||
}
|
||||
const openCustomModal = (name:string, data:DataProps) => {
|
||||
setShowCustomModal({name, data})
|
||||
}
|
||||
|
||||
return (
|
||||
<CustomModalContext.Provider
|
||||
value={{
|
||||
showCustomModal,
|
||||
closeCustomModal,
|
||||
openCustomModal,
|
||||
MODALNAMES
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</CustomModalContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const useCustomModal = () => useContext(CustomModalContext)
|
||||
|
||||
export {CustomModalProvider, useCustomModal}
|
||||
Reference in New Issue
Block a user