diff --git a/.env.production.swp b/.env.production.swp deleted file mode 100644 index 68707c93c..000000000 Binary files a/.env.production.swp and /dev/null differ diff --git a/.env.test b/.env.test deleted file mode 100644 index 3a17854c5..000000000 --- a/.env.test +++ /dev/null @@ -1,2 +0,0 @@ -REACT_APP_BASEURL="https://datahubethdev.farmstack.co/be/" -REACT_APP_BASEURL_without_slash="https://datahubethdev.farmstack.co/be" diff --git a/public/env_config.js b/public/env_config.js index 18e44f11f..b52f64006 100644 --- a/public/env_config.js +++ b/public/env_config.js @@ -8,4 +8,5 @@ Window.ENV_VARS = { REACT_APP_BASEURL: "", REACT_APP_BASEURL_without_slash: "", REACT_APP_BASEURL_without_slash_view_data: "", + REACT_APP_BASEURL_FARMER_REGISTRY: "" }; diff --git a/src/Farmer-Registry/CustomText/CustomText.jsx b/src/Farmer-Registry/CustomText/CustomText.jsx new file mode 100644 index 000000000..f2b0df6e7 --- /dev/null +++ b/src/Farmer-Registry/CustomText/CustomText.jsx @@ -0,0 +1,24 @@ +import React from "react"; +import { Box, Typography } from "@mui/material"; + +const CustomText = (props) => { + return ( + + + {props.value} + + + ); +}; + +export default CustomText; diff --git a/src/Farmer-Registry/Dashboard.jsx b/src/Farmer-Registry/Dashboard.jsx new file mode 100644 index 000000000..ab076ab62 --- /dev/null +++ b/src/Farmer-Registry/Dashboard.jsx @@ -0,0 +1,1569 @@ +import React, { useContext, useEffect, useState } from "react"; +import { Box, useMediaQuery, useTheme } from "@mui/material"; +import CustomText from "./CustomText/CustomText"; +import { Col, Row } from "react-bootstrap"; +import { useHistory } from "react-router-dom"; + +// import "react-bootstrap/Row"; +import CustomCard from "./Stateless/Card/CustomCard"; +import PieChartCard from "./Stateless/PieChart/PieChart"; +import style from "./style.module.css"; +import BarGraphCard from "./Stateless/BarGraph/BarGraph"; +import BarGraphPercentage from "./Stateless/BarGraph/BarGraphPercentage"; + +import UrlConstants from "../features/default/src/Constants/UrlConstants"; +import { + getTokenLocal, + getWoreda, + handleApiError, + isLogedInUserAdmin, + isLogedInUserKebeleOfficer, + isLogedInUserNationalOfficer, + isLogedInUserRegionalOfficer, + isLogedInUserWoredaOfficer, + isLogedInUserZonalOfficer, + setRoleLocal, + setTokenLocal, + setUser, +} from "../features/default/src/Utils/Common" +import HTTPService from "../features/default/src/Services/HTTPServiceFarmer" +import Filters from "./Stateless/Filter/Filters"; +import grass from "../features/default/src/Assets/Img/grass.svg" +import group from "../features/default/src/Assets/Img/group.svg" +import pets from "../features/default/src/Assets/Img/pets.svg" +import { FarmStackContext } from "common/components/context/DefaultContext/FarmstackProvider"; + +const Dashboard = () => { + const [farmerProfileDetails, setFarmerProfileDetails] = useState({}); + const [devlopmentGroupInfo, setDevlopmentGroupInfo] = useState({ + development_group_count: 0, + total_farmers: 0, + female_farmers: 0, + male_farmers: 0, + development_group_type_details: { + "Women only development group": 0, + }, + development_groups_by_location: { + "Kebele 1": 0, + "Kebele 2": 0, + "Kebele 3": 0, + "Kebele 4": 0, + }, + }); + const [auth, setAuth] = useState(false); + const [farmerInfo, setFarmerInfo] = useState({}); + const [livestockDetails, setLivestockDetails] = useState({}); + const [cropInfo, setCropInfo] = useState({}); + const [cropFieldSize, setCropFieldSize] = useState({}); + const [priorityCrops, setPriorityCrops] = useState([]); + const [allRegions, setAllRegions] = useState([]); + const [allZones, setAllZones] = useState([]); + const [allWoreda, setAllWoreda] = useState([]); + const [allKabele, setAllKabele] = useState([]); + const [toggleFilter, setToggleFilter] = useState(0); + const [location, setLocation] = useState({ + region: "", + zone: "", + woreda: "", + kebele: "", + }); + const [farmerFilterOptions, setFarmerFilterOptions] = useState({ + genders: [], + maritalStatus: [], + householdTypes: [], + farmerCategories: [], + }); + const [farmerFilter, setFarmerFilter] = useState({ + gender: [], + maritalStatus: [], + householdType: [], + farmerCategory: "", + }); + const [livestockFilterOptions, setLivestockFilterOptions] = useState({ + livestocks: [], + ages: [], + breeds: [], + }); + const [livestockFilter, setLivestockFilter] = useState({ + livestock: [], + age: "", + breed: "", + }); + const [cropTypeOptions, setCropTypeOptions] = useState({ + cropTypes: [], + farmerTypes: [], + }); + const [cropType, setCropType] = useState({ + cropType: [], + farmerType: "", + }); + const [allLoader, setAllLoader] = useState({ + getFarmerProfileInfo: false, + getDevlopmentGroupInfo: false, + getFarmerInfo: false, + getLivestockDetails: false, + getCropInfo: false, + getRegions: false, + getZones: false, + getWoreda: false, + getKabele: false, + }); + const [selectedRegions, setSeletedRegions] = useState([]); + const [selectedZones, setSelectedZones] = useState([]); + const [selectedWoredas, setSelectedWoredas] = useState([]); + const [selectedKebeles, setSelectedKebeles] = useState([]); + const { callToast, callLoader } = useContext(FarmStackContext); + const history = useHistory(); + + const theme = useTheme(); + const mobile = useMediaQuery(theme.breakpoints.down("sm")); + const tablet = useMediaQuery(theme.breakpoints.down("md")); + const miniLaptop = useMediaQuery(theme.breakpoints.down("lg")); + const containerStyle = { + marginLeft: mobile || tablet ? "30px" : miniLaptop ? "50px" : "50px", + marginRight: mobile || tablet ? "30px" : miniLaptop ? "50px" : "50px", + marginTop: "30px", + }; + + function dataInPieFormat(data) { + const convertedData = []; + + for (const key in data) { + convertedData.push({ name: key, value: data[key] }); + } + + return convertedData; + } + function convertLivestockWithLocation(data) { + const transformedData = + typeof data == "object" && + Object.keys(data).map((key) => { + const obj = data[key]; + const value = Object.values(obj).reduce((acc, val) => + val !== "name" ? acc + val : acc + ); + return { + name: key, + ...obj, + value, + }; + }); + + return transformedData; + } + function getTopNObjects(data) { + data.sort((a, b) => b.value - a.value); + // const topNObjects = data.slice(0, n); + + return data; + } + + const getDevlopmentQueryParam = () => { + const queryParams = {}; + // @ts-ignore + if (cropType.cropType.length > 0) queryParams.crop_type = cropType.cropType; + if (cropType.farmerType) queryParams.farming_type = cropType.farmerType; + + if (livestockFilter.livestock.length > 0) + // @ts-ignore + queryParams.live_stock_type = livestockFilter.livestock; + // @ts-ignore + if (selectedRegions.length > 0) queryParams.region_id = selectedRegions; + // @ts-ignore + if (selectedZones.length > 0) queryParams.zone_id = selectedZones; + // @ts-ignore + + if (selectedWoredas.length > 0) queryParams.woreda_id = selectedWoredas; + // @ts-ignore + + if (selectedKebeles.length > 0) queryParams.kebele_id = selectedKebeles; + + const queryString = new URLSearchParams(queryParams).toString(); + return queryString; + }; + + // dashboard api call + const getFarmerProfileInfo = () => { + let url = UrlConstants.base_url_farmer_registry + UrlConstants.farmer_profile_details; + + setAllLoader((prv) => ({ ...prv, getFarmerProfileInfo: true })); + + HTTPService("GET", url, null, false, false, null, false, { + "X-SHARED-KEY": "zjejd25s", + "Accept": "application/json" + }) + .then((response) => { + setAllLoader((prv) => ({ ...prv, getFarmerProfileInfo: false })); + if(response.data){ + setFarmerProfileDetails(response.data)} + }) + .catch((error) => { + setAllLoader((prv) => ({ ...prv, getFarmerProfileInfo: false })); + let errorRes = handleApiError(error); + if (errorRes?.path) { + history.push(errorRes.path); + } else if (errorRes?.toast) { + callToast("error", errorRes.message, true); + } + }); + }; + const getDevlopmentGroupInfo = (clearFilter) => { + let url = UrlConstants.base_url_farmer_registry + UrlConstants.devlopment_group_info; + let queryParams = getDevlopmentQueryParam(); + if (!clearFilter) { + url += `?${queryParams}`; + } + setAllLoader((prv) => ({ ...prv, getDevlopmentGroupInfo: true })); + + HTTPService("GET", url, null, false, false, null, false, { + "X-SHARED-KEY": "zjejd25s", + "Accept": "application/json" + }) + .then((response) => { + setAllLoader((prv) => ({ ...prv, getDevlopmentGroupInfo: false })); + if(response.data){ + setDevlopmentGroupInfo(response.data) + } + }) + .catch((error) => { + setAllLoader((prv) => ({ ...prv, getDevlopmentGroupInfo: false })); + let errorRes = handleApiError(error); + if (errorRes?.path) { + history.push(errorRes.path); + } else if (errorRes?.toast) { + callToast("error", errorRes.message, true); + } + }); + }; + + const getFarmerInfo = (clearFilter) => { + let url = UrlConstants.base_url_farmer_registry + UrlConstants.farmer_info; + const queryParams = {}; + + // Add filters to queryParams + if (selectedRegions.length > 0) + queryParams.kebele__woreda__zone__region__in = selectedRegions; + if (selectedZones.length > 0) + queryParams.kebele__woreda__zone__in = selectedZones; + if (selectedWoredas.length > 0) + queryParams.kebele__woreda__in = selectedWoredas; + if (selectedKebeles.length > 0) queryParams.kebele__in = selectedKebeles; + if (farmerFilter.maritalStatus.length > 0) + queryParams.marital_status__in = farmerFilter.maritalStatus; + if (cropType.cropType.length > 0) + queryParams.farmers_farmland__farmland_crop__crop__crop_type__in = + cropType.cropType; + if (livestockFilter.livestock.length > 0) + queryParams.farmers_farmland__farmland_livestock__breed_id__livestock__livestock_type__in = + livestockFilter.livestock; + if (farmerFilter.gender.length > 0) + queryParams.gender__in = farmerFilter.gender; + if (farmerFilter.householdType.length > 0) + queryParams.household_type__in = farmerFilter.householdType; + + const queryString = new URLSearchParams(queryParams).toString(); + if (!clearFilter) { + url += `?${queryString}`; + } + + setAllLoader((prv) => ({ ...prv, getFarmerInfo: true })); + + // Making the API call with X-SHARED-KEY header + HTTPService("GET", url, null, false, false, null, false, { + "X-SHARED-KEY": "zjejd25s", + "Accept": "application/json" + }) + .then((response) => { + setAllLoader((prv) => ({ ...prv, getFarmerInfo: false })); + if (response.data) { + setFarmerInfo(response.data); + } + }) + .catch((error) => { + setAllLoader((prv) => ({ ...prv, getFarmerInfo: false })); + let errorRes = handleApiError(error); + if (errorRes?.path) { + history.push(errorRes.path); + } else if (errorRes?.toast) { + callToast("error", errorRes.message, true); + } + }); + }; + + const getLivestockDetails = (clearFilter) => { + let url = UrlConstants.base_url_farmer_registry + UrlConstants.livestock_details; + const queryParams = {}; + // @ts-ignore + if (selectedRegions.length > 0) queryParams.region_id = selectedRegions; + // @ts-ignore + if (selectedZones.length > 0) queryParams.zone_id = selectedZones; + // @ts-ignore + + if (selectedWoredas.length > 0) queryParams.woreda_id = selectedWoredas; + // @ts-ignore + + if (selectedKebeles.length > 0) queryParams.kebele_id = selectedKebeles; + // @ts-ignore + if (farmerFilter.gender.length > 0) + // @ts-ignore + queryParams.gender = farmerFilter.gender; + if (farmerFilter.maritalStatus.length > 0) + // @ts-ignore + queryParams.marital_status = farmerFilter.maritalStatus; + if (farmerFilter.householdType.length > 0) + // @ts-ignore + queryParams.household_type = farmerFilter.householdType; + if (livestockFilter.livestock.length > 0) + // @ts-ignore + queryParams.livestock_type = livestockFilter.livestock; + // @ts-ignore + if (cropType.cropType.length > 0) queryParams.crop_type = cropType.cropType; + + const queryString = new URLSearchParams(queryParams).toString(); + if (!clearFilter) { + url += `?${queryParams}`; + } + setAllLoader((prv) => ({ ...prv, getLivestockDetails: true })); + HTTPService("GET", url, null, false, false, null, false, { + "X-SHARED-KEY": "zjejd25s", + "Accept": "application/json" + }) + .then((response) => { + setAllLoader((prv) => ({ ...prv, getLivestockDetails: false })); + if(response.data){ + setLivestockDetails(response.data) + } + }) + .catch((error) => { + setAllLoader((prv) => ({ ...prv, getLivestockDetails: false })); + let errorRes = handleApiError(error); + if (errorRes?.path) { + history.push(errorRes.path); + } else if (errorRes?.toast) { + callToast("error", errorRes.message, true); + } + }); + }; + const getCropInfo = (clearFilter) => { + let url = UrlConstants.base_url_farmer_registry + UrlConstants.crop_info; + const queryParams = {}; + if (selectedRegions.length > 0) queryParams.region_id = selectedRegions; + + if (selectedZones.length > 0) queryParams.zone_id = selectedZones; + + if (selectedWoredas.length > 0) queryParams.woreda_id = selectedWoredas; + + if (selectedKebeles.length > 0) queryParams.kebele_id = selectedKebeles; + if (farmerFilter.gender.length > 0) + queryParams.gender = farmerFilter.gender; + if (farmerFilter.maritalStatus.length > 0) + queryParams.marital_status = farmerFilter.maritalStatus; + if (farmerFilter.householdType.length > 0) + + queryParams.household_type = farmerFilter.householdType; + if (livestockFilter.livestock.length > 0) + + queryParams.livestock_type = livestockFilter.livestock; + if (cropType.cropType.length > 0) queryParams.crop_type = cropType.cropType; + + callLoader(true); + + const queryString = new URLSearchParams(queryParams).toString(); + if (!clearFilter) { + url += `?${queryParams}`; + } + setAllLoader((prv) => ({ ...prv, getCropInfo: true })); + + HTTPService("GET", url, null, false, false, null, false, { + "X-SHARED-KEY": "zjejd25s", + "Accept": "application/json" + }) + .then((response) => { + setAllLoader((prv) => ({ ...prv, getCropInfo: false })); + if(response.data){ + setCropInfo(response.data) + } + }) + .catch((error) => { + setAllLoader((prv) => ({ ...prv, getCropInfo: false })); + let errorRes = handleApiError(error); + if (errorRes?.path) { + history.push(errorRes.path); + } else if (errorRes?.toast) { + callToast("error", errorRes.message, true); + } + }); + }; + + if ( + !allLoader.getCropInfo && + !allLoader.getDevlopmentGroupInfo && + !allLoader.getFarmerInfo && + !allLoader.getFarmerProfileInfo && + !allLoader.getLivestockDetails && + !allLoader.getRegions && + !allLoader.getZones && + !allLoader.getWoreda && + !allLoader.getKabele + ) { + callLoader(false); + } + if ( + allLoader.getCropInfo || + allLoader.getDevlopmentGroupInfo || + allLoader.getFarmerInfo || + allLoader.getFarmerProfileInfo || + allLoader.getLivestockDetails || + allLoader.getRegions || + allLoader.getZones || + allLoader.getWoreda || + allLoader.getKabele + ) { + callLoader(true); + } + // location filter option + const getRegions = () => { + let url = UrlConstants.base_url_farmer_registry + UrlConstants.regions; + setAllLoader((prv) => ({ ...prv, getRegions: true })); + HTTPService("GET", url, false, false, false) + .then((response) => { + setAllLoader((prv) => ({ ...prv, getRegions: false })); + if(response.data){ + setAllRegions(response.data) + localStorage.setItem("role_farmer", JSON.stringify("national_officer")); + } + }) + .catch((error) => { + setAllLoader((prv) => ({ ...prv, getRegions: false })); + let errorRes = handleApiError(error); + if (errorRes?.path) { + history.push(errorRes.path); + } else if (errorRes?.toast) { + callToast("error", errorRes.message, true); + } + }); + }; + const getZones = (regionId) => { + let url = UrlConstants.base_url_farmer_registry + UrlConstants.zones; + if (regionId) { + url += "?region__in=" + regionId; + } + setAllLoader((prv) => ({ ...prv, getZones: true })); + HTTPService("GET", url, false, false, false) + .then((response) => { + setAllLoader((prv) => ({ ...prv, getZones: false })); + if(response.data){ + setAllZones(response.data) + } + }) + .catch((error) => { + setAllLoader((prv) => ({ ...prv, getZones: false })); + let errorRes = handleApiError(error); + if (errorRes?.path) { + history.push(errorRes.path); + } else if (errorRes?.toast) { + callToast("error", errorRes.message, true); + } + }); + }; + const getWoreda = (zoneId) => { + let url = UrlConstants.base_url_farmer_registry + UrlConstants.woredas; + if (zoneId) { + url += "?zone__in=" + zoneId; + } + setAllLoader((prv) => ({ ...prv, getWoreda: true })); + HTTPService("GET", url, false, false, false) + .then((response) => { + setAllLoader((prv) => ({ ...prv, getWoreda: false })); + if(response.data){ + setAllWoreda(response.data) + } + }) + .catch((error) => { + setAllLoader((prv) => ({ ...prv, getWoreda: false })); + let errorRes = handleApiError(error); + if (errorRes?.path) { + history.push(errorRes.path); + } else if (errorRes?.toast) { + callToast("error", errorRes.message, true); + } + }); + }; + const getKabele = (woredaId) => { + let url = UrlConstants.base_url_farmer_registry + UrlConstants.kebeles; + if (woredaId) { + url += "?woreda__in=" + woredaId; + } + setAllLoader((prv) => ({ ...prv, getKabele: true })); + HTTPService("GET", url, false, false, false) + .then((response) => { + setAllLoader((prv) => ({ ...prv, getKabele: false })); + if(response.data){ + setAllKabele(response.data) + } + }) + .catch((error) => { + setAllLoader((prv) => ({ ...prv, getKabele: false })); + let errorRes = handleApiError(error); + if (errorRes?.path) { + history.push(errorRes.path); + } else if (errorRes?.toast) { + callToast("error", errorRes.message, true); + } + }); + }; + const getFilterOption = () => { + let url = UrlConstants.base_url_farmer_registry + UrlConstants.filter_data; + + callLoader(true); + HTTPService("GET", url, null, false, false, null, false, { + "X-SHARED-KEY": "zjejd25s", + "Accept": "application/json" + }) + .then((response) => { + callLoader(false); + if (response?.data) { + setFarmerFilterOptions({ + genders: response?.data?.gender ?? [], + maritalStatus: response?.data?.marital_status ?? [], + householdTypes: response?.data?.household_type ?? [], + farmerCategories: response?.data?.farmer_category ?? [], + }); + let ageNumber = new Array(100).fill(0); + ageNumber.map((item, index) => (ageNumber[index] = index + 1)); + setLivestockFilterOptions({ + livestocks: response?.data?.livestock_types ?? [], + ages: ageNumber ?? [], + breeds: response?.data?.breed_names ?? [], + }); + setCropTypeOptions({ + cropTypes: response?.data?.crop_type ?? [], + farmerTypes: [], + }); + } + }) + .catch((error) => { + callLoader(false); + let errorRes = handleApiError(error); + if (errorRes?.path) { + history.push(errorRes.path); + } else if (errorRes?.toast) { + callToast("error", errorRes.message, true); + } + }); + }; + + const handleApplyFilter = (clearFilter) => { + getDevlopmentGroupInfo(clearFilter); + getFarmerInfo(clearFilter); + getLivestockDetails(clearFilter); + getCropInfo(clearFilter); + }; + let updatedObj = {}; + + const recursion = (data) => { + // Check if data is an object + if (typeof data !== "object" || data === null) { + return; + } + + // Find the first non-null key + const key = Object.keys(data).find((key) => data[key] !== null); + + // If no non-null key is found, return + if (!key) { + return; + } + + const value = data[key]; + + // Check if the value is an object and has an id property + if (typeof value === "object" && value !== null && value.id) { + let tmpName = `name`; + + updatedObj[key] = { + id: value.id, + [tmpName]: value.name || value[tmpName], + }; + + console.log("updatedObj", updatedObj); + + // Prepare the next data for recursion + let tmpData = { ...value }; + delete tmpData.id; + delete tmpData[tmpName]; + + recursion(tmpData); + } + }; + const updateRes = (data) => { + recursion(data); + return updatedObj; + }; + + useEffect(() => { + if (auth) { + getFarmerProfileInfo(); + getDevlopmentGroupInfo(); + getFarmerInfo(); + getLivestockDetails(); + getCropInfo(); + // allAPICalls(); + getRegions(); + getFilterOption(); + } + }, [auth]); + + useEffect(() => { + // filters + + let jurisdiction = localStorage.getItem("jurisdiction"); + jurisdiction = jurisdiction ? JSON.parse(jurisdiction) : null; + if (isLogedInUserNationalOfficer() || isLogedInUserAdmin()) { + } else if (isLogedInUserRegionalOfficer()) { + // @ts-ignore + if (jurisdiction?.region?.id) { + setLocation((prv) => ({ + ...prv, + // @ts-ignore + region: jurisdiction?.region, + })); + // @ts-ignore + getZones(jurisdiction?.region?.id); + } + } else if (isLogedInUserZonalOfficer()) { + // @ts-ignore + if (jurisdiction?.region?.id) { + setLocation((prv) => ({ + ...prv, + // @ts-ignore + region: jurisdiction?.region, + })); + } + // @ts-ignore + if (jurisdiction?.zone?.id) { + setLocation((prv) => ({ + ...prv, + // @ts-ignore + zone: jurisdiction?.zone, + })); + // @ts-ignore + + getWoreda(jurisdiction?.zone?.id); + } + } else if (isLogedInUserWoredaOfficer()) { + // @ts-ignore + if (jurisdiction?.region?.id) { + setLocation((prv) => ({ + ...prv, + // @ts-ignore + region: jurisdiction?.region, + })); + } + // @ts-ignore + if (jurisdiction?.zone?.id) { + setLocation((prv) => ({ + ...prv, + // @ts-ignore + zone: jurisdiction?.zone, + })); + } + // @ts-ignore + if (jurisdiction?.woreda?.id) { + setLocation((prv) => ({ + ...prv, + // @ts-ignore + woreda: jurisdiction?.woreda, + })); + // @ts-ignore + getKabele(jurisdiction?.woreda?.id); + } + } else if (isLogedInUserKebeleOfficer()) { + // @ts-ignore + if (jurisdiction?.region?.id) { + setLocation((prv) => ({ + ...prv, + // @ts-ignore + region: jurisdiction?.region, + })); + } + // @ts-ignore + if (jurisdiction?.zone?.id) { + setLocation((prv) => ({ + ...prv, + // @ts-ignore + zone: jurisdiction?.zone, + })); + } + // @ts-ignore + if (jurisdiction?.woreda?.id) { + setLocation((prv) => ({ + ...prv, + // @ts-ignore + woreda: jurisdiction?.woreda, + })); + } + // @ts-ignore + if (jurisdiction?.kebele?.id) { + setLocation((prv) => ({ + ...prv, + // @ts-ignore + kebele: jurisdiction?.kebele, + })); + } + } + }, [toggleFilter]); + + useEffect(() => { + // @ts-ignore + let updatedFieldSize = dataInPieFormat(cropInfo?.crop_field_sizes ?? {}); + // getTopNObjects + setCropFieldSize(getTopNObjects(updatedFieldSize)); + // @ts-ignore + setPriorityCrops(getTopNObjects(updatedFieldSize)); + }, [cropInfo, farmerInfo]); + + useEffect(() => { + if (!getTokenLocal()) { + let body = { + email: "national@digitalgreen.org", + password: "@gmail.com", + }; + HTTPService( + "POST", + UrlConstants.base_url_farmer_registry + UrlConstants.login, + body, + false, + false + ) + .then((res) => { + callLoader(false); + setTokenLocal(res?.data?.token); + setUser(res?.data?.user); + setRoleLocal(res?.data?.user?.role); + setAuth(true); + let jurisdiction = updateRes( + res?.data?.user?.jurisdictions?.[0] ?? {} + ); + console.log( + "🚀 ~ file: Login.tsx:113 ~ .then ~ jurisdiction:", + jurisdiction, + res?.data?.user?.jurisdictions, + res?.data?.user + ); + localStorage.setItem("jurisdiction", JSON.stringify(jurisdiction)); + // // @ts-ignore + // setRegion(jurisdiction?.region); + // // @ts-ignore + // setZone(jurisdiction?.zone); + // // @ts-ignore + // setWoreda(jurisdiction?.woreda); + // // @ts-ignore + // setKebele(jurisdiction?.kebele); + history.push("/farmer/dashboard"); + }) + .catch((err) => { + console.log("🚀 ~ file: Login.tsx:101 ~ handleSubmit ~ err:", err); + callLoader(false); + }); + } else { + setAuth(true); + } + }, []); + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* filter */} + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* + + + + + */} + + + + + + + + + + + + + + + + + + + + + +
+ + + + + {cropFieldSize?.[0]?.name ? ( + + + + ) : ( + "" + )} + {cropFieldSize?.[1]?.name ? ( + + + + ) : ( + "" + )} + {cropFieldSize?.[2]?.name ? ( + + + + ) : ( + "" + )} + {cropFieldSize?.[3]?.name ? ( + + + + ) : ( + "" + )} + {cropFieldSize?.[4]?.name ? ( + + + + ) : ( + "" + )} + + + + + + + + + + + + + + + +
+ + + + + + + + + {/* + + */} + + {/* + + + + + */} + + + + + + + + + + + +
+ ); +}; + +export default Dashboard; diff --git a/src/Farmer-Registry/NoData/NoData.jsx b/src/Farmer-Registry/NoData/NoData.jsx new file mode 100644 index 000000000..144b49e82 --- /dev/null +++ b/src/Farmer-Registry/NoData/NoData.jsx @@ -0,0 +1,16 @@ +import React from "react"; +import Typography from "@mui/material/Typography"; +import ReportProblemIcon from "@mui/icons-material/ReportProblem"; + +const NoDataAvailable = () => { + return ( +
+ + + No Data Available + +
+ ); +}; + +export default NoDataAvailable; diff --git a/src/Farmer-Registry/Stateless/BarGraph/BarGraph.jsx b/src/Farmer-Registry/Stateless/BarGraph/BarGraph.jsx new file mode 100644 index 000000000..dccba148c --- /dev/null +++ b/src/Farmer-Registry/Stateless/BarGraph/BarGraph.jsx @@ -0,0 +1,136 @@ +import React from "react"; +import style from "./style.module.css"; +import { Box, useMediaQuery, useTheme } from "@mui/material"; + +import { + BarChart, + Bar, + // @ts-ignore + CartesianGrid, + XAxis, + YAxis, + Tooltip, + ResponsiveContainer, +} from "recharts"; +import NoDataAvailable from "../../NoData/NoData" + +const BarGraphCard = (props) => { + const theme = useTheme(); + const mobile = useMediaQuery(theme.breakpoints.down("sm")); + const tablet = useMediaQuery(theme.breakpoints.down("md")); + const miniLaptop = useMediaQuery(theme.breakpoints.down("lg")); + + const { data, barColor, dataKeys, Values, axisLine } = props; + + // const data = [ + // { + // name: "Page A", + // value: 4000, + // pv: 2400, + // crop_name: 2400, + // }, + // { + // name: "Page B", + // value: 3000, + // pv: 1398, + // crop_name: 2210, + // }, + // { + // name: "Page C", + // value: 2000, + // pv: 9800, + // crop_name: 2290, + // }, + // { + // name: "Page D", + // value: 2780, + // pv: 3908, + // crop_name: 2000, + // }, + // { + // name: "Page E", + // value: 1890, + // pv: 4800, + // crop_name: 2181, + // }, + // { + // name: "Page F", + // value: 2390, + // pv: 3800, + // crop_name: 2500, + // }, + // { + // name: "Page G", + // value: 3490, + // pv: 4300, + // crop_name: 2100, + // }, + // ]; + + return ( + <> + {" "} + {data?.length ? ( + + + + + + + + + {/* */} + + {dataKeys && dataKeys?.length ? ( + dataKeys.map((item) => { + return ( + <> + + ; + + ); + }) + ) : ( + + )} + + + + + ) : ( + + + + )}{" "} + + ); +}; + +export default BarGraphCard; diff --git a/src/Farmer-Registry/Stateless/BarGraph/BarGraphPercentage.jsx b/src/Farmer-Registry/Stateless/BarGraph/BarGraphPercentage.jsx new file mode 100644 index 000000000..90bac06ec --- /dev/null +++ b/src/Farmer-Registry/Stateless/BarGraph/BarGraphPercentage.jsx @@ -0,0 +1,90 @@ +import React from "react"; +import style from "./style.module.css"; +import { Box, useMediaQuery, useTheme } from "@mui/material"; + +import { + BarChart, + Bar, + // @ts-ignore + CartesianGrid, + XAxis, + YAxis, + Tooltip, + ResponsiveContainer, +} from "recharts"; +import NoDataAvailable from "../../NoData/NoData" + +const BarGraphPercentage = (props) => { + const theme = useTheme(); + const mobile = useMediaQuery(theme.breakpoints.down("sm")); + const tablet = useMediaQuery(theme.breakpoints.down("md")); + const miniLaptop = useMediaQuery(theme.breakpoints.down("lg")); + + const { data, barColor, dataKeys } = props; + +const total = data.reduce((acc, entry) => acc + entry.value, 0); +const formatYAxisTick = (value) => `${Math.round((value / total) * 100)}%`; + return ( + <> + {" "} + {data?.length ? ( + + + + + + + + + + {dataKeys && dataKeys?.length ? ( + dataKeys.map((item) => { + return ( + <> + + ; + + ); + }) + ) : ( + + )} + + + + + ) : ( + + + + )}{" "} + + ); +}; + +export default BarGraphPercentage; diff --git a/src/Farmer-Registry/Stateless/BarGraph/style.module.css b/src/Farmer-Registry/Stateless/BarGraph/style.module.css new file mode 100644 index 000000000..87ee4eb4e --- /dev/null +++ b/src/Farmer-Registry/Stateless/BarGraph/style.module.css @@ -0,0 +1,46 @@ +.containerGraph { + display: flex; + width: 100%; + max-height: 320px; + height: 300px; + /* padding: 10px; */ + background-color: #f7f7f7; + justify-content: space-between; + /* margin: 0 10px; */ + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; + } + .graphContainer { + display: flex; + min-height: 120px; + height: 100%; + /* max-height: 120px; */ + min-width: 100%; + max-width: 100%; + /* padding: 10px; */ + background-color: #f7f7f7; + justify-content: space-between; + margin: 0 10px; + } + + .container { + display: flex; + min-height: 120px; + height: 280px; + /* max-height: 120px; */ + min-width: 320px; + max-width: 100%; + /* padding: 10px; */ + background-color: #f7f7f7; + justify-content: space-between; + margin: 0 10px; + } + .noData { + max-width: 80%; + max-height: 100%; + padding: 10px; + margin: 20px auto; + border-radius: 10px; + border: 1px solid #e2e2e2; + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; + } + \ No newline at end of file diff --git a/src/Farmer-Registry/Stateless/Card/CustomCard.jsx b/src/Farmer-Registry/Stateless/Card/CustomCard.jsx new file mode 100644 index 000000000..644c79cac --- /dev/null +++ b/src/Farmer-Registry/Stateless/Card/CustomCard.jsx @@ -0,0 +1,50 @@ + +import * as React from "react"; +import Box from "@mui/material/Box"; +import style from "./CustomCard.module.css"; +import CustomText from "../../CustomText/CustomText" + + +const CustomCard = (props) => { + let colours = ["#F5B406", "#00AB55", "#0050D6", "#FF780A"]; + const { dotColor, title, value, icon } = props; + + let formattedValue = value ? value : 0; + if (typeof value == "number") { + formattedValue = parseFloat(value.toFixed(0)); + } else { + formattedValue = value + } + + return ( + <> + +
+ {icon && } + + {dotColor ? ( + + ) : null} + +
+
+ + ); +}; +export default CustomCard; diff --git a/src/Farmer-Registry/Stateless/Card/CustomCard.module.css b/src/Farmer-Registry/Stateless/Card/CustomCard.module.css new file mode 100644 index 000000000..eb5f4a3cb --- /dev/null +++ b/src/Farmer-Registry/Stateless/Card/CustomCard.module.css @@ -0,0 +1,38 @@ +.container { + display: flex; + min-height: 75px; + max-height: 134px; + min-width: 150px; + max-width: 100%; + padding: 10px; + background-color: #f7f7f7; + /* margin: 0 10px; */ + display: flex; + justify-content: space-between; + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; + } + + .textContainer { + text-align: left; + } + + .mLR10 { + margin-left: 10px; + margin-right: 10px; + } + + .value { + /* display: inline-block !important; */ + } + + .valueContainer { + display: inline-block !important; + margin-left: 10px; + } + + .colorBox { + height: 6px; + display: inline-block; + border-radius: 20px; + width: 6px; + } \ No newline at end of file diff --git a/src/Farmer-Registry/Stateless/Filter/Filters.jsx b/src/Farmer-Registry/Stateless/Filter/Filters.jsx new file mode 100644 index 000000000..ce70e4888 --- /dev/null +++ b/src/Farmer-Registry/Stateless/Filter/Filters.jsx @@ -0,0 +1,1239 @@ +import React from "react"; +import { Box, Button, FormControlLabel, Checkbox, Grid } from "@mui/material"; +import Chip from "@mui/material/Chip"; +import CustomText from "../../CustomText/CustomText" +import style from "./index.module.css"; +import SouthAmericaIcon from "@mui/icons-material/SouthAmerica"; +import LocationCityIcon from "@mui/icons-material/LocationCity"; +import MapIcon from "@mui/icons-material/Map"; +import HolidayVillageIcon from "@mui/icons-material/HolidayVillage"; +import AgricultureIcon from "@mui/icons-material/Agriculture"; +import CloseIcon from "@mui/icons-material/Close"; +import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; +import PetsIcon from "@mui/icons-material/Pets"; +import GrassIcon from "@mui/icons-material/Grass"; +import { useState } from "react"; +import { Row, Col } from "react-bootstrap"; +import { + isLogedInUserAdmin, + isLogedInUserNationalOfficer, + isLogedInUserRegionalOfficer, + isLogedInUserWoredaOfficer, + isLogedInUserZonalOfficer, +} from "../../../features/default/src/Utils/Common" + +export default function Filters(props) { + const { + regions, + zones, + woredas, + kebeles, + getZones, + getWoredas, + getKebeles, + setLocation, + location, + genders, + maritalStatus, + houseHoldTypes, + liveStockTypes, + farmerFilter, + setFarmerFilter, + livestockFilter, + setLivestockFilter, + cropTypeOptions, + cropType, + setCropType, + handleApplyFilter, + setToggleFilter, + setAllZones, + setAllWoreda, + setAllKabele, + selectedRegions, + setSeletedRegions, + selectedZones, + setSelectedZones, + selectedWoredas, + setSelectedWoredas, + selectedKebeles, + setSelectedKebeles, + } = props; + console.log("🚀 ~ file: Filters.tsx:61 ~ Filters ~ zones:", zones); + const [showFilter, setShowFilter] = useState(false); + const [regionName, setRegionName] = useState([]); + + const [type, setType] = useState(""); + + const handleFilterClick = (newType) => { + if (type == newType) { + setType(""); + } else { + setType(newType); + } + if (type == newType) { + setShowFilter(!showFilter); + } else { + setShowFilter(true); + } + }; + const clearAllFilters = () => { + setShowFilter(false); + setCropType({ + cropType: [], + farmerType: "", + }); + + setLivestockFilter({ + livestock: [], + age: "", + breed: "", + }); + + setFarmerFilter({ + gender: [], + maritalStatus: [], + householdType: [], + farmerCategory: "", + }); + + setLocation({ + region: "", + zone: "", + woreda: "", + kebele: "", + }); + setSeletedRegions([]); + setSelectedZones([]); + setSelectedKebeles([]); + setSelectedWoredas([]); + setAllZones([]); + setAllWoreda([]); + setAllKabele([]); + setToggleFilter((prv) => prv + 1); + handleApplyFilter(true); + setType(""); + }; + + const FilterDropdownButton = ({ children, onClick, className }) => { + return ( + +
+ {children} +
+
+ ); + }; + + return ( + + + + + + { + // Check once if the user is a national officer or an admin + const isAuthorizedUser = isLogedInUserNationalOfficer() || isLogedInUserAdmin(); + + if (isAuthorizedUser) { + handleFilterClick("region"); + } + }} + className={() => { + // Check once if the user is a national officer or an admin + const isAuthorizedUser = isLogedInUserNationalOfficer() || isLogedInUserAdmin(); + + // Apply classes based on conditions + if (isAuthorizedUser && type === "region") { + return style.filterComp + " " + style.activeColor; + } else if (isAuthorizedUser) { + return style.filterComp; + } else { + return style.disable; + } + }} +> + + + Region + + + + { + const isAuthorizedUser = + isLogedInUserAdmin() || + isLogedInUserNationalOfficer() || + isLogedInUserRegionalOfficer(); + + if (zones?.length && isAuthorizedUser) { + handleFilterClick("zone"); + } + }} + className={() => { + const isAuthorizedUser = + isLogedInUserAdmin() || + isLogedInUserNationalOfficer() || + isLogedInUserRegionalOfficer(); + + if (!zones?.length) { + return style.disable; + } else if (isAuthorizedUser && type === "zone") { + return style.filterComp + " " + style.activeColor; + } else if (isAuthorizedUser) { + return style.filterComp; + } else { + return style.disable; + } + }} +> + + + Zone + + + + { + const isAuthorizedUser = + isLogedInUserAdmin() || + isLogedInUserNationalOfficer() || + isLogedInUserRegionalOfficer() || + isLogedInUserZonalOfficer(); + + if (woredas?.length && isAuthorizedUser) { + handleFilterClick("woreda"); + } + }} + className={() => { + const isAuthorizedUser = + isLogedInUserAdmin() || + isLogedInUserNationalOfficer() || + isLogedInUserRegionalOfficer() || + isLogedInUserZonalOfficer(); + + if (!woredas?.length) { + return style.disable; + } else if (isAuthorizedUser && type === "woreda") { + return style.filterComp + " " + style.activeColor; + } else if (isAuthorizedUser) { + return style.filterComp; + } else { + return style.disable; + } + }} +> + + + Woreda + + + + { + const isAuthorizedUser = + isLogedInUserAdmin() || + isLogedInUserNationalOfficer() || + isLogedInUserRegionalOfficer() || + isLogedInUserZonalOfficer() || + isLogedInUserWoredaOfficer(); + + if (kebeles?.length && isAuthorizedUser) { + handleFilterClick("kebele"); + } + }} + className={() => { + const isAuthorizedUser = + isLogedInUserAdmin() || + isLogedInUserNationalOfficer() || + isLogedInUserRegionalOfficer() || + isLogedInUserZonalOfficer() || + isLogedInUserWoredaOfficer(); + + if (!kebeles?.length) { + return style.disable; + } else if (isAuthorizedUser && type === "kebele") { + return style.filterComp + " " + style.activeColor; + } else if (isAuthorizedUser) { + return style.filterComp; + } else { + return style.disable; + } + }} +> + + + Kebele + + + + handleFilterClick("farmer")} + className={ + type == "farmer" + ? style.filterComp + " " + style.activeColor + : style.filterComp + } + > + + + Farmer + + + handleFilterClick("livestock")} + className={ + type == "livestock" + ? style.filterComp + " " + style.activeColor + : style.filterComp + } + > + + + Livestock + + + handleFilterClick("crops")} + className={ + type == "crops" + ? style.filterComp + " " + style.activeColor + : style.filterComp + } + > + + + Crop + + + +
+ +
+
+ +
clearAllFilters()} className={style.clearAll}> + + Clear all +
+
+
+ {showFilter ? ( + <> + {type === "region" ? ( + <> + + + {regions?.map((item, index) => ( + { + setSeletedRegions((prevSelectedLocations) => { + const updatedLocations = e.target.checked + ? [...prevSelectedLocations, item.id] + : prevSelectedLocations.filter( + (id) => id !== item.id + ); + console.log( + "🚀 ~ file: Filters.tsx:313 ~ setSeletedRegions ~ updatedLocations:", + updatedLocations, + location + ); + setLocation((prv) => { + return { + ...prv, + region: updatedLocations, + }; + }); + if (updatedLocations?.length < 1) { + setAllZones([]); + setAllWoreda([]); + setAllKabele([]); + setSelectedZones([]); + setSelectedWoredas([]); + setSelectedKebeles([]); + } else { + setAllWoreda([]); + setAllKabele([]); + setSelectedZones([]); + setSelectedWoredas([]); + setSelectedKebeles([]); + getZones(updatedLocations); + } + return updatedLocations; + }); + }} + checked={selectedRegions.includes(item.id)} + /> + } + label={item?.name} + /> + ))} + + + ) : type === "zone" ? ( + + + + {zones?.map((item, index) => ( + { + setSelectedZones((prevSelectedLocations) => { + const updatedLocations = e.target.checked + ? [...prevSelectedLocations, item.id] + : prevSelectedLocations.filter( + (id) => id !== item.id + ); + setLocation((prv) => { + return { + ...prv, + zone: updatedLocations, + }; + }); + if (updatedLocations?.length < 1) { + setAllWoreda([]); + setAllKabele([]); + setSelectedWoredas([]); + setSelectedKebeles([]); + } else { + setAllKabele([]); + setSelectedWoredas([]); + setSelectedKebeles([]); + getWoredas(updatedLocations); + } + // setLocation(updatedLocations); + // getWoredas(updatedLocations); + return updatedLocations; + }); + }} + checked={selectedZones.includes(item.id)} + /> + } + label={item?.name} + /> + ))} + + + ) : type === "woreda" ? ( + + + + {woredas?.map((item, index) => ( + { + setSelectedWoredas((prevSelectedLocations) => { + const updatedLocations = e.target.checked + ? [...prevSelectedLocations, item.id] + : prevSelectedLocations.filter( + (id) => id !== item.id + ); + setLocation((prv) => { + return { + ...prv, + woreda: updatedLocations, + }; + }); + if (updatedLocations?.length < 1) { + setAllKabele([]); + setSelectedKebeles([]); + } else { + setSelectedKebeles([]); + getKebeles(updatedLocations); + } + // setLocation(updatedLocations); + // getKebeles(updatedLocations); + return updatedLocations; + }); + }} + checked={selectedWoredas.includes(item.id)} + /> + } + label={item?.name} + /> + ))} + + + ) : type === "kebele" ? ( + + + + {kebeles?.map((item, index) => ( + { + setSelectedKebeles((prevSelectedLocations) => { + const updatedLocations = e.target.checked + ? [...prevSelectedLocations, item.id] + : prevSelectedLocations.filter( + (id) => id !== item.id + ); + setLocation((prv) => { + return { + ...prv, + kebele: updatedLocations, + }; + }); + // setLocation(updatedLocations); + return updatedLocations; + }); + }} + checked={selectedKebeles.includes(item.id)} + /> + } + label={item?.name} + /> + ))} + + + ) : type === "farmer" ? ( + + + + + {genders?.map((item, index) => ( + { + setFarmerFilter((prevFarmerFilter) => { + const updatedGender = e.target.checked + ? [...prevFarmerFilter.gender, item] + : prevFarmerFilter.gender.filter( + (gender) => gender !== item + ); + + return { + ...prevFarmerFilter, + gender: updatedGender, + }; + }); + }} + checked={farmerFilter.gender.includes(item)} + /> + } + label={item} + /> + ))} + + + + + + {maritalStatus?.map((item, index) => ( + { + setFarmerFilter((prevFarmerFilter) => { + const updatedStatus = e.target.checked + ? [...prevFarmerFilter.maritalStatus, item] + : prevFarmerFilter.maritalStatus.filter( + (maritalStatus) => + maritalStatus !== item + ); + + return { + ...prevFarmerFilter, + maritalStatus: updatedStatus, + }; + }); + }} + checked={farmerFilter.maritalStatus.includes(item)} + /> + } + label={item} + /> + ))} + + + + + + {houseHoldTypes?.map((item, index) => ( + { + setFarmerFilter((prevFarmerFilter) => { + const updatedType = e.target.checked + ? [...prevFarmerFilter.householdType, item] + : prevFarmerFilter.householdType.filter( + (householdType) => + householdType !== item + ); + + return { + ...prevFarmerFilter, + householdType: updatedType, + }; + }); + }} + checked={farmerFilter.householdType.includes(item)} + /> + } + label={item} + /> + ))} + + + + ) : type === "crops" ? ( + + + + {cropTypeOptions?.cropTypes?.map((item, index) => ( + { + setCropType((prevCropType) => { + const updatedType = e.target.checked + ? [...prevCropType.cropType, item] + : prevCropType.cropType.filter( + (cropType) => cropType !== item + ); + + return { + ...prevCropType, + cropType: updatedType, + }; + }); + }} + checked={cropType.cropType.includes(item)} + /> + } + label={item} + /> + ))} + + + ) : type === "livestock" ? ( + + + + + {liveStockTypes?.map((item, index) => ( + { + setLivestockFilter((prevLiveStockFilter) => { + const updatedType = e.target.checked + ? [...prevLiveStockFilter.livestock, item] + : prevLiveStockFilter.livestock.filter( + (livestock) => livestock !== item + ); + + return { + ...prevLiveStockFilter, + livestock: updatedType, + }; + }); + }} + checked={livestockFilter.livestock.includes(item)} + /> + } + label={item} + /> + ))} + + + + ) : ( + " " + )} + + ) : ( + <> + )} + + + + {selectedRegions.length > 0 && ( + <> + {selectedRegions.map((regionId, index) => { + const selectedRegion = regions.find( + (region) => region.id === regionId + ); + const regionName = selectedRegion ? selectedRegion.name : ""; + + return ( + { + let updatedSelectedRegions = selectedRegions.filter( + (id) => id !== regionId + ); + setSeletedRegions((prevSelectedregions) => + prevSelectedregions.filter( + (id) => id !== regionId + ) + ); + setLocation((prev) => ({ + ...prev, + region: updatedSelectedRegions, + })); + if (updatedSelectedRegions?.length < 1) { + setAllZones([]); + setAllWoreda([]); + setAllKabele([]); + setSelectedZones([]); + setSelectedWoredas([]); + setSelectedKebeles([]); + } else { + setAllWoreda([]); + setAllKabele([]); + setSelectedZones([]); + setSelectedWoredas([]); + setSelectedKebeles([]); + getZones(updatedSelectedRegions); + } + // setAllZones([]); + // setAllWoreda([]); + // setAllKabele([]); + } + : false + } + style={{ + color: "#00ab55", + border: "1px solid #00ab55", + marginRight: "5px", + }} + /> + ); + })} + + )} + {selectedZones.length > 0 && ( + <> + {selectedZones.map((zoneId, index) => { + const selectedZone = zones.find((zone) => zone.id === zoneId); + const zoneName = selectedZone ? selectedZone.name : ""; + + return ( + { + // console.log("setSelectedKebeles", selectedKebeles); + + setSelectedZones((prevSelectedzones) => + prevSelectedzones.filter((id) => id !== zoneId) + ); + let updatedSelectedZones = selectedZones.filter( + (id) => id !== zoneId + ); + setLocation((prev) => ({ + ...prev, + zone: updatedSelectedZones, + })); + if (updatedSelectedZones?.length < 1) { + setAllWoreda([]); + setAllKabele([]); + setSelectedWoredas([]); + setSelectedKebeles([]); + } else { + setAllKabele([]); + setSelectedWoredas([]); + setSelectedKebeles([]); + getWoredas(updatedSelectedZones); + } + // setLocation((prv: any) => ({ + // ...prv, + // zone: "", + // woreda: "", + // kebele: "", + // })); + // setAllWoreda([]); + // setAllKabele([]); + } + : false + } + style={{ + color: "#00ab55", + border: "1px solid #00ab55", + marginRight: "5px", + }} + /> + ); + })} + + )} + {selectedZones.length > 0 && ( + <> + {selectedWoredas.map((woredaId, index) => { + const selectedWoreda = woredas.find( + (woreda) => woreda.id === woredaId + ); + const woredaName = selectedWoreda ? selectedWoreda.name : ""; + + return ( + { + setSelectedWoredas((prevSelectedworedas) => + prevSelectedworedas.filter( + (id) => id !== woredaId + ) + ); + let updatedSelectedWoreda = selectedWoredas.filter( + (id) => id !== woredaId + ); + setLocation((prev) => ({ + ...prev, + woreda: updatedSelectedWoreda, + })); + if (updatedSelectedWoreda?.length < 1) { + setAllKabele([]); + setSelectedKebeles([]); + } else { + setSelectedKebeles([]); + getKebeles(updatedSelectedWoreda); + } + // setLocation((prv: any) => ({ + // ...prv, + // woreda: "", + // kebele: "", + // })); + // setAllKabele([]); + } + : false + } + style={{ + color: "#00ab55", + border: "1px solid #00ab55", + marginRight: "5px", + }} + /> + ); + })} + + )} + {selectedKebeles.length > 0 && ( + <> + {selectedKebeles.map((kebeleId, index) => { + const selectedKebele = kebeles.find( + (kebele) => kebele.id === kebeleId + ); + const kebeleName = selectedKebele ? selectedKebele.name : ""; + + return ( + { + setLocation((prv) => ({ ...prv, kebele: "" })); + setSelectedKebeles((prevSelectedKebeles) => + prevSelectedKebeles.filter( + (id) => id !== kebeleId + ) + ); + let updatedSelectedKebele = selectedKebeles.filter( + (id) => id !== kebeleId + ); + setLocation((prev) => ({ + ...prev, + kebele: updatedSelectedKebele, + })); + // if (updatedSelectedKebele?.length < 1) { + // setAllKabele([]); + // } + } + : false + } + style={{ + color: "#00ab55", + border: "1px solid #00ab55", + marginRight: "5px", + }} + /> + ); + })} + + )} + {farmerFilter?.gender.length > 0 && ( +
+ {farmerFilter.gender.map((gender, index) => ( + + setFarmerFilter((prevFarmerFilter) => ({ + ...prevFarmerFilter, + gender: prevFarmerFilter.gender.filter( + (item) => item !== gender + ), + })) + } + style={{ + color: "#00ab55", + border: "1px solid #00ab55", + marginRight: "5px", + }} + /> + ))} +
+ )} + {farmerFilter?.maritalStatus.length > 0 && ( + <> + {farmerFilter.maritalStatus.map((status, index) => ( + + setFarmerFilter((prevFarmerFilter) => ({ + ...prevFarmerFilter, + maritalStatus: prevFarmerFilter.maritalStatus.filter( + (item) => item !== status + ), + })) + } + style={{ + color: "#00ab55", + border: "1px solid #00ab55", + marginRight: "5px", + }} + /> + ))} + + )} + {farmerFilter?.householdType.length > 0 && ( + <> + {farmerFilter.householdType.map((household, index) => ( + + setFarmerFilter((prevFarmerFilter) => ({ + ...prevFarmerFilter, + householdType: prevFarmerFilter.householdType.filter( + (item) => item !== household + ), + })) + } + style={{ + color: "#00ab55", + border: "1px solid #00ab55", + marginRight: "5px", + }} + /> + ))} + + )} + {livestockFilter?.livestock.length > 0 && ( + <> + {livestockFilter.livestock.map((livestock, index) => ( + + setLivestockFilter((prevLivestockFilter) => ({ + ...prevLivestockFilter, + livestock: prevLivestockFilter.livestock.filter( + (item) => item !== livestock + ), + })) + } + style={{ + color: "#00ab55", + border: "1px solid #00ab55", + marginRight: "5px", + }} + /> + ))} + + )} + {cropType?.cropType.length > 0 && ( + <> + {cropType.cropType.map((crop, index) => ( + + setCropType((prevCropType) => ({ + ...prevCropType, + cropType: prevCropType.cropType.filter( + (item) => item !== crop + ), + })) + } + style={{ + color: "#00ab55", + border: "1px solid #00ab55", + marginRight: "5px", + }} + /> + ))} + + )} +
+
+
+ ); +} diff --git a/src/Farmer-Registry/Stateless/Filter/index.module.css b/src/Farmer-Registry/Stateless/Filter/index.module.css new file mode 100644 index 000000000..1715e0369 --- /dev/null +++ b/src/Farmer-Registry/Stateless/Filter/index.module.css @@ -0,0 +1,121 @@ +.select { + display: flex; + margin: 20px; + justify-content: space-around; + } + .selectButtons { + display: flex; + /* align-items: flex-end; */ + justify-content: end; + } + .clearAll { + cursor: pointer; + padding: 10px; + font-weight: 600; + border: 1px solid #ffffff; + max-width: fit-content; + } + .clearAll:hover { + background-color: #ffffff; + color: #00ab55; + border: 1px solid #00ab55; + border-radius: 10px; + padding: 10px; + font-size: 16px; + font-weight: 600; + } + .applyBtn { + cursor: pointer; + padding: 10px; + font-weight: 700; + color: #00ab55; + border: #00ab55; + border-radius: "8px"; + } + + /* .regionFilter:hover .regionDropDown { + display: block; + z-index: 10; + } */ + .regionDropDown { + display: none; + position: absolute; + } + .filterComp { + cursor: pointer; + padding: 10px; + font-size: 16px; + font-weight: 600; + } + .activeColor { + background-color: #00ab55; + color: #ffffff; + border-radius: 10px; + padding: 10px; + font-size: 16px; + font-weight: 600; + } + /* .filterComp:focus { + background-color: #00ab55; + } */ + .filterComp:hover { + background-color: #00ab55; + color: #ffffff; + border-radius: 10px; + padding: 10px; + font-size: 16px; + font-weight: 600; + } + .disable { + opacity: 0.5; + padding: 10px; + } + .enable { + opacity: 1; + } + .mLeft10 { + margin-left: 10px; + font-weight: 600; + } + .filterChipsContainer { + margin-top: 50px; + } + .locationChips { + display: grid; + grid-template-columns: auto auto; + /* width: 25%; */ + } + .locationChips > div { + display: flex; + flex-direction: column; + align-items: baseline; + } + .chipTitle { + margin: 10px 0; + } + .selectComp { + display: flex; + justify-content: space-around; + margin: 30px 0; + } + .hr { + margin-top: 50px; + margin-bottom: 30px; + } + .checkBox { + display: flex; + flex-wrap: wrap; + } + .checkBoxStyle { + text-align: left; + } + .fitContent { + max-width: fit-content !important; + margin-right: 30px !important; + } + .chipStyle { + justify-content: space-around; + text-align: left !important; + margin-top: 20px !important; + } + \ No newline at end of file diff --git a/src/Farmer-Registry/Stateless/PieChart/PieChart.jsx b/src/Farmer-Registry/Stateless/PieChart/PieChart.jsx new file mode 100644 index 000000000..7e598b966 --- /dev/null +++ b/src/Farmer-Registry/Stateless/PieChart/PieChart.jsx @@ -0,0 +1,92 @@ +import React, { useState, useEffect } from "react"; +import { Box, useMediaQuery, useTheme } from "@mui/material"; +import { Cell, Pie, PieChart, Tooltip, ResponsiveContainer } from "recharts"; // Import Tooltip from Recharts +import style from "./style.module.css"; +import NoDataAvailable from "../../NoData/NoData" + +const PieChartCard = (props) => { + const { maxHeight, data, dataKey, dataValue, unit } = props; + const theme = useTheme(); + const mobile = useMediaQuery(theme.breakpoints.down("sm")); + const tablet = useMediaQuery(theme.breakpoints.down("md")); + const miniLaptop = useMediaQuery(theme.breakpoints.down("lg")); + + let colours = [ + "#F5B406", + "#00AB55", + "#0050D6", + "#FF780A", + "#B800D6", + "#5C046A", + "#003690", + "#FF3D00", + ]; + + const total = +data?.reduce((total, item) => total + item.value, 0); + + return ( + <> + {data?.length > 0 ? ( + +
+ + + // @ts-ignore + {data.map((entry, index) => ( + + ))} + + `${value} units`} // Format tooltip value + /> + +
+
+ {data?.map((entry, index, value) => ( +
+ + + {total !== 0 + ? `${Math.round((entry.value / total) * 100)}%` + : "0%"} + + {entry.name} + {entry.value} + {unit} +
+ ))} +
+
+ ) : ( + + + + )} + + ); +}; + +export default PieChartCard; diff --git a/src/Farmer-Registry/Stateless/PieChart/style.module.css b/src/Farmer-Registry/Stateless/PieChart/style.module.css new file mode 100644 index 000000000..0754cf531 --- /dev/null +++ b/src/Farmer-Registry/Stateless/PieChart/style.module.css @@ -0,0 +1,79 @@ +.container { + display: flex; + min-height: 120px; + height: 280px; + /* max-height: 120px; */ + min-width: 320px; + max-width: 100%; + /* padding: 10px; */ + background-color: #f7f7f7; + justify-content: space-between; + margin: 0 10px; + } + .title { + margin: 0 !important; + } + .value { + /* display: inline-block !important; */ + } + .valueContainer { + display: inline-block !important; + margin-left: 10px; + } + .labelText { + color: #000; + font-size: 12px; + font-weight: 400; + text-align: left; + width: 70px; + word-break: break-all; + margin: 10px 10px; + display: inline-block; + } + .percentageText { + margin-left: 10px; + color: #000; + font-size: 12px; + font-weight: 600; + display: inline-block; + } + .colorBox { + height: 6px; + display: inline-block; + border-radius: 20px; + width: 6px; + } + .labelRow { + display: flex; + align-items: center; + } + .textContainer { + /* height: 200px; */ + max-height: 250px; + overflow: scroll; + width: 50%; + display: flex; + flex-direction: column; + justify-content: center; + margin: 10px 0; + } + .containerGraph { + display: flex; + max-width: 100%; + max-height: 100%; + /* padding: 10px; */ + background-color: #f7f7f7; + justify-content: space-between; + /* margin: 0 10px; */ + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; + } + .noData { + max-width: 80%; + max-height: 100%; + padding: 10px; + margin: 20px auto; + + border-radius: 10px; + border: 1px solid #e2e2e2; + } + \ No newline at end of file diff --git a/src/Farmer-Registry/style.module.css b/src/Farmer-Registry/style.module.css new file mode 100644 index 000000000..19acaad14 --- /dev/null +++ b/src/Farmer-Registry/style.module.css @@ -0,0 +1,61 @@ +.graphRow { + margin-top: 50px !important; + margin-bottom: 50px !important; + } + + .graphRows { + margin-top: 20px !important; + margin-bottom: 50px !important; + } + + .devGroup { + /* max-width: 390px !important; */ + border-radius: 10px; + border: 1px solid #00ab55 !important; + margin-top: 20px !important; + margin: 20px 0px; + padding: 2px 20px; + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; + } + + .padding0 { + padding: 0 !important; + } + + .filterContainer { + margin-bottom: 60px; + } + + hr { + background-color: #e2e2e2; + height: 1px; + } + + .typeDev { + /* width: 597px !important; */ + } + + .typeDevloc { + /* width: 514px !important; */ + } + + .top14 { + margin-top: 14px !important; + } + + .top30 { + margin-top: 40px !important; + } + + .staticCard { + /* width: 260px !important; */ + border-radius: 10px !important; + border: 1px !important; + } + + /* .staticCard :hover { + border-radius: 10px !important; + border: 1px solid #00AB55 !important; + background-color: #D8FFEB !important; + } */ + \ No newline at end of file diff --git a/src/features/default/src/Assets/Img/grass.svg b/src/features/default/src/Assets/Img/grass.svg new file mode 100644 index 000000000..b8b55d7bf --- /dev/null +++ b/src/features/default/src/Assets/Img/grass.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/features/default/src/Assets/Img/group.svg b/src/features/default/src/Assets/Img/group.svg new file mode 100644 index 000000000..0cff16169 --- /dev/null +++ b/src/features/default/src/Assets/Img/group.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/features/default/src/Assets/Img/pets.svg b/src/features/default/src/Assets/Img/pets.svg new file mode 100644 index 000000000..50ce472b1 --- /dev/null +++ b/src/features/default/src/Assets/Img/pets.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/features/default/src/Constants/UrlConstants.js b/src/features/default/src/Constants/UrlConstants.js index 28dbcf5b0..b25fb5681 100644 --- a/src/features/default/src/Constants/UrlConstants.js +++ b/src/features/default/src/Constants/UrlConstants.js @@ -5,6 +5,7 @@ const UrlConstant = { base_url: Window?.ENV_VARS?.REACT_APP_BASEURL || process.env.REACT_APP_BASEURL, + base_url_farmer_registry: Window?.ENV_VARS?.REACT_APP_BASEURL_FARMER_REGISTRY ||process.env.REACT_APP_BASEURL_FARMER_REGISTRY, base_url_without_slash: Window?.ENV_VARS?.REACT_APP_BASEURL_without_slash || process.env.REACT_APP_BASEURL_without_slash, @@ -189,6 +190,19 @@ const UrlConstant = { // dahsboard get_dashboard: "microsite/datasets_file/bot_dashboard/", + + + //farmer-registry + regions: "api/v1/regions/", + zones: "api/v1/zones/", + woredas: "api/v1/woredas/", + kebeles: "api/v1/kebeles/", + farmer_info: "api/v1/farmer-registry/farmer-informations/", + farmer_profile_details: "api/v1/farmer-registry/farmer-profile-details/", + devlopment_group_info: "api/v1/farmer-registry/development-grop-info/", + livestock_details: "api/v1/farmer-registry/livestock-details/", + crop_info: "api/v1/farmer-registry/crop-information-details/", + filter_data: "api/v1/farmer-registry/unique-filter-values/", }; export default UrlConstant; diff --git a/src/features/default/src/Constants/labels.js b/src/features/default/src/Constants/labels.js index d73fd3e2f..e40adc46f 100755 --- a/src/features/default/src/Constants/labels.js +++ b/src/features/default/src/Constants/labels.js @@ -410,5 +410,14 @@ const labels = { feedbacks: globalConfig.dynamicLabelling.feedbacks ?? "", dashboard: "dashboard", }, + ROLES: { + ADMIN: "admin", + EA_LEADER: "ea_leader", + WOREDA_OFFICER: "woreda_officer", + ZONAL_OFFICER: "zonal_officer", + REGIONAL_OFFICER: "regional_officer", + NATIONAL_OFFICER: "national_officer", + }, + }; export default labels; diff --git a/src/features/default/src/Services/HTTPServiceFarmer.js b/src/features/default/src/Services/HTTPServiceFarmer.js new file mode 100644 index 000000000..a582e3635 --- /dev/null +++ b/src/features/default/src/Services/HTTPServiceFarmer.js @@ -0,0 +1,43 @@ +import axios from "axios"; +import { getTokenLocal } from "../Utils/Common"; + +const HTTPService = async ( + method, + url, + data = null, + isFormData = false, + isAuthorization = true, // Default to true for auth tokens, but false when using shared key + jwttoken = null, // JWT token, used only if isAuthorization is true + withCredentials = false, // Credentials, like cookies, are optional + customHeaders = {} // Custom headers (e.g., X-SHARED-KEY) +) => { + // If isAuthorization is false, skip Authorization headers + let headers = { + "Content-Type": isFormData ? "multipart/form-data" : "application/json", + ...customHeaders, // Add custom headers (like X-SHARED-KEY) if provided + }; + + // Add Authorization header if isAuthorization is true and token is present + if (isAuthorization && jwttoken) { + headers["Authorization"] = `Bearer ${jwttoken || getTokenLocal()}`; + } + + try { + // Make the API request using Axios + const response = await axios({ + method, + url, + headers, + withCredentials, // Whether to send credentials such as cookies + params: method === "GET" ? data : undefined, // Use params for GET requests + data: method !== "GET" ? data : undefined, // Use data for non-GET requests + }); + + return response; + } catch (error) { + // Handle errors (this can be customized) + throw error; + } +}; + +export default HTTPService; diff --git a/src/features/default/src/Utils/Common.js b/src/features/default/src/Utils/Common.js index 5a3c4aae4..d7e74c7ba 100644 --- a/src/features/default/src/Utils/Common.js +++ b/src/features/default/src/Utils/Common.js @@ -4,6 +4,7 @@ import HTTP_CONSTANTS from "../Constants/HTTPConstants"; import FileSaver from "file-saver"; import HTTPService from "../Services/HTTPService"; import UrlConstant from "../Constants/UrlConstants"; +import labels from "../Constants/labels"; const converter = require("json-2-csv"); @@ -254,7 +255,6 @@ export const getRoleLocal = () => { const userRole = JSON.parse(roleString); return userRole; }; - export const setErrorLocal = (error) => { localStorage.setItem(LocalStorageConstants.KEYS.error, JSON.stringify(error)); }; @@ -495,3 +495,155 @@ export function isHttpOrHttpsLink(str) { return httpHttpsPattern.test(str); } + +export const setUser = (user) => { + localStorage.setItem(LocalStorageConstants.KEYS.user, JSON.stringify(user)); +}; + +export const getUser = () => { + const user = localStorage.getItem(LocalStorageConstants.KEYS.user); + const userInfo = JSON.parse(user); + return userInfo; +}; + +export const setRegion = (region) => { + localStorage.setItem( + LocalStorageConstants.KEYS.region, + JSON.stringify(region) + ); +}; + +export const getRegion = () => { + const roleString = localStorage.getItem(LocalStorageConstants.KEYS.region); + const userRole = JSON.parse(roleString); + return userRole; +}; + +export const setZone = (zone) => { + localStorage.setItem(LocalStorageConstants.KEYS.zone, JSON.stringify(zone)); +}; + +export const getZone = () => { + const roleString = localStorage.getItem(LocalStorageConstants.KEYS.zone); + const userRole = JSON.parse(roleString); + return userRole; +}; + +export const setWoreda = (woreda) => { + localStorage.setItem( + LocalStorageConstants.KEYS.woreda, + JSON.stringify(woreda) + ); +}; + +export const getWoreda = () => { + const roleString = localStorage.getItem(LocalStorageConstants.KEYS.woreda); + const userRole = JSON.parse(roleString); + return userRole; +}; + +export const setKebele = (kebele) => { + localStorage.setItem( + LocalStorageConstants.KEYS.kebele, + JSON.stringify(kebele) + ); +}; + +export const getKebele = () => { + const roleString = localStorage.getItem(LocalStorageConstants.KEYS.kebele); + const userRole = JSON.parse(roleString); + return userRole; +}; +export const isLogedInUserAdmin = () => { + const role = localStorage.getItem("role_farmer"); + return role == labels.ROLES.ADMIN; +}; +export const isLogedInUserNationalOfficer = () => { + const role = localStorage.getItem("role_farmer"); + return role === labels.ROLES.NATIONAL_OFFICER; +}; +export const isLogedInUserRegionalOfficer = () => { + const role = localStorage.getItem("role_farmer"); + return role == labels.ROLES.REGIONAL_OFFICER; +}; + +export const isLogedInUserZonalOfficer = () => { + const role = localStorage.getItem("role_farmer"); + return role == labels.ROLES.ZONAL_OFFICER; +}; + +export const isLogedInUserWoredaOfficer = () => { + const role = localStorage.getItem("role_farmer"); + return role == labels.ROLES.WOREDA_OFFICER; +}; +export const isLogedInUserKebeleOfficer = () => { + const role = localStorage.getItem("role_farmer"); + return role == labels.ROLES.EA_LEADER; +}; + +export const getDateAndTime = (createdAt) => { + const date = new Date(createdAt); + const year = date.getFullYear(); + // const month = date.toLocaleString("default", { month: "long" }); + const month = (date.getMonth() + 1).toString().padStart(2, "0"); + const day = date.getDate(); + const hours = date.getHours(); + const minutes = date.getMinutes(); + const formattedDate = `${day}/${month}/${year}`; + return formattedDate; +}; + +export const handleApiError = (error) => { + // this returns { + // path: "/error/500", or toast: true + // message: errorMessage, + // error: error, + // status: errorStatus, + // } + let errorMessage = "An error occurred while processing your request."; + let errorStatus = null; + + if (error?.response && error?.response?.data) { + errorMessage = error?.response?.data?.message || errorMessage; + errorStatus = error?.response?.status || null; + } else if (error.message) { + errorMessage = error?.message; + } + + console.error( + "API Error:", + errorMessage, + "Status:", + errorStatus, + "error:", + error + ); + + if (errorStatus == 401) { + localStorage.clear(); + // navigate("/login"); + return { + path: "/error/401", + message: errorMessage, + error: error, + status: errorStatus, + }; + } + if (errorStatus >= 500) { + return { + path: "/error/500", + message: errorMessage, + error: error, + status: errorStatus, + }; + } + + return { + toast: true, + message: errorMessage, + error: error, + status: errorStatus, + }; +}; + +export default LocalStorageConstants; diff --git a/src/features/default/src/Views/GuestUser/TempFarmerFile.js b/src/features/default/src/Views/GuestUser/TempFarmerFile.js index d53fc3d01..f9a549df6 100644 --- a/src/features/default/src/Views/GuestUser/TempFarmerFile.js +++ b/src/features/default/src/Views/GuestUser/TempFarmerFile.js @@ -1,43 +1,45 @@ import { FarmStackContext } from "common/components/context/DefaultContext/FarmstackProvider"; import React, { useContext, useEffect, useRef } from "react"; +import Dashboard from "Farmer-Registry/Dashboard"; const TempFarmerFile = () => { const { callToast, callLoader } = useContext(FarmStackContext); - const iframeRef = useRef(null); + // const iframeRef = useRef(null); - useEffect(() => { - callLoader(true); + // useEffect(() => { + // callLoader(true); - const iframe = iframeRef.current; - const sendMessage = () => { - iframe.contentWindow.postMessage( - {}, - "https://farmer-registry-stage.digiext.org/dashboard" - ); - }; + // const iframe = iframeRef.current; + // const sendMessage = () => { + // iframe.contentWindow.postMessage( + // {}, + // "https://farmer-registry-stage.digiext.org/dashboard" + // ); + // }; - iframe.onload = sendMessage; + // iframe.onload = sendMessage; - // If the iframe is already loaded - if ( - iframe && - iframe.contentWindow && - iframe.contentWindow.document.readyState === "complete" - ) { - sendMessage(); - } - callLoader(false); - }, []); + // // If the iframe is already loaded + // if ( + // iframe && + // iframe.contentWindow && + // iframe.contentWindow.document.readyState === "complete" + // ) { + // sendMessage(); + // } + // callLoader(false); + // }, []); return ( -
-