diff --git a/src/components/BMDashboard/ExpenditureGraph/ExpenditureLineGraph.css b/src/components/BMDashboard/ExpenditureGraph/ExpenditureLineGraph.css new file mode 100644 index 00000000000..7098f117bd9 --- /dev/null +++ b/src/components/BMDashboard/ExpenditureGraph/ExpenditureLineGraph.css @@ -0,0 +1,119 @@ +:root { + --bg-color: #f9f9f9; + --section-bg: #f5f5f5; + --text-color: #222; + --card-bg: #fff; + --button-bg: #e8a71c; +} + +.dark-mode { + --bg-color: #1b2a41; + --section-bg: #253342; + --text-color: #ffffff; + --card-bg: #16213e; + --button-bg: #e8a71c; +} + +.expenditure-chart-container { + padding: 20px; + background-color: #f9f9f9; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + transition: all 0.3s ease; + min-height: 100vh; + } + +.expenditure-chart-container.dark-mode { + background-color: #1b2a41 !important; + color: #ffffff !important; + box-shadow: none !important; + padding: 0 !important; + min-height: 100vh; + border-radius: 0 !important; +} + +.expenditure-chart-container.dark-mode .chart-inner-container { + background-color: #16213e !important; + border: 1px solid #233554 !important; + box-shadow: none !important; + border-radius: 0 !important; + width: 100%; + height: 100%; + margin: 0; + padding: 20px; +} + +.expenditure-chart-container.dark-mode .filter-controls, +.expenditure-chart-container.dark-mode .project-filter, +.expenditure-chart-container.dark-mode .filter-group { + background-color: #16213e !important; + color: #ffffff !important; + border: none !important; +} + +.expenditure-chart-container.dark-mode .error { + background-color: #2a3a5a !important; + color: #ff6b6b !important; + border: 1px solid #ff6b6b !important; +} + +.expenditure-chart-container.dark-mode .chart-inner-container { + background-color: #16213e !important; + border: 1px solid #233554 !important; + box-shadow: none !important; +} + +.expenditure-chart-container.dark-mode canvas { + background-color: #16213e !important; + border-radius: 8px; +} + + .expenditure-chart-container h1 { + font-size: 1.5rem; + margin-bottom: 20px; + font-weight: 600; + } + + .project-filter { + margin: 20px; + justify-content: flex-end; + display: flex; + align-items: center; + } + + .filter-group { + margin: 20px; + justify-content: flex-end; + display: flex; + align-items: center; + } + #project-select { + margin-left: 15px; + } + +.project-filter { + margin: 20px; + justify-content:flex-end; + display: flex; + align-items: center; +} + +.filter-group { + margin: 20px; + justify-content:flex-end; + display: flex; + align-items: center; +} + +label { + margin: 20px; +} + +#project-select { + margin-left: 15px; +} + +.dark-mode .project-filter, +.dark-mode .filter-group { + background-color: var(--card-bg); +} \ No newline at end of file diff --git a/src/components/BMDashboard/ExpenditureGraph/ExpenditureLineGraph.jsx b/src/components/BMDashboard/ExpenditureGraph/ExpenditureLineGraph.jsx new file mode 100644 index 00000000000..d9bf3fbcfc5 --- /dev/null +++ b/src/components/BMDashboard/ExpenditureGraph/ExpenditureLineGraph.jsx @@ -0,0 +1,608 @@ +import { useRef, useState, useEffect } from 'react'; +import axios from 'axios'; +import Chart from 'chart.js/auto'; +import { ENDPOINTS } from 'utils/URL'; +import { useSelector } from 'react-redux'; + +export default function ExpenditureLineGraph() { + const chartRef = useRef(null); + const [chartInstance, setChartInstance] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [expenditureData, setExpenditureData] = useState([]); + const [projects, setProjects] = useState([]); + const [selectedProject, setSelectedProject] = useState('all'); + const [dateError, setDateError] = useState(null); + const [noDataError, setNoDataError] = useState(null); + + // date filters + const [startDate, setStartDate] = useState(''); + const [endDate, setEndDate] = useState(''); + const [dateRange, setDateRange] = useState({ start: null, end: null }); + + const darkMode = useSelector(state => state.theme.darkMode); + + // format the date as YYYY-MM-DD + const formatDateForInput = date => { + return date.toISOString().split('T')[0]; + }; + + // use effect fetches data + useEffect(() => { + const fetchExpenditureData = async () => { + try { + setLoading(true); + const response = await axios.get(ENDPOINTS.BM_EXPENDITURE); + if (response?.data?.success) { + const { data } = response.data; + setExpenditureData(data); + // extract unique IDs + const uniqueProjects = [...new Set(data.map(item => item.projectId))]; + setProjects(uniqueProjects); + // default date range + if (data.length > 0) { + const dates = data.map(item => new Date(item.date)); + const minDate = new Date(Math.min(...dates)); + const maxDate = new Date(Math.max(...dates)); + setStartDate(formatDateForInput(minDate)); + setEndDate(formatDateForInput(maxDate)); + // set date range + setDateRange({ + start: minDate, + end: maxDate, + }); + } + } else { + setError('Failed to fetch the data'); + } + } catch (err) { + setError(`Error fetching data: ${err.message}`); + } finally { + setLoading(false); + } + }; + + fetchExpenditureData(); + + // Clean up function + return () => { + if (chartInstance) { + chartInstance.destroy(); + setChartInstance(null); + } + }; + }, []); + + // Destroy and recreate chart when theme changes + useEffect(() => { + if (chartInstance) { + chartInstance.destroy(); + setChartInstance(null); + } + }, [darkMode]); + + const createChart = chartData => { + if (!chartRef.current) return; + + const ctx = chartRef.current.getContext('2d'); + const chartTitle = + selectedProject === 'all' + ? 'Cost Breakdown by Type of Expenditure (all projects)' + : `Cost Breakdown by Type of Expenditure (Project: ${selectedProject})`; + + const gridColor = darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'; + const textColor = darkMode ? '#ffffff' : '#666666'; + const chartBackgroundColor = darkMode ? '#1b2a41' : '#ffffff'; + + if (chartInstance) { + chartInstance.destroy(); + } + + const config = { + type: 'line', + data: chartData, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + text: chartTitle, + color: textColor, + font: { + size: 14, + weight: 'bold', + }, + padding: { + top: 10, + bottom: 15, + }, + }, + legend: { + labels: { + color: textColor, + font: { + size: 12, + }, + }, + }, + tooltip: { + backgroundColor: darkMode ? '#3a506b' : 'rgba(0, 0, 0, 0.7)', + titleColor: '#ffffff', + bodyColor: '#ffffff', + borderColor: darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.1)', + borderWidth: 1, + }, + }, + scales: { + y: { + title: { + display: true, + text: 'Cost($)', + color: textColor, + font: { + size: 12, + weight: 'bold', + }, + }, + ticks: { + color: textColor, + font: { + size: 11, + }, + callback(value) { + if (value >= 1000) { + return `$${value / 1000}k`; + } + return `$${value}`; + }, + }, + grid: { + color: gridColor, + borderColor: gridColor, + }, + }, + x: { + title: { + display: true, + text: 'Month', + color: textColor, + font: { + size: 12, + weight: 'bold', + }, + }, + ticks: { + color: textColor, + font: { + size: 11, + }, + }, + grid: { + color: gridColor, + borderColor: gridColor, + }, + }, + }, + animation: { + onComplete() { + const chart = this; + ctx.save(); + ctx.globalCompositeOperation = 'destination-over'; + ctx.fillStyle = chartBackgroundColor; + ctx.fillRect(0, 0, chart.width, chart.height); + ctx.restore(); + }, + }, + }, + }; + + const newChartInstance = new Chart(ctx, config); + setChartInstance(newChartInstance); + }; + + const processDataForChart = expenditureDataArr => { + // group data by month and cat + const groupedByMonth = {}; + const categories = new Set(); + + // month from date + expenditureDataArr.forEach(item => { + const date = new Date(item.date); + const month = date.toLocaleString('default', { month: 'short' }); + const year = date.getFullYear(); + const monthYear = `${month} ${year}`; + + if (!groupedByMonth[monthYear]) { + groupedByMonth[monthYear] = {}; + } + + if (!groupedByMonth[monthYear][item.category]) { + groupedByMonth[monthYear][item.category] = 0; + } + + groupedByMonth[monthYear][item.category] += item.cost; + categories.add(item.category); + }); + + const labels = Object.keys(groupedByMonth).sort((a, b) => { + const [monthA, yearA] = a.split(' '); + const [monthB, yearB] = b.split(' '); + const months = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ]; + + if (yearA !== yearB) { + return parseInt(yearA, 10) - parseInt(yearB, 10); + } + return months.indexOf(monthA) - months.indexOf(monthB); + }); + + if (labels.length === 1) { + const [month, year] = labels[0].split(' '); + const months = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ]; + const monthIndex = months.indexOf(month); + const nextMonthIndex = (monthIndex + 1) % 12; + const nextYear = nextMonthIndex === 0 ? parseInt(year, 10) + 1 : parseInt(year, 10); + labels.push(`${months[nextMonthIndex]} ${nextYear}`); + } + const datasets = Array.from(categories).map((category, index) => { + const colors = ['#6293CC', '#C55151', '#E8D06B', '#94B66F']; + const data = labels.map(month => groupedByMonth[month]?.[category] || 0); + + return { + label: category, + data, + borderColor: colors[index % colors.length], + backgroundColor: darkMode + ? `${colors[index % colors.length]}33` + : `${colors[index % colors.length]}1A`, + tension: 0.1, + fill: false, + }; + }); + + return { labels, datasets }; + }; + + // handle chart changes when filters change + useEffect(() => { + if (expenditureData.length > 0 && chartRef.current) { + // Reset error states + setDateError(null); + setNoDataError(null); + + // Validate dates + if (dateRange.start && dateRange.end && dateRange.start > dateRange.end) { + setDateError('Start date cannot be greater than end date'); + if (chartInstance) { + chartInstance.destroy(); + setChartInstance(null); + } + return; + } + + let filteredData = expenditureData; + + // if not all data, filter by requested filtered title project + if (selectedProject !== 'all') { + filteredData = expenditureData.filter(item => item.projectId === selectedProject); + } + + // filter dates + if (dateRange.start && dateRange.end) { + filteredData = filteredData.filter(item => { + const itemDate = new Date(item.date); + return itemDate >= dateRange.start && itemDate <= dateRange.end; + }); + } + + // if data after filter? + if (filteredData.length === 0) { + setNoDataError('No data available for the selected date range and project'); + if (chartInstance) { + chartInstance.destroy(); + setChartInstance(null); + } + return; + } + + const processedData = processDataForChart(filteredData); + createChart(processedData); + } + }, [selectedProject, dateRange, expenditureData, darkMode]); + + const handleProjectChange = e => { + setSelectedProject(e.target.value); + }; + + const handleStartDateChange = e => { + const newStartDate = e.target.value; + setStartDate(newStartDate); + if (newStartDate) { + const newStartDateTime = new Date(newStartDate); + setDateRange(prev => ({ + ...prev, + start: newStartDateTime, + })); + } else { + const dates = expenditureData.map(item => new Date(item.date)); + setDateRange(prev => ({ + ...prev, + start: new Date(Math.min(...dates)), + })); + } + }; + + const handleEndDateChange = e => { + const newEndDate = e.target.value; + setEndDate(newEndDate); + if (newEndDate) { + const newEndDateTime = new Date(newEndDate); + setDateRange(prev => ({ + ...prev, + end: newEndDateTime, + })); + } else { + const dates = expenditureData.map(item => new Date(item.date)); + setDateRange(prev => ({ + ...prev, + end: new Date(Math.max(...dates)), + })); + } + }; + + return ( +
+

+ Cost Breakdown by Type of Expenditures +

+
+
+
+
+ + +
+
+ + + + +
+
+
+
+ + {loading && ( +

+ Loading data... +

+ )} + + {error && ( +

+ Error: {error} +

+ )} + {dateError && ( +

+ {dateError} +

+ )} + + {noDataError && ( +

+ {noDataError} +

+ )} + +
+
+ +
+
+
+ ); +} diff --git a/src/components/BMDashboard/ExpenditureGraph/ExpenditureLineGraphComponent.jsx b/src/components/BMDashboard/ExpenditureGraph/ExpenditureLineGraphComponent.jsx new file mode 100644 index 00000000000..9164f41cd5b --- /dev/null +++ b/src/components/BMDashboard/ExpenditureGraph/ExpenditureLineGraphComponent.jsx @@ -0,0 +1,226 @@ +import Chart from 'chart.js/auto'; +import { useEffect, useRef, useState } from 'react'; +import { ENDPOINTS } from 'utils/URL'; +import axios from 'axios'; +import './ExpenditureLineGraph.css'; + +export default function ExpenditureLineGraph() { + const chartRef = useRef(null); + const [chartInstance, setChartInstance] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [expenditureData, setExpenditureData] = useState([]); + + // fetch data on component mount + useEffect(() => { + const fetchExpenditureData = async () => { + try { + setLoading(true); + const response = await axios.get(ENDPOINTS.BM_EXPENDITURE); + if (response.data.success) { + setExpenditureData(response.data.data); + } else { + setError('Failed to fetch data'); + } + } catch (err) { + setError(`Error: ${err.message}`); + } finally { + setLoading(false); + } + }; + + fetchExpenditureData(); + + // Clean up + return () => { + if (chartInstance) { + chartInstance.destroy(); + } + }; + }, []); + + // total expenditure by month - simplified + const processDataForChart = datas => { + // Group by month and sum all expenditures + const monthlyTotals = {}; + + datas.forEach(item => { + const date = new Date(item.date); + const month = date.toLocaleString('default', { month: 'short' }); + const year = date.getFullYear(); + const monthYear = `${month} ${year}`; + + if (!monthlyTotals[monthYear]) { + monthlyTotals[monthYear] = 0; + } + + // add to monthly total + monthlyTotals[monthYear] += item.amount || item.cost || 0; + }); + + const months = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ]; + + const labels = Object.keys(monthlyTotals).sort((a, b) => { + const [monthA, yearA] = a.split(' '); + const [monthB, yearB] = b.split(' '); + + if (yearA !== yearB) { + return parseInt(yearA, 10) - parseInt(yearB, 10); + } + return months.indexOf(monthA) - months.indexOf(monthB); + }); + + const data = labels.map(month => monthlyTotals[month]); + + return { + labels, + datasets: [ + { + label: 'Total Expenditure', + data, + borderColor: '#6293CC', + backgroundColor: 'rgba(98, 147, 204, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.2, + pointBackgroundColor: '#6293CC', + }, + ], + }; + }; + + // create/update chart + useEffect(() => { + if (!loading && !error && expenditureData.length > 0 && chartRef.current) { + const chartData = processDataForChart(expenditureData); + + if (chartInstance) { + chartInstance.data = chartData; + chartInstance.update(); + } else { + const ctx = chartRef.current.getContext('2d'); + const newChart = new Chart(ctx, { + type: 'line', + data: chartData, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + display: false, + }, + title: { + display: true, + text: 'Monthly Expenditure', + font: { + size: 12, + weight: 'bold', + }, + padding: { + top: 5, + bottom: 10, + }, + color: '#333', + }, + tooltip: { + enabled: true, + callbacks: { + label(context) { + return `$${context.parsed.y.toLocaleString()}`; + }, + }, + }, + }, + scales: { + y: { + display: true, + beginAtZero: true, + ticks: { + font: { size: 9 }, + callback(value) { + if (value >= 1000) { + return `$${value / 1000}k`; + } + return `$${value}`; + }, + }, + grid: { + color: 'rgba(0, 0, 0, 0.1)', + drawBorder: true, + }, + title: { + display: true, + text: '', + font: { size: 10 }, + }, + }, + x: { + display: true, + ticks: { + font: { size: 9 }, + maxRotation: 45, + minRotation: 45, + }, + grid: { + display: false, + }, + title: { + display: true, + text: '', + font: { size: 10 }, + }, + }, + }, + elements: { + point: { + radius: 3, + hoverRadius: 5, + }, + line: { + borderWidth: 2, + }, + }, + layout: { + padding: { + left: 10, + right: 10, + top: 5, + bottom: 10, + }, + }, + }, + }); + + setChartInstance(newChart); + } + } + }, [loading, error, expenditureData]); + + return ( +
+ +
+ ); +} diff --git a/src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx b/src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx index 308eb359b71..139a3dee02c 100644 --- a/src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx +++ b/src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx @@ -8,7 +8,7 @@ import WeeklyProjectSummaryHeader from './WeeklyProjectSummaryHeader'; import PaidLaborCost from './PaidLaborCost/PaidLaborCost'; import { fetchAllMaterials } from '../../../actions/bmdashboard/materialsActions'; import QuantityOfMaterialsUsed from './QuantityOfMaterialsUsed/QuantityOfMaterialsUsed'; -import TotalMaterialCostPerProject from './TotalMaterialCostPerProject/TotalMaterialCostPerProject'; +import ExpenditureLineGraph from '../ExpenditureGraph/ExpenditureLineGraphComponent'; import styles from './WeeklyProjectSummary.module.css'; import IssueCharts from '../Issues/openIssueCharts'; @@ -181,7 +181,7 @@ export default function WeeklyProjectSummary() { if (index === 1) { content = ; } else if (index === 2) { - content = ; + // content = ; } else { content =

📊 Card

; } @@ -244,7 +244,7 @@ export default function WeeklyProjectSummary() { className: 'large', content: ( <> - {Array.from({ length: 4 }).map(() => { + {Array.from({ length: 3 }).map(() => { const uniqueId = uuidv4(); return (
); })} - -
- 📊 Big Card +
+
+ +
📊 Big Card
), }, diff --git a/src/routes.js b/src/routes.js index 2db5d2c4000..992791a92c6 100644 --- a/src/routes.js +++ b/src/routes.js @@ -93,10 +93,10 @@ import ToolDetailPage from './components/BMDashboard/Tools/ToolDetailPage'; import CheckTypes from './components/BMDashboard/shared/CheckTypes'; import Toolslist from './components/BMDashboard/Tools/ToolsList'; import AddTool from './components/BMDashboard/Tools/AddTool'; +import AddTeamMember from './components/BMDashboard/AddTeamMember/AddTeamMember'; +import ExpenditureLineGraph from './components/BMDashboard/ExpenditureGraph/ExpenditureLineGraph'; import AttendanceNoShow from './components/AttendanceSystem/AttendanceNoShowCharts'; - -import AddTeamMember from './components/BMDashboard/AddTeamMember/AddTeamMember'; // eslint-disable-next-line import/order import IssueChart from './components/BMDashboard/Issues/issueCharts'; import BMTimeLogger from './components/BMDashboard/BMTimeLogger/BMTimeLogger'; @@ -547,6 +547,7 @@ export default ( /> + diff --git a/src/utils/URL.js b/src/utils/URL.js index bd934a1cb2c..acc340bdf46 100644 --- a/src/utils/URL.js +++ b/src/utils/URL.js @@ -7,7 +7,6 @@ export const ENDPOINTS = { USER_PROFILE_PROPERTY: userId => `${APIEndpoint}/userprofile/${userId}/property`, USER_PROFILES: `${APIEndpoint}/userprofile/`, UPDATE_REHIREABLE_STATUS: userId => `${APIEndpoint}/userprofile/${userId}/rehireable`, - TOGGLE_VISIBILITY: userId => `${APIEndpoint}/userprofile/${userId}/toggleInvisibility`, USER_PROFILE_UPDATE: `${APIEndpoint}/userprofile/update`, ADD_BLUE_SQUARE: userId => `${APIEndpoint}/userprofile/${userId}/addInfringement`, @@ -22,6 +21,7 @@ export const ENDPOINTS = { USER_AUTOCOMPLETE: searchText => `${APIEndpoint}/userProfile/autocomplete/${searchText}`, SEARCH_USER: `${APIEndpoint}/users/search`, TOGGLE_BIO_STATUS: userId => `${APIEndpoint}/userProfile/${userId}/toggleBio`, + TOGGLE_VISIBILITY: userId => `${APIEndpoint}/userProfile/${userId}/toggleVisibility`, INFO_COLLECTIONS: `${APIEndpoint}/informations`, INFO_COLLECTION: infoId => `${APIEndpoint}/informations/${infoId}`, @@ -95,14 +95,6 @@ export const ENDPOINTS = { WEEKLY_SUMMARIES_REPORT: () => `${APIEndpoint}/reports/weeklysummaries`, SAVE_SUMMARY_RECEPIENTS: userid => `${APIEndpoint}/reports/recepients/${userid}`, GET_SUMMARY_RECEPIENTS: () => `${APIEndpoint}/reports/getrecepients`, - GET_CURRENT_WARNINGS: () => `${APIEndpoint}/currentWarnings`, - POST_NEW_WARNING: () => `${APIEndpoint}/currentWarnings`, - UPDATE_WARNING_DESCRIPTION: warningId => `${APIEndpoint}/currentWarnings/${warningId}`, - DELETE_WARNING_DESCRIPTION: warningId => `${APIEndpoint}/currentWarnings/${warningId}`, - EDIT_WARNING_DESCRIPTION: () => `${APIEndpoint}/currentWarnings/edit`, - GET_WARNINGS_BY_USER_ID: userId => `${APIEndpoint}/warnings/${userId}`, - POST_WARNINGS_BY_USER_ID: userId => `${APIEndpoint}/warnings/${userId}`, - DELETE_WARNINGS_BY_USER_ID: userId => `${APIEndpoint}/warnings/${userId}`, AUTHORIZE_WEEKLY_SUMMARY_REPORTS: () => `${APIEndpoint}/userProfile/authorizeUser/weeeklySummaries`, TOTAL_ORG_SUMMARY: (startDate, endDate, comparisonStartDate, comparisonEndDate) => @@ -121,6 +113,10 @@ export const ENDPOINTS = { POPUP_EDITOR_BY_ID: id => `${APIEndpoint}/popupeditor/${id}`, POPUP_EDITOR_BACKUP_BY_ID: id => `${APIEndpoint}/backup/popupeditor/${id}`, + GET_WARNINGS_BY_USER_ID: userId => `${APIEndpoint}/warnings/${userId}`, + POST_WARNINGS_BY_USER_ID: userId => `${APIEndpoint}/warnings/${userId}`, + DELETE_WARNINGS_BY_USER_ID: userId => `${APIEndpoint}/warnings/${userId}`, + TEAM_MEMBERS: teamId => `${APIEndpoint}/team/${teamId}/users`, TEAM_BY_ID: teamId => `${APIEndpoint}/team/${teamId}`, USER_UNREAD_TASK_NOTIFICATIONS: userId => `${APIEndpoint}/tasknotification/user/${userId}`, @@ -177,7 +173,6 @@ export const ENDPOINTS = { NON_HGN_EMAIL_SUBSCRIPTION: `${APIEndpoint}/add-non-hgn-email-subscription`, CONFIRM_EMAIL_SUBSCRIPTION: `${APIEndpoint}/confirm-non-hgn-email-subscription`, REMOVE_EMAIL_SUBSCRIPTION: `${APIEndpoint}/remove-non-hgn-email-subscription`, - // reasons endpoints CREATEREASON: () => { return `${APIEndpoint}/reason/`; @@ -202,7 +197,6 @@ export const ENDPOINTS = { GET_TOTAL_COUNTRY_COUNT: () => `${APIEndpoint}/getTotalCountryCount`, GET_ALL_FOLLOWUPS: () => `${APIEndpoint}/followup`, - SET_USER_FOLLOWUP: (userId, taskId) => `${APIEndpoint}/followup/${userId}/${taskId}`, GET_PROJECT_BY_PERSON: searchName => `${APIEndpoint}/userProfile/projects/${searchName}`, @@ -229,6 +223,7 @@ export const ENDPOINTS = { BM_REUSABLE_TYPES: `${APIEndpoint}/bm/invtypes/reusables`, BM_REUSABLES: `${APIEndpoint}/bm/reusables`, BM_PURCHASE_REUSABLES: `${APIEndpoint}/bm/reusables/purchase`, + BM_EQUIPMENTS: `${APIEndpoint}/bm/equipments`, BM_EQUIPMENT_TYPES: `${APIEndpoint}/bm/invtypes/equipments`, BM_EQUIPMENT_PURCHASE: `${APIEndpoint}/bm/equipment/purchase`, BM_PROJECTS: `${APIEndpoint}/bm/projects`, @@ -249,12 +244,12 @@ export const ENDPOINTS = { BM_EXTERNAL_TEAM: `${APIEndpoint}/bm/externalTeam`, BM_INVENTORY_UNITS: `${APIEndpoint}/bm/inventoryUnits`, BM_INVTYPE_ROOT: `${APIEndpoint}/bm/invtypes`, - BM_TOOLS: `${APIEndpoint}/bm/tools/`, BM_TOOL_BY_ID: singleToolId => `${APIEndpoint}/bm/tools/${singleToolId}`, BM_LOG_TOOLS: `${APIEndpoint}/bm/tools/log`, BM_EQUIPMENT_BY_ID: singleEquipmentId => `${APIEndpoint}/bm/equipment/${singleEquipmentId}`, - BM_EQUIPMENTS: `${APIEndpoint}/bm/equipments`, BM_INVTYPE_TYPE: type => `${APIEndpoint}/bm/invtypes/${type}`, + BM_EXPENDITURE: `${APIEndpoint}/bm/expenditure`, + BM_ISSUE_CHART: `${APIEndpoint}/bm/issue/issue-chart`, BM_ISSUE_FORM: `${APIEndpoint}/bm/issue/add`, @@ -265,6 +260,8 @@ export const ENDPOINTS = { BM_TAG_ADD: `${APIEndpoint}/bm/tags`, BM_TAGS_DELETE: `${APIEndpoint}/bm/tags`, + BM_ORGS_WITH_LOCATION: `${APIEndpoint}/bm/orgLocation`, + ORG_DETAILS: (projectId) => `${APIEndpoint}/bm/orgLocation/${projectId}`, BM_PROJECT_MEMBERS: projectId => `${APIEndpoint}/bm/project/${projectId}/users`, // bm time logger endpoints