Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c9e5237
feat(utilization): add forecast and insights panels
Aditya-gam Mar 27, 2026
38e6808
fix(utilization): harden chart ux and request state
Aditya-gam Mar 27, 2026
8801bec
Merge pull request #5117 from OneCommunityGlobal/development
one-community Apr 8, 2026
3b88381
Merge pull request #5160 from OneCommunityGlobal/development
one-community Apr 17, 2026
d7178fc
Merge pull request #5190 from OneCommunityGlobal/development
one-community Apr 23, 2026
3dee6fa
Merge pull request #5213 from OneCommunityGlobal/development
one-community May 1, 2026
646220f
Revert "Frontend Release to Main [4.87]"
one-community May 1, 2026
b581923
Merge pull request #5218 from OneCommunityGlobal/revert-5213-development
one-community May 1, 2026
04d3373
Merge pull request #5220 from OneCommunityGlobal/development
sundarmachani May 1, 2026
be729cd
Revert "Revert "Frontend Release to Main [4.87]""
sundarmachani May 1, 2026
1a4c550
Merge pull request #5221 from OneCommunityGlobal/revert-5218-revert-5…
sundarmachani May 1, 2026
5345f48
chore: fix github workflow to match main
May 1, 2026
f8fb017
Merge pull request #5222 from OneCommunityGlobal/sundar/dev-main
sundarmachani May 1, 2026
31016a2
Merge pull request #5240 from OneCommunityGlobal/development
one-community May 8, 2026
ae5e7e9
Merge pull request #5248 from OneCommunityGlobal/development
one-community May 9, 2026
f77f7da
Merge pull request #5268 from OneCommunityGlobal/development
one-community May 14, 2026
2f1c8ec
Revert "Frontend Release to Main [4.90]"
one-community May 14, 2026
349528a
Merge pull request #5269 from OneCommunityGlobal/revert-5268-development
one-community May 14, 2026
878d7a6
Resolve merge conflicts in UtilizationChart components
rithika-paii May 18, 2026
91ee34a
Fix remaining merge conflict markers in UtilizationChart.jsx
rithika-paii May 18, 2026
a4146c2
Merge branch 'development' into Aditya-feat/Add-Smart-Insights-and-Pr…
rithika-paii May 18, 2026
2ee47b2
Fix missing ArrowUpDown, ArrowUp, ArrowDown imports in DropOffTrackin…
rithika-paii May 19, 2026
db20a72
Fix CSS syntax error in CPDashboard.module.css
rithika-paii May 19, 2026
3319ee4
Fix SonarQube reliability bug in EventPopularity.jsx
rithika-paii May 19, 2026
1ddf093
Fix SonarQube code smell issues across multiple files
rithika-paii May 19, 2026
42ed138
Fix Prettier formatting in TaskCardView.jsx
rithika-paii May 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/actions/intermediateTasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ export const MARK_INTERMEDIATE_TASK_DONE = 'MARK_INTERMEDIATE_TASK_DONE';
* Fetch intermediate tasks for a parent task
*/
export const fetchIntermediateTasks = taskId => {
return async () => {
return async dispatch => {
try {
const response = await httpService.get(ENDPOINTS.INTERMEDIATE_TASKS_BY_PARENT(taskId));
return response.data;
} catch {
return [];
} catch (error) {
toast.error('Failed to fetch sub-tasks');
throw error;
}
};
};
Expand Down
79 changes: 30 additions & 49 deletions src/actions/studentTasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,27 @@
};

