Compare commits

...

16 Commits

Author SHA1 Message Date
victorAnumudu f52e06af65 employer uid added to request payload 2024-06-15 17:27:59 +01:00
ameye 697a467780 Merge branch 'employer-verify-update' of DigiFi/digifi-bko into master 2024-06-13 20:10:19 +00:00
victorAnumudu 9499422c9a employer verify application uid updated 2024-06-13 21:08:33 +01:00
ameye 148659b453 Merge branch 'edit-loan-modal' of DigiFi/digifi-bko into master 2024-06-13 18:58:52 +00:00
victorAnumudu 98454e2c80 edit loan modal added, employer verify api added 2024-06-13 19:56:17 +01:00
ameye 8a96b10e4b Merge branch 'ready-list-employer-column' of DigiFi/digifi-bko into master 2024-06-13 16:53:26 +00:00
ameye d17ca4f988 Merge branch 'edit-signatory-popout' of DigiFi/digifi-bko into master 2024-06-13 16:53:11 +00:00
victorAnumudu ea90bd6fc5 added employer column in ready table 2024-06-13 17:33:47 +01:00
victorAnumudu 4f99dacf76 edit signatory popout header changed 2024-06-11 09:19:38 +01:00
ameye c970467f16 Merge branch 'sessionTimeout' of DigiFi/digifi-bko into master 2024-06-10 16:48:26 +00:00
Elias 63090f0b74 minor changes 2024-06-07 19:04:20 +01:00
Elias afa81eacd8 session timeout after 7 minutes of inactivity 2024-06-07 17:59:03 +01:00
ameye eea90187e1 Merge branch 'add-signatory-modal' of DigiFi/digifi-bko into master 2024-06-07 13:17:04 +00:00
victorAnumudu 835cb6b074 add signatory API added 2024-06-07 14:12:37 +01:00
victorAnumudu a44c898a66 added modal 2024-06-07 10:10:52 +01:00
ameye 6f616c34cc Merge branch 'add-employer-form' of DigiFi/digifi-bko into master 2024-06-06 21:27:31 +00:00
30 changed files with 669 additions and 44 deletions
@@ -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',
}
@@ -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
View File
@@ -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>
@@ -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: '',
}
@@ -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 */}
@@ -7,9 +7,13 @@ 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 {itemIdForUpdate} = useListView()
const {MODALNAMES, showCustomModal} = useCustomModal()
return (
<>
<KTCard>
@@ -17,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}
@@ -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 };
@@ -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}
@@ -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}
@@ -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`;
@@ -46,6 +47,17 @@ const createUser = (user: any): Promise<UsersQueryResponse | undefined> => { //
.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}`)
@@ -72,6 +84,8 @@ const deleteSelectedUsers = (userIds: Array<ID>): Promise<void> => {
export {
getEmployersList,
createUser,
createSignatory,
deleteUser,
deleteSelectedUsers,
getUserById,
@@ -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()
}, [])
@@ -58,7 +61,7 @@ const UserActionsCell: FC<Props> = ({id}) => {
{/* begin::Menu item */}
<div className='menu-item px-3'>
<a className='menu-link px-3' onClick={openEditModal}>
<a className='menu-link px-3' onClick={()=>{openCustomModal(MODALNAMES.addSignatory, {id})}}>
Add Signatory
</a>
</div>
@@ -207,7 +207,7 @@ const UserEditModalForm: FC<Props> = ({ user, isUserLoading }) => {
{/* begin::Input */}
<input
placeholder="Interest"
{...formik.getFieldProps("interest")}
{...formik.getFieldProps("percent_interest")}
className={clsx(
"form-control form-control-solid mb-3 mb-lg-0",
{ "is-invalid": formik.touched.percent_interest && formik.errors.percent_interest },
+1
View File
@@ -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,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}
@@ -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
@@ -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;
@@ -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);
},
+66
View File
@@ -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}