diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 2f3ba2c6..77d016be 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -13,6 +13,7 @@ "INCORRECT_DATA_ENTRY": "Incorrect Data Entry", "DUPLICATED_USER": "Duplicate User", "NO_USER_FOUND": "User not found", + "NO_CENTER_FOUND": "Centers not found", "ALL": "All", "NO_GO_BACK": "No, go back", "YES": "Yes", @@ -26,7 +27,8 @@ "DELETE": "Delete", "NO_DATA_FOUND": "No data found", "SUBMIT": "Submit", - "BACK": "Back" + "BACK": "Back", + "CANCEL": "Cancel" }, "LOGIN_PAGE": { "USERNAME": "Username", @@ -126,7 +128,10 @@ "RENAME": "Rename", "CENTER_RENAMED": "Center Renamed Successfully!", "SEND_REQUEST": "Send Request", - "REQUEST_TO_DELETE_HAS_BEEN_SENT": "Request to Delete has been sent" + "SURE_DELETE_COHORT": "Are you sure you want to Delete Center ?", + "CENTER_UPDATE_SUCCESSFULLY": "Cohort has been Successfully Updated", + "CENTER_DELETE_SUCCESSFULLY": "Cohort has been Successfully Deleted", + "CENTER_CREATED_SUCCESSFULLY": "Cohort Created Successfully" }, "FORM": { "FULL_NAME": "Full Name", diff --git a/src/components/ActionIcon.tsx b/src/components/ActionIcon.tsx index 73fbc40d..e8a3e4d2 100644 --- a/src/components/ActionIcon.tsx +++ b/src/components/ActionIcon.tsx @@ -7,7 +7,7 @@ import React from "react"; import MoreVertIcon from "@mui/icons-material/MoreVert"; import { useTranslation } from "next-i18next"; import { Box, Typography, Tooltip } from "@mui/material"; -import EditIcon from '@mui/icons-material/Edit'; +import EditIcon from "@mui/icons-material/Edit"; import DeleteIcon from "@mui/icons-material/Delete"; interface ActionCellProps { @@ -41,8 +41,7 @@ const ActionIcon: React.FC = ({ flexDirection: "column", alignItems: "center", cursor: "pointer", - // opacity: 0.5, // Reduced opacity to make it appear disabled - pointerEvents: "auto", // Enable pointer events to allow click + // pointerEvents: "none", }} > diff --git a/src/components/CustomModal.tsx b/src/components/CustomModal.tsx index 12b081cd..6eb49ab1 100644 --- a/src/components/CustomModal.tsx +++ b/src/components/CustomModal.tsx @@ -41,7 +41,7 @@ const CustomModal: React.FC = ({ children, }) => { const isSmallScreen = useMediaQuery((theme: Theme) => - theme.breakpoints.down("sm"), + theme.breakpoints.down("sm") ); return ( @@ -86,9 +86,9 @@ const CustomModal: React.FC = ({ {children} - + + > )} {secondaryText && ( @@ -131,14 +125,14 @@ const SimpleModal: React.FC = ({ variant="contained" color="primary" sx={{ - '&.Mui-disabled': { + "&.Mui-disabled": { backgroundColor: theme?.palette?.primary?.main, }, - minWidth: '84px', - height: '2.5rem', + minWidth: "84px", + height: "2.5rem", padding: theme.spacing(1), - fontWeight: '500', - width: '100%', + fontWeight: "500", + width: "100%", }} onClick={secondaryActionHandler} > diff --git a/src/components/UserTable.tsx b/src/components/UserTable.tsx index ecf7d342..4a097e92 100644 --- a/src/components/UserTable.tsx +++ b/src/components/UserTable.tsx @@ -362,30 +362,36 @@ const UserTable: React.FC = ({ let initialFormData: any = {}; formFields.fields.forEach((item: any) => { const userData = response?.userData; - const customField = userData?.customFields?.find((field: any) => field.fieldId === item.fieldId); - + const customField = userData?.customFields?.find( + (field: any) => field.fieldId === item.fieldId + ); + const getValue = (data: any, field: any) => { if (item?.isMultiSelect) { - if (item?.type === 'checkbox') { - return String(field.value).split(','); + if (item?.type === "checkbox") { + return String(field.value).split(","); } return [field.value]; } else { - if (item?.type === 'numeric') { + if (item?.type === "numeric") { return Number(field.value); - } else if (item?.type === 'text') { + } else if (item?.type === "text") { return String(field.value); } else { return field.value; } } }; - + if (item.coreField) { initialFormData[item.name] = item?.isMultiSelect - ? userData[item.name] ? [userData[item.name]] : userData[item.name] || '' - : item?.type === 'numeric' ? Number(userData[item.name]) - : item?.type === 'text' ? String(userData[item.name]) + ? userData[item.name] + ? [userData[item.name]] + : userData[item.name] || "" + : item?.type === "numeric" + ? Number(userData[item.name]) + : item?.type === "text" + ? String(userData[item.name]) : userData[item.name]; } else { initialFormData[item.name] = getValue(userData, customField); @@ -395,14 +401,14 @@ const UserTable: React.FC = ({ }; const handleEdit = async (rowData: any) => { console.log("Edit row:", rowData); - + try { const userId = rowData.userId; setUserId(userId); const fieldValue = true; const response = await getUserDetails(userId, fieldValue); console.log(role); - + let formFields; if (Role.STUDENT === role) { formFields = await getFormRead("USERS", "STUDENT"); @@ -413,7 +419,7 @@ const UserTable: React.FC = ({ setFormData(mapFields(formFields, response)); handleOpenAddFacilitatorModal(); } - + console.log("response", response); console.log("formFields", formFields); } catch (error) { @@ -553,12 +559,10 @@ const UserTable: React.FC = ({ console.log(selectedUserId); const userId = selectedUserId; const userData = { - userData: [ - { - reason: selectedReason, - status: "archived", - }, - ], + userData: { + reason: selectedReason, + status: "archived", + }, }; const response = await deleteUser(userId, userData); handleCloseDeleteModal(); @@ -587,10 +591,9 @@ const UserTable: React.FC = ({ handleFilterChange: handleFilterChange, handleSearch: handleSearch, handleAddUserClick: handleAddUserClick, - selectedBlockCode:selectedBlockCode, - selectedDistrictCode:selectedDistrictCode, - selectedStateCode:selectedStateCode - + selectedBlockCode: selectedBlockCode, + selectedDistrictCode: selectedDistrictCode, + selectedStateCode: selectedStateCode, }; return ( diff --git a/src/pages/cohorts.tsx b/src/pages/cohorts.tsx index 6e398c41..2480cfe5 100644 --- a/src/pages/cohorts.tsx +++ b/src/pages/cohorts.tsx @@ -9,10 +9,11 @@ import Pagination from "@mui/material/Pagination"; import { SelectChangeEvent } from "@mui/material/Select"; import PageSizeSelector from "@/components/PageSelector"; import { + createCohort, getCohortList, updateCohortUpdate, } from "@/services/CohortService/cohortService"; -import { Role, Storage } from "@/utils/app.constant"; +import { Numbers, Role, SORT, Status, Storage } from "@/utils/app.constant"; import EditIcon from "@mui/icons-material/Edit"; import DeleteIcon from "@mui/icons-material/Delete"; import ConfirmationModal from "@/components/ConfirmationModal"; @@ -32,7 +33,16 @@ import SimpleModal from "@/components/SimpleModal"; import DynamicForm from "@/components/DynamicForm"; import { IChangeEvent } from "@rjsf/core"; import { RJSFSchema } from "@rjsf/utils"; - +import { CustomField } from "@/utils/Interfaces"; +import { showToastMessage } from "@/components/Toastify"; + +type cohortFilterDetails = { + type?: string; + status?: any; + states?: string; + districts?: string; + blocks?: string; +}; type UserDetails = { userId: any; username: any; @@ -43,6 +53,13 @@ type UserDetails = { Programs?: any; }; +interface CohortDetails { + name?: string; + type?: string; + parentId?: string | null; + customFields?: CustomField[]; +} + const Cohorts: React.FC = () => { // use hooks const { t } = useTranslation(); @@ -50,7 +67,7 @@ const Cohorts: React.FC = () => { // colums in table const columns = [ { - key: "cohortName", + key: "name", title: t("TABLE_TITLE.NAME"), dataType: DataType.String, sortDirection: SortDirection.Ascend, @@ -61,25 +78,25 @@ const Cohorts: React.FC = () => { dataType: DataType.String, }, { - key: "createdDate", + key: "createdAt", title: t("TABLE_TITLE.CREATED_DATE"), dataType: DataType.String, }, { - key: "updatedDate", + key: "updatedAt", title: t("TABLE_TITLE.UPDATED_DATE"), dataType: DataType.String, }, - { - key: "createdBy", - title: t("TABLE_TITLE.CREATED_BY"), - dataType: DataType.String, - }, - { - key: "updatedBy", - title: t("TABLE_TITLE.UPDATED_BY"), - dataType: DataType.String, - }, + // { + // key: "createdBy", + // title: t("TABLE_TITLE.CREATED_BY"), + // dataType: DataType.String, + // }, + // { + // key: "updatedBy", + // title: t("TABLE_TITLE.UPDATED_BY"), + // dataType: DataType.String, + // }, { key: "actions", @@ -93,11 +110,9 @@ const Cohorts: React.FC = () => { const [selectedDistrict, setSelectedDistrict] = React.useState([]); const [selectedBlock, setSelectedBlock] = React.useState([]); const [selectedSort, setSelectedSort] = useState("Sort"); - const [pageOffset, setPageOffset] = useState(0); - const [pageLimit, setPageLimit] = useState(10); const [selectedFilter, setSelectedFilter] = useState("All"); const [cohortData, setCohortData] = useState([]); - const [pageSize, setPageSize] = React.useState(""); + const [pageSize, setPageSize] = React.useState("10"); const [open, setOpen] = React.useState(false); const [confirmationModalOpen, setConfirmationModalOpen] = React.useState(false); @@ -114,6 +129,18 @@ const Cohorts: React.FC = () => { const [uiSchema, setUiSchema] = React.useState(); const [openAddNewCohort, setOpenAddNewCohort] = React.useState(false); + + const [pageCount, setPageCount] = useState(Numbers.ONE); + const [pageOffset, setPageOffset] = useState(Numbers.ZERO); + const [pageLimit, setPageLimit] = useState(Numbers.TEN); + const [pageSizeArray, setPageSizeArray] = React.useState([]); + const [filters, setFilters] = useState({ + type: "COHORT", + }); + const [sortBy, setSortBy] = useState(["createdAt", "asc"]); + const [selectedStateCode, setSelectedStateCode] = useState(""); + const [selectedDistrictCode, setSelectedDistrictCode] = useState(""); + const [selectedBlockCode, setSelectedBlockCode] = useState(""); // use api calls useEffect(() => { if (typeof window !== "undefined" && window.localStorage) { @@ -122,28 +149,38 @@ const Cohorts: React.FC = () => { } }, []); - // const { data, error, isLoading } = useCohortList(userId); - // useEffect(() => { - // if (data) { - // setCohortData(data); - // } - // }, [data]); - const fetchUserList = async () => { + setLoading(true); try { const limit = pageLimit; - // const page = 0; - const offset = pageOffset; - // const sort = ["createdAt", "asc"]; - const filters = { role: Role.TEACHER }; - const userId = localStorage.getItem(Storage.USER_ID) || ""; + const offset = pageOffset * limit; + const sort = sortBy; + const data = { + limit: limit, + offset: offset, + sort: sort, + filters: filters, + }; + const resp = await getCohortList(data); + if (resp) { + const result = resp?.results?.cohortDetails; + setCohortData(result); + const totalCount = resp?.count; + if (totalCount >= 15) { + setPageSizeArray([5, 10, 15]); + } else if (totalCount >= 10) { + setPageSizeArray([5, 10]); + } else if (totalCount >= 5 || totalCount < 5) { + setPageSizeArray([5]); + } - const resp = await getCohortList(userId); - const result = resp; - console.log("result", result); + const pageCount = Math.ceil(totalCount / pageLimit); + setPageCount(pageCount); - setCohortData(result); + setLoading(false); + } } catch (error) { + setLoading(false); console.error("Error fetching user list:", error); } }; @@ -179,7 +216,7 @@ const Cohorts: React.FC = () => { useEffect(() => { fetchUserList(); getFormData(); - }, [pageOffset, pageLimit]); + }, [pageOffset, pageLimit, sortBy, filters]); // handle functions const handleChange = (event: SelectChangeEvent) => { @@ -187,47 +224,130 @@ const Cohorts: React.FC = () => { setPageLimit(Number(event.target.value)); }; - const handleClose = () => { - setOpen(false); - }; - - const handleOpen = () => { - setOpen(true); + const handlePaginationChange = ( + event: React.ChangeEvent, + value: number + ) => { + setPageOffset(value - 1); }; const PagesSelector = () => ( - <> + - + ); - const handlePaginationChange = ( - event: React.ChangeEvent, - value: number - ) => { - setPageOffset(value - 1); - }; const PageSizeSelectorFunction = ({}) => ( - <> - - + + + ); - const handleStateChange = (selected: string[]) => { + const handleStateChange = async (selected: string[], code: string[]) => { + setSelectedDistrict([]); + setSelectedBlock([]); setSelectedState(selected); - console.log("Selected categories:", selected); + + if (selected[0] === "") { + if (filters.status) setFilters({ status: filters.status }); + // else setFilters({ role: role }); + } else { + const stateCodes = code?.join(","); + console.log("stateCodes", stateCodes); + setSelectedStateCode(stateCodes); + if (filters.status) + setFilters({ status: filters.status, states: stateCodes }); + else setFilters({ states: stateCodes }); + } + + console.log("Selected categories:", typeof code[0]); }; - const handleDistrictChange = (selected: string[]) => { + + const handleDistrictChange = (selected: string[], code: string[]) => { + setSelectedBlock([]); setSelectedDistrict(selected); + + if (selected[0] === "") { + if (filters.status) { + setFilters({ + status: filters.status, + states: selectedStateCode, + + // role: role, + }); + } else { + setFilters({ + states: selectedStateCode, + // role: role, + }); + } + } else { + const districts = code?.join(","); + setSelectedDistrictCode(districts); + if (filters.status) { + setFilters({ + status: filters.status, + states: selectedStateCode, + districts: districts, + + // role: role, + }); + } else { + setFilters({ + states: selectedStateCode, + districts: districts, + // role: role, + }); + } + } console.log("Selected categories:", selected); }; - const handleBlockChange = (selected: string[]) => { + const handleBlockChange = (selected: string[], code: string[]) => { setSelectedBlock(selected); + if (selected[0] === "") { + if (filters.status) { + setFilters({ + status: filters.status, + states: selectedStateCode, + districts: selectedDistrictCode, + // role: role, + }); + } else { + setFilters({ + states: selectedStateCode, + districts: selectedDistrictCode, + // role: role, + }); + } + } else { + const blocks = code?.join(","); + setSelectedBlockCode(blocks); + if (filters.status) { + setFilters({ + status: filters.status, + states: selectedStateCode, + districts: selectedDistrictCode, + blocks: blocks, + // role: role, + }); + } else { + setFilters({ + states: selectedStateCode, + districts: selectedDistrictCode, + blocks: blocks, + // role: role, + }); + } + } console.log("Selected categories:", selected); }; @@ -238,47 +358,68 @@ const Cohorts: React.FC = () => { const handleActionForDelete = async () => { if (selectedCohortId) { let cohortDetails = { - status: "active", + status: Status.ARCHIVED, }; const resp = await updateCohortUpdate(selectedCohortId, cohortDetails); - console.log("resp:", resp); + console.log(resp); + if (resp?.responseCode === 200) { + console.log(resp?.params?.successmessage); + showToastMessage(t("CENTERS.CENTER_DELETE_SUCCESSFULLY"), "success"); + fetchUserList(); + } else { + console.log("Cohort Not Archived"); + } } else { + console.log("No Cohort Selected"); } }; const handleSortChange = async (event: SelectChangeEvent) => { - //console.log(event.target.value) - try { - const limit = pageLimit; - const offset = pageOffset; - let sort; - switch (event.target.value) { - case "Z-A": - sort = ["name", "desc"]; - break; - case "A-Z": - sort = ["name", "asc"]; - break; - default: - sort = ["createdAt", "asc"]; - break; - } - - const userId = localStorage.getItem(Storage.USER_ID) || ""; - const filters = { role: Role.TEACHER }; - const resp = await getCohortList(userId); - const result = resp?.cohortData; - - setCohortData(result); - } catch (error) { - console.error("Error fetching user list:", error); + if (event.target.value === "Z-A") { + setSortBy(["name", SORT.DESCENDING]); + } else if (event.target.value === "A-Z") { + setSortBy(["name", SORT.ASCENDING]); + } else { + setSortBy(["createdAt", SORT.ASCENDING]); } setSelectedSort(event.target.value as string); }; + const handleSearch = (keyword: string) => { + setFilters((prevFilters) => ({ + ...prevFilters, + name: keyword, + })); + }; + const handleFilterChange = async (event: SelectChangeEvent) => { console.log(event.target.value as string); setSelectedFilter(event.target.value as string); + + if (event.target.value === Status.ACTIVE_LABEL) { + setFilters((prevFilters) => ({ + ...prevFilters, + status: [Status.ACTIVE], + })); + } else if (event.target.value === Status.ARCHIVED_LABEL) { + setFilters((prevFilters) => ({ + ...prevFilters, + status: [Status.ARCHIVED], + })); + } else if (event.target.value === Status.ALL_LABEL) { + setFilters((prevFilters) => ({ + ...prevFilters, + status: "", + })); + } else { + setFilters((prevFilters) => { + const { status, ...restFilters } = prevFilters; + return { + ...restFilters, + }; + }); + } + // console.log(filters); }; const handleEdit = (rowData: any) => { @@ -288,7 +429,7 @@ const Cohorts: React.FC = () => { if (rowData) { const cohortId = rowData?.cohortId; setSelectedCohortId(cohortId); - const cohortName = rowData?.cohortName; + const cohortName = rowData?.name; setInputName(cohortName); setLoading(false); } @@ -304,7 +445,6 @@ const Cohorts: React.FC = () => { setSelectedCohortId(cohortId); setLoading(false); } - handleActionForDelete(); setLoading(false); }; @@ -333,6 +473,7 @@ const Cohorts: React.FC = () => { const resp = await updateCohortUpdate(selectedCohortId, cohortDetails); setLoading(false); console.log("resp:", resp); + showToastMessage(t("CENTERS.CENTER_UPDATE_SUCCESSFULLY"), "success"); } else { setLoading(false); console.log("No cohort Id Selected"); @@ -342,8 +483,6 @@ const Cohorts: React.FC = () => { setLoading(false); }; - const handleSearch = (keyword: string) => {}; - const onCloseAddNewCohort = () => { setOpenAddNewCohort(false); }; @@ -364,12 +503,32 @@ const Cohorts: React.FC = () => { data: IChangeEvent, event: React.FormEvent ) => { - const target = event.target as HTMLFormElement; - const elementsArray = Array.from(target.elements); + const formData = data.formData; + + const parentId = localStorage.getItem("blockParentId") || ""; + const cohortDetails: CohortDetails = { + name: formData.name, + type: "COHORT", + parentId: parentId, + customFields: [], + }; - console.log("elementsArray", elementsArray); - console.log("target", target); - console.log("Form data submitted:", data.formData); + Object.entries(formData).forEach(([fieldKey, fieldValue]) => { + const fieldSchema = schema.properties[fieldKey]; + const fieldId = fieldSchema?.fieldId; + if (fieldId !== null) { + cohortDetails?.customFields?.push({ + fieldId: fieldId, + value: formData.cohort_type, + }); + } + }); + const cohortData = await createCohort(cohortDetails); + if (cohortData) { + showToastMessage(t("CENTERS.CENTER_CREATED_SUCCESSFULLY"), "success"); + } + setOpenAddNewCohort(false); + fetchUserList(); }; const handleError = () => { @@ -381,6 +540,7 @@ const Cohorts: React.FC = () => { userType: t("SIDEBAR.COHORTS"), searchPlaceHolder: t("COHORTS.SEARCHBAR_PLACEHOLDER"), selectedState: selectedState, + selectedStateCode: selectedStateCode, selectedDistrict: selectedDistrict, selectedBlock: selectedBlock, selectedSort: selectedSort, @@ -418,11 +578,11 @@ const Cohorts: React.FC = () => { { data={cohortData} limit={pageLimit} offset={pageOffset} - paginationEnable={false} + paginationEnable={true} PagesSelector={PagesSelector} PageSizeSelector={PageSizeSelectorFunction} + pageSizes={pageSizeArray} extraActions={extraActions} showIcons={true} onEdit={handleEdit} onDelete={handleDelete} /> ) : ( - + - {t("COMMON.NO_USER_FOUND")} + {t("COMMON.NO_CENTER_FOUND")} )} diff --git a/src/services/CohortService/cohortService.ts b/src/services/CohortService/cohortService.ts index d5f0e730..129e23cd 100644 --- a/src/services/CohortService/cohortService.ts +++ b/src/services/CohortService/cohortService.ts @@ -1,14 +1,27 @@ import { get, post, put } from "../RestClient"; -export const getCohortList = async (userId: string): Promise => { - console.log("SS", userId); - let apiUrl: string = `${process.env.NEXT_PUBLIC_BASE_URL}/cohort/mycohorts/${userId}?children=true&customField`; +export interface cohortListFilter { + type: string; + status: string[]; + states: string; + districts: string; + blocks: string; +} + +export interface cohortListData { + limit: Number; + offset: Number; +} + +export const getCohortList = async (data: cohortListData): Promise => { + let apiUrl: string = `${process.env.NEXT_PUBLIC_BASE_URL}/cohort/search`; + try { - const response = await get(apiUrl); + const response = await post(apiUrl, data); return response?.data?.result; } catch (error) { - console.error("Error in getting cohort details", error); - throw error; + console.error("Error in Getting cohort List Details", error); + return error; } }; @@ -24,7 +37,7 @@ export const updateCohortUpdate = async ( try { const response = await put(apiUrl, { name, status }); - return response?.data?.result; + return response?.data; } catch (error) { console.error("Error in updating cohort details", error); throw error; @@ -68,7 +81,7 @@ export const createCohort = async (userData: any): Promise => { const apiUrl: string = `${process.env.NEXT_PUBLIC_BASE_URL}/cohort/create`; try { const response = await post(apiUrl, userData); - return response?.data?.result; + return response?.data; } catch (error) { console.error("error in getting cohort list", error); // throw error; diff --git a/src/utils/app.constant.ts b/src/utils/app.constant.ts index 6e5b595a..c8707474 100644 --- a/src/utils/app.constant.ts +++ b/src/utils/app.constant.ts @@ -7,7 +7,10 @@ export enum Role { export enum Status { ARCHIVED = "archived", + ARCHIVED_LABEL = "Archived", ACTIVE = "active", + ACTIVE_LABEL = "Active", + ALL_LABEL = "All", } export enum SORT { ASCENDING = "asc", @@ -19,21 +22,34 @@ export enum Storage { USER_ID = "userId", } export enum FormContext { - USERS = 'USERS' + USERS = "USERS", } export enum FormContextType { - STUDENT = 'STUDENT', - TEACHER = 'TEACHER', - TEAM_LEADER = 'TEAMLEADER', + STUDENT = "STUDENT", + TEACHER = "TEACHER", + TEAM_LEADER = "TEAMLEADER", } export enum RoleId { STUDENT = "493c04e2-a9db-47f2-b304-503da358d5f4", TEACHER = "3bde0028-6900-4900-9d05-eeb608843718", - TEAM_LEADER="9dd9328f-1bc7-444f-96e3-c5e1daa3514a", + TEAM_LEADER = "9dd9328f-1bc7-444f-96e3-c5e1daa3514a", ADMIN = "ee482faf-8a41-45fe-9656-5533dd6a787c", } +export enum DataKey { + UPDATEDAT = "updatedAt", + CREATEDAT = "createdAt", + ACTIONS = "actions", +} +export enum DateFormat { + YYYY_MM_DD = "yyyy-MM-dd", +} +export enum Numbers { + ZERO = 0, + ONE = 1, + TEN = 10, +}