/**
* Handle API error and fall back to demo data
* @param {Error} apiError - The caught API error
* Handle API error and try fallback options
* @param {Error} apiError - The API error
* @param {Function} dispatch - Redux dispatch function
* @returns {Array} Mock tasks for demo purposes
* @returns {Promise<Array>} Array of tasks (from fallback or mock data)
*/
const handleApiError = (apiError, dispatch) => {
const handleApiError = async (apiError, dispatch) => {
console.error('Error response:', apiError.response?.data);

Check warning on line 135 in src/actions/studentTasks.js

View workflow job for this annotation

GitHub Actions / test

Unexpected console statement
console.error('Error status:', apiError.response?.status);

Check warning on line 136 in src/actions/studentTasks.js

View workflow job for this annotation

GitHub Actions / test

Unexpected console statement
console.error('Error config:', apiError.config);

Check warning on line 137 in src/actions/studentTasks.js

View workflow job for this annotation

GitHub Actions / test

Unexpected console statement

// Try alternative endpoint if the first one fails
if (apiError.response?.status === 404) {
try {
const altResponse = await httpService.post(`${ENDPOINTS.APIEndpoint()}/student-tasks`);
return altResponse.data.tasks || [];
} catch {
// Alternative endpoint failed
}
}

toast.info('Using demo data. Student tasks API is not yet available.');
return mockTasks;
};

Expand All @@ -143,19 +158,20 @@
dispatch(setStudentTasksStart());

try {
let tasks = [];
try {
tasks = await fetchTasksFromPrimaryEndpoint();
} catch (apiError) {
tasks = handleApiError(apiError, dispatch);
const state = getState();
const userId = state.auth.user.userid;

if (!userId) {
dispatch(setStudentTasksError('User not authenticated'));
return;
}

// Fall back to mock data if API returned nothing
if (!tasks || tasks.length === 0) {
toast.info('Using demo data. Student tasks API is not yet available.');
dispatch(setStudentTasks(mockTasks));
} else {
try {
const tasks = await fetchTasksFromPrimaryEndpoint();
dispatch(setStudentTasks(tasks));
} catch (apiError) {
const fallbackTasks = await handleApiError(apiError, dispatch);
dispatch(setStudentTasks(fallbackTasks));
}
} catch (err) {
dispatch(setStudentTasksError(err.message || 'Failed to fetch student tasks'));
Expand Down Expand Up @@ -246,38 +262,3 @@
}
};
};

/**
* Log hours against a student task.
* @param {string} taskId - The task ID
* @param {number} hours - Hours to add (positive number)
*/
export const logStudentTaskHours = (taskId, hours) => {
return async (dispatch, getState) => {
try {
const state = getState();
const userId = state.auth.user.userid;

const response = await httpService.post(ENDPOINTS.STUDENT_TASK_LOG_HOURS(taskId), {
hours,
requestor: { requestorId: userId },
});

const { loggedHours, suggestedTotalHours, status, canMarkDone } = response.data;

dispatch({
type: types.LOG_STUDENT_TASK_HOURS,
taskId,
loggedHours,
suggestedTotalHours,
status,
canMarkDone,
});

toast.success(`${hours} hour(s) logged successfully!`);
} catch (error) {
const msg = error.response?.data?.error || 'Failed to log hours. Please try again.';
toast.error(msg);
}
};
};
22 changes: 15 additions & 7 deletions src/components/BMDashboard/ConsumableList/ConsumableListView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { useDispatch, useSelector } from 'react-redux';
import { fetchAllConsumables } from '../../../actions/bmdashboard/consumableActions';
import ItemListView from '../ItemList/ItemListView';
import UpdateConsumableModal from '../UpdateConsumables/UpdateConsumableModal';
import { Link } from 'react-router-dom';
import styles from '../InventoryTypesList/TypesList.module.css';

function ConsumableListView() {
const dispatch = useDispatch();
Expand Down Expand Up @@ -50,13 +52,19 @@ function ConsumableListView() {
];

return (
<ItemListView
itemType={itemTypeLabel}
items={transformedConsumables}
errors={errors}
UpdateItemModal={UpdateConsumableModal}
dynamicColumns={dynamicColumns}
/>
<>
<Link to="/bmdashboard/inventorytypes" className={styles.backLink}>
All Inventory Types
</Link>

<ItemListView
itemType={itemTypeLabel}
items={transformedConsumables}
errors={errors}
UpdateItemModal={UpdateConsumableModal}
dynamicColumns={dynamicColumns}
/>
</>
);
}

Expand Down
41 changes: 24 additions & 17 deletions src/components/BMDashboard/Equipment/List/EquipmentList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import useTheme from '../../../../hooks/useTheme';
import EquipmentsTable from './EquipmentsTable';
import EquipmentsInputs from './EquipmentsInputs';
import styles from './Equipments.module.css';
import { Link } from 'react-router-dom';
import stylesList from '../../InventoryTypesList/TypesList.module.css';

function EquipmentList() {
const [equipment, setEquipment] = useState({ label: 'All Equipments', value: '0' });
Expand All @@ -12,25 +14,30 @@ function EquipmentList() {
useTheme();

return (
<div className={`${styles.PageViewContainer}`}>
<div className={`${styles.Page}`}>
<div className={`${styles.Box}`}>
<div className={`${styles.BuildingTitle}`}>EQUIPMENTS</div>
<EquipmentsInputs
equipment={equipment}
setEquipment={setEquipment}
project={project}
setProject={setProject}
/>
<EquipmentsTable
equipment={equipment}
setEquipment={setEquipment}
project={project}
setProject={setProject}
/>
<>
<Link to="/bmdashboard/inventorytypes" className={stylesList.backLink}>
All Inventory Types
</Link>
<div className={`${styles.PageViewContainer}`}>
<div className={`${styles.Page}`}>
<div className={`${styles.Box}`}>
<div className={`${styles.BuildingTitle}`}>EQUIPMENTS</div>
<EquipmentsInputs
equipment={equipment}
setEquipment={setEquipment}
project={project}
setProject={setProject}
/>
<EquipmentsTable
equipment={equipment}
setEquipment={setEquipment}
project={project}
setProject={setProject}
/>
</div>
</div>
</div>
</div>
</>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
import { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { useHistory } from 'react-router-dom';

import { Link } from 'react-router-dom';
import { fetchInvTypeByType } from '~/actions/bmdashboard/invTypeActions';
import { fetchInvUnits } from '~/actions/bmdashboard/invUnitActions';
import { Accordion, Card, Button } from 'react-bootstrap';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';

import { Accordion, Card } from 'react-bootstrap';
import BMError from '../shared/BMError';
import TypesTable from './TypesTable';
import UnitsTable from './invUnitsTable';
import AccordionToggle from './AccordionToggle';
import styles from './TypesList.module.css';

const categories = [
{ label: 'Materials', route: '/bmdashboard/materials' },
{ label: 'Consumables', route: '/bmdashboard/consumables' },
{ label: 'Equipments', route: '/bmdashboard/equipment' },
{ label: 'Reusables', route: '/bmdashboard/reusables' },
{ label: 'Tools', route: '/bmdashboard/tools' },
];

export function InventoryTypesList(props) {
const { invUnits, errors, dispatch } = props;
const history = useHistory();

const categories = ['Materials', 'Consumables', 'Equipments', 'Reusables', 'Tools'];

const [isError, setIsError] = useState(false);
const [currentTime, setCurrentTime] = useState(new Date());

const handleBack = () => {
history.goBack();
};

useEffect(() => {
dispatch(fetchInvTypeByType('Materials'));
Expand All @@ -50,52 +44,38 @@ export function InventoryTypesList(props) {
}

return (
<div className={`${styles.typesListContainer}`}>
<h1>All Inventory Types</h1>

<div className={`${styles.timestampContainer}`}>
<span>Time:</span>
<DatePicker
selected={currentTime}
onChange={date => setCurrentTime(date)}
dateFormat="MM-dd-yyyy hh:mm:ss"
id="timestamp"
showTimeInput
/>
<div className={styles.typesListContainer}>
{/* Page Header */}
<div className={styles.pageHeader}>
<h1 className={styles.pageTitle}>All Inventory Types</h1>
<p className={styles.pageSubtitle}>Select a category to view and manage inventory</p>
</div>

<Accordion>
{categories?.map((category, index) => {
return (
<Card key={category}>
<AccordionToggle as={Card.Header} eventKey={index + 1}>
{category}
</AccordionToggle>
<Accordion.Collapse eventKey={index + 1}>
<Card.Body className={`${styles.accordionCollapse}`}>
<TypesTable category={category} />
</Card.Body>
</Accordion.Collapse>
</Card>
);
})}

<Card>
<AccordionToggle as={Card.Header} eventKey={categories.length + 1}>
Unit of Measurement
</AccordionToggle>
<Accordion.Collapse eventKey={categories.length + 1}>
<Card.Body className={`${styles.accordionCollapse}`}>
<UnitsTable invUnits={invUnits} />
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
{/* Category Cards Grid */}
<div className={styles.categoryGrid}>
{categories.map(({ label, route }) => (
<Link key={label} to={route} className={styles.categoryCard}>
<span className={styles.categoryCardLabel}>{label}</span>
<div className={styles.categoryCardArrow}>›</div>
</Link>
))}
</div>

<div className={`${styles.buttonContainer}`}>
<Button variant="primary" className={`${styles.backButton}`} onClick={handleBack}>
Back to previous list page
</Button>
{/* Unit of Measurement */}
<div className={styles.unitSection}>
<h2 className={styles.unitSectionTitle}>Unit of Measurement</h2>
<Accordion>
<Card className={styles.unitCard}>
<AccordionToggle as={Card.Header} eventKey={1} className={styles.cardHeader}>
View all units
</AccordionToggle>
<Accordion.Collapse eventKey={1}>
<Card.Body className={styles.accordionCollapse}>
<UnitsTable invUnits={invUnits} />
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
</div>
);
Expand Down
Loading
Loading