diff --git a/public/locales/en/common.json b/public/locales/en/common.json index fdb5981d..524d2a80 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -227,7 +227,9 @@ "CENTER_DELETE_SUCCESSFULLY": "Center has been Successfully Deleted", "CENTER_CREATED_SUCCESSFULLY": "Center Created Successfully", "SEARCHBAR_PLACEHOLDER": "Search Center..", - "CENTER_UPDATE_FAILED": "Something went wrong while updating center" + "CENTER_UPDATE_FAILED": "Something went wrong while updating center", + "ARCHIVED_MEMBERS": "Archived Members:", + "ACTIVE_MEMBERS": "Active Members" }, "FORM": { "FULL_NAME": "Full Name", diff --git a/src/components/AddNewCenters.tsx b/src/components/AddNewCenters.tsx index 5886e549..2c1347ad 100644 --- a/src/components/AddNewCenters.tsx +++ b/src/components/AddNewCenters.tsx @@ -5,7 +5,7 @@ import { } from "@/components/GeneratedSchemas"; import SimpleModal from "@/components/SimpleModal"; import { getFormRead } from "@/services/CreateUserService"; -import { CohortTypes } from "@/utils/app.constant"; +import { CohortTypes, FormContextType } from "@/utils/app.constant"; import { useLocationState } from "@/utils/useLocationState"; import { Box, Button, Typography } from "@mui/material"; import { IChangeEvent } from "@rjsf/core"; @@ -53,6 +53,7 @@ const AddNewCenters: React.FC = ({ React.useState(false); const { t } = useTranslation(); + const roleType = FormContextType.ADMIN_CENTER; const { states, districts, @@ -76,8 +77,7 @@ const AddNewCenters: React.FC = ({ selectedStateCode, selectedBlockCode, dynamicFormForBlock, - stateDefaultValue - } = useLocationState(open, onClose); + } = useLocationState(open, onClose, roleType); const setSubmittedButtonStatus = useSubmittedButtonStore( (state: any) => state.setSubmittedButtonStatus ); @@ -123,6 +123,7 @@ const AddNewCenters: React.FC = ({ ) => { const formData = data?.formData; console.log("selectedBlockCohortId", selectedBlockCohortId); + if (selectedBlockCohortId) { const parentId = selectedBlockCohortId; const cohortDetails: CohortDetails = { @@ -249,7 +250,6 @@ const AddNewCenters: React.FC = ({ height: "40px", marginLeft: "10px", }} - onClick={onClose} > {t("COMMON.CANCEL")} diff --git a/src/components/KaTableComponent.tsx b/src/components/KaTableComponent.tsx index 9a279747..b0a526cf 100644 --- a/src/components/KaTableComponent.tsx +++ b/src/components/KaTableComponent.tsx @@ -1,6 +1,13 @@ import { firstLetterInUpperCase } from "@/utils/Helper"; import { DataKey, DateFormat, Status } from "@/utils/app.constant"; -import { Checkbox, Chip, Paper, Theme, useMediaQuery } from "@mui/material"; +import { + Checkbox, + Chip, + Paper, + Theme, + Typography, + useMediaQuery, +} from "@mui/material"; import { format } from "date-fns"; import { ITableProps, Table } from "ka-table"; import { PagingPosition, SortDirection, SortingMode } from "ka-table/enums"; @@ -81,7 +88,8 @@ const KaTableComponent: React.FC = ({ {...tableProps} childComponents={{ pagingSizes: { - content: (props) =>!isMobile? (): (<>), + content: (props) => + !isMobile ? : <>, }, sortIcon: { @@ -120,6 +128,22 @@ const KaTableComponent: React.FC = ({ return ; } else if (props.column.key === DataKey.UPDATED_BY) { return ; + } else if (props.column.key === DataKey.ACTIVE_MEMBER) { + return ( + + {props.rowData?.totalActiveMembers + ? props.rowData?.totalActiveMembers + : "-"} + + ); + } else if (props.column.key === DataKey.ARCHIVED_MEMBERS) { + return ( + + {props.rowData?.totalArchivedMembers + ? props.rowData?.totalArchivedMembers + : "-"} + + ); } if (props.column.key === DataKey.STATUS) { if (props.rowData?.status === Status.ARCHIVED) { diff --git a/src/data/tableColumns.ts b/src/data/tableColumns.ts index 282633a8..4b82ee01 100644 --- a/src/data/tableColumns.ts +++ b/src/data/tableColumns.ts @@ -65,15 +65,21 @@ export const getTLTableColumns = (t: any, isMobile: boolean) => { export const getCenterTableData = (t: any, isMobile: boolean) => { const configs: ColumnConfig[] = [ - { key: "name", titleKey: "TABLE_TITLE.NAME", width: 95 }, - { key: "status", titleKey: "TABLE_TITLE.STATUS", width: 95}, - { key: "updatedBy", titleKey: "TABLE_TITLE.UPDATED_BY", width: 95 }, - { key: "createdBy", titleKey: "TABLE_TITLE.CREATED_BY", width: 95 }, - { key: "createdAt", titleKey: "TABLE_TITLE.CREATED_DATE", width: 95 }, - { key: "updatedAt", titleKey: "TABLE_TITLE.UPDATED_DATE", width: 95 }, - { key: "customFieldValues", titleKey: "FORM.TYPE_OF_COHORT", width: 95 }, - { key: "actions", titleKey: "TABLE_TITLE.ACTIONS", width: 125 , isSortable: false} - + { key: "name", titleKey: "TABLE_TITLE.NAME", width: 130 }, + { key: "customFieldValues", titleKey: "TABLE_TITLE.TYPE", width: 130 }, + { key: "status", titleKey: "TABLE_TITLE.STATUS", width: 130 }, + { key: "updatedBy", titleKey: "TABLE_TITLE.UPDATED_BY", width: 130 }, + { key: "createdBy", titleKey: "TABLE_TITLE.CREATED_BY", width: 130 }, + { key: "createdAt", titleKey: "TABLE_TITLE.CREATED_DATE", width: 130 }, + { key: "updatedAt", titleKey: "TABLE_TITLE.UPDATED_DATE", width: 130 }, + + { key: "totalActiveMembers", titleKey: "Active Members", width: 130 }, + { + key: "totalArchivedMembers", + titleKey: "Archived Members", + width: 130, + }, + { key: "actions", titleKey: "TABLE_TITLE.ACTIONS", width: 125 }, ]; return generateColumns(t, configs, isMobile); diff --git a/src/pages/centers.tsx b/src/pages/centers.tsx index d79603a9..68cec648 100644 --- a/src/pages/centers.tsx +++ b/src/pages/centers.tsx @@ -8,10 +8,12 @@ import Pagination from "@mui/material/Pagination"; import { SelectChangeEvent } from "@mui/material/Select"; import PageSizeSelector from "@/components/PageSelector"; import { + fetchCohortMemberList, getCohortList, updateCohortUpdate, } from "@/services/CohortService/cohortService"; import { + CohortTypes, FormValues, Numbers, SORT, @@ -25,6 +27,7 @@ import CustomModal from "@/components/CustomModal"; import { Box, Button, + Chip, TextField, Typography, useMediaQuery, @@ -55,6 +58,8 @@ type cohortFilterDetails = { districts?: string; blocks?: string; name?: string; + activeMembers?: string; + archivedMembers?: string; }; interface centerData { @@ -89,7 +94,7 @@ const Center: React.FC = () => { const [selectedDistrict, setSelectedDistrict] = React.useState([]); const [selectedBlock, setSelectedBlock] = React.useState([]); const [selectedSort, setSelectedSort] = useState("Sort"); - const [selectedFilter, setSelectedFilter] = useState("All"); + const [selectedFilter, setSelectedFilter] = useState("Active"); const [cohortData, setCohortData] = useState([]); const [pageSize, setPageSize] = React.useState("10"); const [confirmationModalOpen, setConfirmationModalOpen] = @@ -110,10 +115,7 @@ const Center: React.FC = () => { const [pageOffset, setPageOffset] = useState(Numbers.ZERO); const [pageLimit, setPageLimit] = useState(Numbers.TEN); const [pageSizeArray, setPageSizeArray] = React.useState([]); - const [filters, setFilters] = useState({ - type: "COHORT", - // states: stateCode, - }); + const [pagination, setPagination] = useState(true); const [sortBy, setSortBy] = useState(["createdAt", "asc"]); const [selectedStateCode, setSelectedStateCode] = useState(""); const [selectedDistrictCode, setSelectedDistrictCode] = useState(""); @@ -122,6 +124,8 @@ const Center: React.FC = () => { const [totalCount, setTotalCound] = useState(0); const [editFormData, setEditFormData] = useState([]); const [isEditForm, setIsEditForm] = useState(false); + const [statesInformation, setStatesInformation] = useState([]); + const [selectedRowData, setSelectedRowData] = useState(""); const setSubmittedButtonStatus = useSubmittedButtonStore( (state: any) => state.setSubmittedButtonStatus ); @@ -129,12 +133,39 @@ const Center: React.FC = () => { (state: any) => state.setAdminInformation ); + const [filters, setFilters] = useState({ + type: CohortTypes.COHORT, + states: selectedStateCode, + status: [Status.ACTIVE], + }); const handleCloseAddLearnerModal = () => { setOpenAddNewCohort(false); }; const isMobile = useMediaQuery((theme: Theme) => theme.breakpoints.down("sm") ); + + const getAdminInformation = () => { + if (typeof window !== "undefined" && window.localStorage) { + const admin = localStorage.getItem("adminInfo"); + if (admin) { + const stateField: any = JSON.parse(admin).customFields.find( + (field: any) => field.label === "STATES" + ); + console.log(stateField.value, stateField.code); + const object = [ + { + value: stateField.code, + label: stateField.value, + }, + ]; + setStatesInformation(object); + console.log("object", object[0]?.value); + setSelectedStateCode(object[0]?.value); + } + } + }; + // use api calls useEffect(() => { if (typeof window !== "undefined" && window.localStorage) { @@ -144,6 +175,8 @@ const Center: React.FC = () => { // get form data for center create getAddCenterFormData(); + getAdminInformation(); + // getCohortMemberlistData(); }, []); const fetchUserList = async () => { @@ -163,11 +196,27 @@ const Center: React.FC = () => { if (resp) { const result = resp?.results?.cohortDetails; const resultData: centerData[] = []; - result?.forEach((item: any) => { + + const cohortIds = result.map((item: any) => item.cohortId); // Extract cohort IDs + + // Fetch member counts for each cohort + const memberCounts = await Promise.all( + cohortIds?.map(async (cohortId: string) => { + return await getCohortMemberlistData(cohortId); + }) + ); + + result?.forEach((item: any, index: number) => { const cohortType = item?.customFields?.map((field: any) => firstLetterInUpperCase(field?.value) ) ?? "-"; + + const counts = memberCounts[index] || { + totalActiveMembers: 0, + totalArchivedMembers: 0, + }; + console.log("cohortType", cohortType); const requiredData = { name: item?.name, @@ -178,27 +227,31 @@ const Center: React.FC = () => { updatedAt: item?.updatedAt, cohortId: item?.cohortId, customFieldValues: cohortType[0] ? cohortType : "-", + totalActiveMembers: counts?.totalActiveMembers, + totalArchivedMembers: counts?.totalArchivedMembers, }; resultData?.push(requiredData); }); - setCohortData(resultData); const totalCount = resp?.count; setTotalCound(totalCount); - if (totalCount >= 20) { - setPageSizeArray([5, 10, 15, 20]); - } else if (totalCount >= 15) { - setPageSizeArray([5, 10, 15]); - } else if (totalCount >= 10) { - setPageSizeArray([5, 10]); - } else if (totalCount >= 5 || totalCount < 5) { - setPageSizeArray([5]); - } + + setPagination(totalCount > 10); + setPageSizeArray( + totalCount > 15 + ? [5, 10, 15] + : totalCount > 10 + ? [5, 10] + : totalCount > 5 + ? [5] + : [] + ); const pageCount = Math.ceil(totalCount / pageLimit); setPageCount(pageCount); setLoading(false); } } catch (error) { + setCohortData([]); setLoading(false); console.error("Error fetching user list:", error); } @@ -219,6 +272,41 @@ const Center: React.FC = () => { } }; + const getCohortMemberlistData = async (cohortId: string) => { + const data = { + limit: 300, + page: 0, + filters: { + cohortId: cohortId, + }, + }; + + const response: any = await fetchCohortMemberList(data); + + if (response?.result) { + const userDetails = response.result.userDetails; + const getActiveMembers = userDetails?.filter( + (member: any) => member?.status === Status.ACTIVE + ); + const totalActiveMembers = getActiveMembers?.length || 0; + + const getArchivedMembers = userDetails?.filter( + (member: any) => member?.status === Status.ARCHIVED + ); + const totalArchivedMembers = getArchivedMembers?.length || 0; + + return { + totalActiveMembers, + totalArchivedMembers, + }; + } + + return { + totalActiveMembers: 0, + totalArchivedMembers: 0, + }; + }; + const getAddCenterFormData = async () => { try { const response = await getFormRead("cohorts", "cohort"); @@ -255,12 +343,16 @@ const Center: React.FC = () => { }; const PagesSelector = () => ( - + ); @@ -477,10 +569,13 @@ const Center: React.FC = () => { const handleDelete = (rowData: any) => { setLoading(true); + const cohortName = rowData?.name; + // SetDeletedRowData setInputName(cohortName); setConfirmationModalOpen(true); if (rowData) { + setSelectedRowData(rowData); const cohortId = rowData?.cohortId; setSelectedCohortId(cohortId); setLoading(false); @@ -603,43 +698,43 @@ const Center: React.FC = () => { setOpenAddNewCohort(true); }; - - useEffect(() => { - const fetchData = () => { + useEffect(() => { + const fetchData = () => { try { const object = { // "limit": 20, // "offset": 0, fieldName: "states", }; - // const response = await getStateBlockDistrictList(object); - // const result = response?.result?.values; + // const response = await getStateBlockDistrictList(object); + // const result = response?.result?.values; if (typeof window !== "undefined" && window.localStorage) { const admin = localStorage.getItem("adminInfo"); - if(admin) - { - const stateField = JSON.parse(admin).customFields.find((field: any) => field.label === "STATES"); - console.log(stateField.value, stateField.code) - if (!stateField.value.includes(',')) { + if (admin) { + const stateField = JSON.parse(admin).customFields.find( + (field: any) => field.label === "STATES" + ); + console.log(stateField.value, stateField.code); + if (!stateField.value.includes(",")) { setSelectedState([stateField.value]); - setSelectedStateCode(stateField.code) - - } - - const object=[{ - value:stateField.code, - label:stateField.value - }] + setSelectedStateCode(stateField.code); + } + + const object = [ + { + value: stateField.code, + label: stateField.value, + }, + ]; // setStates(object); - } } - // setStates(result); + // setStates(result); } catch (error) { console.log(error); } }; - + fetchData(); }, []); @@ -748,6 +843,7 @@ const Center: React.FC = () => { offset={pageOffset} paginationEnable={totalCount > Numbers.TEN} PagesSelector={PagesSelector} + pagination={pagination} PageSizeSelector={PageSizeSelectorFunction} pageSizes={pageSizeArray} extraActions={extraActions} diff --git a/src/services/CohortService/cohortService.ts b/src/services/CohortService/cohortService.ts index a3ca21e9..0d6f56b6 100644 --- a/src/services/CohortService/cohortService.ts +++ b/src/services/CohortService/cohortService.ts @@ -1,3 +1,4 @@ +import { CohortMemberList } from "@/utils/Interfaces"; import { get, post, put } from "../RestClient"; export interface cohortListFilter { @@ -85,3 +86,24 @@ export const createCohort = async (userData: any): Promise => { // throw error; } }; + +export const fetchCohortMemberList = async ({ + limit, + page, + filters, +}: CohortMemberList): Promise => { + const apiUrl: string = `${process.env.NEXT_PUBLIC_BASE_URL}/cohortmember/list`; + try { + const response = await post(apiUrl, { + limit, + page, + filters, + // sort: ["username", "asc"], + }); + console.log("data", response?.data); + return response?.data; + } catch (error) { + console.error("error in cohort member list API ", error); + // throw error; + } +}; diff --git a/src/styles/style.css b/src/styles/style.css index ba36fbd6..d203febc 100644 --- a/src/styles/style.css +++ b/src/styles/style.css @@ -18,4 +18,10 @@ .ka-cell { line-height: 24px !important; -} \ No newline at end of file +} + +@media (max-width: 768px) { + .ka-cell { + word-wrap: break-word; + } +} diff --git a/src/utils/Interfaces.ts b/src/utils/Interfaces.ts index ea19a091..573531fe 100644 --- a/src/utils/Interfaces.ts +++ b/src/utils/Interfaces.ts @@ -31,7 +31,6 @@ export interface Field { required?: boolean; default: string | number; isRequired?: boolean; - } export interface TenantCohortRoleMapping { tenantId: string; @@ -42,7 +41,6 @@ export interface CustomField { fieldId: string; value: string; isRequired?: boolean; - } export interface FormData { formid?: string; @@ -65,4 +63,15 @@ export interface SendCredentialsRequest { email: { receipients: any[]; }; -} \ No newline at end of file +} + +export interface CohortMemberList { + limit: number; + page: number; + filters: { + cohortId: string; + role?: string; + status?: string[]; + }; + sort?: string[]; +} diff --git a/src/utils/app.constant.ts b/src/utils/app.constant.ts index 10722497..dfd58445 100644 --- a/src/utils/app.constant.ts +++ b/src/utils/app.constant.ts @@ -32,7 +32,8 @@ export enum FormContextType { STUDENT = "STUDENT", TEACHER = "TEACHER", TEAM_LEADER = "TEAM LEADER", - ADMIN="ADMIN" + ADMIN = "ADMIN", + ADMIN_CENTER = "ADMIN_CENTER", } export enum RoleId { @@ -50,6 +51,8 @@ export enum DataKey { UPDATED_BY = "updatedBy", STATUS = "status", NAME = "name", + ACTIVE_MEMBER = "totalActiveMembers", + ARCHIVED_MEMBERS = "totalArchivedMembers", } export enum DateFormat { @@ -61,7 +64,7 @@ export enum Numbers { ONE = 1, FIVE = 5, TEN = 10, - FIFTEEN=15, + FIFTEEN = 15, TWENTY = 20, } @@ -81,7 +84,6 @@ export enum InputTypes { NUMERIC = "numeric", TEXT = "text", } -export enum apiCatchingDuration -{ - GETREADFORM= 36000000 -} \ No newline at end of file +export enum apiCatchingDuration { + GETREADFORM = 36000000, +} diff --git a/src/utils/useLocationState.tsx b/src/utils/useLocationState.tsx index b771627e..5fa07e71 100644 --- a/src/utils/useLocationState.tsx +++ b/src/utils/useLocationState.tsx @@ -106,7 +106,8 @@ export const useLocationState = ( console.log(selectedStateCode, selectedDistrictCode); console.log(userType); - if (userType === FormContextType.TEAM_LEADER) { + if (userType === FormContextType.TEAM_LEADER || + userType === FormContextType.ADMIN_CENTER) { console.log("true"); const object = { limit: 200,